From 180791f3e52dbc6b736d997330931376e2c265f3 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sun, 15 Sep 2019 09:43:05 +0100 Subject: [PATCH 1/2] bpo-38081: Add more non-fatal error codes for ntpath.realpath --- Lib/ntpath.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 1b5e16f95f1659..efed64e3b11f71 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -530,15 +530,28 @@ def _readlink_deep(path, seen=None): if seen is None: seen = set() + # These error codes indicate that we should stop reading links and + # return the path we currently have. + # 1: ERROR_INVALID_FUNCTION + # 2: ERROR_FILE_NOT_FOUND + # 3: ERROR_DIRECTORY_NOT_FOUND + # 5: ERROR_ACCESS_DENIED + # 21: ERROR_NOT_READY (implies drive with no media) + # 32: ERROR_SHARING_VIOLATION + # 50: ERROR_NOT_SUPPORTED (implies no file system) + # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) + # 87: ERROR_INVALID_PARAMETER + # 4390: ERROR_NOT_A_REPARSE_POINT + # 4392: ERROR_INVALID_REPARSE_DATA + # 4393: ERROR_REPARSE_TAG_INVALID + allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 67, 87, 4390, 4392, 4393 + while normcase(path) not in seen: seen.add(normcase(path)) try: path = _nt_readlink(path) except OSError as ex: - # Stop on incorrect function (1), file (2) or - # directory (3) not found, or paths that are - # not reparse points (4390) - if ex.winerror in (1, 2, 3, 4390): + if ex.winerror in allowed_winerror: break raise except ValueError: @@ -554,9 +567,20 @@ def _getfinalpathname_nonstrict(path): except OSError: pass - # Allow file (2) or directory (3) not found, incorrect parameter (87), - # invalid syntax (123), and symlinks that cannot be followed (1921) - allowed_winerror = 2, 3, 87, 123, 1921 + # These error codes indicate that we should stop resolving the path + # and return the value we currently have. + # 1: ERROR_INVALID_FUNCTION + # 2: ERROR_FILE_NOT_FOUND + # 3: ERROR_DIRECTORY_NOT_FOUND + # 5: ERROR_ACCESS_DENIED + # 21: ERROR_NOT_READY (implies drive with no media) + # 32: ERROR_SHARING_VIOLATION + # 50: ERROR_NOT_SUPPORTED (implies no file system) + # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) + # 87: ERROR_INVALID_PARAMETER + # 123: ERROR_INVALID_NAME + # 1921: ERROR_CANT_RESOLVE_FILENAME (implies unfollowable symlink) + allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 67, 87, 123, 1921 # Non-strict algorithm is to find as much of the target directory # as we can and join the rest. From 5b29e907df03c7c48766c701d61b948c2e1881a0 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 16 Sep 2019 13:55:38 +0100 Subject: [PATCH 2/2] Clarifies comments and adds TODO for bpo-38186 --- Lib/ntpath.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index efed64e3b11f71..01f1f423c906cd 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -537,8 +537,8 @@ def _readlink_deep(path, seen=None): # 3: ERROR_DIRECTORY_NOT_FOUND # 5: ERROR_ACCESS_DENIED # 21: ERROR_NOT_READY (implies drive with no media) - # 32: ERROR_SHARING_VIOLATION - # 50: ERROR_NOT_SUPPORTED (implies no file system) + # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file) + # 50: ERROR_NOT_SUPPORTED (implies no support for reparse points) # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) # 87: ERROR_INVALID_PARAMETER # 4390: ERROR_NOT_A_REPARSE_POINT @@ -574,8 +574,8 @@ def _getfinalpathname_nonstrict(path): # 3: ERROR_DIRECTORY_NOT_FOUND # 5: ERROR_ACCESS_DENIED # 21: ERROR_NOT_READY (implies drive with no media) - # 32: ERROR_SHARING_VIOLATION - # 50: ERROR_NOT_SUPPORTED (implies no file system) + # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file) + # 50: ERROR_NOT_SUPPORTED # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) # 87: ERROR_INVALID_PARAMETER # 123: ERROR_INVALID_NAME @@ -595,6 +595,9 @@ def _getfinalpathname_nonstrict(path): if ex.winerror not in allowed_winerror: raise path, name = split(path) + # TODO (bpo-38186): Request the real file name from the directory + # entry using FindFirstFileW. For now, we will return the path + # as best we have it if path and not name: return abspath(path + tail) tail = join(name, tail) if tail else name