1
1
package packfile
2
2
3
3
import (
4
+ "bufio"
4
5
"bytes"
5
6
"errors"
6
7
"io"
8
+ "math"
7
9
8
10
"github.com/go-git/go-git/v5/plumbing"
9
11
"github.com/go-git/go-git/v5/utils/ioutil"
@@ -73,6 +75,131 @@ func PatchDelta(src, delta []byte) ([]byte, error) {
73
75
return b .Bytes (), nil
74
76
}
75
77
78
+ func ReaderFromDelta (h * ObjectHeader , base plumbing.EncodedObject , deltaRC io.ReadCloser ) (io.ReadCloser , error ) {
79
+ deltaBuf := bufio .NewReaderSize (deltaRC , 1024 )
80
+ srcSz , err := decodeLEB128ByteReader (deltaBuf )
81
+ if err != nil {
82
+ if err == io .EOF {
83
+ return nil , ErrInvalidDelta
84
+ }
85
+ return nil , err
86
+ }
87
+ if srcSz != uint (base .Size ()) {
88
+ return nil , ErrInvalidDelta
89
+ }
90
+
91
+ targetSz , err := decodeLEB128ByteReader (deltaBuf )
92
+ if err != nil {
93
+ if err == io .EOF {
94
+ return nil , ErrInvalidDelta
95
+ }
96
+ return nil , err
97
+ }
98
+ remainingTargetSz := targetSz
99
+
100
+ dstRd , dstWr := io .Pipe ()
101
+
102
+ go func () {
103
+ baseRd , err := base .Reader ()
104
+ if err != nil {
105
+ _ = dstWr .CloseWithError (ErrInvalidDelta )
106
+ return
107
+ }
108
+ defer baseRd .Close ()
109
+
110
+ baseBuf := bufio .NewReader (baseRd )
111
+ basePos := uint (0 )
112
+
113
+ for {
114
+ cmd , err := deltaBuf .ReadByte ()
115
+ if err == io .EOF {
116
+ _ = dstWr .CloseWithError (ErrInvalidDelta )
117
+ return
118
+ }
119
+ if err != nil {
120
+ _ = dstWr .CloseWithError (err )
121
+ return
122
+ }
123
+
124
+ if isCopyFromSrc (cmd ) {
125
+ offset , err := decodeOffsetByteReader (cmd , deltaBuf )
126
+ if err != nil {
127
+ _ = dstWr .CloseWithError (err )
128
+ return
129
+ }
130
+ sz , err := decodeSizeByteReader (cmd , deltaBuf )
131
+ if err != nil {
132
+ _ = dstWr .CloseWithError (err )
133
+ return
134
+ }
135
+
136
+ if invalidSize (sz , targetSz ) ||
137
+ invalidOffsetSize (offset , sz , srcSz ) {
138
+ _ = dstWr .Close ()
139
+ return
140
+ }
141
+
142
+ discard := offset - basePos
143
+ if discard < 0 {
144
+ _ = baseRd .Close ()
145
+ baseRd , err = base .Reader ()
146
+ if err != nil {
147
+ _ = dstWr .CloseWithError (ErrInvalidDelta )
148
+ return
149
+ }
150
+ baseBuf .Reset (baseRd )
151
+ discard = offset
152
+ }
153
+ for discard > math .MaxInt32 {
154
+ n , err := baseBuf .Discard (math .MaxInt32 )
155
+ if err != nil {
156
+ _ = dstWr .CloseWithError (err )
157
+ return
158
+ }
159
+ basePos += uint (n )
160
+ discard -= uint (n )
161
+ }
162
+ for discard > 0 {
163
+ n , err := baseBuf .Discard (int (discard ))
164
+ if err != nil {
165
+ _ = dstWr .CloseWithError (err )
166
+ return
167
+ }
168
+ basePos += uint (n )
169
+ discard -= uint (n )
170
+ }
171
+ if _ , err := io .Copy (dstWr , io .LimitReader (baseBuf , int64 (sz ))); err != nil {
172
+ _ = dstWr .CloseWithError (err )
173
+ return
174
+ }
175
+ remainingTargetSz -= sz
176
+ basePos += sz
177
+ } else if isCopyFromDelta (cmd ) {
178
+ sz := uint (cmd ) // cmd is the size itself
179
+ if invalidSize (sz , targetSz ) {
180
+ _ = dstWr .CloseWithError (ErrInvalidDelta )
181
+ return
182
+ }
183
+ if _ , err := io .Copy (dstWr , io .LimitReader (deltaBuf , int64 (sz ))); err != nil {
184
+ _ = dstWr .CloseWithError (err )
185
+ return
186
+ }
187
+
188
+ remainingTargetSz -= sz
189
+ } else {
190
+ _ = dstWr .CloseWithError (ErrDeltaCmd )
191
+ return
192
+ }
193
+ if remainingTargetSz <= 0 {
194
+ _ = dstWr .Close ()
195
+ return
196
+ }
197
+ }
198
+ }()
199
+
200
+ return dstRd , nil
201
+ }
202
+
76
203
func patchDelta (dst * bytes.Buffer , src , delta []byte ) error {
77
204
if len (delta ) < deltaSizeMin {
78
205
return ErrInvalidDelta
@@ -161,6 +288,25 @@ func decodeLEB128(input []byte) (uint, []byte) {
161
288
return num , input [sz :]
162
289
}
163
290
291
+ func decodeLEB128ByteReader (input io.ByteReader ) (uint , error ) {
292
+ var num , sz uint
293
+ for {
294
+ b , err := input .ReadByte ()
295
+ if err != nil {
296
+ return 0 , err
297
+ }
298
+
299
+ num |= (uint (b ) & payload ) << (sz * 7 ) // concats 7 bits chunks
300
+ sz ++
301
+
302
+ if uint (b )& continuation == 0 {
303
+ break
304
+ }
305
+ }
306
+
307
+ return num , nil
308
+ }
309
+
164
310
const (
165
311
payload = 0x7f // 0111 1111
166
312
continuation = 0x80 // 1000 0000
@@ -174,6 +320,40 @@ func isCopyFromDelta(cmd byte) bool {
174
320
return (cmd & 0x80 ) == 0 && cmd != 0
175
321
}
176
322
323
+ func decodeOffsetByteReader (cmd byte , delta io.ByteReader ) (uint , error ) {
324
+ var offset uint
325
+ if (cmd & 0x01 ) != 0 {
326
+ next , err := delta .ReadByte ()
327
+ if err != nil {
328
+ return 0 , err
329
+ }
330
+ offset = uint (next )
331
+ }
332
+ if (cmd & 0x02 ) != 0 {
333
+ next , err := delta .ReadByte ()
334
+ if err != nil {
335
+ return 0 , err
336
+ }
337
+ offset |= uint (next ) << 8
338
+ }
339
+ if (cmd & 0x04 ) != 0 {
340
+ next , err := delta .ReadByte ()
341
+ if err != nil {
342
+ return 0 , err
343
+ }
344
+ offset |= uint (next ) << 16
345
+ }
346
+ if (cmd & 0x08 ) != 0 {
347
+ next , err := delta .ReadByte ()
348
+ if err != nil {
349
+ return 0 , err
350
+ }
351
+ offset |= uint (next ) << 24
352
+ }
353
+
354
+ return offset , nil
355
+ }
356
+
177
357
func decodeOffset (cmd byte , delta []byte ) (uint , []byte , error ) {
178
358
var offset uint
179
359
if (cmd & 0x01 ) != 0 {
@@ -208,6 +388,36 @@ func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) {
208
388
return offset , delta , nil
209
389
}
210
390
391
+ func decodeSizeByteReader (cmd byte , delta io.ByteReader ) (uint , error ) {
392
+ var sz uint
393
+ if (cmd & 0x10 ) != 0 {
394
+ next , err := delta .ReadByte ()
395
+ if err != nil {
396
+ return 0 , err
397
+ }
398
+ sz = uint (next )
399
+ }
400
+ if (cmd & 0x20 ) != 0 {
401
+ next , err := delta .ReadByte ()
402
+ if err != nil {
403
+ return 0 , err
404
+ }
405
+ sz |= uint (next ) << 8
406
+ }
407
+ if (cmd & 0x40 ) != 0 {
408
+ next , err := delta .ReadByte ()
409
+ if err != nil {
410
+ return 0 , err
411
+ }
412
+ sz |= uint (next ) << 16
413
+ }
414
+ if sz == 0 {
415
+ sz = 0x10000
416
+ }
417
+
418
+ return sz , nil
419
+ }
420
+
211
421
func decodeSize (cmd byte , delta []byte ) (uint , []byte , error ) {
212
422
var sz uint
213
423
if (cmd & 0x10 ) != 0 {
0 commit comments