diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/tarfile.py | 4 | ||||
-rw-r--r-- | Lib/test/test_tarfile.py | 91 |
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: |