Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,7 @@ def _frombuf(cls, buf, encoding, errors, *, dircheck=True):
obj.gname = nts(buf[297:329], encoding, errors)
obj.devmajor = nti(buf[329:337])
obj.devminor = nti(buf[337:345])
magic = buf[257:265]
prefix = nts(buf[345:500], encoding, errors)

# Old V7 tar format represents a directory as a regular
Expand Down Expand Up @@ -1382,8 +1383,12 @@ def _frombuf(cls, buf, encoding, errors, *, dircheck=True):
if obj.isdir():
obj.name = obj.name.rstrip("/")

# Reconstruct a ustar longname.
if prefix and obj.type not in GNU_TYPES:
# Reconstruct a ustar longname. The prefix field is only defined
# by the ustar format; in the GNU and star formats this byte range
# is used for other data (e.g. atime and ctime), so it must not be
# interpreted as a path prefix unless the header magic identifies
# a ustar header.
if prefix and magic == POSIX_MAGIC and obj.type not in GNU_TYPES:
obj.name = prefix + "/" + obj.name
return obj

Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,20 @@ def test_gnulong_dirname_strips_all_trailing_slashes(self):

self.assertEqual(names, ["b" * 20, "a" * 120])

def test_gnu_atime_not_used_as_ustar_prefix(self):
# gh-155629: in an old-GNU header, bytes 345:357 hold the member's
# atime rather than a ustar path prefix. The atime must not be
# prepended to the member name.
member = tarfile.TarInfo("victim")
header = bytearray(member.tobuf(format=tarfile.GNU_FORMAT))
header[345:357] = b"00000000001\0"
header[148:156] = b" " * 8
header[148:156] = f"{sum(header):06o}\0 ".encode("ascii")

buf = io.BytesIO(bytes(header) + b"\0" * 1024)
with tarfile.open(fileobj=buf, mode="r:") as tar:
self.assertEqual(tar.getnames(), ["victim"])


class PaxReadTest(LongnameTest, ReadTest, unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
When reading a GNU-format archive, the member's atime, which is stored
in the byte range that the ustar format uses for the path prefix, is no
longer mistaken for a ustar path prefix and prepended to the member
name.
Loading