mirror of
https://github.com/python/cpython.git
synced 2025-08-27 12:16:04 +00:00
pathlib ABCs: remove duplicate realpath()
implementation. (#119178)
Add private `posixpath._realpath()` function, which is a generic version of `realpath()` that can be parameterised with string tokens (`sep`, `curdir`, `pardir`) and query functions (`getcwd`, `lstat`, `readlink`). Also add support for limiting the number of symlink traversals. In the private `pathlib._abc.PathBase` class, call `posixpath._realpath()` and remove our re-implementation of the same algorithm. No change to any public APIs, either in `posixpath` or `pathlib`. Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
This commit is contained in:
parent
14e3c7071b
commit
e83ce850f4
2 changed files with 56 additions and 69 deletions
|
@ -22,6 +22,7 @@ defpath = '/bin:/usr/bin'
|
|||
altsep = None
|
||||
devnull = '/dev/null'
|
||||
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
|
@ -401,7 +402,10 @@ symbolic links encountered in the path."""
|
|||
curdir = '.'
|
||||
pardir = '..'
|
||||
getcwd = os.getcwd
|
||||
return _realpath(filename, strict, sep, curdir, pardir, getcwd)
|
||||
|
||||
def _realpath(filename, strict=False, sep=sep, curdir=curdir, pardir=pardir,
|
||||
getcwd=os.getcwd, lstat=os.lstat, readlink=os.readlink, maxlinks=None):
|
||||
# The stack of unresolved path parts. When popped, a special value of None
|
||||
# indicates that a symlink target has been resolved, and that the original
|
||||
# symlink path can be retrieved by popping again. The [::-1] slice is a
|
||||
|
@ -418,6 +422,10 @@ symbolic links encountered in the path."""
|
|||
# the same links.
|
||||
seen = {}
|
||||
|
||||
# Number of symlinks traversed. When the number of traversals is limited
|
||||
# by *maxlinks*, this is used instead of *seen* to detect symlink loops.
|
||||
link_count = 0
|
||||
|
||||
while rest:
|
||||
name = rest.pop()
|
||||
if name is None:
|
||||
|
@ -436,11 +444,19 @@ symbolic links encountered in the path."""
|
|||
else:
|
||||
newpath = path + sep + name
|
||||
try:
|
||||
st = os.lstat(newpath)
|
||||
st = lstat(newpath)
|
||||
if not stat.S_ISLNK(st.st_mode):
|
||||
path = newpath
|
||||
continue
|
||||
if newpath in seen:
|
||||
elif maxlinks is not None:
|
||||
link_count += 1
|
||||
if link_count > maxlinks:
|
||||
if strict:
|
||||
raise OSError(errno.ELOOP, os.strerror(errno.ELOOP),
|
||||
newpath)
|
||||
path = newpath
|
||||
continue
|
||||
elif newpath in seen:
|
||||
# Already seen this path
|
||||
path = seen[newpath]
|
||||
if path is not None:
|
||||
|
@ -448,26 +464,28 @@ symbolic links encountered in the path."""
|
|||
continue
|
||||
# The symlink is not resolved, so we must have a symlink loop.
|
||||
if strict:
|
||||
# Raise OSError(errno.ELOOP)
|
||||
os.stat(newpath)
|
||||
raise OSError(errno.ELOOP, os.strerror(errno.ELOOP),
|
||||
newpath)
|
||||
path = newpath
|
||||
continue
|
||||
target = os.readlink(newpath)
|
||||
target = readlink(newpath)
|
||||
except OSError:
|
||||
if strict:
|
||||
raise
|
||||
path = newpath
|
||||
continue
|
||||
# Resolve the symbolic link
|
||||
seen[newpath] = None # not resolved symlink
|
||||
if target.startswith(sep):
|
||||
# Symlink target is absolute; reset resolved path.
|
||||
path = sep
|
||||
# Push the symlink path onto the stack, and signal its specialness by
|
||||
# also pushing None. When these entries are popped, we'll record the
|
||||
# fully-resolved symlink target in the 'seen' mapping.
|
||||
rest.append(newpath)
|
||||
rest.append(None)
|
||||
if maxlinks is None:
|
||||
# Mark this symlink as seen but not fully resolved.
|
||||
seen[newpath] = None
|
||||
# Push the symlink path onto the stack, and signal its specialness
|
||||
# by also pushing None. When these entries are popped, we'll
|
||||
# record the fully-resolved symlink target in the 'seen' mapping.
|
||||
rest.append(newpath)
|
||||
rest.append(None)
|
||||
# Push the unresolved symlink target parts onto the stack.
|
||||
rest.extend(target.split(sep)[::-1])
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue