From a421f7e38d88ca9b6b58c89c6b3f141c07fdc588 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 26 Aug 2024 11:12:40 -0400 Subject: [PATCH] Invent DirtyZipInfo to create an unsanitized zipfile with backslashes. --- tests/test_path.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/test_path.py b/tests/test_path.py index 15da1c0..5183377 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -5,6 +5,7 @@ import pickle import stat import sys +import time import unittest from zipp.compat.overlay import zipfile @@ -627,7 +628,7 @@ def test_backslash_not_separator(self): """ data = io.BytesIO() zf = zipfile.ZipFile(data, "w") - zf.writestr("foo\\bar", b"content") + zf.writestr(DirtyZipInfo.for_name("foo\\bar", zf), b"content") zf.filename = '' root = zipfile.Path(zf) (first,) = root.iterdir() @@ -640,3 +641,28 @@ def test_interface(self, alpharep): zf = zipfile.Path(alpharep) assert isinstance(zf, Traversable) + + +class DirtyZipInfo(zipfile.ZipInfo): + """ + Bypass name sanitization. + """ + + def __init__(self, filename, *args, **kwargs): + super().__init__(filename, *args, **kwargs) + self.filename = filename + + @classmethod + def for_name(cls, name, archive): + """ + Construct the same way that ZipFile.writestr does. + """ + self = cls(filename=name, date_time=time.localtime(time.time())[:6]) + self.compress_type = archive.compression + self.compress_level = archive.compresslevel + if self.filename.endswith('/'): + self.external_attr = 0o40775 << 16 # drwxrwxr-x + self.external_attr |= 0x10 # MS-DOS directory flag + else: + self.external_attr = 0o600 << 16 # ?rw------- + return self