diff options
author | 2021-05-07 15:59:32 -0700 | |
---|---|---|
committer | 2021-05-08 00:18:04 +0000 | |
commit | 06eea2c9b87c008e3ad7cf3bad8f347aaa342d6b (patch) | |
tree | 19c345aaf90f1e81d2aa63b7aad66f17f09833f9 | |
parent | ee7e359131b4f427ca0085f78a31dac22697d40c (diff) |
Store real number of records in regular end record when possible
Only store uintmax for the number of entries in the regular end record
if it doesn't fit. p7zip 16.02 rejects zip files where the number of
entries in the regular end record is larger than the number of entries
counted in the central directory.
Fixes: 187485108
Test: TestZip64P7ZipRecords
Change-Id: I0d116e228a0ee26e4e95bb3f35771da236a056eb
-rw-r--r-- | third_party/zip/android_test.go | 80 | ||||
-rw-r--r-- | third_party/zip/writer.go | 9 |
2 files changed, 88 insertions, 1 deletions
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go index 9932c1b13..46588d463 100644 --- a/third_party/zip/android_test.go +++ b/third_party/zip/android_test.go @@ -140,3 +140,83 @@ func TestCopyFromZip64(t *testing.T) { t.Errorf("Expected UnompressedSize64 %d, got %d", w, g) } } + +// Test for b/187485108: zip64 output can't be read by p7zip 16.02. +func TestZip64P7ZipRecords(t *testing.T) { + if testing.Short() { + t.Skip("slow test; skipping") + } + + const size = uint32max + 1 + zipBytes := &bytes.Buffer{} + zip := NewWriter(zipBytes) + f, err := zip.CreateHeaderAndroid(&FileHeader{ + Name: "large", + Method: Store, + UncompressedSize64: size, + CompressedSize64: size, + }) + if err != nil { + t.Fatalf("Create: %v", err) + } + _, err = f.Write(make([]byte, size)) + if err != nil { + t.Fatalf("Write: %v", err) + } + err = zip.Close() + if err != nil { + t.Fatalf("Close: %v", err) + } + + buf := zipBytes.Bytes() + p := findSignatureInBlock(buf) + if p < 0 { + t.Fatalf("Missing signature") + } + + b := readBuf(buf[p+4:]) // skip signature + d := &directoryEnd{ + diskNbr: uint32(b.uint16()), + dirDiskNbr: uint32(b.uint16()), + dirRecordsThisDisk: uint64(b.uint16()), + directoryRecords: uint64(b.uint16()), + directorySize: uint64(b.uint32()), + directoryOffset: uint64(b.uint32()), + commentLen: b.uint16(), + } + + // p7zip 16.02 wants regular end record directoryRecords to be accurate. + if g, w := d.directoryRecords, uint64(1); g != w { + t.Errorf("wanted directoryRecords %d, got %d", w, g) + } + + if g, w := d.directorySize, uint64(uint32max); g != w { + t.Errorf("wanted directorySize %d, got %d", w, g) + } + + if g, w := d.directoryOffset, uint64(uint32max); g != w { + t.Errorf("wanted directoryOffset %d, got %d", w, g) + } + + r := bytes.NewReader(buf) + + p64, err := findDirectory64End(r, int64(p)) + if err != nil { + t.Fatalf("findDirectory64End: %v", err) + } + if p < 0 { + t.Fatalf("findDirectory64End: not found") + } + err = readDirectory64End(r, p64, d) + if err != nil { + t.Fatalf("readDirectory64End: %v", err) + } + + if g, w := d.directoryRecords, uint64(1); g != w { + t.Errorf("wanted directoryRecords %d, got %d", w, g) + } + + if g, w := d.directoryOffset, uint64(uint32max); g <= w { + t.Errorf("wanted directoryOffset > %d, got %d", w, g) + } +} diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go index 8dd986eb1..f5268385d 100644 --- a/third_party/zip/writer.go +++ b/third_party/zip/writer.go @@ -155,7 +155,14 @@ func (w *Writer) Close() error { // store max values in the regular end record to signal that // that the zip64 values should be used instead - records = uint16max + // BEGIN ANDROID CHANGE: only store uintmax for the number of entries in the regular + // end record if it doesn't fit. p7zip 16.02 rejects zip files where the number of + // entries in the regular end record is larger than the number of entries counted + // in the central directory. + if records > uint16max { + records = uint16max + } + // END ANDROID CHANGE size = uint32max offset = uint32max } |