diff options
author | Antonin Amand <antonin.amand@gmail.com> | 2018-05-02 12:07:56 +0200 |
---|---|---|
committer | Joe Tsai <thebrokentoaster@gmail.com> | 2018-05-02 23:34:50 +0000 |
commit | 7b451dc715a728ea03edf17fa497d8f72d32a03f (patch) | |
tree | 79c82fc6f57a81748734341865b2a939deb57d1f /src/archive | |
parent | 8cd0094b4ee6b51c49f96de98308701108b45995 (diff) | |
download | go-7b451dc715a728ea03edf17fa497d8f72d32a03f.tar.gz go-7b451dc715a728ea03edf17fa497d8f72d32a03f.zip |
archive/zip: avoid data descriptor when writing directories
Java fails to unzip archives created by archive/zip because directories are
written with the "data descriptor" flag (bit 3) set, but emits no such
descriptor. To fix this, we explicitly clear the flag.
Fixes #25215
Change-Id: Id3af4c7f863758197063df879717c1710f86c0e5
Reviewed-on: https://go-review.googlesource.com/110795
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/archive')
-rw-r--r-- | src/archive/zip/writer.go | 11 | ||||
-rw-r--r-- | src/archive/zip/writer_test.go | 36 |
2 files changed, 45 insertions, 2 deletions
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index f3abe8770c..0f1a193345 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -263,8 +263,6 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { return nil, errors.New("archive/zip: invalid duplicate FileHeader") } - fh.Flags |= 0x8 // we will write a data descriptor - // The ZIP format has a sad state of affairs regarding character encoding. // Officially, the name and comment fields are supposed to be encoded // in CP-437 (which is mostly compatible with ASCII), unless the UTF-8 @@ -331,8 +329,17 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { } if strings.HasSuffix(fh.Name, "/") { + // Set the compression method to Store to ensure data length is truly zero, + // which the writeHeader method always encodes for the size fields. + // This is necessary as most compression formats have non-zero lengths + // even when compressing an empty string. + fh.Method = Store + fh.Flags &^= 0x8 // we will not write a data descriptor + ow = dirWriter{} } else { + fh.Flags |= 0x8 // we will write a data descriptor + fw = &fileWriter{ zipw: w.cw, compCount: &countWriter{w: w.cw}, diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go index 271a36729c..468424c72a 100644 --- a/src/archive/zip/writer_test.go +++ b/src/archive/zip/writer_test.go @@ -6,6 +6,7 @@ package zip import ( "bytes" + "encoding/binary" "fmt" "io" "io/ioutil" @@ -310,6 +311,41 @@ func TestWriterDir(t *testing.T) { } } +func TestWriterDirAttributes(t *testing.T) { + var buf bytes.Buffer + w := NewWriter(&buf) + if _, err := w.Create("dir/"); err != nil { + t.Fatal(err) + } + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + + var sig [4]byte + binary.LittleEndian.PutUint32(sig[:], uint32(fileHeaderSignature)) + + idx := bytes.Index(b, sig[:]) + if idx == -1 { + t.Fatal("file header not found") + } + b = b[idx:] + + if !bytes.Equal(b[6:10], []byte{0, 0, 0, 0}) { // FileHeader.Flags: 0, FileHeader.Method: 0 + t.Errorf("unexpected method and flags: %v", b[6:10]) + } + + if !bytes.Equal(b[14:26], make([]byte, 12)) { // FileHeader.{CRC32,CompressSize,UncompressedSize} all zero. + t.Errorf("unexpected crc, compress and uncompressed size to be 0 was: %v", b[14:26]) + } + + binary.LittleEndian.PutUint32(sig[:], uint32(dataDescriptorSignature)) + if bytes.Index(b, sig[:]) != -1 { + t.Error("there should be no data descriptor") + } +} + func testCreate(t *testing.T, w *Writer, wt *WriteTest) { header := &FileHeader{ Name: wt.Name, |