]> granicus.if.org Git - python/commitdiff
Issue #20912: Now directories added to ZIP file have correct Unix and MS-DOS
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 23 Sep 2014 19:39:59 +0000 (22:39 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 23 Sep 2014 19:39:59 +0000 (22:39 +0300)
directory attributes.

Lib/test/test_zipfile.py
Lib/zipfile.py
Misc/NEWS

index c309e37c8979208dce845fa3eb5d8dab7968a2b0..fbeda53096eb9a050be321756247522ea6edc0fe 100644 (file)
@@ -1472,11 +1472,48 @@ class TestWithDirectory(unittest.TestCase):
         os.mkdir(os.path.join(TESTFN2, "a"))
         self.test_extract_dir()
 
-    def test_store_dir(self):
+    def test_write_dir(self):
+        dirpath = os.path.join(TESTFN2, "x")
+        os.mkdir(dirpath)
+        mode = os.stat(dirpath).st_mode & 0xFFFF
+        with zipfile.ZipFile(TESTFN, "w") as zipf:
+            zipf.write(dirpath)
+            zinfo = zipf.filelist[0]
+            self.assertTrue(zinfo.filename.endswith("/x/"))
+            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
+            zipf.write(dirpath, "y")
+            zinfo = zipf.filelist[1]
+            self.assertTrue(zinfo.filename, "y/")
+            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
+        with zipfile.ZipFile(TESTFN, "r") as zipf:
+            zinfo = zipf.filelist[0]
+            self.assertTrue(zinfo.filename.endswith("/x/"))
+            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
+            zinfo = zipf.filelist[1]
+            self.assertTrue(zinfo.filename, "y/")
+            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
+            target = os.path.join(TESTFN2, "target")
+            os.mkdir(target)
+            zipf.extractall(target)
+            self.assertTrue(os.path.isdir(os.path.join(target, "y")))
+            self.assertEqual(len(os.listdir(target)), 2)
+
+    def test_writestr_dir(self):
         os.mkdir(os.path.join(TESTFN2, "x"))
         with zipfile.ZipFile(TESTFN, "w") as zipf:
-            zipf.write(os.path.join(TESTFN2, "x"), "x")
-            self.assertTrue(zipf.filelist[0].filename.endswith("x/"))
+            zipf.writestr("x/", b'')
+            zinfo = zipf.filelist[0]
+            self.assertEqual(zinfo.filename, "x/")
+            self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
+        with zipfile.ZipFile(TESTFN, "r") as zipf:
+            zinfo = zipf.filelist[0]
+            self.assertTrue(zinfo.filename.endswith("x/"))
+            self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
+            target = os.path.join(TESTFN2, "target")
+            os.mkdir(target)
+            zipf.extractall(target)
+            self.assertTrue(os.path.isdir(os.path.join(target, "x")))
+            self.assertEqual(os.listdir(target), ["x"])
 
     def tearDown(self):
         rmtree(TESTFN2)
index 6722c409978615954af12e89e46a9a181a9e8ef0..ecdd8a55069d48dd57b35e9eca70e89817c29521 100644 (file)
@@ -1150,6 +1150,7 @@ class ZipFile(object):
             zinfo.file_size = 0
             zinfo.compress_size = 0
             zinfo.CRC = 0
+            zinfo.external_attr |= 0x10  # MS-DOS directory flag
             self.filelist.append(zinfo)
             self.NameToInfo[zinfo.filename] = zinfo
             self.fp.write(zinfo.FileHeader(False))
@@ -1211,7 +1212,11 @@ class ZipFile(object):
                             date_time=time.localtime(time.time())[:6])
 
             zinfo.compress_type = self.compression
-            zinfo.external_attr = 0600 << 16
+            if zinfo.filename[-1] == '/':
+                zinfo.external_attr = 0o40775 << 16   # drwxrwxr-x
+                zinfo.external_attr |= 0x10           # MS-DOS directory flag
+            else:
+                zinfo.external_attr = 0o600 << 16     # ?rw-------
         else:
             zinfo = zinfo_or_arcname
 
index 5b69a1b5955db3b9189199666b5fd06f38a258ed..02e9c4c3aac135b3331ce059524f5b9d337bd9cf 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #20912: Now directories added to ZIP file have correct Unix and MS-DOS
+  directory attributes.
+
 - Issue #21866: ZipFile.close() no longer writes ZIP64 central directory
   records if allowZip64 is false.