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
20 changes: 13 additions & 7 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1710,23 +1710,29 @@ def _apply_pax_info(self, pax_headers, encoding, errors):
"""Replace fields with supplemental information from a previous
pax extended or global header.
"""
keyword_to_remove = []
for keyword, value in pax_headers.items():
if keyword == "GNU.sparse.name":
if keyword in ("GNU.sparse.name", "path"):
value = value.rstrip("/")
setattr(self, "path", value)
elif keyword == "GNU.sparse.size":
setattr(self, "size", int(value))
elif keyword == "GNU.sparse.realsize":
setattr(self, "size", int(value))
elif keyword in ("GNU.sparse.size", "GNU.sparse.realsize", "size"):
try:
value = int(value)
except ValueError:
keyword_to_remove.append(keyword)
else:
setattr(self, "size", value)
elif keyword in PAX_FIELDS:
if keyword in PAX_NUMBER_FIELDS:
try:
value = PAX_NUMBER_FIELDS[keyword](value)
except ValueError:
value = 0
if keyword == "path":
value = value.rstrip("/")
setattr(self, keyword, value)

for k in keyword_to_remove:
pax_headers.pop(k)

self.pax_headers = pax_headers.copy()

def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors):
Expand Down
26 changes: 26 additions & 0 deletions Lib/test/test_tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2759,6 +2759,32 @@ def test_pax_extended_header(self):
finally:
tar.close()

def test_invalid_size_pax_extended_header(self):
# When the value of the keyword 'size' is invalid, it should be
# ignored and proceeds to extract all the records instead of
# setting size to 0 and producing a single empty extracted file
t1sz = 89
t2sz = 64
with tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
pax_headers={"size": "xyz"},
encoding="iso8859-1") as tar:
t1 = tarfile.TarInfo()
t1.name = "foo"
t1.size = t1sz
tar.addfile(t1, io.BytesIO(b"a"*t1sz))

t2 = tarfile.TarInfo()
t2.name = "bar"
t2.size = t2sz
tar.addfile(t2, io.BytesIO(b"z"*t2sz))

t1_path = os.path.join(TEMPDIR, "foo")
t2_path = os.path.join(TEMPDIR, "bar")
with tarfile.open(tmpname, encoding="iso8859-1") as tar:
tar.extractall(path=TEMPDIR)
self.assertEqual(os.path.getsize(t1_path), t1sz)
self.assertEqual(os.path.getsize(t2_path), t2sz)

def test_create_pax_header(self):
# The ustar header should contain values that can be
# represented reasonably, even if a better (e.g. higher
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow complete extraction of all records in a tar archive when the PAX
header 'size' is invalid in :mod:`tarfile`.
Loading