]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-116931: Add fileobj parameter check for Tarfile.addfile (GH-117988)
authorlyc8503 <me@lyc8503.site>
Fri, 19 Apr 2024 11:41:51 +0000 (19:41 +0800)
committerGitHub <noreply@github.com>
Fri, 19 Apr 2024 11:41:51 +0000 (11:41 +0000)
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.

Doc/library/tarfile.rst
Lib/tarfile.py
Lib/test/test_tarfile.py
Misc/NEWS.d/next/Library/2024-04-17-21-28-24.gh-issue-116931._AS09h.rst [new file with mode: 0644]

index 2134293a0bb0de10cc1ad5ab3257083987f92fb5..afcad9bf72293417ee5467f61890edeac748dbf5 100644 (file)
@@ -637,11 +637,15 @@ be finalized; only the internally used file object will be closed. See the
 
 .. method:: TarFile.addfile(tarinfo, fileobj=None)
 
-   Add the :class:`TarInfo` object *tarinfo* to the archive. If *fileobj* is given,
-   it should be a :term:`binary file`, and
-   ``tarinfo.size`` bytes are read from it and added to the archive.  You can
+   Add the :class:`TarInfo` object *tarinfo* to the archive. If *tarinfo* represents
+   a non zero-size regular file, the *fileobj* argument should be a :term:`binary file`,
+   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`.
 
+   .. versionchanged:: 3.13
+
+      *fileobj* must be given for non-zero-sized regular files.
+
 
 .. method:: TarFile.gettarinfo(name=None, arcname=None, fileobj=None)
 
index 149b1c3b1bda28567735d3f6f90ed0cb2bd47711..78bb10c80820d71084786bab4e746c7a2375953e 100755 (executable)
@@ -2214,13 +2214,16 @@ class TarFile(object):
             self.addfile(tarinfo)
 
     def addfile(self, tarinfo, fileobj=None):
-        """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
-           given, it should be a binary file, and tarinfo.size bytes are read
-           from it and added to the archive. You can create TarInfo objects
-           directly, or by using gettarinfo().
+        """Add the TarInfo object `tarinfo' to the archive. If `tarinfo' represents
+           a non zero-size regular file, the `fileobj' argument should be a binary file,
+           and tarinfo.size bytes are read from it and added to the archive.
+           You can create TarInfo objects directly, or by using gettarinfo().
         """
         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)
 
         buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
index f18dcc02b23856fb14fbf64b2f849db62c460fe2..c2abc7ef9698fb80beb6575666a8a3a4cd397ebc 100644 (file)
@@ -1612,6 +1612,12 @@ class WriteTest(WriteTestBase, unittest.TestCase):
                                    pax_headers={'non': 'empty'})
             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):
     pass
@@ -3283,7 +3289,8 @@ class NoneInfoTests_Misc(unittest.TestCase):
                 tar = tarfile.open(fileobj=bio, mode='w', format=tarformat)
                 tarinfo = tar.gettarinfo(tarname)
                 try:
-                    tar.addfile(tarinfo)
+                    with open(tarname, 'rb') as f:
+                        tar.addfile(tarinfo, f)
                 except Exception:
                     if tarformat == tarfile.USTAR_FORMAT:
                         # In the old, limited format, adding might fail for
@@ -3298,7 +3305,8 @@ class NoneInfoTests_Misc(unittest.TestCase):
                             replaced = tarinfo.replace(**{attr_name: None})
                             with self.assertRaisesRegex(ValueError,
                                                         f"{attr_name}"):
-                                tar.addfile(replaced)
+                                with open(tarname, 'rb') as f:
+                                    tar.addfile(replaced, f)
 
     def test_list(self):
         # Change some metadata to None, then compare list() output
diff --git a/Misc/NEWS.d/next/Library/2024-04-17-21-28-24.gh-issue-116931._AS09h.rst b/Misc/NEWS.d/next/Library/2024-04-17-21-28-24.gh-issue-116931._AS09h.rst
new file mode 100644 (file)
index 0000000..98df8f5
--- /dev/null
@@ -0,0 +1 @@
+Add parameter *fileobj* check for :func:`tarfile.addfile()`