]> Cypherpunks repositories - gostls13.git/commitdiff
archive/zip: fix size value in ZIP64 end central directory record
authorJoe Shaw <joe@joeshaw.org>
Thu, 12 Feb 2015 22:21:01 +0000 (17:21 -0500)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 26 Feb 2015 15:24:32 +0000 (15:24 +0000)
Section 4.3.14.1 of the ZIP file format
spec (https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) says,

    The value stored into the "size of zip64 end of central directory
    record" should be the size of the remaining record and should not
    include the leading 12 bytes.

We were previously writing the full size, including the 12 bytes.

Fixes #9857

Change-Id: I7cf1fc8457c5f306717cbcf61e02304ab549781f
Reviewed-on: https://go-review.googlesource.com/4760
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>

src/archive/zip/writer.go
src/archive/zip/zip_test.go

index 170beec0eec3fe8a76c96f8f8752afd7d3c6ee8e..6a71887c6360c8c30a6d7f3d86a0f47b0193dc13 100644 (file)
@@ -122,15 +122,15 @@ func (w *Writer) Close() error {
 
                // zip64 end of central directory record
                b.uint32(directory64EndSignature)
-               b.uint64(directory64EndLen)
-               b.uint16(zipVersion45) // version made by
-               b.uint16(zipVersion45) // version needed to extract
-               b.uint32(0)            // number of this disk
-               b.uint32(0)            // number of the disk with the start of the central directory
-               b.uint64(records)      // total number of entries in the central directory on this disk
-               b.uint64(records)      // total number of entries in the central directory
-               b.uint64(size)         // size of the central directory
-               b.uint64(offset)       // offset of start of central directory with respect to the starting disk number
+               b.uint64(directory64EndLen - 12) // length minus signature (uint32) and length fields (uint64)
+               b.uint16(zipVersion45)           // version made by
+               b.uint16(zipVersion45)           // version needed to extract
+               b.uint32(0)                      // number of this disk
+               b.uint32(0)                      // number of the disk with the start of the central directory
+               b.uint64(records)                // total number of entries in the central directory on this disk
+               b.uint64(records)                // total number of entries in the central directory
+               b.uint64(size)                   // size of the central directory
+               b.uint64(offset)                 // offset of start of central directory with respect to the starting disk number
 
                // zip64 end of central directory locator
                b.uint32(directory64LocSignature)
index 32a16a79efbcc78a617093d5f2751f140c17d77d..f00ff47d37ecb29d0fa89cb303a6a17f01cdb812 100644 (file)
@@ -229,10 +229,11 @@ func TestZip64(t *testing.T) {
                t.Skip("slow test; skipping")
        }
        const size = 1 << 32 // before the "END\n" part
-       testZip64(t, size)
+       buf := testZip64(t, size)
+       testZip64DirectoryRecordLength(buf, t)
 }
 
-func testZip64(t testing.TB, size int64) {
+func testZip64(t testing.TB, size int64) *rleBuffer {
        const chunkSize = 1024
        chunks := int(size / chunkSize)
        // write 2^32 bytes plus "END\n" to a zip file
@@ -302,6 +303,37 @@ func testZip64(t testing.TB, size int64) {
        if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
                t.Errorf("UncompressedSize64 %d, want %d", got, want)
        }
+
+       return buf
+}
+
+// Issue 9857
+func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
+       d := make([]byte, 1024)
+       if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
+               t.Fatal("read:", err)
+       }
+
+       sigOff := findSignatureInBlock(d)
+       dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
+       if err != nil {
+               t.Fatal("findDirectory64End:", err)
+       }
+
+       d = make([]byte, directory64EndLen)
+       if _, err := buf.ReadAt(d, dirOff); err != nil {
+               t.Fatal("read:", err)
+       }
+
+       b := readBuf(d)
+       if sig := b.uint32(); sig != directory64EndSignature {
+               t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
+       }
+
+       size := b.uint64()
+       if size != directory64EndLen-12 {
+               t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
+       }
 }
 
 func testInvalidHeader(h *FileHeader, t *testing.T) {