Issue #21866: ZipFile.close() no longer writes ZIP64 central directory
records if allowZip64 is false.
This commit is contained in:
parent
8aa8c47db2
commit
cfbb394488
|
@ -18,7 +18,7 @@ import sys
|
|||
from io import StringIO
|
||||
from tempfile import TemporaryFile
|
||||
|
||||
from test.support import TESTFN, run_unittest, requires_zlib
|
||||
from test.support import TESTFN, requires_zlib
|
||||
|
||||
TESTFN2 = TESTFN + "2"
|
||||
|
||||
|
@ -92,7 +92,7 @@ class OtherTests(unittest.TestCase):
|
|||
def testMoreThan64kFiles(self):
|
||||
# This test checks that more than 64k files can be added to an archive,
|
||||
# and that the resulting archive can be read properly by ZipFile
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=False)
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=True)
|
||||
zipf.debug = 100
|
||||
numfiles = (1 << 16) * 3//2
|
||||
for i in range(numfiles):
|
||||
|
@ -105,14 +105,47 @@ class OtherTests(unittest.TestCase):
|
|||
for i in range(numfiles):
|
||||
content = zipf2.read("foo%08d" % i).decode('ascii')
|
||||
self.assertEqual(content, "%d" % (i**3 % 57))
|
||||
zipf2.close()
|
||||
|
||||
def testMoreThan64kFilesAppend(self):
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=False)
|
||||
zipf.debug = 100
|
||||
numfiles = (1 << 16) - 1
|
||||
for i in range(numfiles):
|
||||
zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
|
||||
self.assertEqual(len(zipf.namelist()), numfiles)
|
||||
with self.assertRaises(zipfile.LargeZipFile):
|
||||
zipf.writestr("foo%08d" % numfiles, b'')
|
||||
self.assertEqual(len(zipf.namelist()), numfiles)
|
||||
zipf.close()
|
||||
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=False)
|
||||
zipf.debug = 100
|
||||
self.assertEqual(len(zipf.namelist()), numfiles)
|
||||
with self.assertRaises(zipfile.LargeZipFile):
|
||||
zipf.writestr("foo%08d" % numfiles, b'')
|
||||
self.assertEqual(len(zipf.namelist()), numfiles)
|
||||
zipf.close()
|
||||
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=True)
|
||||
zipf.debug = 100
|
||||
self.assertEqual(len(zipf.namelist()), numfiles)
|
||||
numfiles2 = (1 << 16) * 3//2
|
||||
for i in range(numfiles, numfiles2):
|
||||
zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
|
||||
self.assertEqual(len(zipf.namelist()), numfiles2)
|
||||
zipf.close()
|
||||
|
||||
zipf2 = zipfile.ZipFile(TESTFN, mode="r")
|
||||
self.assertEqual(len(zipf2.namelist()), numfiles2)
|
||||
for i in range(numfiles2):
|
||||
content = zipf2.read("foo%08d" % i).decode('ascii')
|
||||
self.assertEqual(content, "%d" % (i**3 % 57))
|
||||
zipf2.close()
|
||||
|
||||
def tearDown(self):
|
||||
support.unlink(TESTFN)
|
||||
support.unlink(TESTFN2)
|
||||
|
||||
def test_main():
|
||||
run_unittest(TestsWithSourceFile, OtherTests)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
unittest.main()
|
||||
|
|
|
@ -50,7 +50,7 @@ error = BadZipfile = BadZipFile # Pre-3.2 compatibility names
|
|||
|
||||
|
||||
ZIP64_LIMIT = (1 << 31) - 1
|
||||
ZIP_FILECOUNT_LIMIT = 1 << 16
|
||||
ZIP_FILECOUNT_LIMIT = (1 << 16) - 1
|
||||
ZIP_MAX_COMMENT = (1 << 16) - 1
|
||||
|
||||
# constants for Zip file compression methods
|
||||
|
@ -1304,13 +1304,17 @@ class ZipFile:
|
|||
raise RuntimeError(
|
||||
"Attempt to write ZIP archive that was already closed")
|
||||
_check_compression(zinfo.compress_type)
|
||||
if zinfo.file_size > ZIP64_LIMIT:
|
||||
if not self._allowZip64:
|
||||
raise LargeZipFile("Filesize would require ZIP64 extensions")
|
||||
if zinfo.header_offset > ZIP64_LIMIT:
|
||||
if not self._allowZip64:
|
||||
raise LargeZipFile(
|
||||
"Zipfile size would require ZIP64 extensions")
|
||||
if not self._allowZip64:
|
||||
requires_zip64 = None
|
||||
if len(self.filelist) >= ZIP_FILECOUNT_LIMIT:
|
||||
requires_zip64 = "Files count"
|
||||
elif zinfo.file_size > ZIP64_LIMIT:
|
||||
requires_zip64 = "Filesize"
|
||||
elif zinfo.header_offset > ZIP64_LIMIT:
|
||||
requires_zip64 = "Zipfile size"
|
||||
if requires_zip64:
|
||||
raise LargeZipFile(requires_zip64 +
|
||||
" would require ZIP64 extensions")
|
||||
|
||||
def write(self, filename, arcname=None, compress_type=None):
|
||||
"""Put the bytes from filename into the archive under the name
|
||||
|
@ -1464,10 +1468,8 @@ class ZipFile:
|
|||
|
||||
try:
|
||||
if self.mode in ("w", "a") and self._didModify: # write ending records
|
||||
count = 0
|
||||
pos1 = self.fp.tell()
|
||||
for zinfo in self.filelist: # write central directory
|
||||
count = count + 1
|
||||
dt = zinfo.date_time
|
||||
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
|
||||
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
|
||||
|
@ -1531,13 +1533,21 @@ class ZipFile:
|
|||
|
||||
pos2 = self.fp.tell()
|
||||
# Write end-of-zip-archive record
|
||||
centDirCount = count
|
||||
centDirCount = len(self.filelist)
|
||||
centDirSize = pos2 - pos1
|
||||
centDirOffset = pos1
|
||||
if (centDirCount >= ZIP_FILECOUNT_LIMIT or
|
||||
centDirOffset > ZIP64_LIMIT or
|
||||
centDirSize > ZIP64_LIMIT):
|
||||
requires_zip64 = None
|
||||
if centDirCount > ZIP_FILECOUNT_LIMIT:
|
||||
requires_zip64 = "Files count"
|
||||
elif centDirOffset > ZIP64_LIMIT:
|
||||
requires_zip64 = "Central directory offset"
|
||||
elif centDirSize > ZIP64_LIMIT:
|
||||
requires_zip64 = "Central directory size"
|
||||
if requires_zip64:
|
||||
# Need to write the ZIP64 end-of-archive records
|
||||
if not self._allowZip64:
|
||||
raise LargeZipFile(requires_zip64 +
|
||||
" would require ZIP64 extensions")
|
||||
zip64endrec = struct.pack(
|
||||
structEndArchive64, stringEndArchive64,
|
||||
44, 45, 45, 0, 0, centDirCount, centDirCount,
|
||||
|
|
|
@ -13,6 +13,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #21866: ZipFile.close() no longer writes ZIP64 central directory
|
||||
records if allowZip64 is false.
|
||||
|
||||
- Issue #22415: Fixed debugging output of the GROUPREF_EXISTS opcode in the re
|
||||
module. Removed trailing spaces in debugging output.
|
||||
|
||||
|
|
Loading…
Reference in New Issue