]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Merged revisions 74571 via svnmerge from
authorLars Gustäbel <lars@gustaebel.de>
Fri, 28 Aug 2009 19:59:59 +0000 (19:59 +0000)
committerLars Gustäbel <lars@gustaebel.de>
Fri, 28 Aug 2009 19:59:59 +0000 (19:59 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r74571 | lars.gustaebel | 2009-08-28 21:23:44 +0200 (Fri, 28 Aug 2009) | 7 lines

  Issue #6054: Do not normalize stored pathnames.

  No longer use tarfile.normpath() on pathnames. Store pathnames
  unchanged, i.e. do not remove "./", "../" and "//" occurrences.
  However, still convert absolute to relative paths.
........

Lib/tarfile.py
Lib/test/test_tarfile.py
Misc/NEWS

index 3a3d2c925d710464733df890ad6928332ccaa8cd..ebaffd99a7686131e7fa4af6c973963d767d5865 100644 (file)
@@ -309,11 +309,6 @@ def filemode(mode):
             perm.append("-")
     return "".join(perm)
 
-if os.sep != "/":
-    normpath = lambda path: os.path.normpath(path).replace(os.sep, "/")
-else:
-    normpath = os.path.normpath
-
 class TarError(Exception):
     """Base exception."""
     pass
@@ -955,7 +950,7 @@ class TarInfo(object):
         """Return the TarInfo's attributes as a dictionary.
         """
         info = {
-            "name":     normpath(self.name),
+            "name":     self.name,
             "mode":     self.mode & 0o7777,
             "uid":      self.uid,
             "gid":      self.gid,
@@ -963,7 +958,7 @@ class TarInfo(object):
             "mtime":    self.mtime,
             "chksum":   self.chksum,
             "type":     self.type,
-            "linkname": normpath(self.linkname) if self.linkname else "",
+            "linkname": self.linkname,
             "uname":    self.uname,
             "gname":    self.gname,
             "devmajor": self.devmajor,
@@ -1795,10 +1790,9 @@ class TarFile(object):
         # Absolute paths are turned to relative paths.
         if arcname is None:
             arcname = name
-        arcname = normpath(arcname)
         drv, arcname = os.path.splitdrive(arcname)
-        while arcname[0:1] == "/":
-            arcname = arcname[1:]
+        arcname = arcname.replace(os.sep, "/")
+        arcname = arcname.lstrip("/")
 
         # Now, fill the TarInfo object with
         # information specific for the file.
@@ -1927,16 +1921,6 @@ class TarFile(object):
             self._dbg(2, "tarfile: Skipped %r" % name)
             return
 
-        # Special case: The user wants to add the current
-        # working directory.
-        if name == ".":
-            if recursive:
-                if arcname == ".":
-                    arcname = ""
-                for f in os.listdir(name):
-                    self.add(f, os.path.join(arcname, f), recursive, exclude)
-            return
-
         self._dbg(1, name)
 
         # Create a TarInfo object from the file.
@@ -2103,9 +2087,8 @@ class TarFile(object):
         # Fetch the TarInfo object for the given name
         # and build the destination pathname, replacing
         # forward slashes to platform specific separators.
-        if targetpath[-1:] == "/":
-            targetpath = targetpath[:-1]
-        targetpath = os.path.normpath(targetpath)
+        targetpath = targetpath.rstrip("/")
+        targetpath = targetpath.replace("/", os.sep)
 
         # Create all upper directories.
         upperdirs = os.path.dirname(targetpath)
@@ -2200,23 +2183,23 @@ class TarFile(object):
           (platform limitation), we try to make a copy of the referenced file
           instead of a link.
         """
-        linkpath = tarinfo.linkname
         try:
             if tarinfo.issym():
-                os.symlink(linkpath, targetpath)
+                os.symlink(tarinfo.linkname, targetpath)
             else:
                 # See extract().
                 os.link(tarinfo._link_target, targetpath)
         except AttributeError:
             if tarinfo.issym():
-                linkpath = os.path.join(os.path.dirname(tarinfo.name),
-                                        linkpath)
-                linkpath = normpath(linkpath)
+                linkpath = os.path.dirname(tarinfo.name) + "/" + \
+                                        tarinfo.linkname
+            else:
+                linkpath = tarinfo.linkname
 
             try:
                 self._extract_member(self.getmember(linkpath), targetpath)
             except (EnvironmentError, KeyError) as e:
-                linkpath = os.path.normpath(linkpath)
+                linkpath = linkpath.replace("/", os.sep)
                 try:
                     shutil.copy2(linkpath, targetpath)
                 except EnvironmentError as e:
index 76390c76f1172a5b1a732774f6a3bd19d690b2b9..83f4a8cd58034ead18531425ea328e6bf3151ea0 100644 (file)
@@ -659,6 +659,76 @@ class WriteTest(WriteTestBase):
         finally:
             shutil.rmtree(tempdir)
 
+    # Guarantee that stored pathnames are not modified. Don't
+    # remove ./ or ../ or double slashes. Still make absolute
+    # pathnames relative.
+    # For details see bug #6054.
+    def _test_pathname(self, path, cmp_path=None, dir=False):
+        # Create a tarfile with an empty member named path
+        # and compare the stored name with the original.
+        foo = os.path.join(TEMPDIR, "foo")
+        if not dir:
+            open(foo, "w").close()
+        else:
+            os.mkdir(foo)
+
+        tar = tarfile.open(tmpname, self.mode)
+        tar.add(foo, arcname=path)
+        tar.close()
+
+        tar = tarfile.open(tmpname, "r")
+        t = tar.next()
+        tar.close()
+
+        if not dir:
+            os.remove(foo)
+        else:
+            os.rmdir(foo)
+
+        self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/"))
+
+    def test_pathnames(self):
+        self._test_pathname("foo")
+        self._test_pathname(os.path.join("foo", ".", "bar"))
+        self._test_pathname(os.path.join("foo", "..", "bar"))
+        self._test_pathname(os.path.join(".", "foo"))
+        self._test_pathname(os.path.join(".", "foo", "."))
+        self._test_pathname(os.path.join(".", "foo", ".", "bar"))
+        self._test_pathname(os.path.join(".", "foo", "..", "bar"))
+        self._test_pathname(os.path.join(".", "foo", "..", "bar"))
+        self._test_pathname(os.path.join("..", "foo"))
+        self._test_pathname(os.path.join("..", "foo", ".."))
+        self._test_pathname(os.path.join("..", "foo", ".", "bar"))
+        self._test_pathname(os.path.join("..", "foo", "..", "bar"))
+
+        self._test_pathname("foo" + os.sep + os.sep + "bar")
+        self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True)
+
+    def test_abs_pathnames(self):
+        if sys.platform == "win32":
+            self._test_pathname("C:\\foo", "foo")
+        else:
+            self._test_pathname("/foo", "foo")
+            self._test_pathname("///foo", "foo")
+
+    def test_cwd(self):
+        # Test adding the current working directory.
+        cwd = os.getcwd()
+        os.chdir(TEMPDIR)
+        try:
+            open("foo", "w").close()
+
+            tar = tarfile.open(tmpname, self.mode)
+            tar.add(".")
+            tar.close()
+
+            tar = tarfile.open(tmpname, "r")
+            for t in tar:
+                self.assert_(t.name == "." or t.name.startswith("./"))
+            tar.close()
+        finally:
+            os.chdir(cwd)
+
 
 class StreamWriteTest(WriteTestBase):
 
index 687f31c9d4941d063d5cd291cf49fade265bc75b..d187299c1f95eb426bb143ae82d16709af8fc4d0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -65,6 +65,8 @@ C-API
 Library
 -------
 
+- Issue #6054: Do not normalize stored pathnames in tarfile.
+
 - Issue #6794: Fix Decimal.compare_total and Decimal.compare_total_mag: NaN
   payloads are now ordered by integer value rather than lexicographically.