Repository navigation
[ntpath] realpath fails for broken symlinks with rooted target paths #85035
Description
Activity
ntpath.realpathfails to resolve the non-strict path of a broken relative symlink if the target is a rooted path. For example:>>> os.readlink('symlink') '\\broken\\link' >>> os.path.realpath('symlink') '\\broken\\link' >>> os.path.abspath('symlink') 'C:\\Temp\\symlink'The problem is that relative paths have to be specially handled by
ntpath._readlink_deep, butntpath.isabsincorrectly classifiesr"\broken\link"as an absolute path. It's actually relative to the current device or drive in the access context. Other path libraries get this right, such aspathlib.Path.is_absoluteand C++path::is_absolute. The documented behavior ofntpath.isabsisn't something that we can change (i.e. "begins with a (back)slash after chopping off a potential drive letter"). Sontpath._readlink_deepneeds a private implementation ofisabs. For example:def _isabs(s): s = os.fspath(s) seps = _get_bothseps(s) s = s[1:2] if (s and s[0] in seps) else splitdrive(s)[1] return bool(s) and s[0] in seps
This classifies UNC paths as absolute; rooted paths without a drive as relative; and otherwise depends on
splitdrive()to get the root path, if any.
Background
The target of a relative symlink gets evaluated against the solid path that's used to access the link. A solid path contains directories and mountpoints, but no symlinks. In particular, a rooted target such as
r"\spam\eggs"is relative to the root device of the solid path that's used to access the link. This may or may not be the device on which the link resides. It depends on how it's accessed. For example, if the volume that contains the symlink is accessed via its DOS device name "V:", then it resolves tor"V:\spam\eggs". Similarly, if the symlink is accessed viar"C:\Mount\VolumeSymlink", where "VolumeSymlink" is a directory symlink to"V:\\\\", then it also resolves tor"V:\spam\eggs". On the other hand, if the symlink is accessed via the mount pointr"C:\Mount\VolumeMountpoint", then it resolves tor"C:\spam\eggs".- added3.8 (EOL)end of lifeend of life3.9 (EOL)end of lifeend of life3.10 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Jun 3, 2020 - changed the title
[-]ntpath.realpath fails for broken symlinks with rooted target paths[/-][+][ntpath] realpath fails for broken symlinks with rooted target paths[/+]on Aug 8, 2022 Fixed in 3.13 by GH-113829, which made
ntpath.isabs()returnFalsefor a rooted path without a drive, so_readlink_deep()now joins such target with the location of the link.>>> os.readlink('symlink') '\\broken\\link' >>> os.path.realpath('symlink') 'C:\\broken\\link'
@eryksun, is this the result you expected, and can the issue be closed?
- addedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Aug 8, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsTodo
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: