Skip to content

Commit 62c0327

Browse files
gh-88233: zipfile: handle extras after a zip64 extra (GH-96161)
Previously, any data _after_ the zip64 extra would be removed. With many new tests. Fixes GH-88233 (cherry picked from commit 59e86ca) Co-authored-by: Tim Hatch <[email protected]> Automerge-Triggered-By: GH:jaraco
1 parent 1747be4 commit 62c0327

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

Lib/test/test_zipfile.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3485,5 +3485,67 @@ def test_cli_with_metadata_encoding_extract(self):
34853485
self.assertIn(name, listing)
34863486

34873487

3488+
class StripExtraTests(unittest.TestCase):
3489+
# Note: all of the "z" characters are technically invalid, but up
3490+
# to 3 bytes at the end of the extra will be passed through as they
3491+
# are too short to encode a valid extra.
3492+
3493+
ZIP64_EXTRA = 1
3494+
3495+
def test_no_data(self):
3496+
s = struct.Struct("<HH")
3497+
a = s.pack(self.ZIP64_EXTRA, 0)
3498+
b = s.pack(2, 0)
3499+
c = s.pack(3, 0)
3500+
3501+
self.assertEqual(b'', zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
3502+
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
3503+
self.assertEqual(
3504+
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))
3505+
3506+
self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
3507+
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
3508+
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))
3509+
3510+
def test_with_data(self):
3511+
s = struct.Struct("<HH")
3512+
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
3513+
b = s.pack(2, 2) + b"bb"
3514+
c = s.pack(3, 3) + b"ccc"
3515+
3516+
self.assertEqual(b"", zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
3517+
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
3518+
self.assertEqual(
3519+
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))
3520+
3521+
self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
3522+
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
3523+
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))
3524+
3525+
def test_multiples(self):
3526+
s = struct.Struct("<HH")
3527+
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
3528+
b = s.pack(2, 2) + b"bb"
3529+
3530+
self.assertEqual(b"", zipfile._strip_extra(a+a, (self.ZIP64_EXTRA,)))
3531+
self.assertEqual(b"", zipfile._strip_extra(a+a+a, (self.ZIP64_EXTRA,)))
3532+
self.assertEqual(
3533+
b"z", zipfile._strip_extra(a+a+b"z", (self.ZIP64_EXTRA,)))
3534+
self.assertEqual(
3535+
b+b"z", zipfile._strip_extra(a+a+b+b"z", (self.ZIP64_EXTRA,)))
3536+
3537+
self.assertEqual(b, zipfile._strip_extra(a+a+b, (self.ZIP64_EXTRA,)))
3538+
self.assertEqual(b, zipfile._strip_extra(a+b+a, (self.ZIP64_EXTRA,)))
3539+
self.assertEqual(b, zipfile._strip_extra(b+a+a, (self.ZIP64_EXTRA,)))
3540+
3541+
def test_too_short(self):
3542+
self.assertEqual(b"", zipfile._strip_extra(b"", (self.ZIP64_EXTRA,)))
3543+
self.assertEqual(b"z", zipfile._strip_extra(b"z", (self.ZIP64_EXTRA,)))
3544+
self.assertEqual(
3545+
b"zz", zipfile._strip_extra(b"zz", (self.ZIP64_EXTRA,)))
3546+
self.assertEqual(
3547+
b"zzz", zipfile._strip_extra(b"zzz", (self.ZIP64_EXTRA,)))
3548+
3549+
34883550
if __name__ == "__main__":
34893551
unittest.main()

Lib/zipfile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ def _strip_extra(extra, xids):
211211
i = j
212212
if not modified:
213213
return extra
214+
if start != len(extra):
215+
buffer.append(extra[start:])
214216
return b''.join(buffer)
215217

216218
def _check_zipfile(fp):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Correctly preserve "extra" fields in ``zipfile`` regardless of their
2+
ordering relative to a zip64 "extra."

0 commit comments

Comments
 (0)