https://github.com/python/cpython/commit/6c81e8c57a1d291863c6beaa42392a7f1cf52854
commit: 6c81e8c57a1d291863c6beaa42392a7f1cf52854
branch: main
author: Victor Stinner <vstin...@python.org>
committer: vstinner <vstin...@python.org>
date: 2025-07-08T18:39:47+02:00
summary:

gh-136156: Allow using linkat() with TemporaryFile (#136281)

tempfile.TemporaryFile() no longer uses os.O_EXCL with os.O_TMPFILE,
so it's possible to use linkat() on the file descriptor.

files:
A Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst
M Lib/tempfile.py
M Lib/test/test_tempfile.py

diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 5e3ccab5f48502..53d14ff5c67131 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -656,7 +656,7 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
             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:
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 52b13b98cbcce5..36151b016ea35b 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -1594,6 +1594,29 @@ def test_unexpected_error(self):
             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
index 00000000000000..95606790e991a4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst
@@ -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.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to