Skip to content

gh-110495: ensure ntpath.realpath() result is a final, normalized pathname. #110751

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
15 changes: 9 additions & 6 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ def abspath(path):
# realpath is a no-op on systems without _getfinalpathname support.
realpath = abspath
else:
def _readlink_deep(path):
def _readlink_deep(path, seen):
# These error codes indicate that we should stop reading links and
# return the path we currently have.
# 1: ERROR_INVALID_FUNCTION
Expand All @@ -607,7 +607,6 @@ def _readlink_deep(path):
# 4393: ERROR_REPARSE_TAG_INVALID
allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 67, 87, 4390, 4392, 4393

seen = set()
while normcase(path) not in seen:
seen.add(normcase(path))
try:
Expand Down Expand Up @@ -655,6 +654,7 @@ def _getfinalpathname_nonstrict(path):
# Non-strict algorithm is to find as much of the target directory
# as we can and join the rest.
tail = path[:0]
seen = set()
while path:
try:
path = _getfinalpathname(path)
Expand All @@ -664,11 +664,14 @@ def _getfinalpathname_nonstrict(path):
raise
try:
# The OS could not resolve this path fully, so we attempt
# to follow the link ourselves. If we succeed, join the tail
# and return.
new_path = _readlink_deep(path)
if new_path != path:
# to follow the link ourselves. If we succeed, keep running the loop.
new_path = _readlink_deep(path, seen)
new_path_normcase = normcase(new_path)
if new_path_normcase in seen:
return join(new_path, tail) if tail else new_path
else:
seen.add(new_path_normcase)
path = new_path
except OSError:
# If we fail to readlink(), let's keep traversing
pass
Expand Down
Loading