Skip to content

Commit 1bdd946

Browse files
committed
Fix Zip64 extensions not being properly applied in some cases
This commit fixes an issue where adding a small file to a `ZipFile` object while forcing zip64 extensions causes an extra Zip64 record to be added to the zip, but doesn't update the `min_version` or file sizes. Fixes python#103861
1 parent 86aa8a5 commit 1bdd946

File tree

3 files changed

+44
-7
lines changed

3 files changed

+44
-7
lines changed

Lib/test/test_zipfile/test_core.py

+37
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,43 @@ def test_generated_valid_zip64_extra(self):
10801080
self.assertEqual(zinfo.header_offset, expected_header_offset)
10811081
self.assertEqual(zf.read(zinfo), expected_content)
10821082

1083+
def test_force_zip64(self):
1084+
"""Test that forcing zip64 extensions correctly notes this in the zip file"""
1085+
data = io.BytesIO()
1086+
with zipfile.ZipFile(data, mode="w", allowZip64=True) as zf:
1087+
with zf.open("text.txt", mode="w", force_zip64=True) as zi:
1088+
zi.write(b"_")
1089+
1090+
zipdata = data.getvalue()
1091+
1092+
# check for file header
1093+
self.assertEqual(zipdata[:4], b"PK\x03\x04")
1094+
1095+
# pull out and check file information
1096+
(
1097+
vers, os, flags, comp, _, _, crc, csize, usize, fn_len,
1098+
ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize
1099+
) = struct.unpack("<BB2sHHHIIIHH8shhQQ", zipdata[4:58])
1100+
1101+
self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract
1102+
self.assertEqual(os, 0) # compatible with MS-DOS
1103+
self.assertEqual(flags, b"\x00\x00") # no flags
1104+
self.assertEqual(comp, 0) # compression method = stored
1105+
self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra
1106+
self.assertEqual(usize, 0xFFFFFFFF)
1107+
self.assertEqual(fn_len, 8) # filename len
1108+
self.assertEqual(ex_total_len, 20) # size of extra records
1109+
self.assertEqual(ex_id, 1) # Zip64 extra record
1110+
self.assertEqual(ex_len, 16) # 16 bytes of data
1111+
self.assertEqual(ex_usize, 1) # uncompressed size
1112+
self.assertEqual(ex_csize, 1) # compressed size
1113+
1114+
z = zipfile.ZipFile(io.BytesIO(zipdata))
1115+
zinfos = z.infolist()
1116+
self.assertEqual(len(zinfos), 1)
1117+
1118+
self.assertGreaterEqual(zinfos[0].extract_version, zipfile.ZIP64_VERSION) # requires zip64 to extract
1119+
10831120

10841121
@requires_zlib()
10851122
class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,

Lib/zipfile/__init__.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -455,17 +455,15 @@ def FileHeader(self, zip64=None):
455455
extra = self.extra
456456

457457
min_version = 0
458-
if zip64 is None:
459-
zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT
458+
if (file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT):
459+
if zip64 is None:
460+
zip64 = True
461+
elif not zip64:
462+
raise LargeZipFile("Filesize would require ZIP64 extensions")
460463
if zip64:
461464
fmt = '<HHQQ'
462465
extra = extra + struct.pack(fmt,
463466
1, struct.calcsize(fmt)-4, file_size, compress_size)
464-
if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT:
465-
if not zip64:
466-
raise LargeZipFile("Filesize would require ZIP64 extensions")
467-
# File is larger than what fits into a 4 byte integer,
468-
# fall back to the ZIP64 extension
469467
file_size = 0xffffffff
470468
compress_size = 0xffffffff
471469
min_version = ZIP64_VERSION
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix `zipfile.Zipfile` creating invalid zip files when `force_zip64` was used
2+
to add files to them. Patch by Carey Metcalfe.

0 commit comments

Comments
 (0)