@@ -237,10 +237,24 @@ func TestZip64(t *testing.T) {
237
237
testZip64DirectoryRecordLength (buf , t )
238
238
}
239
239
240
+ func TestZip64EdgeCase (t * testing.T ) {
241
+ if testing .Short () {
242
+ t .Skip ("slow test; skipping" )
243
+ }
244
+ // Test a zip file with uncompressed size 0xFFFFFFFF.
245
+ // That's the magic marker for a 64-bit file, so even though
246
+ // it fits in a 32-bit field we must use the 64-bit field.
247
+ // Go 1.5 and earlier got this wrong,
248
+ // writing an invalid zip file.
249
+ const size = 1 << 32 - 1 - int64 (len ("END\n " )) // before the "END\n" part
250
+ buf := testZip64 (t , size )
251
+ testZip64DirectoryRecordLength (buf , t )
252
+ }
253
+
240
254
func testZip64 (t testing.TB , size int64 ) * rleBuffer {
241
255
const chunkSize = 1024
242
256
chunks := int (size / chunkSize )
243
- // write 2^32 bytes plus "END\n" to a zip file
257
+ // write size bytes plus "END\n" to a zip file
244
258
buf := new (rleBuffer )
245
259
w := NewWriter (buf )
246
260
f , err := w .CreateHeader (& FileHeader {
@@ -261,6 +275,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
261
275
t .Fatal ("write chunk:" , err )
262
276
}
263
277
}
278
+ if frag := int (size % chunkSize ); frag > 0 {
279
+ _ , err := f .Write (chunk [:frag ])
280
+ if err != nil {
281
+ t .Fatal ("write chunk:" , err )
282
+ }
283
+ }
264
284
end := []byte ("END\n " )
265
285
_ , err = f .Write (end )
266
286
if err != nil {
@@ -287,6 +307,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
287
307
t .Fatal ("read:" , err )
288
308
}
289
309
}
310
+ if frag := int (size % chunkSize ); frag > 0 {
311
+ _ , err := io .ReadFull (rc , chunk [:frag ])
312
+ if err != nil {
313
+ t .Fatal ("read:" , err )
314
+ }
315
+ }
290
316
gotEnd , err := ioutil .ReadAll (rc )
291
317
if err != nil {
292
318
t .Fatal ("read end:" , err )
@@ -298,14 +324,14 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
298
324
if err != nil {
299
325
t .Fatal ("closing:" , err )
300
326
}
301
- if size == 1 << 32 {
327
+ if size + int64 ( len ( "END \n " )) >= 1 << 32 - 1 {
302
328
if got , want := f0 .UncompressedSize , uint32 (uint32max ); got != want {
303
- t .Errorf ("UncompressedSize %d , want %d " , got , want )
329
+ t .Errorf ("UncompressedSize %#x , want %#x " , got , want )
304
330
}
305
331
}
306
332
307
333
if got , want := f0 .UncompressedSize64 , uint64 (size )+ uint64 (len (end )); got != want {
308
- t .Errorf ("UncompressedSize64 %d , want %d " , got , want )
334
+ t .Errorf ("UncompressedSize64 %#x , want %#x " , got , want )
309
335
}
310
336
311
337
return buf
@@ -377,9 +403,14 @@ func testValidHeader(h *FileHeader, t *testing.T) {
377
403
}
378
404
379
405
b := buf .Bytes ()
380
- if _ , err = NewReader (bytes .NewReader (b ), int64 (len (b ))); err != nil {
406
+ zf , err := NewReader (bytes .NewReader (b ), int64 (len (b )))
407
+ if err != nil {
381
408
t .Fatalf ("got %v, expected nil" , err )
382
409
}
410
+ zh := zf .File [0 ].FileHeader
411
+ if zh .Name != h .Name || zh .Method != h .Method || zh .UncompressedSize64 != uint64 (len ("hi" )) {
412
+ t .Fatalf ("got %q/%d/%d expected %q/%d/%d" , zh .Name , zh .Method , zh .UncompressedSize64 , h .Name , h .Method , len ("hi" ))
413
+ }
383
414
}
384
415
385
416
// Issue 4302.
@@ -392,20 +423,29 @@ func TestHeaderInvalidTagAndSize(t *testing.T) {
392
423
h := FileHeader {
393
424
Name : filename ,
394
425
Method : Deflate ,
395
- Extra : []byte (ts .Format (time .RFC3339Nano )), // missing tag and len
426
+ Extra : []byte (ts .Format (time .RFC3339Nano )), // missing tag and len, but Extra is best-effort parsing
396
427
}
397
428
h .SetModTime (ts )
398
429
399
- testInvalidHeader (& h , t )
430
+ testValidHeader (& h , t )
400
431
}
401
432
402
433
func TestHeaderTooShort (t * testing.T ) {
403
434
h := FileHeader {
404
435
Name : "foo.txt" ,
405
436
Method : Deflate ,
406
- Extra : []byte {zip64ExtraId }, // missing size
437
+ Extra : []byte {zip64ExtraId }, // missing size and second half of tag, but Extra is best-effort parsing
407
438
}
408
- testInvalidHeader (& h , t )
439
+ testValidHeader (& h , t )
440
+ }
441
+
442
+ func TestHeaderIgnoredSize (t * testing.T ) {
443
+ h := FileHeader {
444
+ Name : "foo.txt" ,
445
+ Method : Deflate ,
446
+ Extra : []byte {zip64ExtraId & 0xFF , zip64ExtraId >> 8 , 24 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 }, // bad size but shouldn't be consulted
447
+ }
448
+ testValidHeader (& h , t )
409
449
}
410
450
411
451
// Issue 4393. It is valid to have an extra data header
0 commit comments