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  }