]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-136156: Allow using linkat() with TemporaryFile (#136281)
authorVictor Stinner <vstinner@python.org>
Tue, 8 Jul 2025 16:39:47 +0000 (18:39 +0200)
committerGitHub <noreply@github.com>
Tue, 8 Jul 2025 16:39:47 +0000 (18:39 +0200)
tempfile.TemporaryFile() no longer uses os.O_EXCL with os.O_TMPFILE,
so it's possible to use linkat() on the file descriptor.

Lib/tempfile.py
Lib/test/test_tempfile.py
Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst [new file with mode: 0644]

index 5e3ccab5f48502b3fb51961c5106a7b13b4ed151..53d14ff5c67131c4deaab7700323bc099b286981 100644 (file)
@@ -656,7 +656,7 @@ else:
             fd = None
             def opener(*args):
                 nonlocal fd
-                flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
+                flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT & ~_os.O_EXCL
                 fd = _os.open(dir, flags2, 0o600)
                 return fd
             try:
index 52b13b98cbcce5cd14afbf8b14e8e51ac0f4d599..36151b016ea35bf5402634020bdffc9d7dce954c 100644 (file)
@@ -1594,6 +1594,29 @@ if tempfile.NamedTemporaryFile is not tempfile.TemporaryFile:
             mock_close.assert_called()
             self.assertEqual(os.listdir(dir), [])
 
+        @unittest.skipUnless(tempfile._O_TMPFILE_WORKS, 'need os.O_TMPFILE')
+        @unittest.skipUnless(os.path.exists('/proc/self/fd'),
+                             'need /proc/self/fd')
+        def test_link_tmpfile(self):
+            dir = tempfile.mkdtemp()
+            self.addCleanup(os_helper.rmtree, dir)
+            filename = os.path.join(dir, "link")
+
+            with tempfile.TemporaryFile('w', dir=dir) as tmp:
+                # the flag can become False on Linux <= 3.11
+                if not tempfile._O_TMPFILE_WORKS:
+                    self.skipTest("O_TMPFILE doesn't work")
+
+                tmp.write("hello")
+                tmp.flush()
+                fd = tmp.fileno()
+
+                os.link(f'/proc/self/fd/{fd}',
+                        filename,
+                        follow_symlinks=True)
+                with open(filename) as fp:
+                    self.assertEqual(fp.read(), "hello")
+
 
 # Helper for test_del_on_shutdown
 class NulledModules:
diff --git a/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst b/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst
new file mode 100644 (file)
index 0000000..9560679
--- /dev/null
@@ -0,0 +1,3 @@
+:func:`tempfile.TemporaryFile` no longer uses :data:`os.O_EXCL` with
+:data:`os.O_TMPFILE`, so it's possible to use ``linkat()`` on the file
+descriptor. Patch by Victor Stinner.