def test_resolve(self):
     # tuples of test data, expected results
     tests = [
         ('C:\\..\\./drupal.js', 'drupal.js'),
         ('\\includes\\..\\webform.components.inc\\',
          'webform.components.inc'),
         ('includes/../webform.components.inc', 'webform.components.inc'),
         ('////.//includes/./../..//..///../webform.components.inc/.',
          'dotdot/dotdot/dotdot/webform.components.inc'),
         (u'////.//includes/./../..//..///../webform.components.inc/.',
          u'dotdot/dotdot/dotdot/webform.components.inc'),
         ('includes/../', '.'),
     ]
     for tst, expected in tests:
         assert expected == paths.resolve(tst)
Example #2
0
 def test_resolve(self):
     # tuples of test data, expected results
     tests = [
         ("C:\\..\\./drupal.js", "drupal.js"),
         ("\\includes\\..\\webform.components.inc\\", "webform.components.inc"),
         ("includes/../webform.components.inc", "webform.components.inc"),
         (
             "////.//includes/./../..//..///../webform.components.inc/.",
             "dotdot/dotdot/dotdot/webform.components.inc",
         ),
         (
             u"////.//includes/./../..//..///../webform.components.inc/.",
             u"dotdot/dotdot/dotdot/webform.components.inc",
         ),
         ("includes/../", "."),
     ]
     for tst, expected in tests:
         assert expected == paths.resolve(tst)
Example #3
0
def extract(location, target_dir):
    """
    Extract all files from the tar archive file at `location` in the
    `target_dir`. Plain tars and tars compressed with gzip and bzip2 are
    supported transparently. Other compressions such as xz or lzma are handled
    in two steps. Return a list of warnings messages. Raise Exceptions on errors.

    Skip special files. Contains code derived from Python tarfile.extractall.

    Copyright (C) 2002 Lars Gustabel <*****@*****.**>
    All rights reserved.

    Permission  is  hereby granted,  free  of charge,  to  any person
    obtaining a  copy of  this software  and associated documentation
    files  (the  "Software"),  to   deal  in  the  Software   without
    restriction,  including  without limitation  the  rights to  use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies  of  the  Software,  and to  permit  persons  to  whom the
    Software  is  furnished  to  do  so,  subject  to  the  following
    conditions:

    The above copyright  notice and this  permission notice shall  be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS  IS", WITHOUT WARRANTY OF ANY  KIND,
    EXPRESS OR IMPLIED, INCLUDING  BUT NOT LIMITED TO  THE WARRANTIES
    OF  MERCHANTABILITY,  FITNESS   FOR  A  PARTICULAR   PURPOSE  AND
    NONINFRINGEMENT.  IN  NO  EVENT SHALL  THE  AUTHORS  OR COPYRIGHT
    HOLDERS  BE LIABLE  FOR ANY  CLAIM, DAMAGES  OR OTHER  LIABILITY,
    WHETHER  IN AN  ACTION OF  CONTRACT, TORT  OR OTHERWISE,  ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

    Credits: Gustavo Niemeyer, Niels Gustabel, Richard Townsend.
    """
    assert location
    assert target_dir

    warnings = defaultdict(list)

    # track directories to fixup modification times at the end
    directories = []

    with closing(tarfile.open(location)) as tar:
        tar.errorlevel = 1
        names = set()
        for tinfo in tar.getmembers():
            is_special = not any(
                (tinfo.isfile(), tinfo.isdir(), tinfo.islnk(), tinfo.issym()))
            if is_special:
                # FIXME: we should not report a warning?
                warnings[tinfo.name].append('Skipping special file.')
                continue

            # hardlinks and symlinks are treated as regular files
            if tinfo.islnk() or tinfo.issym():
                if tinfo.issym():
                    # Always search the entire archive.
                    linkname = '/'.join(
                        filter(None,
                               (os.path.dirname(tinfo.name), tinfo.linkname)))
                    limit = None
                else:
                    # Search the archive before the link, because a hard link
                    # is just a reference to an already archived file.
                    linkname = tinfo.linkname
                    limit = tinfo

                realfile = tar._getmember(linkname,
                                          tarinfo=limit,
                                          normalize=True)
                if realfile is None:
                    warnings[tinfo.name].append(
                        'Skipping broken link to: %(linkname)s' % locals())
                    continue

                if not (realfile.isfile() or realfile.isdir()):
                    warnings[tinfo.name].append(
                        'Skipping link to special file: %(linkname)s' %
                        locals())
                    continue

                if realfile.islnk() or realfile.issym():
                    # FIXME: Check tarbomb
                    warnings[tinfo.name].append(
                        'Skipping multi-level link to: %(linkname)s' %
                        locals())
                    continue

                # replace the tarinfo with the linked-to file info
                # but keep the link name
                lname = tinfo.name
                tinfo = copy.copy(realfile)
                tinfo.name = lname

            # FIXME: we skip duplicates, this can happen and will fail if the
            # location is read-only, we should instead rename duplicates
            # using extractcode.new_name
            if tinfo.name.lower() in names:
                warnings[tinfo.name].append('Skipping duplicate file name.')
            names.add(tinfo.name.lower())

            tinfo = copy.copy(tinfo)
            # ensure we do stay always under the target dir
            tinfo.name = resolve(tinfo.name)
            # Extract all files with a safe mode
            # FIXME: use the current user mask
            tinfo.mode = 0700
            # keep a list of dirs to fix mtime once they are all created
            if tinfo.isdir():
                directories.append(tinfo)
            try:
                tar.extract(tinfo, target_dir)
            except Exception, e:
                # FIXME: we must keep the traceback for diagnostics
                raise ExtractError()
 def test_resolve_6(self):
     test = paths.resolve('includes/../')
     expected = '.'
     assert expected == test
 def test_resolve_3(self):
     test = paths.resolve('includes/../webform.components.inc')
     expected = 'webform.components.inc'
     assert expected == test
 def test_resolve_5(self):
     test = paths.resolve(
         u'////.//includes/./../..//..///../webform.components.inc/.')
     expected = u'dotdot/dotdot/dotdot/webform.components.inc'
     assert expected == test
 def test_resolve_mixed_slash(self):
     test = paths.resolve('C:\\..\\./drupal.js')
     expected = 'C/drupal.js'
     assert expected == test
 def test_resolve_2(self):
     test = paths.resolve('\\includes\\..\\webform.components.inc\\')
     expected = 'webform.components.inc'
     assert expected == test
