From c72aca32319c922c7bc44f665b4a3bb89a51b5ff Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Sat, 24 Jan 2009 14:18:13 +0000 Subject: [PATCH] Merged revisions 68887 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ................ r68887 | martin.v.loewis | 2009-01-24 15:10:07 +0100 (Sa, 24 Jan 2009) | 10 lines Merged revisions 68885 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r68885 | martin.v.loewis | 2009-01-24 15:00:33 +0100 (Sa, 24 Jan 2009) | 3 lines Issue #4710: Extract directories properly in the zipfile module; allow adding directories to a zipfile. ........ ................ --- Lib/test/test_zipfile.py | 26 +++++++++++++++++++++++++- Lib/test/zipdir.zip | Bin 0 -> 374 bytes Lib/zipfile.py | 23 ++++++++++++++++++++--- Misc/NEWS | 3 +++ 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 Lib/test/zipdir.zip diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 9e565fb153f8..c85d21d0074d 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -9,9 +9,10 @@ from tempfile import TemporaryFile from random import randint, random import test.support as support -from test.support import TESTFN, run_unittest +from test.support import TESTFN, run_unittest, findfile TESTFN2 = TESTFN + "2" +TESTFNDIR = TESTFN + "d" FIXEDTEST_SIZE = 1000 SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), @@ -971,6 +972,28 @@ class TestsWithMultipleOpens(unittest.TestCase): def tearDown(self): os.remove(TESTFN2) +class TestWithDirectory(unittest.TestCase): + def setUp(self): + os.mkdir(TESTFN2) + + def testExtractDir(self): + zipf = zipfile.ZipFile(findfile("zipdir.zip")) + zipf.extractall(TESTFN2) + 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.exists(os.path.join(TESTFN2, "a", "b", "c"))) + + def testStoreDir(self): + os.mkdir(os.path.join(TESTFN2, "x")) + zipf = zipfile.ZipFile(TESTFN, "w") + zipf.write(os.path.join(TESTFN2, "x"), "x") + self.assertTrue(zipf.filelist[0].filename.endswith("x/")) + + def tearDown(self): + shutil.rmtree(TESTFN2) + if os.path.exists(TESTFN): + os.remove(TESTFN) + class UniversalNewlineTests(unittest.TestCase): def setUp(self): @@ -1085,6 +1108,7 @@ class UniversalNewlineTests(unittest.TestCase): def test_main(): run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, + TestWithDirectory, UniversalNewlineTests, TestsWithRandomBinaryFiles) if __name__ == "__main__": diff --git a/Lib/test/zipdir.zip b/Lib/test/zipdir.zip new file mode 100644 index 0000000000000000000000000000000000000000..ac21d7a1edd2ca1177f071465ca141ab405b1927 GIT binary patch literal 374 zc-jl_W@h1H0D-@|RIM10026~KL!y3Y2qyz`ZAX&lbRZ6`U}1Q{{DL_Eu8DCsswNh& zrX+~AMxwQ`LbWBs^);gCV`LI%#^p+0C`*9hts{sAxtSH>=FkcT24u~cu0_^t3f7zi i(cVaec2>A{28Jb#IZ*A%X!=>%K=RB$xCf*TtQr9ERyZ91 literal 0 Hc-jL100001 diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 93543b4b06e7..661128ee15ca 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -4,7 +4,7 @@ Read and write ZIP files. XXX references to utf-8 need further investigation. """ import struct, os, time, sys, shutil -import binascii, io +import binascii, io, stat try: import zlib # We may need its compression method @@ -947,11 +947,11 @@ class ZipFile: """ # build the destination pathname, replacing # forward slashes to platform specific separators. - if targetpath[-1:] == "/": + if targetpath[-1:] in (os.path.sep, os.path.altsep): targetpath = targetpath[:-1] # don't include leading "/" from file name if present - if os.path.isabs(member.filename): + if member.filename[0] == '/': targetpath = os.path.join(targetpath, member.filename[1:]) else: targetpath = os.path.join(targetpath, member.filename) @@ -963,6 +963,10 @@ class ZipFile: if upperdirs and not os.path.exists(upperdirs): os.makedirs(upperdirs) + if member.filename[-1] == '/': + os.mkdir(targetpath) + return targetpath + source = self.open(member, pwd=pwd) target = open(targetpath, "wb") shutil.copyfileobj(source, target) @@ -1002,6 +1006,7 @@ class ZipFile: "Attempt to write to ZIP archive that was already closed") st = os.stat(filename) + isdir = stat.S_ISDIR(st.st_mode) mtime = time.localtime(st.st_mtime) date_time = mtime[0:6] # Create ZipInfo instance to store file information @@ -1010,6 +1015,8 @@ class ZipFile: arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) while arcname[0] in (os.sep, os.altsep): arcname = arcname[1:] + if isdir: + arcname += '/' zinfo = ZipInfo(arcname, date_time) zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes if compress_type is None: @@ -1023,6 +1030,16 @@ class ZipFile: self._writecheck(zinfo) self._didModify = True + + if isdir: + zinfo.file_size = 0 + zinfo.compress_size = 0 + zinfo.CRC = 0 + self.filelist.append(zinfo) + self.NameToInfo[zinfo.filename] = zinfo + self.fp.write(zinfo.FileHeader()) + return + fp = io.open(filename, "rb") # Must overwrite CRC and sizes with correct data later zinfo.CRC = CRC = 0 diff --git a/Misc/NEWS b/Misc/NEWS index 1a252d2a62fa..92732cae503c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -100,6 +100,9 @@ Core and Builtins Library ------- +- Issue #4710: Extract directories properly in the zipfile module; + allow adding directories to a zipfile. + - Issue #5008: When a file is opened in append mode with the new IO library, do an explicit seek to the end of file (so that e.g. tell() returns the file size rather than 0). This is consistent with the behaviour of the -- 2.47.3