From bf53859bcdba222eceeb2947da71dbc30b335c15 Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Mon, 3 Jul 2023 16:26:30 -0400 Subject: [PATCH] Ensure output files are zip64-compliant (again) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #110 fixed this incorrectly. I misinterpreted "set to zero in the local header" from ยง4.4.4 in the spec as referring to the two 32-bit size fields in the local header. However, the spec considers the zip64 extra record as part of the local header. The correct behavior for writing zip64 entries to unseekable files is 0xffffffff in the 32-bit local header size fields (to enable zip64), 0 in the zip64 extra record (due to streaming writes), and the actual sizes in the data descriptor. Fixes: #109 Signed-off-by: Andrew Gunnerson --- avbroot/main.py | 21 ++++++++++++--------- tests/tests.yaml | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/avbroot/main.py b/avbroot/main.py index 63a6197..a61311b 100644 --- a/avbroot/main.py +++ b/avbroot/main.py @@ -259,22 +259,25 @@ def strip_bad_extra_fields(extra): @contextlib.contextmanager def fix_streaming_local_header_sizes(): ''' - Some Python versions have a regression [1] where the local file header's - compressed and uncompressed size fields are incorrectly set to 0xffffffff - when data descriptors are used. This function monkey patches zipfile's - local file header serialization to manually fix this issue. - - [1] https://github.com/python/cpython/issues/106218 + Older Python versions don't set the local header's two 32-bit size fields to + 0xffffffff when writing a zip64 entry to an unseekable file. This function + monkey patches zipfile's local file header serialization to manually fix + this issue. ''' orig = zipfile.ZipInfo.FileHeader def wrapper(*args, **kwargs): blob = orig(*args, **kwargs) + zip64 = kwargs.get('zip64') + if zip64 is None: + zip64 = args[0].file_size > zipfile.ZIP64_LIMIT or \ + args[0].compress_size > zipfile.ZIP64_LIMIT + fields = list(struct.unpack_from(zipfile.structFileHeader, blob)) - if fields[3] & (1 << 3): - fields[8] = 0 - fields[9] = 0 + if fields[3] & (1 << 3) and zip64: + fields[8] = 0xffffffff + fields[9] = 0xffffffff return struct.pack(zipfile.structFileHeader, *fields) + \ blob[zipfile.sizeFileHeader:] diff --git a/tests/tests.yaml b/tests/tests.yaml index 10320de..a3aacdd 100644 --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -143,8 +143,8 @@ device: full: 929f892fbd70699cf7f118a119aac1ae1b86351e1ada17715666fa4401e63472 stripped: 4eabaf79b6c2b5df305e3ecdc2b9570c0dd27350b4e8d6434584000c4989ff3d patched: - full: c152a9c49a81d521b7652662807d017655cbb999d503f869599753ab907b2133 - stripped: 15e04f3fcca564384c2258c9a93cd5986d82f5b8b68d08a4e067fa7aae0b3dcc + full: 2c44c34fa25feda472ded5ab693e9b7fdd746c770ecfcc0e3b95d06a1fe35a61 + stripped: 24a8cbd86a3221aef9cca0751e9218a2221f33a8e1a34f3a60a10473fc18d495 avb_images: boot.img: ec703e143c24e7eb5b2eb96beb1d4342c1dd2179b12612d41430b1b55e7dec0f recovery.img: 2ff62bc52a5900eb170cc44df0f0ee8062ee6dcb48ecf1899ac556145161f53c