diff options
Diffstat (limited to 'src/pkg/archive/zip/reader_test.go')
-rw-r--r-- | src/pkg/archive/zip/reader_test.go | 252 |
1 files changed, 211 insertions, 41 deletions
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go index 066a61580..5f1d1b28a 100644 --- a/src/pkg/archive/zip/reader_test.go +++ b/src/pkg/archive/zip/reader_test.go @@ -7,26 +7,31 @@ package zip import ( "bytes" "encoding/binary" + "encoding/hex" "io" "io/ioutil" "os" + "path/filepath" + "regexp" "testing" "time" ) type ZipTest struct { Name string + Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file Comment string File []ZipTestFile Error error // the error that Opening this file should return } type ZipTestFile struct { - Name string - Content []byte // if blank, will attempt to compare against File - File string // name of file to compare to (relative to testdata/) - Mtime string // modified time in format "mm-dd-yy hh:mm:ss" - Mode os.FileMode + Name string + Content []byte // if blank, will attempt to compare against File + ContentErr error + File string // name of file to compare to (relative to testdata/) + Mtime string // modified time in format "mm-dd-yy hh:mm:ss" + Mode os.FileMode } // Caution: The Mtime values found for the test files should correspond to @@ -59,13 +64,14 @@ var tests = []ZipTest{ }, }, { - Name: "r.zip", + Name: "r.zip", + Source: returnRecursiveZip, File: []ZipTestFile{ { - Name: "r/r.zip", - File: "r.zip", - Mtime: "03-04-10 00:24:16", - Mode: 0666, + Name: "r/r.zip", + Content: rZipBytes(), + Mtime: "03-04-10 00:24:16", + Mode: 0666, }, }, }, @@ -107,6 +113,99 @@ var tests = []ZipTest{ Name: "unix.zip", File: crossPlatform, }, + { + // created by Go, before we wrote the "optional" data + // descriptor signatures (which are required by OS X) + Name: "go-no-datadesc-sig.zip", + File: []ZipTestFile{ + { + Name: "foo.txt", + Content: []byte("foo\n"), + Mtime: "03-08-12 16:59:10", + Mode: 0644, + }, + { + Name: "bar.txt", + Content: []byte("bar\n"), + Mtime: "03-08-12 16:59:12", + Mode: 0644, + }, + }, + }, + { + // created by Go, after we wrote the "optional" data + // descriptor signatures (which are required by OS X) + Name: "go-with-datadesc-sig.zip", + File: []ZipTestFile{ + { + Name: "foo.txt", + Content: []byte("foo\n"), + Mode: 0666, + }, + { + Name: "bar.txt", + Content: []byte("bar\n"), + Mode: 0666, + }, + }, + }, + { + Name: "Bad-CRC32-in-data-descriptor", + Source: returnCorruptCRC32Zip, + File: []ZipTestFile{ + { + Name: "foo.txt", + Content: []byte("foo\n"), + Mode: 0666, + ContentErr: ErrChecksum, + }, + { + Name: "bar.txt", + Content: []byte("bar\n"), + Mode: 0666, + }, + }, + }, + // Tests that we verify (and accept valid) crc32s on files + // with crc32s in their file header (not in data descriptors) + { + Name: "crc32-not-streamed.zip", + File: []ZipTestFile{ + { + Name: "foo.txt", + Content: []byte("foo\n"), + Mtime: "03-08-12 16:59:10", + Mode: 0644, + }, + { + Name: "bar.txt", + Content: []byte("bar\n"), + Mtime: "03-08-12 16:59:12", + Mode: 0644, + }, + }, + }, + // Tests that we verify (and reject invalid) crc32s on files + // with crc32s in their file header (not in data descriptors) + { + Name: "crc32-not-streamed.zip", + Source: returnCorruptNotStreamedZip, + File: []ZipTestFile{ + { + Name: "foo.txt", + Content: []byte("foo\n"), + Mtime: "03-08-12 16:59:10", + Mode: 0644, + ContentErr: ErrChecksum, + }, + { + Name: "bar.txt", + Content: []byte("bar\n"), + Mtime: "03-08-12 16:59:12", + Mode: 0644, + }, + }, + }, } var crossPlatform = []ZipTestFile{ @@ -139,7 +238,18 @@ func TestReader(t *testing.T) { } func readTestZip(t *testing.T, zt ZipTest) { - z, err := OpenReader("testdata/" + zt.Name) + var z *Reader + var err error + if zt.Source != nil { + rat, size := zt.Source() + z, err = NewReader(rat, size) + } else { + var rc *ReadCloser + rc, err = OpenReader(filepath.Join("testdata", zt.Name)) + if err == nil { + z = &rc.Reader + } + } if err != zt.Error { t.Errorf("error=%v, want %v", err, zt.Error) return @@ -149,11 +259,6 @@ func readTestZip(t *testing.T, zt ZipTest) { if err == ErrFormat { return } - defer func() { - if err := z.Close(); err != nil { - t.Errorf("error %q when closing zip file", err) - } - }() // bail here if no Files expected to be tested // (there may actually be files in the zip, but we don't care) @@ -170,7 +275,7 @@ func readTestZip(t *testing.T, zt ZipTest) { // test read of each file for i, ft := range zt.File { - readTestFile(t, ft, z.File[i]) + readTestFile(t, zt, ft, z.File[i]) } // test simultaneous reads @@ -179,7 +284,7 @@ func readTestZip(t *testing.T, zt ZipTest) { for i := 0; i < 5; i++ { for j, ft := range zt.File { go func(j int, ft ZipTestFile) { - readTestFile(t, ft, z.File[j]) + readTestFile(t, zt, ft, z.File[j]) done <- true }(j, ft) n++ @@ -188,26 +293,11 @@ func readTestZip(t *testing.T, zt ZipTest) { for ; n > 0; n-- { <-done } - - // test invalid checksum - if !z.File[0].hasDataDescriptor() { // skip test when crc32 in dd - z.File[0].CRC32++ // invalidate - r, err := z.File[0].Open() - if err != nil { - t.Error(err) - return - } - var b bytes.Buffer - _, err = io.Copy(&b, r) - if err != ErrChecksum { - t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ErrChecksum) - } - } } -func readTestFile(t *testing.T, ft ZipTestFile, f *File) { +func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { if f.Name != ft.Name { - t.Errorf("name=%q, want %q", f.Name, ft.Name) + t.Errorf("%s: name=%q, want %q", zt.Name, f.Name, ft.Name) } if ft.Mtime != "" { @@ -217,11 +307,11 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { return } if ft := f.ModTime(); !ft.Equal(mtime) { - t.Errorf("%s: mtime=%s, want %s", f.Name, ft, mtime) + t.Errorf("%s: %s: mtime=%s, want %s", zt.Name, f.Name, ft, mtime) } } - testFileMode(t, f, ft.Mode) + testFileMode(t, zt.Name, f, ft.Mode) size0 := f.UncompressedSize @@ -237,8 +327,10 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { } _, err = io.Copy(&b, r) + if err != ft.ContentErr { + t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr) + } if err != nil { - t.Error(err) return } r.Close() @@ -264,12 +356,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { } } -func testFileMode(t *testing.T, f *File, want os.FileMode) { +func testFileMode(t *testing.T, zipName string, f *File, want os.FileMode) { mode := f.Mode() if want == 0 { - t.Errorf("%s mode: got %v, want none", f.Name, mode) + t.Errorf("%s: %s mode: got %v, want none", zipName, f.Name, mode) } else if mode != want { - t.Errorf("%s mode: want %v, got %v", f.Name, want, mode) + t.Errorf("%s: %s mode: want %v, got %v", zipName, f.Name, want, mode) } } @@ -294,3 +386,81 @@ func TestInvalidFiles(t *testing.T) { t.Errorf("sigs: error=%v, want %v", err, ErrFormat) } } + +func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) { + data, err := ioutil.ReadFile(filepath.Join("testdata", fileName)) + if err != nil { + panic("Error reading " + fileName + ": " + err.Error()) + } + corrupter(data) + return bytes.NewReader(data), int64(len(data)) +} + +func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) { + return messWith("go-with-datadesc-sig.zip", func(b []byte) { + // Corrupt one of the CRC32s in the data descriptor: + b[0x2d]++ + }) +} + +func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) { + return messWith("crc32-not-streamed.zip", func(b []byte) { + // Corrupt foo.txt's final crc32 byte, in both + // the file header and TOC. (0x7e -> 0x7f) + b[0x11]++ + b[0x9d]++ + + // TODO(bradfitz): add a new test that only corrupts + // one of these values, and verify that that's also an + // error. Currently, the reader code doesn't verify the + // fileheader and TOC's crc32 match if they're both + // non-zero and only the second line above, the TOC, + // is what matters. + }) +} + +// rZipBytes returns the bytes of a recursive zip file, without +// putting it on disk and triggering certain virus scanners. +func rZipBytes() []byte { + s := ` +0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4 +0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f +0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00 +0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 +0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 +0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00 +0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8 +0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f +0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e +0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb +00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff +00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 +00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14 +00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21 +00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb +00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff +0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a +0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3 +0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06 +0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00 +0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf +0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06 +0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01 +0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89 +0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00 +0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a +00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00 +00001b0 00 00 6d 01 00 00 00 00` + s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "") + s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "") + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +func returnRecursiveZip() (r io.ReaderAt, size int64) { + b := rZipBytes() + return bytes.NewReader(b), int64(len(b)) +} |