Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-114545: [Lib/tempfile.py] mkdtemp - canonicalise directory name #114691

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/multiprocessing/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def get_temp_dir():
tempdir = process.current_process()._config.get('tempdir')
if tempdir is None:
import shutil, tempfile
tempdir = tempfile.mkdtemp(prefix='pymp-')
tempdir = tempfile.mkdtemp(prefix='pymp-', run_realpath=False)
info('created temp directory %s', tempdir)
# keep a strong reference to shutil.rmtree(), since the finalizer
# can be called late during Python shutdown
Expand Down
36 changes: 21 additions & 15 deletions Lib/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,11 @@ def _get_candidate_names():
return _name_sequence


def _mkstemp_inner(dir, pre, suf, flags, output_type):
def _mkstemp_inner(dir, pre, suf, flags, output_type, run_realpath=True):
"""Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""

dir = _os.path.abspath(dir)
dir = getattr(_os.path,
"realpath" if run_realpath else "abspath")(dir)
names = _get_candidate_names()
if output_type is bytes:
names = map(_os.fsencode, names)
Expand Down Expand Up @@ -312,13 +313,13 @@ def _gettempdir():

def gettempdir():
"""Returns tempfile.tempdir as str."""
return _os.fsdecode(_gettempdir())
return _os.path.realpath(_os.fsdecode(_gettempdir()))

def gettempdirb():
"""Returns tempfile.tempdir as bytes."""
return _os.fsencode(_gettempdir())
return _os.path.realpath(_os.fsencode(_gettempdir()))

def mkstemp(suffix=None, prefix=None, dir=None, text=False):
def mkstemp(suffix=None, prefix=None, dir=None, text=False, run_realpath=True):
"""User-callable function to create and return a unique temporary
file. The return value is a pair (fd, name) where fd is the
file descriptor returned by os.open, and name is the filename.
Expand All @@ -339,6 +340,9 @@ def mkstemp(suffix=None, prefix=None, dir=None, text=False):
same type. If they are bytes, the returned name will be bytes; str
otherwise.

If 'run_realpath' is true, `os.path.realpath` is run on the path.
Otherwise, only `os.path.abspath` is run.

The file is readable and writable only by the creating user ID.
If the operating system uses permission bits to indicate whether a
file is executable, the file is executable by no one. The file
Expand All @@ -354,10 +358,10 @@ def mkstemp(suffix=None, prefix=None, dir=None, text=False):
else:
flags = _bin_openflags

return _mkstemp_inner(dir, prefix, suffix, flags, output_type)
return _mkstemp_inner(dir, prefix, suffix, flags, output_type, run_realpath)


def mkdtemp(suffix=None, prefix=None, dir=None):
def mkdtemp(suffix=None, prefix=None, dir=None, run_realpath=True):
"""User-callable function to create and return a unique temporary
directory. The return value is the pathname of the directory.

Expand All @@ -370,15 +374,15 @@ def mkdtemp(suffix=None, prefix=None, dir=None):
Caller is responsible for deleting the directory when done with it.
"""

prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
prefix, suffix, path, output_type = _sanitize_params(prefix, suffix, path)

names = _get_candidate_names()
if output_type is bytes:
names = map(_os.fsencode, names)

for seq in range(TMP_MAX):
name = next(names)
file = _os.path.join(dir, prefix + name + suffix)
file = _os.path.join(path, prefix + name + suffix)
_sys.audit("tempfile.mkdtemp", file)
try:
_os.mkdir(file, 0o700)
Expand All @@ -387,12 +391,12 @@ def mkdtemp(suffix=None, prefix=None, dir=None):
except PermissionError:
# This exception is thrown when a directory with the chosen name
# already exists on windows.
if (_os.name == 'nt' and _os.path.isdir(dir) and
_os.access(dir, _os.W_OK)):
if (_os.name == 'nt' and _os.path.isdir(path) and
_os.access(path, _os.W_OK)):
continue
else:
raise
return _os.path.abspath(file)
return getattr(_os.path, "realpath" if run_realpath else "abspath")(file)

raise FileExistsError(_errno.EEXIST,
"No usable temporary directory name found")
Expand Down Expand Up @@ -537,7 +541,7 @@ def __iter__(self):
def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
newline=None, suffix=None, prefix=None,
dir=None, delete=True, *, errors=None,
delete_on_close=True):
delete_on_close=True, run_realpath=True):
"""Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
Expand Down Expand Up @@ -576,7 +580,8 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
name = None
def opener(*args):
nonlocal name
fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
fd, name = _mkstemp_inner(
dir, prefix, suffix, flags, output_type, run_realpath)
return fd
try:
file = _io.open(dir, mode, buffering=buffering,
Expand Down Expand Up @@ -667,7 +672,8 @@ def opener(*args):
fd = None
def opener(*args):
nonlocal fd
fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
fd, name = _mkstemp_inner(dir, prefix, suffix, flags,
output_type, run_realpath)
try:
_os.unlink(name)
except BaseException as e:
Expand Down
7 changes: 7 additions & 0 deletions Lib/test/test_tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,13 @@ def test_path_is_absolute(self):
finally:
os.rmdir(path)

def test_path_is_realpath(self):
try:
path = tempfile.mkdtemp()
self.assertEqual(os.path.realpath(path), path)
finally:
os.rmdir(path)


class TestMktemp(BaseTestCase):
"""Test mktemp()."""
Expand Down
Loading