aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/posixpath.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2021-04-28 16:50:17 +0100
committerGitHub <noreply@github.com>2021-04-28 16:50:17 +0100
commitbaecfbd849dbf42360d3a84af6cc13160838f24d (patch)
tree5d82a6504cd2859197e1bcd81ceaecef035a6aad /Lib/posixpath.py
parent859577c24981d6b36960d309f99f7fc810fe75c2 (diff)
downloadcpython-baecfbd849dbf42360d3a84af6cc13160838f24d.tar.gz
cpython-baecfbd849dbf42360d3a84af6cc13160838f24d.zip
bpo-43757: Make pathlib use os.path.realpath() to resolve symlinks in a path (GH-25264)
Also adds a new "strict" argument to realpath() to avoid changing the default behaviour of pathlib while sharing the implementation.
Diffstat (limited to 'Lib/posixpath.py')
-rw-r--r--Lib/posixpath.py26
1 files changed, 19 insertions, 7 deletions
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index 62afbd0ccf0..259baa64b19 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -387,16 +387,16 @@ def abspath(path):
# Return a canonical path (i.e. the absolute location of a file on the
# filesystem).
-def realpath(filename):
+def realpath(filename, *, strict=False):
"""Return the canonical path of the specified filename, eliminating any
symbolic links encountered in the path."""
filename = os.fspath(filename)
- path, ok = _joinrealpath(filename[:0], filename, {})
+ path, ok = _joinrealpath(filename[:0], filename, strict, {})
return abspath(path)
# Join two paths, normalizing and eliminating any symbolic links
# encountered in the second path.
-def _joinrealpath(path, rest, seen):
+def _joinrealpath(path, rest, strict, seen):
if isinstance(path, bytes):
sep = b'/'
curdir = b'.'
@@ -425,7 +425,15 @@ def _joinrealpath(path, rest, seen):
path = pardir
continue
newpath = join(path, name)
- if not islink(newpath):
+ try:
+ st = os.lstat(newpath)
+ except OSError:
+ if strict:
+ raise
+ is_link = False
+ else:
+ is_link = stat.S_ISLNK(st.st_mode)
+ if not is_link:
path = newpath
continue
# Resolve the symbolic link
@@ -436,10 +444,14 @@ def _joinrealpath(path, rest, seen):
# use cached value
continue
# The symlink is not resolved, so we must have a symlink loop.
- # Return already resolved part + rest of the path unchanged.
- return join(newpath, rest), False
+ if strict:
+ # Raise OSError(errno.ELOOP)
+ os.stat(newpath)
+ else:
+ # Return already resolved part + rest of the path unchanged.
+ return join(newpath, rest), False
seen[newpath] = None # not resolved symlink
- path, ok = _joinrealpath(path, os.readlink(newpath), seen)
+ path, ok = _joinrealpath(path, os.readlink(newpath), strict, seen)
if not ok:
return join(path, rest), False
seen[newpath] = path # resolved symlink