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
8 changes: 8 additions & 0 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,14 @@ def _proc_pax(self, tarfile):
# Fetch the next header.
try:
next = self._fromtarfile(tarfile, dircheck=False)
except EOFHeaderError:
if self.type == XGLTYPE:
# If this is a global header at the end of the archive
# (no regular members follow), let the EOFHeaderError
# propagate so the caller handles end-of-archive normally.
tarfile.offset = tarfile.fileobj.tell() - BLOCKSIZE
raise
raise SubsequentHeaderError("end of file header") from None
except HeaderError as e:
raise SubsequentHeaderError(str(e)) from None

Expand Down
29 changes: 29 additions & 0 deletions Lib/test/test_tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,35 @@ def test_pax_global_header(self):
finally:
tar.close()

def test_pax_global_header_empty_archive(self):
# An archive that contains only a global header and no regular
# members should be opened successfully (gh-149578).
pax_headers = {"foo": "bar"}

# Create a PAX archive with global headers but no file entries.
with tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
pax_headers=pax_headers):
pass

# Reading the archive should work and preserve global headers.
with tarfile.open(tmpname) as tar:
self.assertEqual(tar.pax_headers, pax_headers)
self.assertEqual(tar.getmembers(), [])

# Appending to the archive should work.
with tarfile.open(tmpname, "a") as tar:
self.assertEqual(tar.pax_headers, pax_headers)
self.assertEqual(tar.getmembers(), [])
tar.addfile(tarfile.TarInfo("test"))

# Verify the appended member is present and global headers
# are preserved.
with tarfile.open(tmpname) as tar:
self.assertEqual(tar.pax_headers, pax_headers)
members = tar.getmembers()
self.assertEqual(len(members), 1)
self.assertEqual(members[0].name, "test")

def test_pax_extended_header(self):
# The fields from the pax header have priority over the
# TarInfo.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :func:`tarfile.open` failing with :exc:`~tarfile.ReadError` when
opening a PAX format tar archive that contains only global headers and
no regular members.
Loading