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