Skip to content

Commit 0d971d8

Browse files
committed
Add strict_descriptor option
1 parent 51c9254 commit 0d971d8

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

Lib/test/test_zipfile/test_core.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,45 @@ def test_repack_data_descriptor_no_sig(self):
19501950
# check file size
19511951
self.assertEqual(os.path.getsize(TESTFN), expected_size)
19521952

1953+
def test_repack_data_descriptor_no_sig_strict(self):
1954+
"""Should skip data descriptor without signature when `strict_descriptor` is set."""
1955+
for ii in ([0], [0, 1]):
1956+
with self.subTest(remove=ii):
1957+
# calculate the expected results
1958+
with open(TESTFN, 'wb') as fh:
1959+
with mock.patch('zipfile.struct.pack', side_effect=struct_pack_no_dd_sig):
1960+
self._prepare_zip_from_test_files(Unseekable(fh), self.test_files)
1961+
with zipfile.ZipFile(TESTFN, 'a') as zh:
1962+
for i in ii:
1963+
zh.remove(self.test_files[i][0])
1964+
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1965+
expected_size = os.path.getsize(TESTFN)
1966+
1967+
# do the removal and check the result
1968+
with open(TESTFN, 'wb') as fh:
1969+
with mock.patch('zipfile.struct.pack', side_effect=struct_pack_no_dd_sig):
1970+
zinfos = self._prepare_zip_from_test_files(Unseekable(fh), self.test_files)
1971+
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
1972+
# make sure data descriptor bit is really set (by making zipfile unseekable)
1973+
for zi in zh.infolist():
1974+
self.assertTrue(zi.flag_bits & 8, f'data descriptor flag not set: {zi.filename}')
1975+
1976+
for i in ii:
1977+
zh.remove(self.test_files[i][0])
1978+
zh.repack(strict_descriptor=True)
1979+
1980+
# check infolist
1981+
self.assertEqual(
1982+
[ComparableZipInfo(zi) for zi in zh.infolist()],
1983+
expected_zinfos,
1984+
)
1985+
1986+
# make sure the zip file is still valid
1987+
self.assertIsNone(zh.testzip())
1988+
1989+
# check file size
1990+
self.assertEqual(os.path.getsize(TESTFN), expected_size)
1991+
19531992
def test_repack_data_descriptor_no_sig_and_zip64(self):
19541993
"""Should correctly handle file entries using data descriptor without signature and zip64."""
19551994
for ii in ([0], [0, 1], [1], [2]):

Lib/zipfile/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,9 +1369,10 @@ def close(self):
13691369

13701370
class _ZipRepacker:
13711371
"""Class for ZipFile repacking."""
1372-
def __init__(self, *, chunk_size=2**20, debug=0):
1372+
def __init__(self, *, chunk_size=2**20, strict_descriptor=False, debug=0):
13731373
self.debug = debug # Level of printing: 0 through 3
13741374
self.chunk_size = chunk_size
1375+
self.strict_descriptor = strict_descriptor
13751376

13761377
def _debug(self, level, *msg):
13771378
if self.debug >= level:
@@ -1593,7 +1594,7 @@ def _validate_local_file_entry(self, fp, offset, end_offset):
15931594
)
15941595

15951596
dd = self._scan_data_descriptor(fp, pos, end_offset, zip64)
1596-
if dd is None:
1597+
if dd is None and not self.strict_descriptor:
15971598
dd = self._scan_data_descriptor_no_sig(fp, pos, end_offset, zip64)
15981599
if dd is None:
15991600
return None

0 commit comments

Comments
 (0)