aboutsummaryrefslogtreecommitdiff
path: root/pack_midx.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2025-11-20 08:00:00 +0800
committerGravatar Runxi Yu2025-11-20 08:00:00 +0800
commitfc157e9c71a0c64ff27ff0428eb68ca5660dd495 (patch)
treeab0c885ada4ae9b121b23e37e554bb763fe1019d /pack_midx.go
parentrefs: Support resolving hashes as refs (diff)
signatureNo signature
Revert "Add initial support for multi pack indexes"
This reverts commit 6f8acbf1503d2fa1ef705d35a743fc6b279942e5. Apparently my MIDX support is broken and it breaks some repos... it'll be added back when ready.
Diffstat (limited to 'pack_midx.go')
-rw-r--r--pack_midx.go313
1 files changed, 0 insertions, 313 deletions
diff --git a/pack_midx.go b/pack_midx.go
deleted file mode 100644
index 748bdaf6..00000000
--- a/pack_midx.go
+++ /dev/null
@@ -1,313 +0,0 @@
-package furgit
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "syscall"
-)
-
-const (
- midxMagic = 0x4d494458 // MIDX
- midxVersion = 1
-
- midxOIDVersionSHA1 = 1
- midxOIDVersionSHA256 = 2
-
- chunkPNAM = 0x504e414d // PNAM
- chunkOIDF = 0x4f494446 // OIDF
- chunkOIDL = 0x4f49444c // OIDL
- chunkOOFF = 0x4f4f4646 // OOFF
- chunkLOFF = 0x4c4f4646 // LOFF
-)
-
-type multiPackIndex struct {
- repo *Repository
-
- loadOnce sync.Once
- loadErr error
-
- numPacks int
- numObjects int
- packNames []string
- fanout []byte
- oids []byte
- offsets []byte
- largeOffs []byte
- data []byte
-
- closeOnce sync.Once
-}
-
-func (midx *multiPackIndex) Close() error {
- if midx == nil {
- return nil
- }
- var closeErr error
- midx.closeOnce.Do(func() {
- if len(midx.data) > 0 {
- if err := syscall.Munmap(midx.data); closeErr == nil {
- closeErr = err
- }
- midx.data = nil
- midx.fanout = nil
- midx.oids = nil
- midx.offsets = nil
- midx.largeOffs = nil
- midx.packNames = nil
- midx.numObjects = 0
- midx.numPacks = 0
- }
- })
- return closeErr
-}
-
-func (midx *multiPackIndex) ensureLoaded() error {
- midx.loadOnce.Do(func() {
- midx.loadErr = midx.load()
- })
- return midx.loadErr
-}
-
-func (midx *multiPackIndex) load() error {
- if midx.repo == nil {
- return ErrInvalidObject
- }
- path := midx.repo.repoPath(filepath.Join("objects", "pack", "multi-pack-index"))
- f, err := os.Open(path)
- if err != nil {
- return err
- }
- stat, err := f.Stat()
- if err != nil {
- _ = f.Close()
- return err
- }
- if stat.Size() < 12 {
- _ = f.Close()
- return ErrInvalidObject
- }
- region, err := syscall.Mmap(
- int(f.Fd()),
- 0,
- int(stat.Size()),
- syscall.PROT_READ,
- syscall.MAP_PRIVATE,
- )
- if err != nil {
- _ = f.Close()
- return err
- }
- err = f.Close()
- if err != nil {
- _ = syscall.Munmap(region)
- return err
- }
- err = midx.parse(region)
- if err != nil {
- _ = syscall.Munmap(region)
- return err
- }
- midx.data = region
- return nil
-}
-
-func (midx *multiPackIndex) parse(buf []byte) error {
- if len(buf) < 12 {
- return ErrInvalidObject
- }
-
- if readBE32(buf[0:4]) != midxMagic {
- return ErrInvalidObject
- }
- if buf[4] != midxVersion {
- return ErrInvalidObject
- }
- oidVersion := buf[5]
- if oidVersion != midxOIDVersionSHA1 && oidVersion != midxOIDVersionSHA256 {
- return ErrInvalidObject
- }
- numChunks := int(buf[6])
- numBaseMIDX := int(buf[7])
- if numBaseMIDX != 0 {
- return ErrInvalidObject
- }
- numPacks := int(readBE32(buf[8:12]))
-
- chunkTableStart := 12
- chunkTableSize := (numChunks + 1) * 12
- if len(buf) < chunkTableStart+chunkTableSize {
- return ErrInvalidObject
- }
-
- chunks := make(map[uint32]int64)
- for i := 0; i < numChunks; i++ {
- chunkStart := chunkTableStart + i*12
- chunkID := readBE32(buf[chunkStart : chunkStart+4])
- chunkOffset := int64(readBE64(buf[chunkStart+4 : chunkStart+12]))
- chunks[chunkID] = chunkOffset
- }
-
- pnamOffset, ok := chunks[chunkPNAM]
- if !ok {
- return ErrInvalidObject
- }
- if pnamOffset < 0 || pnamOffset >= int64(len(buf)) {
- return ErrInvalidObject
- }
-
- nextOffset := int64(len(buf))
- for _, offset := range chunks {
- if offset > pnamOffset && offset < nextOffset {
- nextOffset = offset
- }
- }
-
- pnamData := buf[pnamOffset:nextOffset]
- packNames := make([]string, 0, numPacks)
- start := 0
- for i := 0; i < numPacks; i++ {
- end := start
- for end < len(pnamData) && pnamData[end] != 0 {
- end++
- }
- if end >= len(pnamData) {
- return ErrInvalidObject
- }
- name := string(pnamData[start:end])
- if strings.HasSuffix(name, ".idx") { // why...
- name = name[:len(name)-4] + ".pack"
- }
- packNames = append(packNames, name)
- start = end + 1
- }
-
- oidfOffset, ok := chunks[chunkOIDF]
- if !ok {
- return ErrInvalidObject
- }
- if oidfOffset < 0 || oidfOffset+256*4 > int64(len(buf)) {
- return ErrInvalidObject
- }
- fanout := buf[oidfOffset : oidfOffset+256*4]
- numObjects := int(readBE32(fanout[len(fanout)-4:]))
-
- oidlOffset, ok := chunks[chunkOIDL]
- if !ok {
- return ErrInvalidObject
- }
- oidlSize := int64(numObjects) * int64(midx.repo.hashSize)
- if oidlOffset < 0 || oidlOffset+oidlSize > int64(len(buf)) {
- return ErrInvalidObject
- }
- oids := buf[oidlOffset : oidlOffset+oidlSize]
-
- ooffOffset, ok := chunks[chunkOOFF]
- if !ok {
- return ErrInvalidObject
- }
- ooffSize := int64(numObjects) * 8
- if ooffOffset < 0 || ooffOffset+ooffSize > int64(len(buf)) {
- return ErrInvalidObject
- }
- offsets := buf[ooffOffset : ooffOffset+ooffSize]
-
- var largeOffs []byte
- if loffOffset, ok := chunks[chunkLOFF]; ok {
- loffEnd := int64(len(buf))
- for _, offset := range chunks {
- if offset > loffOffset && offset < loffEnd {
- loffEnd = offset
- }
- }
- if loffOffset < 0 || loffOffset > int64(len(buf)) {
- return ErrInvalidObject
- }
- largeOffs = buf[loffOffset:loffEnd]
- }
-
- midx.numPacks = numPacks
- midx.numObjects = numObjects
- midx.packNames = packNames
- midx.fanout = fanout
- midx.oids = oids
- midx.offsets = offsets
- midx.largeOffs = largeOffs
- return nil
-}
-
-func (midx *multiPackIndex) lookup(id Hash) (packlocation, error) {
- if len(midx.data) == 0 {
- err := midx.ensureLoaded()
- if err != nil {
- return packlocation{}, err
- }
- }
-
- if id.size != midx.repo.hashSize {
- return packlocation{}, fmt.Errorf("furgit: hash size mismatch: got %d, expected %d", id.size, midx.repo.hashSize)
- }
-
- first := int(id.data[0])
- var lo int
- if first > 0 {
- lo = int(readBE32(midx.fanout[(first-1)*4 : first*4]))
- }
- hi := int(readBE32(midx.fanout[first*4 : (first+1)*4]))
-
- idx, found := bsearchHash(midx.oids, midx.repo.hashSize, lo, hi, id)
- if !found {
- return packlocation{}, ErrNotFound
- }
-
- offsetEntry := midx.offsets[idx*8 : (idx+1)*8]
- packIntID := readBE32(offsetEntry[0:4])
- offset := readBE32(offsetEntry[4:8])
-
- if int(packIntID) >= len(midx.packNames) {
- return packlocation{}, ErrInvalidObject
- }
-
- var finalOffset uint64
- if offset&0x80000000 != 0 {
- if len(midx.largeOffs) == 0 {
- return packlocation{}, ErrInvalidObject
- }
- largeIdx := int(offset & 0x7fffffff)
- if largeIdx*8+8 > len(midx.largeOffs) {
- return packlocation{}, ErrInvalidObject
- }
- finalOffset = readBE64(midx.largeOffs[largeIdx*8 : largeIdx*8+8])
- } else {
- finalOffset = uint64(offset)
- }
-
- packName := midx.packNames[packIntID]
- packPath := filepath.Join("objects", "pack", packName)
-
- return packlocation{
- PackPath: packPath,
- Offset: finalOffset,
- }, nil
-}
-
-func (repo *Repository) multiPackIndex() (*multiPackIndex, error) {
- repo.midxOnce.Do(func() {
- repo.midx, repo.midxErr = repo.loadMultiPackIndex()
- })
- return repo.midx, repo.midxErr
-}
-
-func (repo *Repository) loadMultiPackIndex() (*multiPackIndex, error) {
- midx := &multiPackIndex{repo: repo}
- err := midx.ensureLoaded()
- if err != nil {
- if os.IsNotExist(err) {
- return nil, ErrNotFound
- }
- return nil, err
- }
- return midx, nil
-}