gh-110495: ensure ntpath.realpath() result is a final, normalized pathname.#110751
gh-110495: ensure ntpath.realpath() result is a final, normalized pathname.#110751moonsikpark wants to merge 4 commits intopython:mainfrom
ntpath.realpath() result is a final, normalized pathname.#110751Conversation
|
@eryksun can you review this? |
|
cc @serhiy-storchaka (os.path expert) & @barneygale (with the reproducer in the issue, |
1f8656e to
3ae56f0
Compare
…-normalized-pathname
|
I'm not having much luck getting this to work with a common def _getfinalpathname_nonstrict(path):
# These error codes indicate that we should stop resolving the
# path and return the value we currently have.
allowed_winerror = (
1, # ERROR_INVALID_FUNCTION
2, # ERROR_FILE_NOT_FOUND
3, # ERROR_DIRECTORY_NOT_FOUND
5, # ERROR_ACCESS_DENIED
21, # ERROR_NOT_READY (e.g. drive with no media)
32, # ERROR_SHARING_VIOLATION (e.g. NTFS paging file)
50, # ERROR_NOT_SUPPORTED
53, # ERROR_BAD_NETPATH
65, # ERROR_NETWORK_ACCESS_DENIED
67, # ERROR_BAD_NET_NAME (e.g. remote server unavailable)
87, # ERROR_INVALID_PARAMETER
123, # ERROR_INVALID_NAME
161, # ERROR_BAD_PATHNAME
1920, # ERROR_CANT_ACCESS_FILE
1921, # ERROR_CANT_RESOLVE_FILENAME (e.g. can't follow symlink)
)
# 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 and normcase(path) not in seen:
seen.add(normcase(path))
try:
path = _getfinalpathname(path)
return join(path, tail) if tail else path
except OSError as ex:
if ex.winerror not in allowed_winerror:
raise
# Split off the base name, and break if it's root.
parent_path, name = split(path)
if not name:
break
try:
# Try resolving the final component as a link. If
# successful, continue resolving the real path.
new_path = _readlink_deep(path)
if new_path != path:
path = new_path
continue
except OSError:
pass
# For some error cases, try to get the real name from
# the directory entry.
if ex.winerror in (1, 5, 32, 50, 87, 1920, 1921):
try:
name = _findfirstfile(path)
except OSError:
pass
path = parent_path
tail = join(name, tail) if tail else name
if path:
return join(path, tail) if tail else path
return tail |
|
Some of the checks in cpython/Lib/test/test_ntpath.py Lines 471 to 480 in 73dc1c6 New checks: self.assertPathEqual(ntpath.realpath(r"broken1"),
ABSTFN + r"\missing\bar")
self.assertPathEqual(ntpath.realpath(r"broken1\baz"),
ABSTFN + r"\missing\bar\baz")
self.assertPathEqual(ntpath.realpath("broken2"),
ABSTFN + r"\missing")
self.assertPathEqual(ntpath.realpath("broken3"),
ABSTFN + r"\missing")The corresponding |
|
This PR is stale because it has been open for 30 days with no activity. |
By not breaking out of the loop when
_readlink_deep()is successful, we can ensure that the result ofntpath.realpath()is a final, normalized pathname.ntpath.realpath()result is a final, normalized pathname. #110495