summaryrefslogtreecommitdiff
path: root/src/pkg/archive/zip
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/archive/zip')
-rw-r--r--src/pkg/archive/zip/reader.go2
-rw-r--r--src/pkg/archive/zip/reader_test.go28
-rw-r--r--src/pkg/archive/zip/register.go41
-rw-r--r--src/pkg/archive/zip/struct.go4
-rw-r--r--src/pkg/archive/zip/testdata/zip64-2.zipbin0 -> 266 bytes
-rw-r--r--src/pkg/archive/zip/writer_test.go18
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
new file mode 100644
index 000000000..f844e3537
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/zip64-2.zip
Binary files differ
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()
+ }
+}