https://github.com/python/cpython/commit/cc316410177c29f0398135f208e28e9525ca8bd9
commit: cc316410177c29f0398135f208e28e9525ca8bd9
branch: main
author: Daniele Nicolodi <[email protected]>
committer: encukou <[email protected]>
date: 2026-07-10T15:53:01+02:00
summary:

gh-151669: Normalize symlink targets in tarfile.TarFile.gettarinfo() (GH-151671)

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.

files:
A Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst
M Doc/whatsnew/3.15.rst
M Lib/tarfile.py
M Lib/test/test_tarfile.py

diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index aad4758297c30d..8cba187bf31dd1 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -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
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 385dbb536d8a7d..5d5cef2f139a42 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2255,7 +2255,7 @@ def gettarinfo(self, name=None, arcname=None, 
fileobj=None):
             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):
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 2998a3667b4d17..514cfbb07cd76a 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -1668,6 +1668,22 @@ def test_symlink_size(self):
         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
index 00000000000000..d8e4850ba94e14
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-24-23-28-42.gh-issue-151669.tPUavQ.rst
@@ -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.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to