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

This commit is contained in:
Anton Samarchyan 2016-12-28 15:20:24 -05:00 committed by Tim Graham
parent 4579c3f6b8
commit 5cf4894836
7 changed files with 19 additions and 3 deletions

View File

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

View File

@ -23,6 +23,7 @@ THE SOFTWARE.
""" """
import os import os
import shutil import shutil
import stat
import tarfile import tarfile
import zipfile import zipfile
@ -98,6 +99,16 @@ class BaseArchive(object):
""" """
Base Archive class. Implementations should inherit this class. 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): def split_leading_dir(self, path):
path = str(path) path = str(path)
path = path.lstrip('/').lstrip('\\') path = path.lstrip('/').lstrip('\\')
@ -164,7 +175,7 @@ class TarArchive(BaseArchive):
os.makedirs(dirname) os.makedirs(dirname)
with open(filename, 'wb') as outfile: with open(filename, 'wb') as outfile:
shutil.copyfileobj(extracted, outfile) shutil.copyfileobj(extracted, outfile)
os.chmod(filename, member.mode) self._copy_permissions(member.mode, filename)
finally: finally:
if extracted: if extracted:
extracted.close() extracted.close()
@ -200,9 +211,9 @@ class ZipArchive(BaseArchive):
else: else:
with open(filename, 'wb') as outfile: with open(filename, 'wb') as outfile:
outfile.write(data) outfile.write(data)
# convert ZipInfo.external_attr to mode # Convert ZipInfo.external_attr to mode
mode = info.external_attr >> 16 mode = info.external_attr >> 16
os.chmod(filename, mode) self._copy_permissions(mode, filename)
def close(self): def close(self):
self._archive.close() self._archive.close()

View File

@ -51,6 +51,10 @@ class ArchiveTester(object):
filepath = os.path.join(self.tmpdir, 'executable') filepath = os.path.join(self.tmpdir, 'executable')
# The file has executable permission. # The file has executable permission.
self.assertTrue(os.stat(filepath).st_mode & stat.S_IXOTH) 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): def test_extract_function_with_leadpath(self):
extract(self.archive_lead_path, self.tmpdir) extract(self.archive_lead_path, self.tmpdir)