@@ -257,38 +257,99 @@ func (z *Reader) folderReader(si *streamsInfo, f int) (*folderReadCloser, uint32
257
257
return si .FolderReader (io .NewSectionReader (z .r , z .start , z .end - z .start ), f , z .p )
258
258
}
259
259
260
- //nolint:cyclop,funlen,gocognit
260
+ const (
261
+ chunkSize = 4096
262
+ searchLimit = 1 << 20 // 1 MiB
263
+ )
264
+
265
+ func findSignature (r io.ReaderAt , search []byte ) ([]int64 , error ) {
266
+ var (
267
+ offset int64
268
+ offsets []int64
269
+ )
270
+
271
+ chunk := make ([]byte , chunkSize + len (search ))
272
+
273
+ for offset < searchLimit {
274
+ n , err := r .ReadAt (chunk , offset )
275
+
276
+ for i := 0 ; ; {
277
+ idx := bytes .Index (chunk [i :n ], search )
278
+ if idx == - 1 {
279
+ break
280
+ }
281
+
282
+ offsets = append (offsets , offset + int64 (i + idx ))
283
+ if offsets [0 ] == 0 {
284
+ // If signature is at the beginning, return immediately, it's a regular archive
285
+ return offsets , nil
286
+ }
287
+
288
+ i += idx + 1
289
+ }
290
+
291
+ if err != nil {
292
+ if errors .Is (err , io .EOF ) {
293
+ break
294
+ }
295
+
296
+ return nil , err
297
+ }
298
+
299
+ offset += chunkSize
300
+ }
301
+
302
+ return offsets , nil
303
+ }
304
+
305
+ //nolint:cyclop,funlen,gocognit,gocyclo
261
306
func (z * Reader ) init (r io.ReaderAt , size int64 ) error {
262
307
h := crc32 .NewIEEE ()
263
308
tra := plumbing .TeeReaderAt (r , h )
264
- sr := io .NewSectionReader (tra , 0 , size ) // Will only read first 32 bytes
265
309
266
- var sh signatureHeader
267
- if err := binary .Read (sr , binary .LittleEndian , & sh ); err != nil {
310
+ signature := []byte {'7' , 'z' , 0xbc , 0xaf , 0x27 , 0x1c }
311
+
312
+ offsets , err := findSignature (r , signature )
313
+ if err != nil {
268
314
return err
269
315
}
270
316
271
- signature := []byte {'7' , 'z' , 0xbc , 0xaf , 0x27 , 0x1c }
272
- if ! bytes .Equal (sh .Signature [:], signature ) {
317
+ if len (offsets ) == 0 {
273
318
return errFormat
274
319
}
275
320
276
- z .r = r
277
-
278
- h .Reset ()
279
-
280
321
var (
281
- err error
322
+ sr * io.SectionReader
323
+ off int64
282
324
start startHeader
283
325
)
284
326
285
- if err = binary .Read (sr , binary .LittleEndian , & start ); err != nil {
286
- return err
327
+ for _ , off = range offsets {
328
+ sr = io .NewSectionReader (tra , off , size - off ) // Will only read first 32 bytes
329
+
330
+ var sh signatureHeader
331
+ if err = binary .Read (sr , binary .LittleEndian , & sh ); err != nil {
332
+ return err
333
+ }
334
+
335
+ z .r = r
336
+
337
+ h .Reset ()
338
+
339
+ if err = binary .Read (sr , binary .LittleEndian , & start ); err != nil {
340
+ return err
341
+ }
342
+
343
+ // CRC of the start header should match
344
+ if util .CRC32Equal (h .Sum (nil ), sh .CRC ) {
345
+ break
346
+ }
347
+
348
+ err = errChecksum
287
349
}
288
350
289
- // CRC of the start header should match
290
- if ! util .CRC32Equal (h .Sum (nil ), sh .CRC ) {
291
- return errChecksum
351
+ if err != nil {
352
+ return err
292
353
}
293
354
294
355
// Work out where we are in the file (32, avoiding magic numbers)
@@ -301,6 +362,9 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
301
362
return err
302
363
}
303
364
365
+ z .start += off
366
+ z .end += off
367
+
304
368
h .Reset ()
305
369
306
370
// Bound bufio.Reader otherwise it can read trailing garbage which screws up the CRC check
0 commit comments