mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
gh-116931: Add fileobj parameter check for Tarfile.addfile (GH-117988)
Tarfile.addfile now throws an ValueError when the user passes in a non-zero size tarinfo but does not provide a fileobj, instead of writing an incomplete entry.
This commit is contained in:
parent
3e7d990a09
commit
15b3555e4a
4 changed files with 25 additions and 9 deletions
|
@ -637,11 +637,15 @@ be finalized; only the internally used file object will be closed. See the
|
||||||
|
|
||||||
.. method:: TarFile.addfile(tarinfo, fileobj=None)
|
.. method:: TarFile.addfile(tarinfo, fileobj=None)
|
||||||
|
|
||||||
Add the :class:`TarInfo` object *tarinfo* to the archive. If *fileobj* is given,
|
Add the :class:`TarInfo` object *tarinfo* to the archive. If *tarinfo* represents
|
||||||
it should be a :term:`binary file`, and
|
a non zero-size regular file, the *fileobj* argument should be a :term:`binary file`,
|
||||||
``tarinfo.size`` bytes are read from it and added to the archive. You can
|
and ``tarinfo.size`` bytes are read from it and added to the archive. You can
|
||||||
create :class:`TarInfo` objects directly, or by using :meth:`gettarinfo`.
|
create :class:`TarInfo` objects directly, or by using :meth:`gettarinfo`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.13
|
||||||
|
|
||||||
|
*fileobj* must be given for non-zero-sized regular files.
|
||||||
|
|
||||||
|
|
||||||
.. method:: TarFile.gettarinfo(name=None, arcname=None, fileobj=None)
|
.. method:: TarFile.gettarinfo(name=None, arcname=None, fileobj=None)
|
||||||
|
|
||||||
|
|
|
@ -2214,13 +2214,16 @@ class TarFile(object):
|
||||||
self.addfile(tarinfo)
|
self.addfile(tarinfo)
|
||||||
|
|
||||||
def addfile(self, tarinfo, fileobj=None):
|
def addfile(self, tarinfo, fileobj=None):
|
||||||
"""Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
|
"""Add the TarInfo object `tarinfo' to the archive. If `tarinfo' represents
|
||||||
given, it should be a binary file, and tarinfo.size bytes are read
|
a non zero-size regular file, the `fileobj' argument should be a binary file,
|
||||||
from it and added to the archive. You can create TarInfo objects
|
and tarinfo.size bytes are read from it and added to the archive.
|
||||||
directly, or by using gettarinfo().
|
You can create TarInfo objects directly, or by using gettarinfo().
|
||||||
"""
|
"""
|
||||||
self._check("awx")
|
self._check("awx")
|
||||||
|
|
||||||
|
if fileobj is None and tarinfo.isreg() and tarinfo.size != 0:
|
||||||
|
raise ValueError("fileobj not provided for non zero-size regular file")
|
||||||
|
|
||||||
tarinfo = copy.copy(tarinfo)
|
tarinfo = copy.copy(tarinfo)
|
||||||
|
|
||||||
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
|
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
|
||||||
|
|
|
@ -1612,6 +1612,12 @@ class WriteTest(WriteTestBase, unittest.TestCase):
|
||||||
pax_headers={'non': 'empty'})
|
pax_headers={'non': 'empty'})
|
||||||
self.assertFalse(f.closed)
|
self.assertFalse(f.closed)
|
||||||
|
|
||||||
|
def test_missing_fileobj(self):
|
||||||
|
with tarfile.open(tmpname, self.mode) as tar:
|
||||||
|
tarinfo = tar.gettarinfo(tarname)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
tar.addfile(tarinfo)
|
||||||
|
|
||||||
|
|
||||||
class GzipWriteTest(GzipTest, WriteTest):
|
class GzipWriteTest(GzipTest, WriteTest):
|
||||||
pass
|
pass
|
||||||
|
@ -3283,7 +3289,8 @@ class NoneInfoTests_Misc(unittest.TestCase):
|
||||||
tar = tarfile.open(fileobj=bio, mode='w', format=tarformat)
|
tar = tarfile.open(fileobj=bio, mode='w', format=tarformat)
|
||||||
tarinfo = tar.gettarinfo(tarname)
|
tarinfo = tar.gettarinfo(tarname)
|
||||||
try:
|
try:
|
||||||
tar.addfile(tarinfo)
|
with open(tarname, 'rb') as f:
|
||||||
|
tar.addfile(tarinfo, f)
|
||||||
except Exception:
|
except Exception:
|
||||||
if tarformat == tarfile.USTAR_FORMAT:
|
if tarformat == tarfile.USTAR_FORMAT:
|
||||||
# In the old, limited format, adding might fail for
|
# In the old, limited format, adding might fail for
|
||||||
|
@ -3298,7 +3305,8 @@ class NoneInfoTests_Misc(unittest.TestCase):
|
||||||
replaced = tarinfo.replace(**{attr_name: None})
|
replaced = tarinfo.replace(**{attr_name: None})
|
||||||
with self.assertRaisesRegex(ValueError,
|
with self.assertRaisesRegex(ValueError,
|
||||||
f"{attr_name}"):
|
f"{attr_name}"):
|
||||||
tar.addfile(replaced)
|
with open(tarname, 'rb') as f:
|
||||||
|
tar.addfile(replaced, f)
|
||||||
|
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
# Change some metadata to None, then compare list() output
|
# Change some metadata to None, then compare list() output
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add parameter *fileobj* check for :func:`tarfile.addfile()`
|
Loading…
Add table
Add a link
Reference in a new issue