@@ -530,15 +530,28 @@ def _readlink_deep(path, seen=None):
530530 if seen is None :
531531 seen = set ()
532532
533+ # These error codes indicate that we should stop reading links and
534+ # return the path we currently have.
535+ # 1: ERROR_INVALID_FUNCTION
536+ # 2: ERROR_FILE_NOT_FOUND
537+ # 3: ERROR_DIRECTORY_NOT_FOUND
538+ # 5: ERROR_ACCESS_DENIED
539+ # 21: ERROR_NOT_READY (implies drive with no media)
540+ # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file)
541+ # 50: ERROR_NOT_SUPPORTED (implies no support for reparse points)
542+ # 67: ERROR_BAD_NET_NAME (implies remote server unavailable)
543+ # 87: ERROR_INVALID_PARAMETER
544+ # 4390: ERROR_NOT_A_REPARSE_POINT
545+ # 4392: ERROR_INVALID_REPARSE_DATA
546+ # 4393: ERROR_REPARSE_TAG_INVALID
547+ allowed_winerror = 1 , 2 , 3 , 5 , 21 , 32 , 50 , 67 , 87 , 4390 , 4392 , 4393
548+
533549 while normcase (path ) not in seen :
534550 seen .add (normcase (path ))
535551 try :
536552 path = _nt_readlink (path )
537553 except OSError as ex :
538- # Stop on incorrect function (1), file (2) or
539- # directory (3) not found, or paths that are
540- # not reparse points (4390)
541- if ex .winerror in (1 , 2 , 3 , 4390 ):
554+ if ex .winerror in allowed_winerror :
542555 break
543556 raise
544557 except ValueError :
@@ -554,9 +567,20 @@ def _getfinalpathname_nonstrict(path):
554567 except OSError :
555568 pass
556569
557- # Allow file (2) or directory (3) not found, incorrect parameter (87),
558- # invalid syntax (123), and symlinks that cannot be followed (1921)
559- allowed_winerror = 2 , 3 , 87 , 123 , 1921
570+ # These error codes indicate that we should stop resolving the path
571+ # and return the value we currently have.
572+ # 1: ERROR_INVALID_FUNCTION
573+ # 2: ERROR_FILE_NOT_FOUND
574+ # 3: ERROR_DIRECTORY_NOT_FOUND
575+ # 5: ERROR_ACCESS_DENIED
576+ # 21: ERROR_NOT_READY (implies drive with no media)
577+ # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file)
578+ # 50: ERROR_NOT_SUPPORTED
579+ # 67: ERROR_BAD_NET_NAME (implies remote server unavailable)
580+ # 87: ERROR_INVALID_PARAMETER
581+ # 123: ERROR_INVALID_NAME
582+ # 1921: ERROR_CANT_RESOLVE_FILENAME (implies unfollowable symlink)
583+ allowed_winerror = 1 , 2 , 3 , 5 , 21 , 32 , 50 , 67 , 87 , 123 , 1921
560584
561585 # Non-strict algorithm is to find as much of the target directory
562586 # as we can and join the rest.
@@ -571,6 +595,9 @@ def _getfinalpathname_nonstrict(path):
571595 if ex .winerror not in allowed_winerror :
572596 raise
573597 path , name = split (path )
598+ # TODO (bpo-38186): Request the real file name from the directory
599+ # entry using FindFirstFileW. For now, we will return the path
600+ # as best we have it
574601 if path and not name :
575602 return abspath (path + tail )
576603 tail = join (name , tail ) if tail else name
0 commit comments