github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/git/odb/pack/index_v2.go (about) 1 package pack 2 3 import ( 4 "encoding/binary" 5 ) 6 7 // V2 implements IndexVersion for v2 packfiles. 8 type V2 struct{} 9 10 // Name implements IndexVersion.Name by returning the 20 byte SHA-1 object name 11 // for the given entry at offset "at" in the v2 index file "idx". 12 func (v *V2) Name(idx *Index, at int64) ([]byte, error) { 13 var sha [20]byte 14 if _, err := idx.readAt(sha[:], v2ShaOffset(at)); err != nil { 15 return nil, err 16 } 17 18 return sha[:], nil 19 } 20 21 // Entry implements IndexVersion.Entry for v2 packfiles by parsing and returning 22 // the IndexEntry specified at the offset "at" in the given index file. 23 func (v *V2) Entry(idx *Index, at int64) (*IndexEntry, error) { 24 var offs [4]byte 25 if _, err := idx.readAt(offs[:], v2SmallOffsetOffset(at, int64(idx.Count()))); err != nil { 26 return nil, err 27 } 28 29 loc := uint64(binary.BigEndian.Uint32(offs[:])) 30 if loc&0x80000000 > 0 { 31 // If the most significant bit (MSB) of the offset is set, then 32 // the offset encodes the indexed location for an 8-byte offset. 33 // 34 // Mask away (offs&0x7fffffff) the MSB to use as an index to 35 // find the offset of the 8-byte pack offset. 36 lo := v2LargeOffsetOffset(int64(loc&0x7fffffff), int64(idx.Count())) 37 38 var offs [8]byte 39 if _, err := idx.readAt(offs[:], lo); err != nil { 40 return nil, err 41 } 42 43 loc = binary.BigEndian.Uint64(offs[:]) 44 } 45 return &IndexEntry{PackOffset: loc}, nil 46 } 47 48 // Width implements IndexVersion.Width() by returning the number of bytes that 49 // v2 packfile index header occupy. 50 func (v *V2) Width() int64 { 51 return indexV2Width 52 } 53 54 // v2ShaOffset returns the offset of a SHA1 given at "at" in the V2 index file. 55 func v2ShaOffset(at int64) int64 { 56 // Skip the packfile index header and the L1 fanout table. 57 return indexOffsetV2Start + 58 // Skip until the desired name in the sorted names table. 59 (indexObjectNameWidth * at) 60 } 61 62 // v2SmallOffsetOffset returns the offset of an object's small (4-byte) offset 63 // given by "at". 64 func v2SmallOffsetOffset(at, total int64) int64 { 65 // Skip the packfile index header and the L1 fanout table. 66 return indexOffsetV2Start + 67 // Skip the name table. 68 (indexObjectNameWidth * total) + 69 // Skip the CRC table. 70 (indexObjectCRCWidth * total) + 71 // Skip until the desired index in the small offsets table. 72 (indexObjectSmallOffsetWidth * at) 73 } 74 75 // v2LargeOffsetOffset returns the offset of an object's large (4-byte) offset, 76 // given by the index "at". 77 func v2LargeOffsetOffset(at, total int64) int64 { 78 // Skip the packfile index header and the L1 fanout table. 79 return indexOffsetV2Start + 80 // Skip the name table. 81 (indexObjectNameWidth * total) + 82 // Skip the CRC table. 83 (indexObjectCRCWidth * total) + 84 // Skip the small offsets table. 85 (indexObjectSmallOffsetWidth * total) + 86 // Seek to the large offset within the large offset(s) table. 87 (indexObjectLargeOffsetWidth * at) 88 }