Index: Lib/zipfile.py =================================================================== --- Lib/zipfile.py (revision 59764) +++ Lib/zipfile.py (working copy) @@ -25,6 +25,7 @@ error = BadZipfile # The exception raised by this module ZIP64_LIMIT= (1 << 31) - 1 +ZIP_FILECOUNT_LIMIT = 1 << 16 # constants for Zip file compression methods ZIP_STORED = 0 @@ -1015,12 +1016,14 @@ # XXX Why is `pos3` computed next? It's never referenced. pos3 = self.fp.tell() endrec = struct.pack(structEndArchive, stringEndArchive, - 0, 0, count, count, pos2 - pos1, -1, 0) + 0, 0, count % ZIP_FILECOUNT_LIMIT, + count % ZIP_FILECOUNT_LIMIT, pos2 - pos1, -1, 0) self.fp.write(endrec) else: endrec = struct.pack(structEndArchive, stringEndArchive, - 0, 0, count, count, pos2 - pos1, pos1, 0) + 0, 0, count % ZIP_FILECOUNT_LIMIT, + count % ZIP_FILECOUNT_LIMIT, pos2 - pos1, pos1, 0) self.fp.write(endrec) self.fp.flush() if not self._filePassed: Index: Lib/test/test_zipfile.py =================================================================== --- Lib/test/test_zipfile.py (revision 59764) +++ Lib/test/test_zipfile.py (working copy) @@ -625,6 +625,23 @@ zipf.writestr("foo.txt\x00qqq", "O, for a Muse of Fire!") self.assertEqual(zipf.namelist(), ['foo.txt']) + 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") + zipf.debug = 100 + numfiles = (1 << 16) * 3/2 + for i in xrange(numfiles): + zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57)) + self.assertEqual(len(zipf.namelist()), numfiles) + zipf.close() + + zipf2 = zipfile.ZipFile(TESTFN, mode="r") + self.assertEqual(len(zipf2.namelist()), numfiles) + for i in xrange(numfiles): + self.assertEqual(zipf2.read("foo%08d" % i), "%d" % (i**3 % 57)) + zipf.close() + def tearDown(self): support.unlink(TESTFN) support.unlink(TESTFN2)