@@ -490,6 +490,9 @@ def to_posixpath(path: str):
490490 return posixpath .sep .join (path .split (ntpath .sep ))
491491
492492
493+ _WINDOWS_MAX_PATH = 259 # Win32 MAX_PATH minus the null terminator
494+
495+
493496def _windows_realpath (path : str ) -> str :
494497 """Resolve symlinks and junctions on Windows without expanding mapped drives.
495498
@@ -513,14 +516,31 @@ def _windows_realpath(path: str) -> str:
513516 target = os .readlink (candidate )
514517 # os.readlink on Windows may return an extended-length path
515518 # (\\?\C:\... or \\?\UNC\server\share\...). Strip the prefix so
516- # subsequent abspath/normpath calls produce ordinary paths .
519+ # we can work with ordinary path strings .
517520 if target .startswith ("\\ \\ ?\\ UNC\\ " ):
518521 target = "\\ \\ " + target [8 :]
519522 elif target .startswith ("\\ \\ ?\\ " ):
520523 target = target [4 :]
521524 if not os .path .isabs (target ):
522525 target = os .path .join (os .path .dirname (candidate ), target )
523- candidate = os .path .normpath (os .path .abspath (target ))
526+ # For paths that exceed MAX_PATH, re-add the extended-length
527+ # prefix before calling abspath so the Win32 API (GetFullPathNameW)
528+ # can handle the length on hosts without LongPathsEnabled in the
529+ # registry. We strip the prefix again afterwards so the rest of
530+ # the walk operates on ordinary path strings.
531+ if len (target ) > _WINDOWS_MAX_PATH :
532+ if target .startswith ("\\ \\ " ):
533+ target = "\\ \\ ?\\ UNC\\ " + target [2 :]
534+ else :
535+ target = "\\ \\ ?\\ " + target
536+ candidate = os .path .abspath (target )
537+ if candidate .startswith ("\\ \\ ?\\ UNC\\ " ):
538+ candidate = "\\ \\ " + candidate [8 :]
539+ elif candidate .startswith ("\\ \\ ?\\ " ):
540+ candidate = candidate [4 :]
541+ candidate = os .path .normpath (candidate )
542+ else :
543+ candidate = os .path .normpath (os .path .abspath (target ))
524544 depth += 1
525545 result = candidate
526546 return result
0 commit comments