Skip to content

Commit f260160

Browse files
authored
Update tarfile.py to 3.14.5 (RustPython#7879)
1 parent 451bdcc commit f260160

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

Lib/tarfile.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,20 @@ def _create_pax_generic_header(cls, pax_headers, type, encoding):
12781278
@classmethod
12791279
def frombuf(cls, buf, encoding, errors):
12801280
"""Construct a TarInfo object from a 512 byte bytes object.
1281+
1282+
To support the old v7 tar format AREGTYPE headers are
1283+
transformed to DIRTYPE headers if their name ends in '/'.
1284+
"""
1285+
return cls._frombuf(buf, encoding, errors)
1286+
1287+
@classmethod
1288+
def _frombuf(cls, buf, encoding, errors, *, dircheck=True):
1289+
"""Construct a TarInfo object from a 512 byte bytes object.
1290+
1291+
If ``dircheck`` is set to ``True`` then ``AREGTYPE`` headers will
1292+
be normalized to ``DIRTYPE`` if the name ends in a trailing slash.
1293+
``dircheck`` must be set to ``False`` if this function is called
1294+
on a follow-up header such as ``GNUTYPE_LONGNAME``.
12811295
"""
12821296
if len(buf) == 0:
12831297
raise EmptyHeaderError("empty header")
@@ -1308,7 +1322,7 @@ def frombuf(cls, buf, encoding, errors):
13081322

13091323
# Old V7 tar format represents a directory as a regular
13101324
# file with a trailing slash.
1311-
if obj.type == AREGTYPE and obj.name.endswith("/"):
1325+
if dircheck and obj.type == AREGTYPE and obj.name.endswith("/"):
13121326
obj.type = DIRTYPE
13131327

13141328
# The old GNU sparse format occupies some of the unused
@@ -1343,8 +1357,15 @@ def fromtarfile(cls, tarfile):
13431357
"""Return the next TarInfo object from TarFile object
13441358
tarfile.
13451359
"""
1360+
return cls._fromtarfile(tarfile)
1361+
1362+
@classmethod
1363+
def _fromtarfile(cls, tarfile, *, dircheck=True):
1364+
"""
1365+
See dircheck documentation in _frombuf().
1366+
"""
13461367
buf = tarfile.fileobj.read(BLOCKSIZE)
1347-
obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors)
1368+
obj = cls._frombuf(buf, tarfile.encoding, tarfile.errors, dircheck=dircheck)
13481369
obj.offset = tarfile.fileobj.tell() - BLOCKSIZE
13491370
return obj._proc_member(tarfile)
13501371

@@ -1402,7 +1423,7 @@ def _proc_gnulong(self, tarfile):
14021423

14031424
# Fetch the next header and process it.
14041425
try:
1405-
next = self.fromtarfile(tarfile)
1426+
next = self._fromtarfile(tarfile, dircheck=False)
14061427
except HeaderError as e:
14071428
raise SubsequentHeaderError(str(e)) from None
14081429

@@ -1537,7 +1558,7 @@ def _proc_pax(self, tarfile):
15371558

15381559
# Fetch the next header.
15391560
try:
1540-
next = self.fromtarfile(tarfile)
1561+
next = self._fromtarfile(tarfile, dircheck=False)
15411562
except HeaderError as e:
15421563
raise SubsequentHeaderError(str(e)) from None
15431564

Lib/test/test_tarfile.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
import lzma
3939
except ImportError:
4040
lzma = None
41-
# XXX: RUSTPYTHON; xz is not supported yet
42-
lzma = None
4341
try:
4442
from compression import zstd
4543
except ImportError:
@@ -1236,6 +1234,25 @@ def test_longname_directory(self):
12361234
self.assertIsNotNone(tar.getmember(longdir))
12371235
self.assertIsNotNone(tar.getmember(longdir.removesuffix('/')))
12381236

1237+
def test_longname_file_not_directory(self):
1238+
# Test reading a longname file and ensure it is not handled as a directory
1239+
# Issue #141707
1240+
buf = io.BytesIO()
1241+
with tarfile.open(mode='w', fileobj=buf, format=self.format) as tar:
1242+
ti = tarfile.TarInfo()
1243+
ti.type = tarfile.AREGTYPE
1244+
ti.name = ('a' * 99) + '/' + ('b' * 3)
1245+
tar.addfile(ti)
1246+
1247+
expected = {t.name: t.type for t in tar.getmembers()}
1248+
1249+
buf.seek(0)
1250+
with tarfile.open(mode='r', fileobj=buf) as tar:
1251+
actual = {t.name: t.type for t in tar.getmembers()}
1252+
1253+
self.assertEqual(expected, actual)
1254+
1255+
12391256
class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
12401257

12411258
subdir = "gnu"

0 commit comments

Comments
 (0)