|
@@ -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()
|