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.
........
This commit is contained in:
Martin v. Löwis 2009-01-24 14:04:33 +00:00
parent 19fec8b58f
commit 3a8071a26f
4 changed files with 48 additions and 4 deletions

View File

@ -11,9 +11,10 @@ from tempfile import TemporaryFile
from random import randint, random from random import randint, random
import test.test_support as support 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" TESTFN2 = TESTFN + "2"
TESTFNDIR = TESTFN + "d"
FIXEDTEST_SIZE = 1000 FIXEDTEST_SIZE = 1000
SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
@ -982,6 +983,28 @@ class TestsWithMultipleOpens(unittest.TestCase):
def tearDown(self): def tearDown(self):
os.remove(TESTFN2) 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): class UniversalNewlineTests(unittest.TestCase):
def setUp(self): def setUp(self):
@ -1090,6 +1113,7 @@ class UniversalNewlineTests(unittest.TestCase):
def test_main(): def test_main():
run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, PyZipFileTests, DecryptionTests, TestsWithMultipleOpens,
TestWithDirectory,
UniversalNewlineTests, TestsWithRandomBinaryFiles) UniversalNewlineTests, TestsWithRandomBinaryFiles)
if __name__ == "__main__": if __name__ == "__main__":

BIN
Lib/test/zipdir.zip Normal file

Binary file not shown.

View File

@ -2,7 +2,7 @@
Read and write ZIP files. Read and write ZIP files.
""" """
import struct, os, time, sys, shutil import struct, os, time, sys, shutil
import binascii, cStringIO import binascii, cStringIO, stat
try: try:
import zlib # We may need its compression method import zlib # We may need its compression method
@ -940,11 +940,11 @@ class ZipFile:
""" """
# build the destination pathname, replacing # build the destination pathname, replacing
# forward slashes to platform specific separators. # forward slashes to platform specific separators.
if targetpath[-1:] == "/": if targetpath[-1:] in (os.path.sep, os.path.altsep):
targetpath = targetpath[:-1] targetpath = targetpath[:-1]
# don't include leading "/" from file name if present # 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:]) targetpath = os.path.join(targetpath, member.filename[1:])
else: else:
targetpath = os.path.join(targetpath, member.filename) targetpath = os.path.join(targetpath, member.filename)
@ -956,6 +956,10 @@ class ZipFile:
if upperdirs and not os.path.exists(upperdirs): if upperdirs and not os.path.exists(upperdirs):
os.makedirs(upperdirs) os.makedirs(upperdirs)
if member.filename[-1] == '/':
os.mkdir(targetpath)
return targetpath
source = self.open(member, pwd=pwd) source = self.open(member, pwd=pwd)
target = file(targetpath, "wb") target = file(targetpath, "wb")
shutil.copyfileobj(source, target) shutil.copyfileobj(source, target)
@ -995,6 +999,7 @@ class ZipFile:
"Attempt to write to ZIP archive that was already closed") "Attempt to write to ZIP archive that was already closed")
st = os.stat(filename) st = os.stat(filename)
isdir = stat.S_ISDIR(st.st_mode)
mtime = time.localtime(st.st_mtime) mtime = time.localtime(st.st_mtime)
date_time = mtime[0:6] date_time = mtime[0:6]
# Create ZipInfo instance to store file information # Create ZipInfo instance to store file information
@ -1003,6 +1008,8 @@ class ZipFile:
arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
while arcname[0] in (os.sep, os.altsep): while arcname[0] in (os.sep, os.altsep):
arcname = arcname[1:] arcname = arcname[1:]
if isdir:
arcname += '/'
zinfo = ZipInfo(arcname, date_time) zinfo = ZipInfo(arcname, date_time)
zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes
if compress_type is None: if compress_type is None:
@ -1016,6 +1023,16 @@ class ZipFile:
self._writecheck(zinfo) self._writecheck(zinfo)
self._didModify = True 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") fp = open(filename, "rb")
# Must overwrite CRC and sizes with correct data later # Must overwrite CRC and sizes with correct data later
zinfo.CRC = CRC = 0 zinfo.CRC = CRC = 0

View File

@ -76,6 +76,9 @@ Core and Builtins
Library 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, - 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 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 file size rather than 0). This is consistent with the behaviour of the