github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/archive/zip/reader_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package zip 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "encoding/hex" 11 "internal/obscuretestdata" 12 "io" 13 "io/fs" 14 "os" 15 "path/filepath" 16 "reflect" 17 "regexp" 18 "strings" 19 "testing" 20 "testing/fstest" 21 "time" 22 ) 23 24 type ZipTest struct { 25 Name string 26 Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file 27 Comment string 28 File []ZipTestFile 29 Obscured bool // needed for Apple notarization (golang.org/issue/34986) 30 Error error // the error that Opening this file should return 31 } 32 33 type ZipTestFile struct { 34 Name string 35 Mode fs.FileMode 36 NonUTF8 bool 37 ModTime time.Time 38 Modified time.Time 39 40 // Information describing expected zip file content. 41 // First, reading the entire content should produce the error ContentErr. 42 // Second, if ContentErr==nil, the content should match Content. 43 // If content is large, an alternative to setting Content is to set File, 44 // which names a file in the testdata/ directory containing the 45 // uncompressed expected content. 46 // If content is very large, an alternative to setting Content or File 47 // is to set Size, which will then be checked against the header-reported size 48 // but will bypass the decompressing of the actual data. 49 // This last option is used for testing very large (multi-GB) compressed files. 50 ContentErr error 51 Content []byte 52 File string 53 Size uint64 54 } 55 56 var tests = []ZipTest{ 57 { 58 Name: "test.zip", 59 Comment: "This is a zipfile comment.", 60 File: []ZipTestFile{ 61 { 62 Name: "test.txt", 63 Content: []byte("This is a test text file.\n"), 64 Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), 65 Mode: 0644, 66 }, 67 { 68 Name: "gophercolor16x16.png", 69 File: "gophercolor16x16.png", 70 Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), 71 Mode: 0644, 72 }, 73 }, 74 }, 75 { 76 Name: "test-trailing-junk.zip", 77 Comment: "This is a zipfile comment.", 78 File: []ZipTestFile{ 79 { 80 Name: "test.txt", 81 Content: []byte("This is a test text file.\n"), 82 Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), 83 Mode: 0644, 84 }, 85 { 86 Name: "gophercolor16x16.png", 87 File: "gophercolor16x16.png", 88 Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), 89 Mode: 0644, 90 }, 91 }, 92 }, 93 { 94 Name: "test-prefix.zip", 95 Comment: "This is a zipfile comment.", 96 File: []ZipTestFile{ 97 { 98 Name: "test.txt", 99 Content: []byte("This is a test text file.\n"), 100 Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), 101 Mode: 0644, 102 }, 103 { 104 Name: "gophercolor16x16.png", 105 File: "gophercolor16x16.png", 106 Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), 107 Mode: 0644, 108 }, 109 }, 110 }, 111 { 112 Name: "test-baddirsz.zip", 113 Comment: "This is a zipfile comment.", 114 File: []ZipTestFile{ 115 { 116 Name: "test.txt", 117 Content: []byte("This is a test text file.\n"), 118 Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), 119 Mode: 0644, 120 }, 121 { 122 Name: "gophercolor16x16.png", 123 File: "gophercolor16x16.png", 124 Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), 125 Mode: 0644, 126 }, 127 }, 128 }, 129 { 130 Name: "test-badbase.zip", 131 Comment: "This is a zipfile comment.", 132 File: []ZipTestFile{ 133 { 134 Name: "test.txt", 135 Content: []byte("This is a test text file.\n"), 136 Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), 137 Mode: 0644, 138 }, 139 { 140 Name: "gophercolor16x16.png", 141 File: "gophercolor16x16.png", 142 Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), 143 Mode: 0644, 144 }, 145 }, 146 }, 147 { 148 Name: "r.zip", 149 Source: returnRecursiveZip, 150 File: []ZipTestFile{ 151 { 152 Name: "r/r.zip", 153 Content: rZipBytes(), 154 Modified: time.Date(2010, 3, 4, 0, 24, 16, 0, time.UTC), 155 Mode: 0666, 156 }, 157 }, 158 }, 159 { 160 Name: "symlink.zip", 161 File: []ZipTestFile{ 162 { 163 Name: "symlink", 164 Content: []byte("../target"), 165 Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)), 166 Mode: 0777 | fs.ModeSymlink, 167 }, 168 }, 169 }, 170 { 171 Name: "readme.zip", 172 }, 173 { 174 Name: "readme.notzip", 175 Error: ErrFormat, 176 }, 177 { 178 Name: "dd.zip", 179 File: []ZipTestFile{ 180 { 181 Name: "filename", 182 Content: []byte("This is a test textfile.\n"), 183 Modified: time.Date(2011, 2, 2, 13, 6, 20, 0, time.UTC), 184 Mode: 0666, 185 }, 186 }, 187 }, 188 { 189 // created in windows XP file manager. 190 Name: "winxp.zip", 191 File: []ZipTestFile{ 192 { 193 Name: "hello", 194 Content: []byte("world \r\n"), 195 Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, time.UTC), 196 Mode: 0666, 197 }, 198 { 199 Name: "dir/bar", 200 Content: []byte("foo \r\n"), 201 Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, time.UTC), 202 Mode: 0666, 203 }, 204 { 205 Name: "dir/empty/", 206 Content: []byte{}, 207 Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC), 208 Mode: fs.ModeDir | 0777, 209 }, 210 { 211 Name: "readonly", 212 Content: []byte("important \r\n"), 213 Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, time.UTC), 214 Mode: 0444, 215 }, 216 }, 217 }, 218 { 219 // created by Zip 3.0 under Linux 220 Name: "unix.zip", 221 File: []ZipTestFile{ 222 { 223 Name: "hello", 224 Content: []byte("world \r\n"), 225 Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, timeZone(0)), 226 Mode: 0666, 227 }, 228 { 229 Name: "dir/bar", 230 Content: []byte("foo \r\n"), 231 Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, timeZone(0)), 232 Mode: 0666, 233 }, 234 { 235 Name: "dir/empty/", 236 Content: []byte{}, 237 Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)), 238 Mode: fs.ModeDir | 0777, 239 }, 240 { 241 Name: "readonly", 242 Content: []byte("important \r\n"), 243 Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, timeZone(0)), 244 Mode: 0444, 245 }, 246 }, 247 }, 248 { 249 // created by Go, before we wrote the "optional" data 250 // descriptor signatures (which are required by macOS). 251 // Use obscured file to avoid Apple’s notarization service 252 // rejecting the toolchain due to an inability to unzip this archive. 253 // See golang.org/issue/34986 254 Name: "go-no-datadesc-sig.zip.base64", 255 Obscured: true, 256 File: []ZipTestFile{ 257 { 258 Name: "foo.txt", 259 Content: []byte("foo\n"), 260 Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), 261 Mode: 0644, 262 }, 263 { 264 Name: "bar.txt", 265 Content: []byte("bar\n"), 266 Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), 267 Mode: 0644, 268 }, 269 }, 270 }, 271 { 272 // created by Go, after we wrote the "optional" data 273 // descriptor signatures (which are required by macOS) 274 Name: "go-with-datadesc-sig.zip", 275 File: []ZipTestFile{ 276 { 277 Name: "foo.txt", 278 Content: []byte("foo\n"), 279 Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), 280 Mode: 0666, 281 }, 282 { 283 Name: "bar.txt", 284 Content: []byte("bar\n"), 285 Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), 286 Mode: 0666, 287 }, 288 }, 289 }, 290 { 291 Name: "Bad-CRC32-in-data-descriptor", 292 Source: returnCorruptCRC32Zip, 293 File: []ZipTestFile{ 294 { 295 Name: "foo.txt", 296 Content: []byte("foo\n"), 297 Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), 298 Mode: 0666, 299 ContentErr: ErrChecksum, 300 }, 301 { 302 Name: "bar.txt", 303 Content: []byte("bar\n"), 304 Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), 305 Mode: 0666, 306 }, 307 }, 308 }, 309 // Tests that we verify (and accept valid) crc32s on files 310 // with crc32s in their file header (not in data descriptors) 311 { 312 Name: "crc32-not-streamed.zip", 313 File: []ZipTestFile{ 314 { 315 Name: "foo.txt", 316 Content: []byte("foo\n"), 317 Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), 318 Mode: 0644, 319 }, 320 { 321 Name: "bar.txt", 322 Content: []byte("bar\n"), 323 Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), 324 Mode: 0644, 325 }, 326 }, 327 }, 328 // Tests that we verify (and reject invalid) crc32s on files 329 // with crc32s in their file header (not in data descriptors) 330 { 331 Name: "crc32-not-streamed.zip", 332 Source: returnCorruptNotStreamedZip, 333 File: []ZipTestFile{ 334 { 335 Name: "foo.txt", 336 Content: []byte("foo\n"), 337 Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), 338 Mode: 0644, 339 ContentErr: ErrChecksum, 340 }, 341 { 342 Name: "bar.txt", 343 Content: []byte("bar\n"), 344 Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), 345 Mode: 0644, 346 }, 347 }, 348 }, 349 { 350 Name: "zip64.zip", 351 File: []ZipTestFile{ 352 { 353 Name: "README", 354 Content: []byte("This small file is in ZIP64 format.\n"), 355 Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, time.UTC), 356 Mode: 0644, 357 }, 358 }, 359 }, 360 // Another zip64 file with different Extras fields. (golang.org/issue/7069) 361 { 362 Name: "zip64-2.zip", 363 File: []ZipTestFile{ 364 { 365 Name: "README", 366 Content: []byte("This small file is in ZIP64 format.\n"), 367 Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, timeZone(-4*time.Hour)), 368 Mode: 0644, 369 }, 370 }, 371 }, 372 // Largest possible non-zip64 file, with no zip64 header. 373 { 374 Name: "big.zip", 375 Source: returnBigZipBytes, 376 File: []ZipTestFile{ 377 { 378 Name: "big.file", 379 Content: nil, 380 Size: 1<<32 - 1, 381 Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), 382 Mode: 0666, 383 }, 384 }, 385 }, 386 { 387 Name: "utf8-7zip.zip", 388 File: []ZipTestFile{ 389 { 390 Name: "世界", 391 Content: []byte{}, 392 Mode: 0666, 393 Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)), 394 }, 395 }, 396 }, 397 { 398 Name: "utf8-infozip.zip", 399 File: []ZipTestFile{ 400 { 401 Name: "世界", 402 Content: []byte{}, 403 Mode: 0644, 404 // Name is valid UTF-8, but format does not have UTF-8 flag set. 405 // We don't do UTF-8 detection for multi-byte runes due to 406 // false-positives with other encodings (e.g., Shift-JIS). 407 // Format says encoding is not UTF-8, so we trust it. 408 NonUTF8: true, 409 Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)), 410 }, 411 }, 412 }, 413 { 414 Name: "utf8-osx.zip", 415 File: []ZipTestFile{ 416 { 417 Name: "世界", 418 Content: []byte{}, 419 Mode: 0644, 420 // Name is valid UTF-8, but format does not have UTF-8 set. 421 NonUTF8: true, 422 Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)), 423 }, 424 }, 425 }, 426 { 427 Name: "utf8-winrar.zip", 428 File: []ZipTestFile{ 429 { 430 Name: "世界", 431 Content: []byte{}, 432 Mode: 0666, 433 Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)), 434 }, 435 }, 436 }, 437 { 438 Name: "utf8-winzip.zip", 439 File: []ZipTestFile{ 440 { 441 Name: "世界", 442 Content: []byte{}, 443 Mode: 0666, 444 Modified: time.Date(2017, 11, 6, 13, 9, 27, 867000000, timeZone(-8*time.Hour)), 445 }, 446 }, 447 }, 448 { 449 Name: "time-7zip.zip", 450 File: []ZipTestFile{ 451 { 452 Name: "test.txt", 453 Content: []byte{}, 454 Size: 1<<32 - 1, 455 Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)), 456 Mode: 0666, 457 }, 458 }, 459 }, 460 { 461 Name: "time-infozip.zip", 462 File: []ZipTestFile{ 463 { 464 Name: "test.txt", 465 Content: []byte{}, 466 Size: 1<<32 - 1, 467 Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), 468 Mode: 0644, 469 }, 470 }, 471 }, 472 { 473 Name: "time-osx.zip", 474 File: []ZipTestFile{ 475 { 476 Name: "test.txt", 477 Content: []byte{}, 478 Size: 1<<32 - 1, 479 Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), 480 Mode: 0644, 481 }, 482 }, 483 }, 484 { 485 Name: "time-win7.zip", 486 File: []ZipTestFile{ 487 { 488 Name: "test.txt", 489 Content: []byte{}, 490 Size: 1<<32 - 1, 491 Modified: time.Date(2017, 10, 31, 21, 11, 58, 0, time.UTC), 492 Mode: 0666, 493 }, 494 }, 495 }, 496 { 497 Name: "time-winrar.zip", 498 File: []ZipTestFile{ 499 { 500 Name: "test.txt", 501 Content: []byte{}, 502 Size: 1<<32 - 1, 503 Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)), 504 Mode: 0666, 505 }, 506 }, 507 }, 508 { 509 Name: "time-winzip.zip", 510 File: []ZipTestFile{ 511 { 512 Name: "test.txt", 513 Content: []byte{}, 514 Size: 1<<32 - 1, 515 Modified: time.Date(2017, 10, 31, 21, 11, 57, 244000000, timeZone(-7*time.Hour)), 516 Mode: 0666, 517 }, 518 }, 519 }, 520 { 521 Name: "time-go.zip", 522 File: []ZipTestFile{ 523 { 524 Name: "test.txt", 525 Content: []byte{}, 526 Size: 1<<32 - 1, 527 Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), 528 Mode: 0666, 529 }, 530 }, 531 }, 532 { 533 Name: "time-22738.zip", 534 File: []ZipTestFile{ 535 { 536 Name: "file", 537 Content: []byte{}, 538 Mode: 0666, 539 Modified: time.Date(1999, 12, 31, 19, 0, 0, 0, timeZone(-5*time.Hour)), 540 ModTime: time.Date(1999, 12, 31, 19, 0, 0, 0, time.UTC), 541 }, 542 }, 543 }, 544 { 545 Name: "dupdir.zip", 546 File: []ZipTestFile{ 547 { 548 Name: "a/", 549 Content: []byte{}, 550 Mode: fs.ModeDir | 0666, 551 Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)), 552 }, 553 { 554 Name: "a/b", 555 Content: []byte{}, 556 Mode: 0666, 557 Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)), 558 }, 559 { 560 Name: "a/b/", 561 Content: []byte{}, 562 Mode: fs.ModeDir | 0666, 563 Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)), 564 }, 565 { 566 Name: "a/b/c", 567 Content: []byte{}, 568 Mode: 0666, 569 Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)), 570 }, 571 }, 572 }, 573 } 574 575 func TestReader(t *testing.T) { 576 for _, zt := range tests { 577 t.Run(zt.Name, func(t *testing.T) { 578 readTestZip(t, zt) 579 }) 580 } 581 } 582 583 func readTestZip(t *testing.T, zt ZipTest) { 584 var z *Reader 585 var err error 586 var raw []byte 587 if zt.Source != nil { 588 rat, size := zt.Source() 589 z, err = NewReader(rat, size) 590 raw = make([]byte, size) 591 if _, err := rat.ReadAt(raw, 0); err != nil { 592 t.Errorf("ReadAt error=%v", err) 593 return 594 } 595 } else { 596 path := filepath.Join("testdata", zt.Name) 597 if zt.Obscured { 598 tf, err := obscuretestdata.DecodeToTempFile(path) 599 if err != nil { 600 t.Errorf("obscuretestdata.DecodeToTempFile(%s): %v", path, err) 601 return 602 } 603 defer os.Remove(tf) 604 path = tf 605 } 606 var rc *ReadCloser 607 rc, err = OpenReader(path) 608 if err == nil { 609 defer rc.Close() 610 z = &rc.Reader 611 } 612 var err2 error 613 raw, err2 = os.ReadFile(path) 614 if err2 != nil { 615 t.Errorf("ReadFile(%s) error=%v", path, err2) 616 return 617 } 618 } 619 if err != zt.Error { 620 t.Errorf("error=%v, want %v", err, zt.Error) 621 return 622 } 623 624 // bail if file is not zip 625 if err == ErrFormat { 626 return 627 } 628 629 // bail here if no Files expected to be tested 630 // (there may actually be files in the zip, but we don't care) 631 if zt.File == nil { 632 return 633 } 634 635 if z.Comment != zt.Comment { 636 t.Errorf("comment=%q, want %q", z.Comment, zt.Comment) 637 } 638 if len(z.File) != len(zt.File) { 639 t.Fatalf("file count=%d, want %d", len(z.File), len(zt.File)) 640 } 641 642 // test read of each file 643 for i, ft := range zt.File { 644 readTestFile(t, zt, ft, z.File[i], raw) 645 } 646 if t.Failed() { 647 return 648 } 649 650 // test simultaneous reads 651 n := 0 652 done := make(chan bool) 653 for i := 0; i < 5; i++ { 654 for j, ft := range zt.File { 655 go func(j int, ft ZipTestFile) { 656 readTestFile(t, zt, ft, z.File[j], raw) 657 done <- true 658 }(j, ft) 659 n++ 660 } 661 } 662 for ; n > 0; n-- { 663 <-done 664 } 665 } 666 667 func equalTimeAndZone(t1, t2 time.Time) bool { 668 name1, offset1 := t1.Zone() 669 name2, offset2 := t2.Zone() 670 return t1.Equal(t2) && name1 == name2 && offset1 == offset2 671 } 672 673 func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File, raw []byte) { 674 if f.Name != ft.Name { 675 t.Errorf("name=%q, want %q", f.Name, ft.Name) 676 } 677 if !ft.Modified.IsZero() && !equalTimeAndZone(f.Modified, ft.Modified) { 678 t.Errorf("%s: Modified=%s, want %s", f.Name, f.Modified, ft.Modified) 679 } 680 if !ft.ModTime.IsZero() && !equalTimeAndZone(f.ModTime(), ft.ModTime) { 681 t.Errorf("%s: ModTime=%s, want %s", f.Name, f.ModTime(), ft.ModTime) 682 } 683 684 testFileMode(t, f, ft.Mode) 685 686 size := uint64(f.UncompressedSize) 687 if size == uint32max { 688 size = f.UncompressedSize64 689 } else if size != f.UncompressedSize64 { 690 t.Errorf("%v: UncompressedSize=%#x does not match UncompressedSize64=%#x", f.Name, size, f.UncompressedSize64) 691 } 692 693 // Check that OpenRaw returns the correct byte segment 694 rw, err := f.OpenRaw() 695 if err != nil { 696 t.Errorf("%v: OpenRaw error=%v", f.Name, err) 697 return 698 } 699 start, err := f.DataOffset() 700 if err != nil { 701 t.Errorf("%v: DataOffset error=%v", f.Name, err) 702 return 703 } 704 got, err := io.ReadAll(rw) 705 if err != nil { 706 t.Errorf("%v: OpenRaw ReadAll error=%v", f.Name, err) 707 return 708 } 709 end := uint64(start) + f.CompressedSize64 710 want := raw[start:end] 711 if !bytes.Equal(got, want) { 712 t.Logf("got %q", got) 713 t.Logf("want %q", want) 714 t.Errorf("%v: OpenRaw returned unexpected bytes", f.Name) 715 return 716 } 717 718 r, err := f.Open() 719 if err != nil { 720 t.Errorf("%v", err) 721 return 722 } 723 724 // For very large files, just check that the size is correct. 725 // The content is expected to be all zeros. 726 // Don't bother uncompressing: too big. 727 if ft.Content == nil && ft.File == "" && ft.Size > 0 { 728 if size != ft.Size { 729 t.Errorf("%v: uncompressed size %#x, want %#x", ft.Name, size, ft.Size) 730 } 731 r.Close() 732 return 733 } 734 735 var b bytes.Buffer 736 _, err = io.Copy(&b, r) 737 if err != ft.ContentErr { 738 t.Errorf("copying contents: %v (want %v)", err, ft.ContentErr) 739 } 740 if err != nil { 741 return 742 } 743 r.Close() 744 745 if g := uint64(b.Len()); g != size { 746 t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size) 747 } 748 749 var c []byte 750 if ft.Content != nil { 751 c = ft.Content 752 } else if c, err = os.ReadFile("testdata/" + ft.File); err != nil { 753 t.Error(err) 754 return 755 } 756 757 if b.Len() != len(c) { 758 t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c)) 759 return 760 } 761 762 for i, b := range b.Bytes() { 763 if b != c[i] { 764 t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i]) 765 return 766 } 767 } 768 } 769 770 func testFileMode(t *testing.T, f *File, want fs.FileMode) { 771 mode := f.Mode() 772 if want == 0 { 773 t.Errorf("%s mode: got %v, want none", f.Name, mode) 774 } else if mode != want { 775 t.Errorf("%s mode: want %v, got %v", f.Name, want, mode) 776 } 777 } 778 779 func TestInvalidFiles(t *testing.T) { 780 const size = 1024 * 70 // 70kb 781 b := make([]byte, size) 782 783 // zeroes 784 _, err := NewReader(bytes.NewReader(b), size) 785 if err != ErrFormat { 786 t.Errorf("zeroes: error=%v, want %v", err, ErrFormat) 787 } 788 789 // repeated directoryEndSignatures 790 sig := make([]byte, 4) 791 binary.LittleEndian.PutUint32(sig, directoryEndSignature) 792 for i := 0; i < size-4; i += 4 { 793 copy(b[i:i+4], sig) 794 } 795 _, err = NewReader(bytes.NewReader(b), size) 796 if err != ErrFormat { 797 t.Errorf("sigs: error=%v, want %v", err, ErrFormat) 798 } 799 800 // negative size 801 _, err = NewReader(bytes.NewReader([]byte("foobar")), -1) 802 if err == nil { 803 t.Errorf("archive/zip.NewReader: expected error when negative size is passed") 804 } 805 } 806 807 func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) { 808 data, err := os.ReadFile(filepath.Join("testdata", fileName)) 809 if err != nil { 810 panic("Error reading " + fileName + ": " + err.Error()) 811 } 812 corrupter(data) 813 return bytes.NewReader(data), int64(len(data)) 814 } 815 816 func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) { 817 return messWith("go-with-datadesc-sig.zip", func(b []byte) { 818 // Corrupt one of the CRC32s in the data descriptor: 819 b[0x2d]++ 820 }) 821 } 822 823 func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) { 824 return messWith("crc32-not-streamed.zip", func(b []byte) { 825 // Corrupt foo.txt's final crc32 byte, in both 826 // the file header and TOC. (0x7e -> 0x7f) 827 b[0x11]++ 828 b[0x9d]++ 829 830 // TODO(bradfitz): add a new test that only corrupts 831 // one of these values, and verify that that's also an 832 // error. Currently, the reader code doesn't verify the 833 // fileheader and TOC's crc32 match if they're both 834 // non-zero and only the second line above, the TOC, 835 // is what matters. 836 }) 837 } 838 839 // rZipBytes returns the bytes of a recursive zip file, without 840 // putting it on disk and triggering certain virus scanners. 841 func rZipBytes() []byte { 842 s := ` 843 0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4 844 0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f 845 0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00 846 0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 847 0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 848 0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00 849 0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8 850 0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f 851 0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e 852 0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb 853 00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff 854 00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 855 00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14 856 00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21 857 00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb 858 00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff 859 0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a 860 0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3 861 0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06 862 0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00 863 0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf 864 0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06 865 0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01 866 0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89 867 0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00 868 0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a 869 00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00 870 00001b0 00 00 6d 01 00 00 00 00` 871 s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "") 872 s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "") 873 b, err := hex.DecodeString(s) 874 if err != nil { 875 panic(err) 876 } 877 return b 878 } 879 880 func returnRecursiveZip() (r io.ReaderAt, size int64) { 881 b := rZipBytes() 882 return bytes.NewReader(b), int64(len(b)) 883 } 884 885 // biggestZipBytes returns the bytes of a zip file biggest.zip 886 // that contains a zip file bigger.zip that contains a zip file 887 // big.zip that contains big.file, which contains 2³²-1 zeros. 888 // The big.zip file is interesting because it has no zip64 header, 889 // much like the innermost zip files in the well-known 42.zip. 890 // 891 // biggest.zip was generated by changing isZip64 to use > uint32max 892 // instead of >= uint32max and then running this program: 893 // 894 // package main 895 // 896 // import ( 897 // "archive/zip" 898 // "bytes" 899 // "io" 900 // "log" 901 // "os" 902 // ) 903 // 904 // type zeros struct{} 905 // 906 // func (zeros) Read(b []byte) (int, error) { 907 // for i := range b { 908 // b[i] = 0 909 // } 910 // return len(b), nil 911 // } 912 // 913 // func main() { 914 // bigZip := makeZip("big.file", io.LimitReader(zeros{}, 1<<32-1)) 915 // if err := os.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil { 916 // log.Fatal(err) 917 // } 918 // 919 // biggerZip := makeZip("big.zip", bytes.NewReader(bigZip)) 920 // if err := os.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil { 921 // log.Fatal(err) 922 // } 923 // 924 // biggestZip := makeZip("bigger.zip", bytes.NewReader(biggerZip)) 925 // if err := os.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil { 926 // log.Fatal(err) 927 // } 928 // } 929 // 930 // func makeZip(name string, r io.Reader) []byte { 931 // var buf bytes.Buffer 932 // w := zip.NewWriter(&buf) 933 // wf, err := w.Create(name) 934 // if err != nil { 935 // log.Fatal(err) 936 // } 937 // if _, err = io.Copy(wf, r); err != nil { 938 // log.Fatal(err) 939 // } 940 // if err := w.Close(); err != nil { 941 // log.Fatal(err) 942 // } 943 // return buf.Bytes() 944 // } 945 // 946 // The 4 GB of zeros compresses to 4 MB, which compresses to 20 kB, 947 // which compresses to 1252 bytes (in the hex dump below). 948 // 949 // It's here in hex for the same reason as rZipBytes above: to avoid 950 // problems with on-disk virus scanners or other zip processors. 951 func biggestZipBytes() []byte { 952 s := ` 953 0000000 50 4b 03 04 14 00 08 00 08 00 00 00 00 00 00 00 954 0000010 00 00 00 00 00 00 00 00 00 00 0a 00 00 00 62 69 955 0000020 67 67 65 72 2e 7a 69 70 ec dc 6b 4c 53 67 18 07 956 0000030 f0 16 c5 ca 65 2e cb b8 94 20 61 1f 44 33 c7 cd 957 0000040 c0 86 4a b5 c0 62 8a 61 05 c6 cd 91 b2 54 8c 1b 958 0000050 63 8b 03 9c 1b 95 52 5a e3 a0 19 6c b2 05 59 44 959 0000060 64 9d 73 83 71 11 46 61 14 b9 1d 14 09 4a c3 60 960 0000070 2e 4c 6e a5 60 45 02 62 81 95 b6 94 9e 9e 77 e7 961 0000080 d0 43 b6 f8 71 df 96 3c e7 a4 69 ce bf cf e9 79 962 0000090 ce ef 79 3f bf f1 31 db b6 bb 31 76 92 e7 f3 07 963 00000a0 8b fc 9c ca cc 08 cc cb cc 5e d2 1c 88 d9 7e bb 964 00000b0 4f bb 3a 3f 75 f1 5d 7f 8f c2 68 67 77 8f 25 ff 965 00000c0 84 e2 93 2d ef a4 95 3d 71 4e 2c b9 b0 87 c3 be 966 00000d0 3d f8 a7 60 24 61 c5 ef ae 9e c8 6c 6d 4e 69 c8 967 00000e0 67 65 34 f8 37 76 2d 76 5c 54 f3 95 65 49 c7 0f 968 00000f0 18 71 4b 7e 5b 6a d1 79 47 61 41 b0 4e 2a 74 45 969 0000100 43 58 12 b2 5a a5 c6 7d 68 55 88 d4 98 75 18 6d 970 0000110 08 d1 1f 8f 5a 9e 96 ee 45 cf a4 84 4e 4b e8 50 971 0000120 a7 13 d9 06 de 52 81 97 36 b2 d7 b8 fc 2b 5f 55 972 0000130 23 1f 32 59 cf 30 27 fb e2 8a b9 de 45 dd 63 9c 973 0000140 4b b5 8b 96 4c 7a 62 62 cc a1 a7 cf fa f1 fe dd 974 0000150 54 62 11 bf 36 78 b3 c7 b1 b5 f2 61 4d 4e dd 66 975 0000160 32 2e e6 70 34 5f f4 c9 e6 6c 43 6f da 6b c6 c3 976 0000170 09 2c ce 09 57 7f d2 7e b4 23 ba 7c 1b 99 bc 22 977 0000180 3e f1 de 91 2f e3 9c 1b 82 cc c2 84 39 aa e6 de 978 0000190 b4 69 fc cc cb 72 a6 61 45 f0 d3 1d 26 19 7c 8d 979 00001a0 29 c8 66 02 be 77 6a f9 3d 34 79 17 19 c8 96 24 980 00001b0 a3 ac e4 dd 3b 1a 8e c6 fe 96 38 6b bf 67 5a 23 981 00001c0 f4 16 f4 e6 8a b4 fc c2 cd bf 95 66 1d bb 35 aa 982 00001d0 92 7d 66 d8 08 8d a5 1f 54 2a af 09 cf 61 ff d2 983 00001e0 85 9d 8f b6 d7 88 07 4a 86 03 db 64 f3 d9 92 73 984 00001f0 df ec a7 fc 23 4c 8d 83 79 63 2a d9 fd 8d b3 c8 985 0000200 8f 7e d4 19 85 e6 8d 1c 76 f0 8b 58 32 fd 9a d6 986 0000210 85 e2 48 ad c3 d5 60 6f 7e 22 dd ef 09 49 7c 7f 987 0000220 3a 45 c3 71 b7 df f3 4c 63 fb b5 d9 31 5f 6e d6 988 0000230 24 1d a4 4a fe 32 a7 5c 16 48 5c 3e 08 6b 8a d3 989 0000240 25 1d a2 12 a5 59 24 ea 20 5f 52 6d ad 94 db 6b 990 0000250 94 b9 5d eb 4b a7 5c 44 bb 1e f2 3c 6b cf 52 c9 991 0000260 e9 e5 ba 06 b9 c4 e5 0a d0 00 0d d0 00 0d d0 00 992 0000270 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d 993 0000280 d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 994 0000290 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 995 00002a0 0d d0 00 cd ff 9e 46 86 fa a7 7d 3a 43 d7 8e 10 996 00002b0 52 e9 be e6 6e cf eb 9e 85 4d 65 ce cc 30 c1 44 997 00002c0 c0 4e af bc 9c 6c 4b a0 d7 54 ff 1d d5 5c 89 fb 998 00002d0 b5 34 7e c4 c2 9e f5 a0 f6 5b 7e 6e ca 73 c7 ef 999 00002e0 5d be de f9 e8 81 eb a5 0a a5 63 54 2c d7 1c d1 1000 00002f0 89 17 85 f8 16 94 f2 8a b2 a3 f5 b6 6d df 75 cd 1001 0000300 90 dd 64 bd 5d 55 4e f2 55 19 1b b7 cc ef 1b ea 1002 0000310 2e 05 9c f4 aa 1e a8 cd a6 82 c7 59 0f 5e 9d e0 1003 0000320 bb fc 6c d6 99 23 eb 36 ad c6 c5 e1 d8 e1 e2 3e 1004 0000330 d9 90 5a f7 91 5d 6f bc 33 6d 98 47 d2 7c 2e 2f 1005 0000340 99 a4 25 72 85 49 2c be 0b 5b af 8f e5 6e 81 a6 1006 0000350 a3 5a 6f 39 53 3a ab 7a 8b 1e 26 f7 46 6c 7d 26 1007 0000360 53 b3 22 31 94 d3 83 f2 18 4d f5 92 33 27 53 97 1008 0000370 0f d3 e6 55 9c a6 c5 31 87 6f d3 f3 ae 39 6f 56 1009 0000380 10 7b ab 7e d0 b4 ca f2 b8 05 be 3f 0e 6e 5a 75 1010 0000390 ab 0c f5 37 0e ba 8e 75 71 7a aa ed 7a dd 6a 63 1011 00003a0 be 9b a0 97 27 6a 6f e7 d3 8b c4 7c ec d3 91 56 1012 00003b0 d9 ac 5e bf 16 42 2f 00 1f 93 a2 23 87 bd e2 59 1013 00003c0 a0 de 1a 66 c8 62 eb 55 8f 91 17 b4 61 42 7a 50 1014 00003d0 40 03 34 40 03 34 40 03 34 40 03 34 40 03 34 40 1015 00003e0 03 34 40 03 34 40 03 34 40 03 34 40 03 34 40 03 1016 00003f0 34 40 03 34 40 03 34 ff 85 86 90 8b ea 67 90 0d 1017 0000400 e1 42 1b d2 61 d6 79 ec fd 3e 44 28 a4 51 6c 5c 1018 0000410 fc d2 72 ca ba 82 18 46 16 61 cd 93 a9 0f d1 24 1019 0000420 17 99 e2 2c 71 16 84 0c c8 7a 13 0f 9a 5e c5 f0 1020 0000430 79 64 e2 12 4d c8 82 a1 81 19 2d aa 44 6d 87 54 1021 0000440 84 71 c1 f6 d4 ca 25 8c 77 b9 08 c7 c8 5e 10 8a 1022 0000450 8f 61 ed 8c ba 30 1f 79 9a c7 60 34 2b b9 8c f8 1023 0000460 18 a6 83 1b e3 9f ad 79 fe fd 1b 8b f1 fc 41 6f 1024 0000470 d4 13 1f e3 b8 83 ba 64 92 e7 eb e4 77 05 8f ba 1025 0000480 fa 3b 00 00 ff ff 50 4b 07 08 a6 18 b1 91 5e 04 1026 0000490 00 00 e4 47 00 00 50 4b 01 02 14 00 14 00 08 00 1027 00004a0 08 00 00 00 00 00 a6 18 b1 91 5e 04 00 00 e4 47 1028 00004b0 00 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 1029 00004c0 00 00 00 00 62 69 67 67 65 72 2e 7a 69 70 50 4b 1030 00004d0 05 06 00 00 00 00 01 00 01 00 38 00 00 00 96 04 1031 00004e0 00 00 00 00` 1032 s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "") 1033 s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "") 1034 b, err := hex.DecodeString(s) 1035 if err != nil { 1036 panic(err) 1037 } 1038 return b 1039 } 1040 1041 func returnBigZipBytes() (r io.ReaderAt, size int64) { 1042 b := biggestZipBytes() 1043 for i := 0; i < 2; i++ { 1044 r, err := NewReader(bytes.NewReader(b), int64(len(b))) 1045 if err != nil { 1046 panic(err) 1047 } 1048 f, err := r.File[0].Open() 1049 if err != nil { 1050 panic(err) 1051 } 1052 b, err = io.ReadAll(f) 1053 if err != nil { 1054 panic(err) 1055 } 1056 } 1057 return bytes.NewReader(b), int64(len(b)) 1058 } 1059 1060 func TestIssue8186(t *testing.T) { 1061 // Directory headers & data found in the TOC of a JAR file. 1062 dirEnts := []string{ 1063 "PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\xaa\x1b\x06\xf0\x81\x02\x00\x00\x81\x02\x00\x00-\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00res/drawable-xhdpi-v4/ic_actionbar_accept.png\xfe\xca\x00\x00\x00", 1064 "PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\x90K\x89\xc7t\n\x00\x00t\n\x00\x00\x0e\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x02\x00\x00resources.arsc\x00\x00\x00", 1065 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xff$\x18\xed3\x03\x00\x00\xb4\b\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\r\x00\x00AndroidManifest.xml", 1066 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\x14\xc5K\xab\x192\x02\x00\xc8\xcd\x04\x00\v\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x10\x00\x00classes.dex", 1067 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?E\x96\nD\xac\x01\x00\x00P\x03\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:C\x02\x00res/layout/actionbar_set_wallpaper.xml", 1068 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?Ļ\x14\xe3\xd8\x01\x00\x00\xd8\x03\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:E\x02\x00res/layout/wallpaper_cropper.xml", 1069 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?}\xc1\x15\x9eZ\x01\x00\x00!\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`G\x02\x00META-INF/MANIFEST.MF", 1070 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xe6\x98Ьo\x01\x00\x00\x84\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcH\x02\x00META-INF/CERT.SF", 1071 "PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xbfP\x96b\x86\x04\x00\x00\xb2\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9J\x02\x00META-INF/CERT.RSA", 1072 } 1073 for i, s := range dirEnts { 1074 var f File 1075 err := readDirectoryHeader(&f, strings.NewReader(s)) 1076 if err != nil { 1077 t.Errorf("error reading #%d: %v", i, err) 1078 } 1079 } 1080 } 1081 1082 // Verify we return ErrUnexpectedEOF when length is short. 1083 func TestIssue10957(t *testing.T) { 1084 data := []byte("PK\x03\x040000000PK\x01\x0200000" + 1085 "0000000000000000000\x00" + 1086 "\x00\x00\x00\x00\x00000000000000PK\x01" + 1087 "\x020000000000000000000" + 1088 "00000\v\x00\x00\x00\x00\x00000000000" + 1089 "00000000000000PK\x01\x0200" + 1090 "00000000000000000000" + 1091 "00\v\x00\x00\x00\x00\x00000000000000" + 1092 "00000000000PK\x01\x020000<" + 1093 "0\x00\x0000000000000000\v\x00\v" + 1094 "\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" + 1095 "00000000PK\x01\x0200000000" + 1096 "0000000000000000\v\x00\x00\x00" + 1097 "\x00\x0000PK\x05\x06000000\x05\x00\xfd\x00\x00\x00" + 1098 "\v\x00\x00\x00\x00\x00") 1099 z, err := NewReader(bytes.NewReader(data), int64(len(data))) 1100 if err != nil { 1101 t.Fatal(err) 1102 } 1103 for i, f := range z.File { 1104 r, err := f.Open() 1105 if err != nil { 1106 continue 1107 } 1108 if f.UncompressedSize64 < 1e6 { 1109 n, err := io.Copy(io.Discard, r) 1110 if i == 3 && err != io.ErrUnexpectedEOF { 1111 t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err) 1112 } 1113 if err == nil && uint64(n) != f.UncompressedSize64 { 1114 t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64) 1115 } 1116 } 1117 r.Close() 1118 } 1119 } 1120 1121 // Verify that this particular malformed zip file is rejected. 1122 func TestIssue10956(t *testing.T) { 1123 data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" + 1124 "0000PK\x05\x06000000000000" + 1125 "0000\v\x00000\x00\x00\x00\x00\x00\x00\x000") 1126 r, err := NewReader(bytes.NewReader(data), int64(len(data))) 1127 if err == nil { 1128 t.Errorf("got nil error, want ErrFormat") 1129 } 1130 if r != nil { 1131 t.Errorf("got non-nil Reader, want nil") 1132 } 1133 } 1134 1135 // Verify we return ErrUnexpectedEOF when reading truncated data descriptor. 1136 func TestIssue11146(t *testing.T) { 1137 data := []byte("PK\x03\x040000000000000000" + 1138 "000000\x01\x00\x00\x000\x01\x00\x00\xff\xff0000" + 1139 "0000000000000000PK\x01\x02" + 1140 "0000\b0\b\x00000000000000" + 1141 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" + 1142 "\x00\x0000\x01\x00\x26\x00\x00\x008\x00\x00\x00\x00\x00") 1143 z, err := NewReader(bytes.NewReader(data), int64(len(data))) 1144 if err != nil { 1145 t.Fatal(err) 1146 } 1147 r, err := z.File[0].Open() 1148 if err != nil { 1149 t.Fatal(err) 1150 } 1151 _, err = io.ReadAll(r) 1152 if err != io.ErrUnexpectedEOF { 1153 t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err) 1154 } 1155 r.Close() 1156 } 1157 1158 // Verify we do not treat non-zip64 archives as zip64 1159 func TestIssue12449(t *testing.T) { 1160 data := []byte{ 1161 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 1162 0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46, 0x00, 0x00, 1163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1164 0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0xca, 0x64, 1165 0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05, 1166 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 1167 0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 1168 0x00, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x0a, 1169 0x50, 0x4b, 0x07, 0x08, 0x1d, 0x88, 0x77, 0xb0, 1170 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 1171 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 1172 0x08, 0x00, 0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46, 1173 0x1d, 0x88, 0x77, 0xb0, 0x07, 0x00, 0x00, 0x00, 1174 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 1175 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1176 0xa0, 0x81, 0x00, 0x00, 0x00, 0x00, 0xca, 0x64, 1177 0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05, 1178 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 1179 0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 1180 0x00, 0x97, 0x2b, 0x49, 0x23, 0x05, 0xc5, 0x0b, 1181 0xa7, 0xd1, 0x52, 0xa2, 0x9c, 0x50, 0x4b, 0x06, 1182 0x07, 0xc8, 0x19, 0xc1, 0xaf, 0x94, 0x9c, 0x61, 1183 0x44, 0xbe, 0x94, 0x19, 0x42, 0x58, 0x12, 0xc6, 1184 0x5b, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 1185 0x00, 0x01, 0x00, 0x01, 0x00, 0x69, 0x00, 0x00, 1186 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 1187 } 1188 // Read in the archive. 1189 _, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data))) 1190 if err != nil { 1191 t.Errorf("Error reading the archive: %v", err) 1192 } 1193 } 1194 1195 func TestFS(t *testing.T) { 1196 for _, test := range []struct { 1197 file string 1198 want []string 1199 }{ 1200 { 1201 "testdata/unix.zip", 1202 []string{"hello", "dir/bar", "readonly"}, 1203 }, 1204 { 1205 "testdata/subdir.zip", 1206 []string{"a/b/c"}, 1207 }, 1208 } { 1209 test := test 1210 t.Run(test.file, func(t *testing.T) { 1211 t.Parallel() 1212 z, err := OpenReader(test.file) 1213 if err != nil { 1214 t.Fatal(err) 1215 } 1216 defer z.Close() 1217 if err := fstest.TestFS(z, test.want...); err != nil { 1218 t.Error(err) 1219 } 1220 }) 1221 } 1222 } 1223 1224 func TestFSWalk(t *testing.T) { 1225 for _, test := range []struct { 1226 file string 1227 want []string 1228 wantErr bool 1229 }{ 1230 { 1231 file: "testdata/unix.zip", 1232 want: []string{".", "dir", "dir/bar", "dir/empty", "hello", "readonly"}, 1233 }, 1234 { 1235 file: "testdata/subdir.zip", 1236 want: []string{".", "a", "a/b", "a/b/c"}, 1237 }, 1238 { 1239 file: "testdata/dupdir.zip", 1240 wantErr: true, 1241 }, 1242 } { 1243 test := test 1244 t.Run(test.file, func(t *testing.T) { 1245 t.Parallel() 1246 z, err := OpenReader(test.file) 1247 if err != nil { 1248 t.Fatal(err) 1249 } 1250 var files []string 1251 sawErr := false 1252 err = fs.WalkDir(z, ".", func(path string, d fs.DirEntry, err error) error { 1253 if err != nil { 1254 if !test.wantErr { 1255 t.Errorf("%s: %v", path, err) 1256 } 1257 sawErr = true 1258 return nil 1259 } 1260 files = append(files, path) 1261 return nil 1262 }) 1263 if err != nil { 1264 t.Errorf("fs.WalkDir error: %v", err) 1265 } 1266 if test.wantErr && !sawErr { 1267 t.Error("succeeded but want error") 1268 } else if !test.wantErr && sawErr { 1269 t.Error("unexpected error") 1270 } 1271 if test.want != nil && !reflect.DeepEqual(files, test.want) { 1272 t.Errorf("got %v want %v", files, test.want) 1273 } 1274 }) 1275 } 1276 } 1277 1278 func TestFSModTime(t *testing.T) { 1279 t.Parallel() 1280 z, err := OpenReader("testdata/subdir.zip") 1281 if err != nil { 1282 t.Fatal(err) 1283 } 1284 defer z.Close() 1285 1286 for _, test := range []struct { 1287 name string 1288 want time.Time 1289 }{ 1290 { 1291 "a", 1292 time.Date(2021, 4, 19, 12, 29, 56, 0, timeZone(-7*time.Hour)).UTC(), 1293 }, 1294 { 1295 "a/b/c", 1296 time.Date(2021, 4, 19, 12, 29, 59, 0, timeZone(-7*time.Hour)).UTC(), 1297 }, 1298 } { 1299 fi, err := fs.Stat(z, test.name) 1300 if err != nil { 1301 t.Errorf("%s: %v", test.name, err) 1302 continue 1303 } 1304 if got := fi.ModTime(); !got.Equal(test.want) { 1305 t.Errorf("%s: got modtime %v, want %v", test.name, got, test.want) 1306 } 1307 } 1308 } 1309 1310 func TestCVE202127919(t *testing.T) { 1311 t.Setenv("GODEBUG", "zipinsecurepath=0") 1312 // Archive containing only the file "../test.txt" 1313 data := []byte{ 1314 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 1315 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1317 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e, 1318 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 1319 0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c, 1320 0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51, 1321 0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc, 1322 0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff, 1323 0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed, 1324 0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 1325 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 1326 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 1327 0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00, 1328 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 1329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 1331 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 1332 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 1333 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00, 1334 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 1335 } 1336 r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data))) 1337 if err != ErrInsecurePath { 1338 t.Fatalf("Error reading the archive: %v", err) 1339 } 1340 _, err = r.Open("test.txt") 1341 if err != nil { 1342 t.Errorf("Error reading file: %v", err) 1343 } 1344 if len(r.File) != 1 { 1345 t.Fatalf("No entries in the file list") 1346 } 1347 if r.File[0].Name != "../test.txt" { 1348 t.Errorf("Unexpected entry name: %s", r.File[0].Name) 1349 } 1350 if _, err := r.File[0].Open(); err != nil { 1351 t.Errorf("Error opening file: %v", err) 1352 } 1353 } 1354 1355 func TestOpenReaderInsecurePath(t *testing.T) { 1356 t.Setenv("GODEBUG", "zipinsecurepath=0") 1357 // Archive containing only the file "../test.txt" 1358 data := []byte{ 1359 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 1360 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1362 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e, 1363 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 1364 0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c, 1365 0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51, 1366 0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc, 1367 0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff, 1368 0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed, 1369 0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 1370 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 1371 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 1372 0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00, 1373 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 1374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 1376 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 1377 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 1378 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00, 1379 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 1380 } 1381 1382 // Read in the archive with the OpenReader interface 1383 name := filepath.Join(t.TempDir(), "test.zip") 1384 err := os.WriteFile(name, data, 0644) 1385 if err != nil { 1386 t.Fatalf("Unable to write out the bugos zip entry") 1387 } 1388 r, err := OpenReader(name) 1389 if r != nil { 1390 defer r.Close() 1391 } 1392 1393 if err != ErrInsecurePath { 1394 t.Fatalf("Error reading the archive, we expected ErrInsecurePath but got: %v", err) 1395 } 1396 _, err = r.Open("test.txt") 1397 if err != nil { 1398 t.Errorf("Error reading file: %v", err) 1399 } 1400 if len(r.File) != 1 { 1401 t.Fatalf("No entries in the file list") 1402 } 1403 if r.File[0].Name != "../test.txt" { 1404 t.Errorf("Unexpected entry name: %s", r.File[0].Name) 1405 } 1406 if _, err := r.File[0].Open(); err != nil { 1407 t.Errorf("Error opening file: %v", err) 1408 } 1409 } 1410 1411 func TestCVE202133196(t *testing.T) { 1412 // Archive that indicates it has 1 << 128 -1 files, 1413 // this would previously cause a panic due to attempting 1414 // to allocate a slice with 1 << 128 -1 elements. 1415 data := []byte{ 1416 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 1417 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1419 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 1420 0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00, 1421 0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20, 1422 0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 1423 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 1424 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 1425 0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00, 1426 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 1427 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1429 0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c, 1430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 1431 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1432 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 1433 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 1434 0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00, 1435 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 1436 0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00, 1437 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 1438 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 1439 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, 1440 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1441 0xff, 0xff, 0xff, 0x00, 0x00, 1442 } 1443 _, err := NewReader(bytes.NewReader(data), int64(len(data))) 1444 if err != ErrFormat { 1445 t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat) 1446 } 1447 1448 // Also check that an archive containing a handful of empty 1449 // files doesn't cause an issue 1450 b := bytes.NewBuffer(nil) 1451 w := NewWriter(b) 1452 for i := 0; i < 5; i++ { 1453 _, err := w.Create("") 1454 if err != nil { 1455 t.Fatalf("Writer.Create failed: %s", err) 1456 } 1457 } 1458 if err := w.Close(); err != nil { 1459 t.Fatalf("Writer.Close failed: %s", err) 1460 } 1461 r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len())) 1462 if err != nil { 1463 t.Fatalf("NewReader failed: %s", err) 1464 } 1465 if len(r.File) != 5 { 1466 t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File)) 1467 } 1468 } 1469 1470 func TestCVE202139293(t *testing.T) { 1471 // directory size is so large, that the check in Reader.init 1472 // overflows when subtracting from the archive size, causing 1473 // the pre-allocation check to be bypassed. 1474 data := []byte{ 1475 0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 1476 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 1477 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 1478 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 1479 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 1480 0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff, 1481 } 1482 _, err := NewReader(bytes.NewReader(data), int64(len(data))) 1483 if err != ErrFormat { 1484 t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat) 1485 } 1486 } 1487 1488 func TestCVE202141772(t *testing.T) { 1489 t.Setenv("GODEBUG", "zipinsecurepath=0") 1490 // Archive contains a file whose name is exclusively made up of '/', '\' 1491 // characters, or "../", "..\" paths, which would previously cause a panic. 1492 // 1493 // Length Method Size Cmpr Date Time CRC-32 Name 1494 // -------- ------ ------- ---- ---------- ----- -------- ---- 1495 // 0 Stored 0 0% 08-05-2021 18:32 00000000 / 1496 // 0 Stored 0 0% 09-14-2021 12:59 00000000 // 1497 // 0 Stored 0 0% 09-14-2021 12:59 00000000 \ 1498 // 11 Stored 11 0% 09-14-2021 13:04 0d4a1185 /test.txt 1499 // -------- ------- --- ------- 1500 // 11 11 0% 4 files 1501 data := []byte{ 1502 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08, 1503 0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00, 1504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1505 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50, 1506 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 1507 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 1508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1509 0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50, 1510 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 1511 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 1512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1513 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b, 1514 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 1515 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d, 1516 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 1517 0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73, 1518 0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c, 1519 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 1520 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00, 1521 0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 1522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1523 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 1524 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 1525 0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50, 1526 0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 1527 0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 1528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1529 0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 1530 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 1531 0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a, 1532 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 1533 0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25, 1534 0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25, 1535 0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25, 1536 0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f, 1537 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 1538 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 1539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 1540 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1541 0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 1542 0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 1543 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98, 1544 0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98, 1545 0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98, 1546 0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b, 1547 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00, 1548 0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 1549 0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 1550 0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00, 1551 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 1552 0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73, 1553 0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20, 1554 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 1555 0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7, 1556 0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7, 1557 0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7, 1558 0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 1559 0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00, 1560 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 1561 } 1562 r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data))) 1563 if err != ErrInsecurePath { 1564 t.Fatalf("Error reading the archive: %v", err) 1565 } 1566 entryNames := []string{`/`, `//`, `\`, `/test.txt`} 1567 var names []string 1568 for _, f := range r.File { 1569 names = append(names, f.Name) 1570 if _, err := f.Open(); err != nil { 1571 t.Errorf("Error opening %q: %v", f.Name, err) 1572 } 1573 if _, err := r.Open(f.Name); err == nil { 1574 t.Errorf("Opening %q with fs.FS API succeeded", f.Name) 1575 } 1576 } 1577 if !reflect.DeepEqual(names, entryNames) { 1578 t.Errorf("Unexpected file entries: %q", names) 1579 } 1580 if _, err := r.Open(""); err == nil { 1581 t.Errorf("Opening %q with fs.FS API succeeded", "") 1582 } 1583 if _, err := r.Open("test.txt"); err != nil { 1584 t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err) 1585 } 1586 dirEntries, err := fs.ReadDir(r, ".") 1587 if err != nil { 1588 t.Fatalf("Error reading the root directory: %v", err) 1589 } 1590 if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" { 1591 t.Errorf("Unexpected directory entries") 1592 for _, dirEntry := range dirEntries { 1593 _, err := r.Open(dirEntry.Name()) 1594 t.Logf("%q (Open error: %v)", dirEntry.Name(), err) 1595 } 1596 t.FailNow() 1597 } 1598 info, err := dirEntries[0].Info() 1599 if err != nil { 1600 t.Fatalf("Error reading info entry: %v", err) 1601 } 1602 if name := info.Name(); name != "test.txt" { 1603 t.Errorf("Inconsistent name in info entry: %v", name) 1604 } 1605 } 1606 1607 func TestUnderSize(t *testing.T) { 1608 z, err := OpenReader("testdata/readme.zip") 1609 if err != nil { 1610 t.Fatal(err) 1611 } 1612 defer z.Close() 1613 1614 for _, f := range z.File { 1615 f.UncompressedSize64 = 1 1616 } 1617 1618 for _, f := range z.File { 1619 t.Run(f.Name, func(t *testing.T) { 1620 rd, err := f.Open() 1621 if err != nil { 1622 t.Fatal(err) 1623 } 1624 defer rd.Close() 1625 1626 _, err = io.Copy(io.Discard, rd) 1627 if err != ErrFormat { 1628 t.Fatalf("Error mismatch\n\tGot: %v\n\tWant: %v", err, ErrFormat) 1629 } 1630 }) 1631 } 1632 } 1633 1634 func TestIssue54801(t *testing.T) { 1635 for _, input := range []string{"testdata/readme.zip", "testdata/dd.zip"} { 1636 z, err := OpenReader(input) 1637 if err != nil { 1638 t.Fatal(err) 1639 } 1640 defer z.Close() 1641 1642 for _, f := range z.File { 1643 // Make file a directory 1644 f.Name += "/" 1645 1646 t.Run(f.Name, func(t *testing.T) { 1647 t.Logf("CompressedSize64: %d, Flags: %#x", f.CompressedSize64, f.Flags) 1648 1649 rd, err := f.Open() 1650 if err != nil { 1651 t.Fatal(err) 1652 } 1653 defer rd.Close() 1654 1655 n, got := io.Copy(io.Discard, rd) 1656 if n != 0 || got != ErrFormat { 1657 t.Fatalf("Error mismatch, got: %d, %v, want: %v", n, got, ErrFormat) 1658 } 1659 }) 1660 } 1661 } 1662 } 1663 1664 func TestInsecurePaths(t *testing.T) { 1665 t.Setenv("GODEBUG", "zipinsecurepath=0") 1666 for _, path := range []string{ 1667 "../foo", 1668 "/foo", 1669 "a/b/../../../c", 1670 `a\b`, 1671 } { 1672 var buf bytes.Buffer 1673 zw := NewWriter(&buf) 1674 _, err := zw.Create(path) 1675 if err != nil { 1676 t.Errorf("zw.Create(%q) = %v", path, err) 1677 continue 1678 } 1679 zw.Close() 1680 1681 zr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) 1682 if err != ErrInsecurePath { 1683 t.Errorf("NewReader for archive with file %q: got err %v, want ErrInsecurePath", path, err) 1684 continue 1685 } 1686 var gotPaths []string 1687 for _, f := range zr.File { 1688 gotPaths = append(gotPaths, f.Name) 1689 } 1690 if !reflect.DeepEqual(gotPaths, []string{path}) { 1691 t.Errorf("NewReader for archive with file %q: got files %q", path, gotPaths) 1692 continue 1693 } 1694 } 1695 } 1696 1697 func TestDisableInsecurePathCheck(t *testing.T) { 1698 t.Setenv("GODEBUG", "zipinsecurepath=1") 1699 var buf bytes.Buffer 1700 zw := NewWriter(&buf) 1701 const name = "/foo" 1702 _, err := zw.Create(name) 1703 if err != nil { 1704 t.Fatalf("zw.Create(%q) = %v", name, err) 1705 } 1706 zw.Close() 1707 zr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) 1708 if err != nil { 1709 t.Fatalf("NewReader with zipinsecurepath=1: got err %v, want nil", err) 1710 } 1711 var gotPaths []string 1712 for _, f := range zr.File { 1713 gotPaths = append(gotPaths, f.Name) 1714 } 1715 if want := []string{name}; !reflect.DeepEqual(gotPaths, want) { 1716 t.Errorf("NewReader with zipinsecurepath=1: got files %q, want %q", gotPaths, want) 1717 } 1718 } 1719 1720 func TestCompressedDirectory(t *testing.T) { 1721 // Empty Java JAR, with a compressed directory with uncompressed size 0 1722 // which should not fail. 1723 // 1724 // Length Method Size Cmpr Date Time CRC-32 Name 1725 // -------- ------ ------- ---- ---------- ----- -------- ---- 1726 // 0 Defl:N 2 0% 12-01-2022 16:50 00000000 META-INF/ 1727 // 60 Defl:N 59 2% 12-01-2022 16:50 af937e93 META-INF/MANIFEST.MF 1728 // -------- ------- --- ------- 1729 // 60 61 -2% 2 files 1730 data := []byte{ 1731 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 1732 0x08, 0x00, 0x49, 0x86, 0x81, 0x55, 0x00, 0x00, 1733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1734 0x00, 0x00, 0x09, 0x00, 0x04, 0x00, 0x4d, 0x45, 1735 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, 0x2f, 0xfe, 1736 0xca, 0x00, 0x00, 0x03, 0x00, 0x50, 0x4b, 0x07, 1737 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 1738 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x03, 1739 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x49, 1740 0x86, 0x81, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 1741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 1742 0x00, 0x00, 0x00, 0x4d, 0x45, 0x54, 0x41, 0x2d, 1743 0x49, 0x4e, 0x46, 0x2f, 0x4d, 0x41, 0x4e, 0x49, 1744 0x46, 0x45, 0x53, 0x54, 0x2e, 0x4d, 0x46, 0xf3, 1745 0x4d, 0xcc, 0xcb, 0x4c, 0x4b, 0x2d, 0x2e, 0xd1, 1746 0x0d, 0x4b, 0x2d, 0x2a, 0xce, 0xcc, 0xcf, 0xb3, 1747 0x52, 0x30, 0xd4, 0x33, 0xe0, 0xe5, 0x72, 0x2e, 1748 0x4a, 0x4d, 0x2c, 0x49, 0x4d, 0xd1, 0x75, 0xaa, 1749 0x04, 0x0a, 0x00, 0x45, 0xf4, 0x0c, 0x8d, 0x15, 1750 0x34, 0xdc, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0x15, 1751 0x3c, 0xf3, 0x92, 0xf5, 0x34, 0x79, 0xb9, 0x78, 1752 0xb9, 0x00, 0x50, 0x4b, 0x07, 0x08, 0x93, 0x7e, 1753 0x93, 0xaf, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 1754 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 1755 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x49, 0x86, 1756 0x81, 0x55, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 1757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 1758 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1760 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, 1761 0x2f, 0xfe, 0xca, 0x00, 0x00, 0x50, 0x4b, 0x01, 1762 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 1763 0x00, 0x49, 0x86, 0x81, 0x55, 0x93, 0x7e, 0x93, 1764 0xaf, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 1765 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 1767 0x00, 0x00, 0x00, 0x4d, 0x45, 0x54, 0x41, 0x2d, 1768 0x49, 0x4e, 0x46, 0x2f, 0x4d, 0x41, 0x4e, 0x49, 1769 0x46, 0x45, 0x53, 0x54, 0x2e, 0x4d, 0x46, 0x50, 1770 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 1771 0x00, 0x02, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xba, 1772 0x00, 0x00, 0x00, 0x00, 0x00, 1773 } 1774 r, err := NewReader(bytes.NewReader(data), int64(len(data))) 1775 if err != nil { 1776 t.Fatalf("unexpected error: %v", err) 1777 } 1778 for _, f := range r.File { 1779 r, err := f.Open() 1780 if err != nil { 1781 t.Fatalf("unexpected error: %v", err) 1782 } 1783 if _, err := io.Copy(io.Discard, r); err != nil { 1784 t.Fatalf("unexpected error: %v", err) 1785 } 1786 } 1787 } 1788 1789 func TestBaseOffsetPlusOverflow(t *testing.T) { 1790 // directoryOffset > maxInt64 && size-directoryOffset < 0 1791 data := []byte{ 1792 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1793 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1794 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1795 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1796 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1797 0xff, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1798 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1799 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1800 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1801 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1802 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1803 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1804 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1805 0x20, 0x20, 0x20, 0x50, 0x4b, 0x06, 0x06, 0x20, 1806 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1807 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1808 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1809 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1810 0x20, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 1811 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 1812 0x00, 0x00, 0x80, 0x50, 0x4b, 0x06, 0x07, 0x00, 1813 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 1814 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 1815 0x4b, 0x05, 0x06, 0x20, 0x20, 0x20, 0x20, 0xff, 1816 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1817 0xff, 0xff, 0xff, 0x20, 0x00, 1818 } 1819 defer func() { 1820 if r := recover(); r != nil { 1821 t.Fatalf("NewReader panicked: %s", r) 1822 } 1823 }() 1824 // Previously, this would trigger a panic as we attempt to read from 1825 // a io.SectionReader which would access a slice at a negative offset 1826 // as the section reader offset & size were < 0. 1827 NewReader(bytes.NewReader(data), int64(len(data))+1875) 1828 }