SF #846659, fix bufsize violation and GNU longname/longlink extensions
This commit is contained in:
parent
13e50fe453
commit
0662f8a5ea
|
@ -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):
|
||||||
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):
|
||||||
|
|
||||||
# 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):
|
||||||
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():
|
||||||
ReadTest,
|
ReadTest,
|
||||||
ReadStreamTest,
|
ReadStreamTest,
|
||||||
WriteTest,
|
WriteTest,
|
||||||
WriteStreamTest
|
WriteStreamTest,
|
||||||
|
WriteGNULongTest,
|
||||||
]
|
]
|
||||||
|
|
||||||
if gzip:
|
if gzip:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue