mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
GH-118289: Fix handling of non-directories in posixpath.realpath()
(#120127)
In strict mode, raise `NotADirectoryError` if we encounter a non-directory while we still have path parts left to process. We use a `part_count` variable rather than `len(rest)` because the `rest` stack also contains markers for unresolved symlinks.
This commit is contained in:
parent
c695e37a3f
commit
fd4b5453df
3 changed files with 75 additions and 4 deletions
|
@ -412,6 +412,10 @@ def _realpath(filename, strict=False, sep=sep, curdir=curdir, pardir=pardir,
|
|||
# very fast way of spelling list(reversed(...)).
|
||||
rest = filename.split(sep)[::-1]
|
||||
|
||||
# Number of unprocessed parts in 'rest'. This can differ from len(rest)
|
||||
# later, because 'rest' might contain markers for unresolved symlinks.
|
||||
part_count = len(rest)
|
||||
|
||||
# The resolved path, which is absolute throughout this function.
|
||||
# Note: getcwd() returns a normalized and symlink-free path.
|
||||
path = sep if filename.startswith(sep) else getcwd()
|
||||
|
@ -426,12 +430,13 @@ def _realpath(filename, strict=False, sep=sep, curdir=curdir, pardir=pardir,
|
|||
# by *maxlinks*, this is used instead of *seen* to detect symlink loops.
|
||||
link_count = 0
|
||||
|
||||
while rest:
|
||||
while part_count:
|
||||
name = rest.pop()
|
||||
if name is None:
|
||||
# resolved symlink target
|
||||
seen[rest.pop()] = path
|
||||
continue
|
||||
part_count -= 1
|
||||
if not name or name == curdir:
|
||||
# current dir
|
||||
continue
|
||||
|
@ -444,8 +449,11 @@ def _realpath(filename, strict=False, sep=sep, curdir=curdir, pardir=pardir,
|
|||
else:
|
||||
newpath = path + sep + name
|
||||
try:
|
||||
st = lstat(newpath)
|
||||
if not stat.S_ISLNK(st.st_mode):
|
||||
st_mode = lstat(newpath).st_mode
|
||||
if not stat.S_ISLNK(st_mode):
|
||||
if strict and part_count and not stat.S_ISDIR(st_mode):
|
||||
raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR),
|
||||
newpath)
|
||||
path = newpath
|
||||
continue
|
||||
elif maxlinks is not None:
|
||||
|
@ -487,7 +495,9 @@ def _realpath(filename, strict=False, sep=sep, curdir=curdir, pardir=pardir,
|
|||
rest.append(newpath)
|
||||
rest.append(None)
|
||||
# Push the unresolved symlink target parts onto the stack.
|
||||
rest.extend(target.split(sep)[::-1])
|
||||
target_parts = target.split(sep)[::-1]
|
||||
rest.extend(target_parts)
|
||||
part_count += len(target_parts)
|
||||
|
||||
return path
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue