diff -r 9d335a54d728 Lib/test/test_zipfile64.py --- a/Lib/test/test_zipfile64.py Fri Sep 05 11:01:43 2014 +0300 +++ b/Lib/test/test_zipfile64.py Fri Sep 05 14:45:29 2014 +0300 @@ -92,7 +92,7 @@ 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,8 +105,44 @@ 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) diff -r 9d335a54d728 Lib/zipfile.py --- a/Lib/zipfile.py Fri Sep 05 11:01:43 2014 +0300 +++ b/Lib/zipfile.py Fri Sep 05 14:45:29 2014 +0300 @@ -50,7 +50,7 @@ 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,11 +1304,13 @@ 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: + if not self._allowZip64: + if len(self.filelist) >= ZIP_FILECOUNT_LIMIT: + raise LargeZipFile( + "Files count would require ZIP64 extensions") + if zinfo.file_size > ZIP64_LIMIT: raise LargeZipFile("Filesize would require ZIP64 extensions") - if zinfo.header_offset > ZIP64_LIMIT: - if not self._allowZip64: + if zinfo.header_offset > ZIP64_LIMIT: raise LargeZipFile( "Zipfile size would require ZIP64 extensions") @@ -1464,10 +1466,8 @@ 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 +1531,23 @@ 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 + if (centDirCount > ZIP_FILECOUNT_LIMIT or centDirOffset > ZIP64_LIMIT or centDirSize > ZIP64_LIMIT): # Need to write the ZIP64 end-of-archive records + if not self._allowZip64: + if centDirCount > ZIP_FILECOUNT_LIMIT: + raise LargeZipFile("Files count " + "would require ZIP64 extensions") + if centDirOffset > ZIP64_LIMIT: + raise LargeZipFile("Central directory offset " + "would require ZIP64 extensions") + if centDirSize > ZIP64_LIMIT: + raise LargeZipFile("Central directory size " + "would require ZIP64 extensions") zip64endrec = struct.pack( structEndArchive64, stringEndArchive64, 44, 45, 45, 0, 0, centDirCount, centDirCount,