Skip to content

Commit 9571ffa

Browse files
committed
gh-152486: Fix force_zip64 not honored when writing central directory
1 parent 65585ca commit 9571ffa

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

Lib/test/test_zipfile/test_core.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,22 @@ def test_force_zip64(self):
12431243
self.assertEqual(len(zinfos), 1)
12441244
self.assertGreaterEqual(zinfos[0].extract_version, zipfile.ZIP64_VERSION) # requires zip64 to extract
12451245

1246+
def test_force_zip64_central(self):
1247+
"""Test that force_zip64 is honored when writing to central directory"""
1248+
fh = io.BytesIO()
1249+
with zipfile.ZipFile(fh, 'w') as zh:
1250+
with zh.open('strfile', 'w', force_zip64=True) as zi:
1251+
pass
1252+
1253+
fh.seek(0)
1254+
with zipfile.ZipFile(fh, 'r') as zh:
1255+
zinfo = zh.getinfo('strfile')
1256+
self.assertEqual(zinfo.extra, (
1257+
b'\x01\x00\x10\x00'
1258+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
1259+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
1260+
))
1261+
12461262
def test_unseekable_zip_unknown_filesize(self):
12471263
"""Test that creating a zip with/without seeking will raise a RuntimeError if zip64 was required but not used"""
12481264

@@ -1448,6 +1464,11 @@ def comparable_zinfo(zinfo):
14481464
# pretending it's always set.
14491465
attrs['flag_bits'] |= 0x800
14501466

1467+
# Check decoded data (file size, compressed size) and ignore zip64 subfield
1468+
# in extra data since is may be inconsistent for a ZipInfo before writing
1469+
# and one read from a file.
1470+
attrs['extra'] = zipfile._Extra.strip(attrs['extra'], (1,))
1471+
14511472
return attrs
14521473

14531474
_struct_pack = struct.pack

Lib/zipfile/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ class ZipInfo:
453453
'file_size',
454454
'_raw_time',
455455
'_end_offset',
456+
'_force_zip64',
456457
)
457458

458459
def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
@@ -488,6 +489,7 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
488489
self.compress_size = 0 # Size of the compressed file
489490
self.file_size = 0 # Size of the uncompressed file
490491
self._end_offset = None # Start of the next local header or central directory
492+
self._force_zip64 = None # Whether zip64 extension is forced
491493
# Other attributes are set by class ZipFile:
492494
# header_offset Byte offset to the file header
493495
# CRC CRC-32 of the uncompressed file
@@ -2202,6 +2204,7 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
22022204
zinfo = self.getinfo(name)
22032205

22042206
if mode == 'w':
2207+
zinfo._force_zip64 = force_zip64
22052208
return self._open_to_write(zinfo, force_zip64=force_zip64)
22062209

22072210
if self._writing:
@@ -2646,8 +2649,10 @@ def _write_end_record(self):
26462649
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
26472650
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
26482651
extra = []
2649-
if zinfo.file_size > ZIP64_LIMIT \
2650-
or zinfo.compress_size > ZIP64_LIMIT:
2652+
if (zinfo._force_zip64
2653+
or zinfo.file_size > ZIP64_LIMIT
2654+
or zinfo.compress_size > ZIP64_LIMIT
2655+
):
26512656
extra.append(zinfo.file_size)
26522657
extra.append(zinfo.compress_size)
26532658
file_size = 0xffffffff

0 commit comments

Comments
 (0)