Skip to content

Commit

Permalink
[3.11] [3.12] pythongh-117084: Fix ZIP file extraction for directory …
Browse files Browse the repository at this point in the history
…entry names with backslashes on Windows (pythonGH-117129) (pythonGH-117162)

(cherry picked from commit f3fee23)

Co-authored-by: Serhiy Storchaka <[email protected]>
(cherry picked from commit 567ab3b)
  • Loading branch information
serhiy-storchaka committed Mar 22, 2024
1 parent da5efeb commit c23d242
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 1 deletion.
16 changes: 16 additions & 0 deletions Lib/test/test_zipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,22 @@ def test_bug_6050(self):
os.mkdir(os.path.join(TESTFN2, "a"))
self.test_extract_dir()

def test_extract_dir_backslash(self):
zfname = findfile("zipdir_backslash.zip")
with zipfile.ZipFile(zfname) as zipf:
zipf.extractall(TESTFN2)
if os.name == 'nt':
self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
self.assertTrue(os.path.isfile(os.path.join(TESTFN2, "a", "b", "c")))
self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "d")))
self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "d", "e")))
else:
self.assertTrue(os.path.isfile(os.path.join(TESTFN2, "a\\b\\c")))
self.assertTrue(os.path.isfile(os.path.join(TESTFN2, "d\\e\\")))
self.assertFalse(os.path.exists(os.path.join(TESTFN2, "a")))
self.assertFalse(os.path.exists(os.path.join(TESTFN2, "d")))

def test_write_dir(self):
dirpath = os.path.join(TESTFN2, "x")
os.mkdir(dirpath)
Expand Down
Binary file added Lib/test/zipdir_backslash.zip
Binary file not shown.
10 changes: 9 additions & 1 deletion Lib/zipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,15 @@ def from_file(cls, filename, arcname=None, *, strict_timestamps=True):

def is_dir(self):
"""Return True if this archive member is a directory."""
return self.filename[-1] == '/'
if self.filename.endswith('/'):
return True
# The ZIP format specification requires to use forward slashes
# as the directory separator, but in practice some ZIP files
# created on Windows can use backward slashes. For compatibility
# with the extraction code which already handles this:
if os.path.altsep:
return self.filename.endswith((os.path.sep, os.path.altsep))
return False


# ZIP encryption uses the CRC32 one-byte primitive for scrambling some
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :mod:`zipfile` extraction for directory entries with the name containing
backslashes on Windows.

0 comments on commit c23d242

Please sign in to comment.