mirror of https://github.com/python/cpython
Merge with 3.5: Issue #24259: tarfile now raises a ReadError if an archive is truncated inside a data segment.
This commit is contained in:
commit
7afe40e40e
|
@ -225,7 +225,7 @@ def calc_chksums(buf):
|
||||||
signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf))
|
signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf))
|
||||||
return unsigned_chksum, signed_chksum
|
return unsigned_chksum, signed_chksum
|
||||||
|
|
||||||
def copyfileobj(src, dst, length=None):
|
def copyfileobj(src, dst, length=None, exception=OSError):
|
||||||
"""Copy length bytes from fileobj src to fileobj dst.
|
"""Copy length bytes from fileobj src to fileobj dst.
|
||||||
If length is None, copy the entire content.
|
If length is None, copy the entire content.
|
||||||
"""
|
"""
|
||||||
|
@ -240,13 +240,13 @@ def copyfileobj(src, dst, length=None):
|
||||||
for b in range(blocks):
|
for b in range(blocks):
|
||||||
buf = src.read(BUFSIZE)
|
buf = src.read(BUFSIZE)
|
||||||
if len(buf) < BUFSIZE:
|
if len(buf) < BUFSIZE:
|
||||||
raise OSError("end of file reached")
|
raise exception("unexpected end of data")
|
||||||
dst.write(buf)
|
dst.write(buf)
|
||||||
|
|
||||||
if remainder != 0:
|
if remainder != 0:
|
||||||
buf = src.read(remainder)
|
buf = src.read(remainder)
|
||||||
if len(buf) < remainder:
|
if len(buf) < remainder:
|
||||||
raise OSError("end of file reached")
|
raise exception("unexpected end of data")
|
||||||
dst.write(buf)
|
dst.write(buf)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -690,7 +690,10 @@ class _FileInFile(object):
|
||||||
length = min(size, stop - self.position)
|
length = min(size, stop - self.position)
|
||||||
if data:
|
if data:
|
||||||
self.fileobj.seek(offset + (self.position - start))
|
self.fileobj.seek(offset + (self.position - start))
|
||||||
buf += self.fileobj.read(length)
|
b = self.fileobj.read(length)
|
||||||
|
if len(b) != length:
|
||||||
|
raise ReadError("unexpected end of data")
|
||||||
|
buf += b
|
||||||
else:
|
else:
|
||||||
buf += NUL * length
|
buf += NUL * length
|
||||||
size -= length
|
size -= length
|
||||||
|
@ -2150,9 +2153,9 @@ class TarFile(object):
|
||||||
if tarinfo.sparse is not None:
|
if tarinfo.sparse is not None:
|
||||||
for offset, size in tarinfo.sparse:
|
for offset, size in tarinfo.sparse:
|
||||||
target.seek(offset)
|
target.seek(offset)
|
||||||
copyfileobj(source, target, size)
|
copyfileobj(source, target, size, ReadError)
|
||||||
else:
|
else:
|
||||||
copyfileobj(source, target, tarinfo.size)
|
copyfileobj(source, target, tarinfo.size, ReadError)
|
||||||
target.seek(tarinfo.size)
|
target.seek(tarinfo.size)
|
||||||
target.truncate()
|
target.truncate()
|
||||||
|
|
||||||
|
@ -2267,8 +2270,13 @@ class TarFile(object):
|
||||||
self.firstmember = None
|
self.firstmember = None
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
# Advance the file pointer.
|
||||||
|
if self.offset != self.fileobj.tell():
|
||||||
|
self.fileobj.seek(self.offset - 1)
|
||||||
|
if not self.fileobj.read(1):
|
||||||
|
raise ReadError("unexpected end of data")
|
||||||
|
|
||||||
# Read the next block.
|
# Read the next block.
|
||||||
self.fileobj.seek(self.offset)
|
|
||||||
tarinfo = None
|
tarinfo = None
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -364,6 +364,29 @@ class CommonReadTest(ReadTest):
|
||||||
finally:
|
finally:
|
||||||
tar.close()
|
tar.close()
|
||||||
|
|
||||||
|
def test_premature_end_of_archive(self):
|
||||||
|
for size in (512, 600, 1024, 1200):
|
||||||
|
with tarfile.open(tmpname, "w:") as tar:
|
||||||
|
t = tarfile.TarInfo("foo")
|
||||||
|
t.size = 1024
|
||||||
|
tar.addfile(t, io.BytesIO(b"a" * 1024))
|
||||||
|
|
||||||
|
with open(tmpname, "r+b") as fobj:
|
||||||
|
fobj.truncate(size)
|
||||||
|
|
||||||
|
with tarfile.open(tmpname) as tar:
|
||||||
|
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
|
||||||
|
for t in tar:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with tarfile.open(tmpname) as tar:
|
||||||
|
t = tar.next()
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
|
||||||
|
tar.extract(t, TEMPDIR)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
|
||||||
|
tar.extractfile(t).read()
|
||||||
|
|
||||||
class MiscReadTestBase(CommonReadTest):
|
class MiscReadTestBase(CommonReadTest):
|
||||||
def requires_name_attribute(self):
|
def requires_name_attribute(self):
|
||||||
|
|
|
@ -33,6 +33,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #24259: tarfile now raises a ReadError if an archive is truncated
|
||||||
|
inside a data segment.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.5.0 beta 3?
|
What's New in Python 3.5.0 beta 3?
|
||||||
==================================
|
==================================
|
||||||
|
|
Loading…
Reference in New Issue