Commit 0662f8a5 authored by Neal Norwitz's avatar Neal Norwitz

SF #846659, fix bufsize violation and GNU longname/longlink extensions

parent 13e50fe4
...@@ -353,7 +353,6 @@ class _Stream: ...@@ -353,7 +353,6 @@ class _Stream:
if self.mode == "w" and self.buf: if self.mode == "w" and self.buf:
if self.type != "tar": if self.type != "tar":
self.buf += self.cmp.flush() self.buf += self.cmp.flush()
self.__write("") # Write remaining blocks to output
self.fileobj.write(self.buf) self.fileobj.write(self.buf)
self.buf = "" self.buf = ""
if self.type == "gz": if self.type == "gz":
...@@ -1775,6 +1774,8 @@ class TarFile(object): ...@@ -1775,6 +1774,8 @@ class TarFile(object):
of the longname as size, followed by data blocks, of the longname as size, followed by data blocks,
which contain the longname as a null terminated string. which contain the longname as a null terminated string.
""" """
name += NUL
tarinfo = TarInfo() tarinfo = TarInfo()
tarinfo.name = "././@LongLink" tarinfo.name = "././@LongLink"
tarinfo.type = type tarinfo.type = type
...@@ -1783,6 +1784,7 @@ class TarFile(object): ...@@ -1783,6 +1784,7 @@ class TarFile(object):
# write extended header # write extended header
self.fileobj.write(tarinfo.tobuf()) self.fileobj.write(tarinfo.tobuf())
self.offset += BLOCKSIZE
# write name blocks # write name blocks
self.fileobj.write(name) self.fileobj.write(name)
blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) blocks, remainder = divmod(tarinfo.size, BLOCKSIZE)
......
...@@ -205,6 +205,94 @@ class WriteTest(BaseTest): ...@@ -205,6 +205,94 @@ class WriteTest(BaseTest):
class WriteStreamTest(WriteTest): class WriteStreamTest(WriteTest):
sep = '|' 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 # Gzip TestCases
class ReadTestGzip(ReadTest): class ReadTestGzip(ReadTest):
comp = "gz" comp = "gz"
...@@ -245,7 +333,8 @@ def test_main(): ...@@ -245,7 +333,8 @@ def test_main():
ReadTest, ReadTest,
ReadStreamTest, ReadStreamTest,
WriteTest, WriteTest,
WriteStreamTest WriteStreamTest,
WriteGNULongTest,
] ]
if gzip: if gzip:
......
...@@ -39,6 +39,9 @@ Extension modules ...@@ -39,6 +39,9 @@ Extension modules
Library Library
------- -------
- Patch #846659. Fix an error in tarfile.py when using
GNU longname/longlink creation.
- The obsolete FCNTL.py has been deleted. The builtin fcntl module - The obsolete FCNTL.py has been deleted. The builtin fcntl module
has been available (on platforms that support fcntl) since Python has been available (on platforms that support fcntl) since Python
1.5a3, and all FCNTL.py did is export fcntl's names, after generating 1.5a3, and all FCNTL.py did is export fcntl's names, after generating
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment