diff options
Diffstat (limited to 'src/pkg/archive/zip')
-rw-r--r-- | src/pkg/archive/zip/reader.go | 2 | ||||
-rw-r--r-- | src/pkg/archive/zip/reader_test.go | 28 | ||||
-rw-r--r-- | src/pkg/archive/zip/register.go | 41 | ||||
-rw-r--r-- | src/pkg/archive/zip/struct.go | 4 | ||||
-rw-r--r-- | src/pkg/archive/zip/testdata/zip64-2.zip | bin | 0 -> 266 bytes | |||
-rw-r--r-- | src/pkg/archive/zip/writer_test.go | 18 |
6 files changed, 82 insertions, 11 deletions
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go index 116737337..80ee03006 100644 --- a/src/pkg/archive/zip/reader.go +++ b/src/pkg/archive/zip/reader.go @@ -253,7 +253,7 @@ func readDirectoryHeader(f *File, r io.Reader) error { } if tag == zip64ExtraId { // update directory values from the zip64 extra block - eb := readBuf(b) + eb := readBuf(b[:size]) if len(eb) >= 8 { f.UncompressedSize64 = eb.uint64() } diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go index 78875ecbf..5652f3a50 100644 --- a/src/pkg/archive/zip/reader_test.go +++ b/src/pkg/archive/zip/reader_test.go @@ -235,6 +235,18 @@ var tests = []ZipTest{ }, }, }, + // Another zip64 file with different Extras fields. (golang.org/issue/7069) + { + Name: "zip64-2.zip", + File: []ZipTestFile{ + { + Name: "README", + Content: []byte("This small file is in ZIP64 format.\n"), + Mtime: "08-10-12 14:33:32", + Mode: 0644, + }, + }, + }, } var crossPlatform = []ZipTestFile{ @@ -343,19 +355,13 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { testFileMode(t, zt.Name, f, ft.Mode) - size0 := f.UncompressedSize - var b bytes.Buffer r, err := f.Open() if err != nil { - t.Error(err) + t.Errorf("%s: %v", zt.Name, err) return } - if size1 := f.UncompressedSize; size0 != size1 { - t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1) - } - _, err = io.Copy(&b, r) if err != ft.ContentErr { t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr) @@ -365,6 +371,14 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { } r.Close() + size := uint64(f.UncompressedSize) + if size == uint32max { + size = f.UncompressedSize64 + } + if g := uint64(b.Len()); g != size { + t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size) + } + var c []byte if ft.Content != nil { c = ft.Content diff --git a/src/pkg/archive/zip/register.go b/src/pkg/archive/zip/register.go index c046f081b..4211ec7af 100644 --- a/src/pkg/archive/zip/register.go +++ b/src/pkg/archive/zip/register.go @@ -6,6 +6,7 @@ package zip import ( "compress/flate" + "errors" "io" "io/ioutil" "sync" @@ -21,12 +22,50 @@ type Compressor func(io.Writer) (io.WriteCloser, error) // when they're finished reading. type Decompressor func(io.Reader) io.ReadCloser +var flateWriterPool sync.Pool + +func newFlateWriter(w io.Writer) io.WriteCloser { + fw, ok := flateWriterPool.Get().(*flate.Writer) + if ok { + fw.Reset(w) + } else { + fw, _ = flate.NewWriter(w, 5) + } + return &pooledFlateWriter{fw: fw} +} + +type pooledFlateWriter struct { + mu sync.Mutex // guards Close and Write + fw *flate.Writer +} + +func (w *pooledFlateWriter) Write(p []byte) (n int, err error) { + w.mu.Lock() + defer w.mu.Unlock() + if w.fw == nil { + return 0, errors.New("Write after Close") + } + return w.fw.Write(p) +} + +func (w *pooledFlateWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + var err error + if w.fw != nil { + err = w.fw.Close() + flateWriterPool.Put(w.fw) + w.fw = nil + } + return err +} + var ( mu sync.RWMutex // guards compressor and decompressor maps compressors = map[uint16]Compressor{ Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }, - Deflate: func(w io.Writer) (io.WriteCloser, error) { return flate.NewWriter(w, 5) }, + Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }, } decompressors = map[uint16]Decompressor{ diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go index 65e5238c3..cb28e8324 100644 --- a/src/pkg/archive/zip/struct.go +++ b/src/pkg/archive/zip/struct.go @@ -174,13 +174,13 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { return } -// ModTime returns the modification time. +// ModTime returns the modification time in UTC. // The resolution is 2s. func (h *FileHeader) ModTime() time.Time { return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) } -// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time. +// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC. // The resolution is 2s. func (h *FileHeader) SetModTime(t time.Time) { h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t) diff --git a/src/pkg/archive/zip/testdata/zip64-2.zip b/src/pkg/archive/zip/testdata/zip64-2.zip Binary files differnew file mode 100644 index 000000000..f844e3537 --- /dev/null +++ b/src/pkg/archive/zip/testdata/zip64-2.zip diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go index 8b1c4dfd2..4bfa87080 100644 --- a/src/pkg/archive/zip/writer_test.go +++ b/src/pkg/archive/zip/writer_test.go @@ -125,3 +125,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) { t.Errorf("File contents %q, want %q", b, wt.Data) } } + +func BenchmarkCompressedZipGarbage(b *testing.B) { + b.ReportAllocs() + var buf bytes.Buffer + bigBuf := bytes.Repeat([]byte("a"), 1<<20) + for i := 0; i < b.N; i++ { + buf.Reset() + zw := NewWriter(&buf) + for j := 0; j < 3; j++ { + w, _ := zw.CreateHeader(&FileHeader{ + Name: "foo", + Method: Deflate, + }) + w.Write(bigBuf) + } + zw.Close() + } +} |