diff options
Diffstat (limited to 'setuptools/archive_util.py')
| -rwxr-xr-x | setuptools/archive_util.py | 94 |
1 files changed, 70 insertions, 24 deletions
diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index d24c6c13..1109f346 100755 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -3,10 +3,10 @@ __all__ = [ "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", - "UnrecognizedFormat", "extraction_drivers" + "UnrecognizedFormat", "extraction_drivers", "unpack_directory", ] -import zipfile, tarfile, os +import zipfile, tarfile, os, shutil, posixpath from pkg_resources import ensure_directory from distutils.errors import DistutilsError @@ -80,6 +80,47 @@ def unpack_archive(filename, extract_dir, progress_filter=default_filter, +def unpack_directory(filename, extract_dir, progress_filter=default_filter): + """"Unpack" a directory, using the same interface as for archives + + Raises ``UnrecognizedFormat`` if `filename` is not a directory + """ + if not os.path.isdir(filename): + raise UnrecognizedFormat("%s is not a directory" % (filename,)) + + paths = {filename:('',extract_dir)} + for base, dirs, files in os.walk(filename): + src,dst = paths[base] + for d in dirs: + paths[os.path.join(base,d)] = src+d+'/', os.path.join(dst,d) + for f in files: + name = src+f + target = os.path.join(dst,f) + target = progress_filter(src+f, target) + if not target: + continue # skip non-files + ensure_directory(target) + f = os.path.join(base,f) + shutil.copyfile(f, target) + shutil.copystat(f, target) + + + + + + + + + + + + + + + + + + def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): """Unpack zip `filename` to `extract_dir` @@ -97,7 +138,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): name = info.filename # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: + if name.startswith('/') or '..' in name.split('/'): continue target = os.path.join(extract_dir, *name.split('/')) @@ -117,6 +158,9 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): finally: f.close() del data + unix_attributes = info.external_attr >> 16 + if unix_attributes: + os.chmod(target, unix_attributes) finally: z.close() @@ -128,37 +172,39 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): by ``tarfile.open()``). See ``unpack_archive()`` for an explanation of the `progress_filter` argument. """ - try: tarobj = tarfile.open(filename) except tarfile.TarError: raise UnrecognizedFormat( "%s is not a compressed or uncompressed tar file" % (filename,) ) - try: tarobj.chown = lambda *args: None # don't do any chowning! for member in tarobj: - if member.isfile() or member.isdir(): - name = member.name - # don't extract absolute paths or ones with .. in them - if not name.startswith('/') and '..' not in name: - dst = os.path.join(extract_dir, *name.split('/')) - dst = progress_filter(name, dst) - if dst: - if dst.endswith(os.sep): - dst = dst[:-1] - tarobj._extract_member(member,dst) # XXX Ugh + name = member.name + # don't extract absolute paths or ones with .. in them + if not name.startswith('/') and '..' not in name.split('/'): + prelim_dst = os.path.join(extract_dir, *name.split('/')) + + # resolve any links and to extract the link targets as normal files + while member is not None and (member.islnk() or member.issym()): + linkpath = member.linkname + if member.issym(): + linkpath = posixpath.join(posixpath.dirname(member.name), linkpath) + linkpath = posixpath.normpath(linkpath) + member = tarobj._getmember(linkpath) + + if member is not None and (member.isfile() or member.isdir()): + final_dst = progress_filter(name, prelim_dst) + if final_dst: + if final_dst.endswith(os.sep): + final_dst = final_dst[:-1] + try: + tarobj._extract_member(member, final_dst) # XXX Ugh + except tarfile.ExtractError: + pass # chown/chmod/mkfifo/mknode/makedev failed return True finally: tarobj.close() - - - -extraction_drivers = unpack_zipfile, unpack_tarfile - - - - - +extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile |
