Skip to content

Commit 6c81e8c

Browse files
authored
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.
1 parent 490eea0 commit 6c81e8c

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

Lib/tempfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
656656
fd = None
657657
def opener(*args):
658658
nonlocal fd
659-
flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
659+
flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT & ~_os.O_EXCL
660660
fd = _os.open(dir, flags2, 0o600)
661661
return fd
662662
try:

Lib/test/test_tempfile.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,29 @@ def test_unexpected_error(self):
15941594
mock_close.assert_called()
15951595
self.assertEqual(os.listdir(dir), [])
15961596

1597+
@unittest.skipUnless(tempfile._O_TMPFILE_WORKS, 'need os.O_TMPFILE')
1598+
@unittest.skipUnless(os.path.exists('/proc/self/fd'),
1599+
'need /proc/self/fd')
1600+
def test_link_tmpfile(self):
1601+
dir = tempfile.mkdtemp()
1602+
self.addCleanup(os_helper.rmtree, dir)
1603+
filename = os.path.join(dir, "link")
1604+
1605+
with tempfile.TemporaryFile('w', dir=dir) as tmp:
1606+
# the flag can become False on Linux <= 3.11
1607+
if not tempfile._O_TMPFILE_WORKS:
1608+
self.skipTest("O_TMPFILE doesn't work")
1609+
1610+
tmp.write("hello")
1611+
tmp.flush()
1612+
fd = tmp.fileno()
1613+
1614+
os.link(f'/proc/self/fd/{fd}',
1615+
filename,
1616+
follow_symlinks=True)
1617+
with open(filename) as fp:
1618+
self.assertEqual(fp.read(), "hello")
1619+
15971620

15981621
# Helper for test_del_on_shutdown
15991622
class NulledModules:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`tempfile.TemporaryFile` no longer uses :data:`os.O_EXCL` with
2+
:data:`os.O_TMPFILE`, so it's possible to use ``linkat()`` on the file
3+
descriptor. Patch by Victor Stinner.

0 commit comments

Comments
 (0)