Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 854ffa1

Browse files
authored
Merge pull request #512 from mcuadros/idx-64bits
format: idxfile, support for >2Gb packfiles
2 parents c256136 + 48900a1 commit 854ffa1

File tree

6 files changed

+123
-2
lines changed

6 files changed

+123
-2
lines changed

plumbing/format/idxfile/decoder.go

+14
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func readCRC32(idx *Idxfile, r io.Reader) error {
123123

124124
func readOffsets(idx *Idxfile, r io.Reader) error {
125125
c := int(idx.ObjectCount)
126+
126127
for i := 0; i < c; i++ {
127128
o, err := binary.ReadUint32(r)
128129
if err != nil {
@@ -132,6 +133,19 @@ func readOffsets(idx *Idxfile, r io.Reader) error {
132133
idx.Entries[i].Offset = uint64(o)
133134
}
134135

136+
for i := 0; i < c; i++ {
137+
if idx.Entries[i].Offset <= offsetLimit {
138+
continue
139+
}
140+
141+
o, err := binary.ReadUint64(r)
142+
if err != nil {
143+
return err
144+
}
145+
146+
idx.Entries[i].Offset = o
147+
}
148+
135149
return nil
136150
}
137151

plumbing/format/idxfile/decoder_test.go

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

33
import (
44
"bytes"
5+
"encoding/base64"
56
"fmt"
67
"testing"
78

@@ -65,3 +66,76 @@ func (s *IdxfileSuite) TestDecodeCRCs(c *C) {
6566

6667
c.Assert(idx.Entries, DeepEquals, i.Entries)
6768
}
69+
70+
func (s *IdxfileSuite) TestDecode64bitsOffsets(c *C) {
71+
f := bytes.NewBufferString(fixtureLarge4GB)
72+
73+
idx := &Idxfile{}
74+
75+
d := NewDecoder(base64.NewDecoder(base64.StdEncoding, f))
76+
err := d.Decode(idx)
77+
c.Assert(err, IsNil)
78+
79+
expected := map[string]uint64{
80+
"303953e5aa461c203a324821bc1717f9b4fff895": 12,
81+
"5296768e3d9f661387ccbff18c4dea6c997fd78c": 142,
82+
"03fc8d58d44267274edef4585eaeeb445879d33f": 1601322837,
83+
"8f3ceb4ea4cb9e4a0f751795eb41c9a4f07be772": 2646996529,
84+
"e0d1d625010087f79c9e01ad9d8f95e1628dda02": 3452385606,
85+
"90eba326cdc4d1d61c5ad25224ccbf08731dd041": 3707047470,
86+
"bab53055add7bc35882758a922c54a874d6b1272": 5323223332,
87+
"1b8995f51987d8a449ca5ea4356595102dc2fbd4": 5894072943,
88+
"35858be9c6f5914cbe6768489c41eb6809a2bceb": 5924278919,
89+
}
90+
91+
for _, e := range idx.Entries {
92+
c.Assert(expected[e.Hash.String()], Equals, e.Offset)
93+
}
94+
}
95+
96+
func (s *IdxfileSuite) TestDecode64bitsOffsetsIdempotent(c *C) {
97+
f := bytes.NewBufferString(fixtureLarge4GB)
98+
99+
expected := &Idxfile{}
100+
101+
d := NewDecoder(base64.NewDecoder(base64.StdEncoding, f))
102+
err := d.Decode(expected)
103+
c.Assert(err, IsNil)
104+
105+
buf := bytes.NewBuffer(nil)
106+
_, err = NewEncoder(buf).Encode(expected)
107+
c.Assert(err, IsNil)
108+
109+
idx := &Idxfile{}
110+
err = NewDecoder(buf).Decode(idx)
111+
c.Assert(err, IsNil)
112+
113+
c.Assert(idx.Entries, DeepEquals, expected.Entries)
114+
}
115+
116+
const fixtureLarge4GB = `/3RPYwAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEA
117+
AAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA
118+
AAEAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAA
119+
AgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAADAAAAAwAAAAMAAAADAAAAAwAAAAQAAAAE
120+
AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQA
121+
AAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABQAA
122+
AAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAA
123+
BQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAF
124+
AAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUA
125+
AAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAA
126+
AAUAAAAFAAAABQAAAAYAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAA
127+
BwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAH
128+
AAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcA
129+
AAAHAAAABwAAAAcAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAA
130+
AAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAA
131+
CAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAkAAAAJ
132+
AAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkA
133+
AAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAA
134+
AAkAAAAJA/yNWNRCZydO3vRYXq7rRFh50z8biZX1GYfYpEnKXqQ1ZZUQLcL71DA5U+WqRhwgOjJI
135+
IbwXF/m0//iVNYWL6cb1kUy+Z2hInEHraAmivOtSlnaOPZ9mE4fMv/GMTepsmX/XjI88606ky55K
136+
D3UXletByaTwe+dykOujJs3E0dYcWtJSJMy/CHMd0EG6tTBVrde8NYgnWKkixUqHTWsScuDR1iUB
137+
AIf3nJ4BrZ2PleFijdoCkp36qiGHwFa8NHxMnInZ0s3CKEKmHe+KcZPzuqwmm44GvqGAX3I/VYAA
138+
AAAAAAAMgAAAAQAAAI6AAAACgAAAA4AAAASAAAAFAAAAAV9Qam8AAAABYR1ShwAAAACdxfYxAAAA
139+
ANz1Di4AAAABPUnxJAAAAADNxzlGr6vCJpIFz4XaG/fi/f9C9zgQ8ptKSQpfQ1NMJBGTDTxxYGGp
140+
ch2xUA==
141+
`

plumbing/format/idxfile/encoder.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,28 @@ func (e *Encoder) encodeCRC32(idx *Idxfile) (int, error) {
9898

9999
func (e *Encoder) encodeOffsets(idx *Idxfile) (int, error) {
100100
sz := 0
101+
102+
var o64bits []uint64
101103
for _, ent := range idx.Entries {
102-
if err := binary.WriteUint32(e, uint32(ent.Offset)); err != nil {
104+
o := ent.Offset
105+
if o > offsetLimit {
106+
o64bits = append(o64bits, o)
107+
o = offsetLimit + uint64(len(o64bits))
108+
}
109+
110+
if err := binary.WriteUint32(e, uint32(o)); err != nil {
103111
return sz, err
104112
}
105113

106114
sz += 4
115+
}
116+
117+
for _, o := range o64bits {
118+
if err := binary.WriteUint64(e, o); err != nil {
119+
return sz, err
120+
}
107121

122+
sz += 8
108123
}
109124

110125
return sz, nil

plumbing/format/idxfile/idxfile.go

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import "gopkg.in/src-d/go-git.v4/plumbing"
55
const (
66
// VersionSupported is the only idx version supported.
77
VersionSupported = 2
8+
9+
offsetLimit = 0x7fffffff
810
)
911

1012
var (

utils/binary/read.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,17 @@ const (
9494
lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length
9595
)
9696

97-
// ReadUint32 reads 4 bytes and returns them as a Big ndian uint32
97+
// ReadUint64 reads 8 bytes and returns them as a BigEndian uint32
98+
func ReadUint64(r io.Reader) (uint64, error) {
99+
var v uint64
100+
if err := binary.Read(r, binary.BigEndian, &v); err != nil {
101+
return 0, err
102+
}
103+
104+
return v, nil
105+
}
106+
107+
// ReadUint32 reads 4 bytes and returns them as a BigEndian uint32
98108
func ReadUint32(r io.Reader) (uint32, error) {
99109
var v uint32
100110
if err := binary.Read(r, binary.BigEndian, &v); err != nil {

utils/binary/write.go

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ func WriteVariableWidthInt(w io.Writer, n int64) error {
3131
return err
3232
}
3333

34+
// WriteUint64 writes the binary representation of a uint64 into w, in BigEndian
35+
// order
36+
func WriteUint64(w io.Writer, value uint64) error {
37+
return binary.Write(w, binary.BigEndian, value)
38+
}
39+
3440
// WriteUint32 writes the binary representation of a uint32 into w, in BigEndian
3541
// order
3642
func WriteUint32(w io.Writer, value uint32) error {

0 commit comments

Comments
 (0)