Skip to content

Commit 26a97bf

Browse files
committed
object: make Decode take a hash.Hash as parameter
In most cases, we can determine the object ID algorithm in use from its length without much difficulty. However, for trees, the data is stored in a binary format, and consequently it's not possible to correctly parse a tree without knowing the hash algorithm in use. Let's pass the hash algorithm down through the Decode function so we can know the correct length to parse. While we're at it, increase the buffer length for the tree parsing code and make it work for both SHA-1 and SHA-256.
1 parent 67c4825 commit 26a97bf

11 files changed

+36
-22
lines changed

blob.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gitobj
33
import (
44
"bytes"
55
"fmt"
6+
"hash"
67
"io"
78
"os"
89
)
@@ -75,7 +76,7 @@ func (b *Blob) Type() ObjectType { return BlobObjectType }
7576
// stream, which is always zero.
7677
//
7778
// If any errors are encountered while reading the blob, they will be returned.
78-
func (b *Blob) Decode(r io.Reader, size int64) (n int, err error) {
79+
func (b *Blob) Decode(hash hash.Hash, r io.Reader, size int64) (n int, err error) {
7980
b.Size = size
8081
b.Contents = io.LimitReader(r, size)
8182

blob_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gitobj
22

33
import (
44
"bytes"
5+
"crypto/sha1"
56
"errors"
67
"io/ioutil"
78
"strings"
@@ -48,7 +49,7 @@ func TestBlobDecoding(t *testing.T) {
4849
from := strings.NewReader(contents)
4950

5051
b := new(Blob)
51-
n, err := b.Decode(from, int64(len(contents)))
52+
n, err := b.Decode(sha1.New(), from, int64(len(contents)))
5253

5354
assert.Equal(t, 0, n)
5455
assert.Nil(t, err)

commit.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"encoding/hex"
77
"fmt"
8+
"hash"
89
"io"
910
"strings"
1011
"time"
@@ -91,12 +92,12 @@ func (c *Commit) Type() ObjectType { return CommitObjectType }
9192
//
9293
// If any error was encountered along the way, that will be returned, along with
9394
// the number of bytes read up to that point.
94-
func (c *Commit) Decode(from io.Reader, size int64) (n int, err error) {
95+
func (c *Commit) Decode(hash hash.Hash, from io.Reader, size int64) (n int, err error) {
9596
var finishedHeaders bool
9697
var messageParts []string
9798

9899
s := bufio.NewScanner(from)
99-
s.Buffer(nil, 1024 * 1024)
100+
s.Buffer(nil, 1024*1024)
100101
for s.Scan() {
101102
text := s.Text()
102103
n = n + len(text+"\n")

commit_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gitobj
22

33
import (
44
"bytes"
5+
"crypto/sha1"
56
"encoding/hex"
67
"fmt"
78
"io"
@@ -77,7 +78,7 @@ func TestCommitDecoding(t *testing.T) {
7778
flen := from.Len()
7879

7980
commit := new(Commit)
80-
n, err := commit.Decode(from, int64(flen))
81+
n, err := commit.Decode(sha1.New(), from, int64(flen))
8182

8283
assert.Nil(t, err)
8384
assert.Equal(t, flen, n)
@@ -107,7 +108,7 @@ func TestCommitDecodingWithEmptyName(t *testing.T) {
107108
flen := from.Len()
108109

109110
commit := new(Commit)
110-
n, err := commit.Decode(from, int64(flen))
111+
n, err := commit.Decode(sha1.New(), from, int64(flen))
111112

112113
assert.Nil(t, err)
113114
assert.Equal(t, flen, n)
@@ -138,7 +139,7 @@ func TestCommitDecodingWithLargeCommitMessage(t *testing.T) {
138139
flen := from.Len()
139140

140141
commit := new(Commit)
141-
n, err := commit.Decode(from, int64(flen))
142+
n, err := commit.Decode(sha1.New(), from, int64(flen))
142143

143144
assert.Nil(t, err)
144145
assert.Equal(t, flen, n)
@@ -164,7 +165,7 @@ func TestCommitDecodingWithMessageKeywordPrefix(t *testing.T) {
164165
flen := from.Len()
165166

166167
commit := new(Commit)
167-
n, err := commit.Decode(from, int64(flen))
168+
n, err := commit.Decode(sha1.New(), from, int64(flen))
168169

169170
assert.NoError(t, err)
170171
assert.Equal(t, flen, n)
@@ -191,7 +192,7 @@ func TestCommitDecodingWithWhitespace(t *testing.T) {
191192
flen := from.Len()
192193

193194
commit := new(Commit)
194-
n, err := commit.Decode(from, int64(flen))
195+
n, err := commit.Decode(sha1.New(), from, int64(flen))
195196

196197
assert.NoError(t, err)
197198
assert.Equal(t, flen, n)
@@ -221,7 +222,7 @@ func TestCommitDecodingMultilineHeader(t *testing.T) {
221222
flen := from.Len()
222223

223224
commit := new(Commit)
224-
n, err := commit.Decode(from, int64(flen))
225+
n, err := commit.Decode(sha1.New(), from, int64(flen))
225226

226227
require.Nil(t, err)
227228
require.Equal(t, flen, n)

object.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package gitobj
22

3-
import "io"
3+
import (
4+
"hash"
5+
"io"
6+
)
47

58
// Object is an interface satisfied by any concrete type that represents a loose
69
// Git object.
@@ -29,7 +32,7 @@ type Object interface {
2932
//
3033
// If an(y) error was encountered, it should be returned immediately,
3134
// along with the number of bytes read up to that point.
32-
Decode(from io.Reader, size int64) (n int, err error)
35+
Decode(hash hash.Hash, from io.Reader, size int64) (n int, err error)
3336

3437
// Type returns the ObjectType constant that represents an instance of
3538
// the implementing type.

object_db.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ func (o *ObjectDatabase) decode(r *ObjectReader, into Object) error {
370370
return &UnexpectedObjectType{Got: typ, Wanted: into.Type()}
371371
}
372372

373-
if _, err = into.Decode(r, size); err != nil {
373+
if _, err = into.Decode(o.Hasher(), r, size); err != nil {
374374
return err
375375
}
376376

object_db_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gitobj
33
import (
44
"bytes"
55
"compress/zlib"
6+
"crypto/sha1"
67
"encoding/hex"
78
"fmt"
89
"io"
@@ -270,6 +271,7 @@ func TestWriteCommitWithGPGSignature(t *testing.T) {
270271

271272
commit := new(Commit)
272273
_, err = commit.Decode(
274+
sha1.New(),
273275
strings.NewReader(roundTripCommit), int64(len(roundTripCommit)))
274276
require.NoError(t, err)
275277

tag.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"encoding/hex"
77
"fmt"
8+
"hash"
89
"io"
910
"strings"
1011
)
@@ -24,7 +25,7 @@ type Tag struct {
2425
//
2526
// If any error was encountered along the way it will be returned, and the
2627
// receiving *Tag is considered invalid.
27-
func (t *Tag) Decode(r io.Reader, size int64) (int, error) {
28+
func (t *Tag) Decode(hash hash.Hash, r io.Reader, size int64) (int, error) {
2829
scanner := bufio.NewScanner(io.LimitReader(r, size))
2930

3031
var (

tag_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gitobj
22

33
import (
44
"bytes"
5+
"crypto/sha1"
56
"fmt"
67
"testing"
78

@@ -52,7 +53,7 @@ func TestTagDecode(t *testing.T) {
5253
flen := from.Len()
5354

5455
tag := new(Tag)
55-
n, err := tag.Decode(from, int64(flen))
56+
n, err := tag.Decode(sha1.New(), from, int64(flen))
5657

5758
assert.Nil(t, err)
5859
assert.Equal(t, n, flen)

tree.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"bytes"
66
"fmt"
7+
"hash"
78
"io"
89
"sort"
910
"strconv"
@@ -27,7 +28,8 @@ func (t *Tree) Type() ObjectType { return TreeObjectType }
2728
//
2829
// If any error was encountered along the way, that will be returned, along with
2930
// the number of bytes read up to that point.
30-
func (t *Tree) Decode(from io.Reader, size int64) (n int, err error) {
31+
func (t *Tree) Decode(hash hash.Hash, from io.Reader, size int64) (n int, err error) {
32+
hashlen := hash.Size()
3133
buf := bufio.NewReader(from)
3234

3335
var entries []*TreeEntry
@@ -51,15 +53,15 @@ func (t *Tree) Decode(from io.Reader, size int64) (n int, err error) {
5153
n += len(fname)
5254
fname = strings.TrimSuffix(fname, "\x00")
5355

54-
var sha [20]byte
55-
if _, err = io.ReadFull(buf, sha[:]); err != nil {
56+
var sha [32]byte
57+
if _, err = io.ReadFull(buf, sha[:hashlen]); err != nil {
5658
return n, err
5759
}
58-
n += 20
60+
n += hashlen
5961

6062
entries = append(entries, &TreeEntry{
6163
Name: fname,
62-
Oid: sha[:],
64+
Oid: sha[:hashlen],
6365
Filemode: int32(mode),
6466
})
6567
}

tree_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gitobj
33
import (
44
"bufio"
55
"bytes"
6+
"crypto/sha1"
67
"fmt"
78
"sort"
89
"strconv"
@@ -68,7 +69,7 @@ func TestTreeDecoding(t *testing.T) {
6869
flen := from.Len()
6970

7071
tree := new(Tree)
71-
n, err := tree.Decode(from, int64(flen))
72+
n, err := tree.Decode(sha1.New(), from, int64(flen))
7273

7374
assert.Nil(t, err)
7475
assert.Equal(t, flen, n)
@@ -106,7 +107,7 @@ func TestTreeDecodingShaBoundary(t *testing.T) {
106107
flen := from.Len()
107108

108109
tree := new(Tree)
109-
n, err := tree.Decode(bufio.NewReaderSize(&from, flen-2), int64(flen))
110+
n, err := tree.Decode(sha1.New(), bufio.NewReaderSize(&from, flen-2), int64(flen))
110111

111112
assert.Nil(t, err)
112113
assert.Equal(t, flen, n)

0 commit comments

Comments
 (0)