diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2018-09-18 23:28:34 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-18 23:28:34 +0300 |
commit | 29034baf58156e2462b0680e9092c0a3cccb0798 (patch) | |
tree | a7abbcea6616ea323a4fe23c9317543586daa124 /Lib | |
parent | 18b20bad75b4ff0486940fba4ec680e96e70f3a2 (diff) | |
download | cpython-git-29034baf58156e2462b0680e9092c0a3cccb0798.tar.gz |
[2.7] bpo-34341: Fix appending to ZIP archives with the ZIP64 extension. (GH-8683). (GH-9400)
(cherry picked from commit 9bdb7be482aef8f60daa1d36606568a132dcb616)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_zipfile.py | 14 | ||||
-rw-r--r-- | Lib/zipfile.py | 22 |
2 files changed, 36 insertions, 0 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 9c63aebbbe..4e545f140a 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -812,6 +812,20 @@ class TestZip64InSmallFiles(unittest.TestCase): self.assertEqual(content, "%d" % (i**3 % 57)) zipf2.close() + def test_append(self): + # Test that appending to the Zip64 archive doesn't change + # extra fields of existing entries. + with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp: + zipfp.writestr("strfile", self.data) + with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp: + zinfo = zipfp.getinfo("strfile") + extra = zinfo.extra + with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp: + zipfp.writestr("strfile2", self.data) + with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp: + zinfo = zipfp.getinfo("strfile") + self.assertEqual(zinfo.extra, extra) + def tearDown(self): zipfile.ZIP64_LIMIT = self._limit zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 3ab66cea69..0f890ac6f3 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -131,6 +131,27 @@ _CD64_NUMBER_ENTRIES_TOTAL = 7 _CD64_DIRECTORY_SIZE = 8 _CD64_OFFSET_START_CENTDIR = 9 +_EXTRA_FIELD_STRUCT = struct.Struct('<HH') + +def _strip_extra(extra, xids): + # Remove Extra Fields with specified IDs. + unpack = _EXTRA_FIELD_STRUCT.unpack + modified = False + buffer = [] + start = i = 0 + while i + 4 <= len(extra): + xid, xlen = unpack(extra[i : i + 4]) + j = i + 4 + xlen + if xid in xids: + if i != start: + buffer.append(extra[start : i]) + start = j + modified = True + i = j + if not modified: + return extra + return b''.join(buffer) + def _check_zipfile(fp): try: if _EndRecData(fp): @@ -1293,6 +1314,7 @@ class ZipFile(object): extra_data = zinfo.extra if extra: # Append a ZIP64 field to the extra's + extra_data = _strip_extra(extra_data, (1,)) extra_data = struct.pack( '<HH' + 'Q'*len(extra), 1, 8*len(extra), *extra) + extra_data |