Skip to content

Commit 528473b

Browse files
committed
pack: support SHA-256 in v2 indices
Let's add support for handling SHA-256 in v2 indices by adjusting our buffer size and computing the offsets base on the hash length. Update our tests to be less SHA-1 centric by creating a new index for each test with appropriate test data.
1 parent ffe5ffc commit 528473b

File tree

2 files changed

+52
-44
lines changed

2 files changed

+52
-44
lines changed

pack/index_v2.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,25 @@ type V2 struct {
1313
// Name implements IndexVersion.Name by returning the 20 byte SHA-1 object name
1414
// for the given entry at offset "at" in the v2 index file "idx".
1515
func (v *V2) Name(idx *Index, at int64) ([]byte, error) {
16-
var sha [20]byte
17-
if _, err := idx.readAt(sha[:], v2ShaOffset(at)); err != nil {
16+
var sha [maxHashSize]byte
17+
18+
hashlen := v.hash.Size()
19+
20+
if _, err := idx.readAt(sha[:hashlen], v2ShaOffset(at, int64(hashlen))); err != nil {
1821
return nil, err
1922
}
2023

21-
return sha[:], nil
24+
return sha[:hashlen], nil
2225
}
2326

2427
// Entry implements IndexVersion.Entry for v2 packfiles by parsing and returning
2528
// the IndexEntry specified at the offset "at" in the given index file.
2629
func (v *V2) Entry(idx *Index, at int64) (*IndexEntry, error) {
2730
var offs [4]byte
28-
if _, err := idx.readAt(offs[:], v2SmallOffsetOffset(at, int64(idx.Count()))); err != nil {
31+
32+
hashlen := v.hash.Size()
33+
34+
if _, err := idx.readAt(offs[:], v2SmallOffsetOffset(at, int64(idx.Count()), int64(hashlen))); err != nil {
2935
return nil, err
3036
}
3137

@@ -36,7 +42,7 @@ func (v *V2) Entry(idx *Index, at int64) (*IndexEntry, error) {
3642
//
3743
// Mask away (offs&0x7fffffff) the MSB to use as an index to
3844
// find the offset of the 8-byte pack offset.
39-
lo := v2LargeOffsetOffset(int64(loc&0x7fffffff), int64(idx.Count()))
45+
lo := v2LargeOffsetOffset(int64(loc&0x7fffffff), int64(idx.Count()), int64(hashlen))
4046

4147
var offs [8]byte
4248
if _, err := idx.readAt(offs[:], lo); err != nil {
@@ -55,20 +61,20 @@ func (v *V2) Width() int64 {
5561
}
5662

5763
// v2ShaOffset returns the offset of a SHA1 given at "at" in the V2 index file.
58-
func v2ShaOffset(at int64) int64 {
64+
func v2ShaOffset(at int64, hashlen int64) int64 {
5965
// Skip the packfile index header and the L1 fanout table.
6066
return indexOffsetV2Start +
6167
// Skip until the desired name in the sorted names table.
62-
(indexObjectNameWidth * at)
68+
(hashlen * at)
6369
}
6470

6571
// v2SmallOffsetOffset returns the offset of an object's small (4-byte) offset
6672
// given by "at".
67-
func v2SmallOffsetOffset(at, total int64) int64 {
73+
func v2SmallOffsetOffset(at, total, hashlen int64) int64 {
6874
// Skip the packfile index header and the L1 fanout table.
6975
return indexOffsetV2Start +
7076
// Skip the name table.
71-
(indexObjectNameWidth * total) +
77+
(hashlen * total) +
7278
// Skip the CRC table.
7379
(indexObjectCRCWidth * total) +
7480
// Skip until the desired index in the small offsets table.
@@ -77,11 +83,11 @@ func v2SmallOffsetOffset(at, total int64) int64 {
7783

7884
// v2LargeOffsetOffset returns the offset of an object's large (4-byte) offset,
7985
// given by the index "at".
80-
func v2LargeOffsetOffset(at, total int64) int64 {
86+
func v2LargeOffsetOffset(at, total, hashlen int64) int64 {
8187
// Skip the packfile index header and the L1 fanout table.
8288
return indexOffsetV2Start +
8389
// Skip the name table.
84-
(indexObjectNameWidth * total) +
90+
(hashlen * total) +
8591
// Skip the CRC table.
8692
(indexObjectCRCWidth * total) +
8793
// Skip the small offsets table.

pack/index_v2_test.go

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package pack
33
import (
44
"bytes"
55
"crypto/sha1"
6+
"crypto/sha256"
67
"encoding/binary"
8+
"hash"
79
"testing"
810

911
"github.com/stretchr/testify/assert"
@@ -16,20 +18,6 @@ var (
1618
}
1719
V2IndexFanout = make([]uint32, indexFanoutEntries)
1820

19-
V2IndexNames = []byte{
20-
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
21-
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
22-
23-
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
24-
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
25-
26-
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
27-
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
28-
}
29-
V2IndexSmallSha = V2IndexNames[0:20]
30-
V2IndexMediumSha = V2IndexNames[20:40]
31-
V2IndexLargeSha = V2IndexNames[40:60]
32-
3321
V2IndexCRCs = []byte{
3422
0x0, 0x0, 0x0, 0x0,
3523
0x1, 0x1, 0x1, 0x1,
@@ -44,35 +32,38 @@ var (
4432
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // filler data
4533
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // large offset
4634
}
47-
48-
V2Index = &Index{
49-
fanout: V2IndexFanout,
50-
version: &V2{hash: sha1.New()},
51-
}
5235
)
5336

5437
func TestIndexV2EntryExact(t *testing.T) {
55-
v := &V2{hash: sha1.New()}
56-
e, err := v.Entry(V2Index, 1)
38+
for _, algo := range []hash.Hash{sha1.New(), sha256.New()} {
39+
index := newV2Index(algo)
40+
v := &V2{hash: algo}
41+
e, err := v.Entry(index, 1)
5742

58-
assert.NoError(t, err)
59-
assert.EqualValues(t, 2, e.PackOffset)
43+
assert.NoError(t, err)
44+
assert.EqualValues(t, 2, e.PackOffset)
45+
}
6046
}
6147

6248
func TestIndexV2EntryExtendedOffset(t *testing.T) {
63-
v := &V2{hash: sha1.New()}
64-
e, err := v.Entry(V2Index, 2)
49+
for _, algo := range []hash.Hash{sha1.New(), sha256.New()} {
50+
index := newV2Index(algo)
51+
v := &V2{hash: algo}
52+
e, err := v.Entry(index, 2)
6553

66-
assert.NoError(t, err)
67-
assert.EqualValues(t, 3, e.PackOffset)
54+
assert.NoError(t, err)
55+
assert.EqualValues(t, 3, e.PackOffset)
56+
}
6857
}
6958

7059
func TestIndexVersionWidthV2(t *testing.T) {
71-
v := &V2{hash: sha1.New()}
72-
assert.EqualValues(t, 8, v.Width())
60+
for _, algo := range []hash.Hash{sha1.New(), sha256.New()} {
61+
v := &V2{hash: algo}
62+
assert.EqualValues(t, 8, v.Width())
63+
}
7364
}
7465

75-
func init() {
66+
func newV2Index(hash hash.Hash) *Index {
7667
V2IndexFanout[1] = 1
7768
V2IndexFanout[2] = 2
7869
V2IndexFanout[3] = 3
@@ -86,12 +77,23 @@ func init() {
8677
binary.BigEndian.PutUint32(fanout[i*indexFanoutEntryWidth:], n)
8778
}
8879

89-
buf := make([]byte, 0, indexOffsetV2Start+3*(indexObjectEntryV2Width)+indexObjectLargeOffsetWidth)
80+
hashlen := hash.Size()
81+
names := make([]byte, hashlen*3)
82+
83+
for i := range names {
84+
names[i] = byte((i / hashlen) + 1)
85+
}
86+
87+
buf := make([]byte, 0, indexOffsetV2Start+3)
9088
buf = append(buf, V2IndexHeader...)
9189
buf = append(buf, fanout...)
92-
buf = append(buf, V2IndexNames...)
90+
buf = append(buf, names...)
9391
buf = append(buf, V2IndexCRCs...)
9492
buf = append(buf, V2IndexOffsets...)
9593

96-
V2Index.r = bytes.NewReader(buf)
94+
return &Index{
95+
fanout: V2IndexFanout,
96+
version: &V2{hash: hash},
97+
r: bytes.NewReader(buf),
98+
}
9799
}

0 commit comments

Comments
 (0)