Browse Source

Fixed #27628 -- Fixed unarchiving a file without permission data.

Anton Samarchyan 8 năm trước cách đây
mục cha
commit
5cf4894836

+ 1 - 0
AUTHORS

@@ -63,6 +63,7 @@ answer newbie questions, and generally made Django that much better:
     Anssi Kääriäinen <akaariai@gmail.com>
     ant9000@netwise.it
     Anthony Briggs <anthony.briggs@gmail.com>
+    Anton Samarchyan <desecho@gmail.com>
     Antoni Aloy
     Antonio Cavedoni <http://cavedoni.com/>
     Antonis Christofides <anthony@itia.ntua.gr>

+ 14 - 3
django/utils/archive.py

@@ -23,6 +23,7 @@ THE SOFTWARE.
 """
 import os
 import shutil
+import stat
 import tarfile
 import zipfile
 
@@ -98,6 +99,16 @@ class BaseArchive(object):
     """
     Base Archive class.  Implementations should inherit this class.
     """
+    @staticmethod
+    def _copy_permissions(mode, filename):
+        """
+        If the file in the archive has some permissions (this assumes a file
+        won't be writable/executable without being readable), apply those
+        permissions to the unarchived file.
+        """
+        if mode & stat.S_IROTH:
+            os.chmod(filename, mode)
+
     def split_leading_dir(self, path):
         path = str(path)
         path = path.lstrip('/').lstrip('\\')
@@ -164,7 +175,7 @@ class TarArchive(BaseArchive):
                         os.makedirs(dirname)
                     with open(filename, 'wb') as outfile:
                         shutil.copyfileobj(extracted, outfile)
-                        os.chmod(filename, member.mode)
+                        self._copy_permissions(member.mode, filename)
                 finally:
                     if extracted:
                         extracted.close()
@@ -200,9 +211,9 @@ class ZipArchive(BaseArchive):
             else:
                 with open(filename, 'wb') as outfile:
                     outfile.write(data)
-                # convert ZipInfo.external_attr to mode
+                # Convert ZipInfo.external_attr to mode
                 mode = info.external_attr >> 16
-                os.chmod(filename, mode)
+                self._copy_permissions(mode, filename)
 
     def close(self):
         self._archive.close()

BIN
tests/utils_tests/archives/foobar.tar


BIN
tests/utils_tests/archives/foobar.tar.bz2


BIN
tests/utils_tests/archives/foobar.tar.gz


BIN
tests/utils_tests/archives/foobar.zip


+ 4 - 0
tests/utils_tests/test_archive.py

@@ -51,6 +51,10 @@ class ArchiveTester(object):
         filepath = os.path.join(self.tmpdir, 'executable')
         # The file has executable permission.
         self.assertTrue(os.stat(filepath).st_mode & stat.S_IXOTH)
+        filepath = os.path.join(self.tmpdir, 'no_permissions')
+        # The file is readable even though it doesn't have permission data in
+        # the archive.
+        self.assertTrue(os.stat(filepath).st_mode & stat.S_IROTH)
 
     def test_extract_function_with_leadpath(self):
         extract(self.archive_lead_path, self.tmpdir)