Example #9
0
 def test_resolve_4(self):
     test = paths.resolve(
         '////.//includes/./../..//..///../webform.components.inc/.')
     expected = 'dotdot/dotdot/dotdot/webform.components.inc'
     assert test == expected
Example #10
0
def extract(location, target_dir):
    """
    Extract all files from the tar archive file at `location` in the
    `target_dir`. Plain tars and tars compressed with gzip and bzip2 are
    supported transparently. Other compressions such as xz or lzma are handled
    in two steps. Return a list of warnings messages. Raise Exceptions on errors.

    Skip special files. Contains code derived from Python tarfile.extractall.

    Copyright (C) 2002 Lars Gustabel <*****@*****.**>
    All rights reserved.

    Permission  is  hereby granted,  free  of charge,  to  any person
    obtaining a  copy of  this software  and associated documentation
    files  (the  "Software"),  to   deal  in  the  Software   without
    restriction,  including  without limitation  the  rights to  use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies  of  the  Software,  and to  permit  persons  to  whom the
    Software  is  furnished  to  do  so,  subject  to  the  following
    conditions:

    The above copyright  notice and this  permission notice shall  be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS  IS", WITHOUT WARRANTY OF ANY  KIND,
    EXPRESS OR IMPLIED, INCLUDING  BUT NOT LIMITED TO  THE WARRANTIES
    OF  MERCHANTABILITY,  FITNESS   FOR  A  PARTICULAR   PURPOSE  AND
    NONINFRINGEMENT.  IN  NO  EVENT SHALL  THE  AUTHORS  OR COPYRIGHT
    HOLDERS  BE LIABLE  FOR ANY  CLAIM, DAMAGES  OR OTHER  LIABILITY,
    WHETHER  IN AN  ACTION OF  CONTRACT, TORT  OR OTHERWISE,  ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

    Credits: Gustavo Niemeyer, Niels Gustabel, Richard Townsend.
    """
    assert location
    assert target_dir

    warnings = defaultdict(list)

    with closing(tarfile.open(location)) as tar:
        tar.errorlevel = 1
        directories = []
        names = set()
        for tinfo in tar.getmembers():
            is_special = not (tinfo.isfile() or tinfo.isdir()
                              or tinfo.islnk() or tinfo.issym())
            if is_special:
                # FIXME: we should not report a warning?
                warnings[tinfo.name].append('Skipping special file.')
                continue

            # hardlinks and symlinks are treated as regular files
            if tinfo.islnk() or tinfo.issym():
                if tinfo.issym():
                    # Always search the entire archive.
                    linkname = '/'.join(filter(None,
                               (os.path.dirname(tinfo.name), tinfo.linkname)))
                    limit = None
                else:
                    # Search the archive before the link, because a hard link
                    # is just a reference to an already archived file.
                    linkname = tinfo.linkname
                    limit = tinfo

                realfile = tar._getmember(linkname, tarinfo=limit, normalize=True)
                if realfile is None:
                    warnings[tinfo.name].append('Skipping broken link to: %(linkname)r' % locals())
                    continue

                if not (realfile.isfile() or realfile.isdir()):
                    warnings[tinfo.name].append('Skipping link to special file: %(linkname)r' % locals())
                    continue

                if realfile.islnk() or realfile.issym():
                    # FIXME: Check tarbomb
                    warnings[tinfo.name].append('Skipping multi-level link to: %(linkname)r' % locals())
                    continue

                # replace the tarinfo with the linked-to file info
                # but keep the link name
                lname = tinfo.name
                tinfo = copy.copy(realfile)
                tinfo.name = lname

            # FIXME: we skip duplicates, this can happen and will fail if the
            # location is read-only, we should instead rename duplicates
            # using extractcode.new_name
            if tinfo.name.lower() in names:
                warnings[tinfo.name].append('Skipping duplicate file name.')
            names.add(tinfo.name.lower())

            tinfo = copy.copy(tinfo)
            # ensure we do stay always under the target dir
            tinfo.name = resolve(tinfo.name)
            # Extract all files with a safe mode
            # FIXME: use the current user mask
            tinfo.mode = 0700
            # keep a list of dirs to fix mtime once they are all created
            if tinfo.isdir():
                directories.append(tinfo)
            try:
                tar.extract(tinfo, target_dir)
            except Exception, e:
                raise ExtractError()

        # Set correct mtime on directories, starting from the bottom of the
        # tree
        for tinfo in sorted(directories,
                            cmp=lambda a, b: cmp(a.name, b.name),
                            reverse=True):
            dir_loc = os.path.join(target_dir, tinfo.name)
            try:
                # NOTE: this may not work at all on Windows
                tar.utime(tinfo, dir_loc)
            except Exception, e:
                warnings[tinfo.name].append(str(e))
Example #11
0
 def test_resolve_6(self):
     test = paths.resolve('includes/../')
     expected = '.'
     assert expected == test
Example #12
0
 def test_resolve_5(self):
     test = paths.resolve(u'////.//includes/./../..//..///../webform.components.inc/.')
     expected = u'dotdot/dotdot/dotdot/webform.components.inc'
     assert expected == test
Example #13
0
 def test_resolve_3(self):
     test = paths.resolve('includes/../webform.components.inc')
     expected = 'webform.components.inc'
     assert expected == test
Example #14
0
 def test_resolve_2(self):
     test = paths.resolve('\\includes\\..\\webform.components.inc\\')
     expected = 'webform.components.inc'
     assert expected == test
Example #15
0
 def test_resolve_mixed_slash(self):
     test = paths.resolve('C:\\..\\./drupal.js')
     expected = 'C/drupal.js'
     assert expected == test