Skip to content

Commit 0a86a34

Browse files
gh-150075: tar.addfile() now sets member offsets in active TarInfo (GH-150278)
The on-disk data was correct, but the in-memory TarInfo was not being properly updated. --------- Signed-off-by: grantlouisherman <grantlouisherman041@gmail.com> Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
1 parent ba96fab commit 0a86a34

3 files changed

Lines changed: 28 additions & 1 deletion

File tree

‎Lib/tarfile.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2456,11 +2456,14 @@ def addfile(self, tarinfo, fileobj=None):
24562456
raise ValueError("fileobj not provided for non zero-size regular file")
24572457

24582458
tarinfo = copy.copy(tarinfo)
2459-
2459+
# get current offset
2460+
tarinfo.offset = self.offset
24602461
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
24612462
self.fileobj.write(buf)
24622463
self.offset += len(buf)
2464+
# add original offset to block size
24632465
bufsize=self.copybufsize
2466+
tarinfo.offset_data = self.offset
24642467
# If there's data to follow, append it.
24652468
if fileobj is not None:
24662469
copyfileobj(fileobj, self.fileobj, tarinfo.size, bufsize=bufsize)

‎Lib/test/test_tarfile.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,29 @@ class WriteTest(WriteTestBase, unittest.TestCase):
17001700

17011701
prefix = "w:"
17021702

1703+
def test_addfile_sets_offsets(self):
1704+
# gh-150075: addfile() must set offset and offset_data on the
1705+
# TarInfo stored in the archive so they match a subsequent read.
1706+
data = b"data"
1707+
1708+
with tarfile.open(tmpname, self.mode) as tar:
1709+
t1 = tarfile.TarInfo("test1.txt")
1710+
t1.size = len(data)
1711+
tar.addfile(t1, io.BytesIO(data))
1712+
1713+
t2 = tarfile.TarInfo("test2.txt")
1714+
t2.size = len(data)
1715+
tar.addfile(t2, io.BytesIO(data))
1716+
1717+
write_members = tar.getmembers()
1718+
1719+
with tarfile.open(tmpname) as tar:
1720+
read_members = tar.getmembers()
1721+
1722+
for w, r in zip(write_members, read_members):
1723+
self.assertEqual(w.offset, r.offset)
1724+
self.assertEqual(w.offset_data, r.offset_data)
1725+
17031726
def test_100_char_name(self):
17041727
# The name field in a tar header stores strings of at most 100 chars.
17051728
# If a string is shorter than 100 chars it has to be padded with '\0',
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tar.addfile() now sets member offsets in TarInfo objects

0 commit comments

Comments
 (0)