From 09005630c016d86683ae3d63d3149d4177f6aa70 Mon Sep 17 00:00:00 2001
From: Chris Fernald <chfernal@microsoft.com>
Date: Fri, 8 Apr 2022 15:07:03 -0700
Subject: [PATCH 1/3] bpo-47231: Strip trailing slash from tarfile longname
 directories

---
 Lib/tarfile.py           | 10 ++++++++++
 Lib/test/test_tarfile.py | 17 +++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 8d43d0da7b9880..7a4880565b8891 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -1163,6 +1163,11 @@ def _proc_builtin(self, tarfile):
         # header information.
         self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors)
 
+        # Remove redundant slashes from directories. This is to be consistent
+        # with frombuf().
+        if self.isdir():
+            self.name = self.name.rstrip("/")
+
         return self
 
     def _proc_gnulong(self, tarfile):
@@ -1185,6 +1190,11 @@ def _proc_gnulong(self, tarfile):
         elif self.type == GNUTYPE_LONGLINK:
             next.linkname = nts(buf, tarfile.encoding, tarfile.errors)
 
+        # Remove redundant slashes from directories. This is to be consistent
+        # with frombuf().
+        if next.isdir():
+            next.name = next.name.rstrip("/")
+
         return next
 
     def _proc_sparse(self, tarfile):
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 12850cd635e995..c7004698246a41 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -228,6 +228,7 @@ def test_add_dir_getmember(self):
     def add_dir_and_getmember(self, name):
         with os_helper.temp_cwd():
             with tarfile.open(tmpname, 'w') as tar:
+                tar.format = tarfile.USTAR_FORMAT
                 try:
                     os.mkdir(name)
                     tar.add(name)
@@ -1018,11 +1019,26 @@ def test_header_offset(self):
                                               "iso8859-1", "strict")
             self.assertEqual(tarinfo.type, self.longnametype)
 
+    def test_longname_directory(self):
+        # Test reading a longlink directory. Issue #47231.
+        longdir = ('a' * 101) + '/'
+        with os_helper.temp_cwd():
+            with tarfile.open(tmpname, 'w') as tar:
+                tar.format = self.format
+                try:
+                    os.mkdir(longdir)
+                    tar.add(longdir)
+                finally:
+                    os.rmdir(longdir)
+            with tarfile.open(tmpname) as tar:
+                self.assertIsNotNone(tar.getmember(longdir))
+                self.assertIsNotNone(tar.getmember(longdir.rstrip('/')))
 
 class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
 
     subdir = "gnu"
     longnametype = tarfile.GNUTYPE_LONGNAME
+    format = tarfile.GNU_FORMAT
 
     # Since 3.2 tarfile is supposed to accurately restore sparse members and
     # produce files with holes. This is what we actually want to test here.
@@ -1082,6 +1098,7 @@ class PaxReadTest(LongnameTest, ReadTest, unittest.TestCase):
 
     subdir = "pax"
     longnametype = tarfile.XHDTYPE
+    format = tarfile.PAX_FORMAT
 
     def test_pax_global_headers(self):
         tar = tarfile.open(tarname, encoding="iso8859-1")

From 3c1a545e74fde4adcf3b59ca54f995711684ec11 Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Fri, 8 Apr 2022 22:12:12 +0000
Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?=
 =?UTF-8?q?rb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst

diff --git a/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst b/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst
new file mode 100644
index 00000000000000..ee05c5e2856756
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-04-08-22-12-11.bpo-47231.lvyglt.rst
@@ -0,0 +1 @@
+Fixed an issue with inconsistent trailing slashes in tarfile longname directories.

From bcfd09a8818c8b5cf2730de9db8adac7b7ebf0ff Mon Sep 17 00:00:00 2001
From: Brett Cannon <brett@python.org>
Date: Fri, 17 Jun 2022 14:51:12 -0700
Subject: [PATCH 3/3] Apply suggestions from code review

---
 Lib/tarfile.py           | 2 +-
 Lib/test/test_tarfile.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 7a4880565b8891..169c88d63f781b 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -1193,7 +1193,7 @@ def _proc_gnulong(self, tarfile):
         # Remove redundant slashes from directories. This is to be consistent
         # with frombuf().
         if next.isdir():
-            next.name = next.name.rstrip("/")
+            next.name = next.name.removesuffix("/")
 
         return next
 
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 4a669344ea5149..f1aed5ccc6b76b 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -1034,7 +1034,7 @@ def test_longname_directory(self):
                     os.rmdir(longdir)
             with tarfile.open(tmpname) as tar:
                 self.assertIsNotNone(tar.getmember(longdir))
-                self.assertIsNotNone(tar.getmember(longdir.rstrip('/')))
+                self.assertIsNotNone(tar.getmember(longdir.removesuffix('/')))
 
 class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):