From 3f4ccbabaf8beacdc108dc476b1c2c7c5671109f Mon Sep 17 00:00:00 2001 From: R David Murray Date: Thu, 12 Apr 2012 18:42:47 -0400 Subject: [PATCH] #14399: zipfile now correctly handles comments added to empty zipfiles. Patch by Serhiy Storchaka. --- Lib/test/test_zipfile.py | 16 ++++++++++++++++ Lib/zipfile.py | 33 +++++++++++++++++++++------------ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 7ebb66376d..76fcc7048e 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -908,6 +908,22 @@ class OtherTests(unittest.TestCase): with zipfile.ZipFile(TESTFN, mode="r") as zipf: self.assertEqual(zipf.comment, comment2) + def test_change_comment_in_empty_archive(self): + with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf: + self.assertFalse(zipf.filelist) + zipf.comment = b"this is a comment" + with zipfile.ZipFile(TESTFN, "r") as zipf: + self.assertEqual(zipf.comment, b"this is a comment") + + def test_change_comment_in_nonempty_archive(self): + with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf: + zipf.writestr("foo.txt", "O, for a Muse of Fire!") + with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf: + self.assertTrue(zipf.filelist) + zipf.comment = b"this is a comment" + with zipfile.ZipFile(TESTFN, "r") as zipf: + self.assertEqual(zipf.comment, b"this is a comment") + def check_testzip_with_bad_crc(self, compression): """Tests that files with bad CRCs return their name from testzip.""" zipdata = self.zips_with_bad_crc[compression] diff --git a/Lib/zipfile.py b/Lib/zipfile.py index d9181f2393..05c31438d7 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -651,7 +651,7 @@ class ZipExtFile(io.BufferedIOBase): -class ZipFile: +class ZipFile(object): """ Class with methods to open, read, write, close, list zip files. z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=False) @@ -690,7 +690,7 @@ class ZipFile: self.compression = compression # Method of compression self.mode = key = mode.replace('b', '')[0] self.pwd = None - self.comment = '' + self._comment = '' # Check if we were passed a file-like object if isinstance(file, basestring): @@ -765,7 +765,7 @@ class ZipFile: print endrec size_cd = endrec[_ECD_SIZE] # bytes in central directory offset_cd = endrec[_ECD_OFFSET] # offset of central directory - self.comment = endrec[_ECD_COMMENT] # archive comment + self._comment = endrec[_ECD_COMMENT] # archive comment # "concat" is zero, unless zip was concatenated to another file concat = endrec[_ECD_LOCATION] - size_cd - offset_cd @@ -864,6 +864,22 @@ class ZipFile: """Set default password for encrypted files.""" self.pwd = pwd + @property + def comment(self): + """The comment text associated with the ZIP file.""" + return self._comment + + @comment.setter + def comment(self, comment): + # check for valid comment length + if len(comment) >= ZIP_MAX_COMMENT: + if self.debug: + print('Archive comment is too long; truncating to %d bytes' + % ZIP_MAX_COMMENT) + comment = comment[:ZIP_MAX_COMMENT] + self._comment = comment + self._didModify = True + def read(self, name, pwd=None): """Return file bytes (as a string) for name.""" return self.open(name, "r", pwd).read() @@ -1243,18 +1259,11 @@ class ZipFile: centDirSize = min(centDirSize, 0xFFFFFFFF) centDirOffset = min(centDirOffset, 0xFFFFFFFF) - # check for valid comment length - if len(self.comment) >= ZIP_MAX_COMMENT: - if self.debug > 0: - msg = 'Archive comment is too long; truncating to %d bytes' \ - % ZIP_MAX_COMMENT - self.comment = self.comment[:ZIP_MAX_COMMENT] - endrec = struct.pack(structEndArchive, stringEndArchive, 0, 0, centDirCount, centDirCount, - centDirSize, centDirOffset, len(self.comment)) + centDirSize, centDirOffset, len(self._comment)) self.fp.write(endrec) - self.fp.write(self.comment) + self.fp.write(self._comment) self.fp.flush() if not self._filePassed: diff --git a/Misc/ACKS b/Misc/ACKS index e36e626ca3..af0cd5f51c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -814,6 +814,7 @@ Richard Stoakley Peter Stoehr Casper Stoel Michael Stone +Serhiy Storchaka Ken Stox Patrick Strawderman Dan Stromberg diff --git a/Misc/NEWS b/Misc/NEWS index 8aa7315b96..64ecbd68b6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,10 @@ Core and Builtins Library ------- +- Issue #14399: zipfile now correctly adds a comment even when the zipfile + being created is otherwise empty. As a consequence of this fix, ZipFile is + now a new style class. + - Issue #7978: SocketServer now restarts the select() call when EINTR is returned. This avoids crashing the server loop when a signal is received. Patch by Jerzy Kozera. -- 2.40.0