summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2009-01-24 14:04:33 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2009-01-24 14:04:33 (GMT)
commit3a8071a26fda8832a6cdd5ec89ce72b622f33604 (patch)
tree668f64789405f261d59fb45e5e1965dc2c618fd3 /Lib
parent19fec8b58fe46de77c7d12c91fe198584da5d0c8 (diff)
downloadcpython-3a8071a26fda8832a6cdd5ec89ce72b622f33604.zip
cpython-3a8071a26fda8832a6cdd5ec89ce72b622f33604.tar.gz
cpython-3a8071a26fda8832a6cdd5ec89ce72b622f33604.tar.bz2
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. ........
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_zipfile.py26
-rw-r--r--Lib/test/zipdir.zipbin0 -> 374 bytes
-rw-r--r--Lib/zipfile.py23
3 files changed, 45 insertions, 4 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 5e99382..21fc703 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -11,9 +11,10 @@ from tempfile import TemporaryFile
from random import randint, random
import test.test_support as support
-from test.test_support import TESTFN, run_unittest
+from test.test_support import TESTFN, run_unittest, findfile
TESTFN2 = TESTFN + "2"
+TESTFNDIR = TESTFN + "d"
FIXEDTEST_SIZE = 1000
SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
@@ -982,6 +983,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):
@@ -1090,6 +1113,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 0000000..ac21d7a
--- /dev/null
+++ b/Lib/test/zipdir.zip
Binary files differ
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index 85012d8..fe01296 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -2,7 +2,7 @@
Read and write ZIP files.
"""
import struct, os, time, sys, shutil
-import binascii, cStringIO
+import binascii, cStringIO, stat
try:
import zlib # We may need its compression method
@@ -940,11 +940,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)
@@ -956,6 +956,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 = file(targetpath, "wb")
shutil.copyfileobj(source, target)
@@ -995,6 +999,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
@@ -1003,6 +1008,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) << 16L # Unix attributes
if compress_type is None:
@@ -1016,6 +1023,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 = open(filename, "rb")
# Must overwrite CRC and sizes with correct data later
zinfo.CRC = CRC = 0