Skip to content

Commit e3d43fd

Browse files
Keep the offset of a member which follows a global header
_proc_pax() handles the global extended header too, so setting the offset of the next member unconditionally made it the offset of the global header instead of its own. It only has to be set after the offset of the next header is computed.
1 parent 1ba542d commit e3d43fd

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

Lib/tarfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,7 @@ def _proc_pax(self, tarfile):
16251625
offset += next._block(size)
16261626
tarfile.offset = offset
16271627

1628-
next.offset = self.offset
1628+
next.offset = self.offset
16291629

16301630
return next
16311631

Lib/test/test_tarfile.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,31 @@ def test_pax_global_headers(self):
15031503
finally:
15041504
tar.close()
15051505

1506+
def test_offset_after_global_header(self):
1507+
# gh-83869: a global header is a member of its own, the member which
1508+
# follows it keeps the offset of its own header.
1509+
rec = b"30 comment=global header here\n"
1510+
glob = tarfile.TarInfo("././@PaxHeader")
1511+
glob.type = tarfile.XGLTYPE
1512+
glob.size = len(rec)
1513+
buf = glob.tobuf(tarfile.USTAR_FORMAT)
1514+
buf += rec + b"\0" * (-len(rec) % tarfile.BLOCKSIZE)
1515+
1516+
member = tarfile.TarInfo("member")
1517+
data = b"hello\n"
1518+
member.size = len(data)
1519+
offset = len(buf)
1520+
buf += member.tobuf(tarfile.USTAR_FORMAT)
1521+
buf += data + b"\0" * (-len(data) % tarfile.BLOCKSIZE)
1522+
buf += b"\0" * (tarfile.BLOCKSIZE * 2)
1523+
1524+
with tarfile.open(fileobj=io.BytesIO(buf)) as tar:
1525+
tarinfo = tar.getmember("member")
1526+
self.assertEqual(tarinfo.offset, offset)
1527+
self.assertEqual(tarinfo.pax_headers.get("comment"),
1528+
"global header here")
1529+
self.assertEqual(tar.extractfile(tarinfo).read(), data)
1530+
15061531
def test_pax_number_fields(self):
15071532
# All following number fields are read from the pax header.
15081533
tar = tarfile.open(tarname, encoding="iso8859-1")

0 commit comments

Comments
 (0)