summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/tarfile.py4
-rw-r--r--Lib/test/test_tarfile.py91
2 files changed, 93 insertions, 2 deletions
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 41257f1..d20107e 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -353,7 +353,6 @@ class _Stream:
if self.mode == "w" and self.buf:
if self.type != "tar":
self.buf += self.cmp.flush()
- self.__write("") # Write remaining blocks to output
self.fileobj.write(self.buf)
self.buf = ""
if self.type == "gz":
@@ -1775,6 +1774,8 @@ class TarFile(object):
of the longname as size, followed by data blocks,
which contain the longname as a null terminated string.
"""
+ name += NUL
+
tarinfo = TarInfo()
tarinfo.name = "././@LongLink"
tarinfo.type = type
@@ -1783,6 +1784,7 @@ class TarFile(object):
# write extended header
self.fileobj.write(tarinfo.tobuf())
+ self.offset += BLOCKSIZE
# write name blocks
self.fileobj.write(name)
blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 9d40ace..bd3fd8e 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -205,6 +205,94 @@ class WriteTest(BaseTest):
class WriteStreamTest(WriteTest):
sep = '|'
+class WriteGNULongTest(unittest.TestCase):
+ """This testcase checks for correct creation of GNU Longname
+ and Longlink extensions.
+
+ It creates a tarfile and adds empty members with either
+ long names, long linknames or both and compares the size
+ of the tarfile with the expected size.
+
+ It checks for SF bug #812325 in TarFile._create_gnulong().
+
+ While I was writing this testcase, I noticed a second bug
+ in the same method:
+ Long{names,links} weren't null-terminated which lead to
+ bad tarfiles when their length was a multiple of 512. This
+ is tested as well.
+ """
+
+ def setUp(self):
+ self.tar = tarfile.open(tmpname(), "w")
+ self.tar.posix = False
+
+ def tearDown(self):
+ self.tar.close()
+
+ def _length(self, s):
+ blocks, remainder = divmod(len(s) + 1, 512)
+ if remainder:
+ blocks += 1
+ return blocks * 512
+
+ def _calc_size(self, name, link=None):
+ # initial tar header
+ count = 512
+
+ if len(name) > tarfile.LENGTH_NAME:
+ # gnu longname extended header + longname
+ count += 512
+ count += self._length(name)
+
+ if link is not None and len(link) > tarfile.LENGTH_LINK:
+ # gnu longlink extended header + longlink
+ count += 512
+ count += self._length(link)
+
+ return count
+
+ def _test(self, name, link=None):
+ tarinfo = tarfile.TarInfo(name)
+ if link:
+ tarinfo.linkname = link
+ tarinfo.type = tarfile.LNKTYPE
+
+ self.tar.addfile(tarinfo)
+
+ v1 = self._calc_size(name, link)
+ v2 = self.tar.offset
+ self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
+
+ def test_longname_1023(self):
+ self._test(("longnam/" * 127) + "longnam")
+
+ def test_longname_1024(self):
+ self._test(("longnam/" * 127) + "longname")
+
+ def test_longname_1025(self):
+ self._test(("longnam/" * 127) + "longname_")
+
+ def test_longlink_1023(self):
+ self._test("name", ("longlnk/" * 127) + "longlnk")
+
+ def test_longlink_1024(self):
+ self._test("name", ("longlnk/" * 127) + "longlink")
+
+ def test_longlink_1025(self):
+ self._test("name", ("longlnk/" * 127) + "longlink_")
+
+ def test_longnamelink_1023(self):
+ self._test(("longnam/" * 127) + "longnam",
+ ("longlnk/" * 127) + "longlnk")
+
+ def test_longnamelink_1024(self):
+ self._test(("longnam/" * 127) + "longname",
+ ("longlnk/" * 127) + "longlink")
+
+ def test_longnamelink_1025(self):
+ self._test(("longnam/" * 127) + "longname_",
+ ("longlnk/" * 127) + "longlink_")
+
# Gzip TestCases
class ReadTestGzip(ReadTest):
comp = "gz"
@@ -245,7 +333,8 @@ def test_main():
ReadTest,
ReadStreamTest,
WriteTest,
- WriteStreamTest
+ WriteStreamTest,
+ WriteGNULongTest,
]
if gzip: