Skip to content

Commit ffe5ffc

Browse files
bk2204chrisd8088
andcommitted
pack: support SHA-256 in v1 indices
Let's add support for handling SHA-256 in v1 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. Co-authored-by: Chris Darroch <chrisd8088@github.com>
1 parent 841e05c commit ffe5ffc

File tree

2 files changed

+47
-49
lines changed

2 files changed

+47
-49
lines changed

pack/index_v1.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@ type V1 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 v1 index file "idx".
1515
func (v *V1) Name(idx *Index, at int64) ([]byte, error) {
16-
var sha [20]byte
17-
if _, err := idx.readAt(sha[:], v1ShaOffset(at)); err != nil {
16+
var sha [maxHashSize]byte
17+
18+
hashlen := v.hash.Size()
19+
20+
if _, err := idx.readAt(sha[:hashlen], v1ShaOffset(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 v1 packfiles by parsing and returning
2528
// the IndexEntry specified at the offset "at" in the given index file.
2629
func (v *V1) Entry(idx *Index, at int64) (*IndexEntry, error) {
2730
var offs [4]byte
28-
if _, err := idx.readAt(offs[:], v1EntryOffset(at)); err != nil {
31+
if _, err := idx.readAt(offs[:], v1EntryOffset(at, int64(v.hash.Size()))); err != nil {
2932
return nil, err
3033
}
3134

@@ -41,19 +44,19 @@ func (v *V1) Width() int64 {
4144
}
4245

4346
// v1ShaOffset returns the location of the SHA1 of an object given at "at".
44-
func v1ShaOffset(at int64) int64 {
47+
func v1ShaOffset(at int64, hashlen int64) int64 {
4548
// Skip forward until the desired entry.
46-
return v1EntryOffset(at) +
49+
return v1EntryOffset(at, hashlen) +
4750
// Skip past the 4-byte object offset in the desired entry to
4851
// the SHA1.
4952
indexObjectSmallOffsetWidth
5053
}
5154

5255
// v1EntryOffset returns the location of the packfile offset for the object
5356
// given at "at".
54-
func v1EntryOffset(at int64) int64 {
57+
func v1EntryOffset(at int64, hashlen int64) int64 {
5558
// Skip the L1 fanout table
5659
return indexOffsetV1Start +
5760
// Skip the object entries before the one located at "at"
58-
(indexObjectEntryV1Width * at)
61+
((hashlen + indexObjectSmallOffsetWidth) * at)
5962
}

pack/index_v1_test.go

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,59 +3,37 @@ 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"
1012
)
1113

1214
var (
1315
V1IndexFanout = make([]uint32, indexFanoutEntries)
14-
15-
V1IndexSmallEntry = []byte{
16-
0x0, 0x0, 0x0, 0x1,
17-
18-
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
19-
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
20-
}
21-
V1IndexSmallSha = V1IndexSmallEntry[4:]
22-
23-
V1IndexMediumEntry = []byte{
24-
0x0, 0x0, 0x0, 0x2,
25-
26-
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
27-
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
28-
}
29-
V1IndexMediumSha = V1IndexMediumEntry[4:]
30-
31-
V1IndexLargeEntry = []byte{
32-
0x0, 0x0, 0x0, 0x3,
33-
34-
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
35-
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
36-
}
37-
V1IndexLargeSha = V1IndexLargeEntry[4:]
38-
39-
V1Index = &Index{
40-
fanout: V1IndexFanout,
41-
version: &V1{hash: sha1.New()},
42-
}
4316
)
4417

4518
func TestIndexV1SearchExact(t *testing.T) {
46-
v := &V1{hash: sha1.New()}
47-
e, err := v.Entry(V1Index, 1)
19+
for _, algo := range []hash.Hash{sha1.New(), sha256.New()} {
20+
index := newV1Index(algo)
21+
v := &V1{hash: algo}
22+
e, err := v.Entry(index, 1)
4823

49-
assert.NoError(t, err)
50-
assert.EqualValues(t, 2, e.PackOffset)
24+
assert.NoError(t, err)
25+
assert.EqualValues(t, 2, e.PackOffset)
26+
}
5127
}
5228

5329
func TestIndexVersionWidthV1(t *testing.T) {
54-
v := &V1{hash: sha1.New()}
55-
assert.EqualValues(t, 0, v.Width())
30+
for _, algo := range []hash.Hash{sha1.New(), sha256.New()} {
31+
v := &V1{hash: algo}
32+
assert.EqualValues(t, 0, v.Width())
33+
}
5634
}
5735

58-
func init() {
36+
func newV1Index(hash hash.Hash) *Index {
5937
V1IndexFanout[1] = 1
6038
V1IndexFanout[2] = 2
6139
V1IndexFanout[3] = 3
@@ -69,12 +47,29 @@ func init() {
6947
binary.BigEndian.PutUint32(fanout[i*indexFanoutEntryWidth:], n)
7048
}
7149

72-
buf := make([]byte, 0, indexOffsetV1Start+(3*indexObjectEntryV1Width))
50+
hashlen := hash.Size()
51+
entrylen := hashlen + indexObjectCRCWidth
52+
entries := make([]byte, entrylen*3)
53+
54+
for i := 0; i < 3; i++ {
55+
// For each entry, set the first three bytes to 0 and the
56+
// remainder to the same value. That creates an initial 4-byte
57+
// CRC field with the value of i+1, followed by a series of data
58+
// bytes which all have that same value.
59+
for j := entrylen*i + 3; j < entrylen*(i+1); j++ {
60+
entries[j] = byte(i + 1)
61+
}
62+
}
63+
64+
buf := make([]byte, 0, indexOffsetV1Start)
7365

7466
buf = append(buf, fanout...)
75-
buf = append(buf, V1IndexSmallEntry...)
76-
buf = append(buf, V1IndexMediumEntry...)
77-
buf = append(buf, V1IndexLargeEntry...)
67+
buf = append(buf, entries...)
68+
69+
return &Index{
70+
fanout: V1IndexFanout,
71+
version: &V1{hash: hash},
72+
r: bytes.NewReader(buf),
73+
}
7874

79-
V1Index.r = bytes.NewReader(buf)
8075
}

0 commit comments

Comments
 (0)