]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-151669: Normalize symlink targets in tarfile.TarFile.gettarinfo() (GH-151671)
authorDaniele Nicolodi <daniele@grinta.net>
Fri, 10 Jul 2026 13:53:01 +0000 (15:53 +0200)
committerGitHub <noreply@github.com>
Fri, 10 Jul 2026 13:53:01 +0000 (15:53 +0200)
This applies a normalization when creating members vrom the filesystem,
 complementary to the one added to tarfile.TarFile.extract() in gh-138309
that does it in the other direction.
This solves an issue with round-tripping through the filesystem.

Doc/whatsnew/3.15.rst
Lib/tarfile.py
Lib/test/test_tarfile.py
Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst [new file with mode: 0644]

index aad4758297c30d18f8d4c6c72de6ebf7dcac8095..8cba187bf31dd16b8e253b5a653cebad27ec2d6c 100644 (file)
@@ -1549,6 +1549,9 @@ tarfile
   now replace slashes with backslashes in symlink targets on Windows to prevent
   creation of corrupted links.
   (Contributed by Christoph Walcher in :gh:`57911`.)
+* :func:`~tarfile.TarFile.gettarinfo` now replaces backslashes with slashes in
+  symlink targets on Windows to conform to the tar format standard. (Contributed
+  by Daniele Nicolodi in :gh:`151669`.)
 
 
 threading
index 385dbb536d8a7dce4f6846be3d79e411715de2ae..5d5cef2f139a42620cebc003005abee4f2a28a3e 100644 (file)
@@ -2255,7 +2255,7 @@ class TarFile(object):
             type = FIFOTYPE
         elif stat.S_ISLNK(stmd):
             type = SYMTYPE
-            linkname = os.readlink(name)
+            linkname = os.readlink(name).replace(os.sep, "/")
         elif stat.S_ISCHR(stmd):
             type = CHRTYPE
         elif stat.S_ISBLK(stmd):
index 2998a3667b4d17d74435984debd7378c7b9e8d99..514cfbb07cd76ada3623b6e9b8434815457a1266 100644 (file)
@@ -1668,6 +1668,22 @@ class WriteTest(WriteTestBase, unittest.TestCase):
         finally:
             os_helper.unlink(path)
 
+    @os_helper.skip_unless_symlink
+    def test_symlink_target_normalization(self):
+        # Test for gh-151669.
+        path = os.path.join(TEMPDIR, "symlink")
+        target = "subdir/link/target"
+        os.symlink(target.replace("/", os.sep), path)
+        try:
+            tar = tarfile.open(tmpname, self.mode)
+            try:
+                tarinfo = tar.gettarinfo(path)
+                self.assertEqual(tarinfo.linkname, target)
+            finally:
+                tar.close()
+        finally:
+            os_helper.unlink(path)
+
     def test_add_self(self):
         # Test for #1257255.
         dstname = os.path.abspath(tmpname)
diff --git a/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst b/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst
new file mode 100644 (file)
index 0000000..d8e4850
--- /dev/null
@@ -0,0 +1,3 @@
+On Windows, when populating tar archives from filesystem content, to
+conform to the tar format standard, backslashes in symlink targets are
+be replaced by slashes.