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.
This commit is contained in:
Victor Stinner 2025-07-08 18:39:47 +02:00 committed by GitHub
parent 490eea0281
commit 6c81e8c57a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 27 additions and 1 deletions

View 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:

View 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:

View file

@ -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.