Message389628
Here's a concrete implementation of the above discussion.
_is_windows = (sys.platform == 'win32')
def ismount(path):
"""Test whether a path is a mount point"""
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'\\'
extended_devices = b'\\\\?\\'
normal_devices = b'\\\\.\\'
global_link = b'GLOBAL'
unc_device = b'UNC'
else:
sep = '\\'
extended_devices = '\\\\?\\'
normal_devices = '\\\\.\\'
global_link = 'GLOBAL'
unc_device = 'UNC'
# In Windows, require an existing, accessible directory.
if _is_windows:
if not isdir(path):
return False
try:
s = os.lstat(path)
if s.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
# isdir() verified the target directory.
return True
except (OSError, ValueError):
return False
path = abspath(path)
drive, drive_path = splitdrive(path)
if not drive:
return False
# A drive root is a mount point.
if drive_path == sep:
return True
# A root path is not required for a UNC drive.
if not drive_path and drive[0] in sep:
if not drive.startswith((extended_devices, normal_devices)):
return True
# Check for \\?\[Global]\UNC. Ignore repeated "Global" links.
comps = [c.upper() for c in drive[4:].split(sep)]
for c in comps:
if c != global_link:
break
if c == unc_device:
return True
return False
Removing the dependency on GetVolumePathNameW() also eliminates buggy behavior with substitute drives. For example, if substitute drive "W:" maps to r"C:\Windows", GetVolumePathNameW() mistakenly claims r"W:\System32" is a volume mount point.
In principle, this implementation also supports "\\?\[Global]\UNC\server\share" mount points on the "UNC" device, but it depends on fixing bpo-37609. The suggested rewrite for the latter issue also includes support for repeated slashes in a UNC drive, e.g. r"\\server\\\share" and r"\\?\\\Global\\\UNC\\\server\\\share" are valid.
For POSIX, ntpath._abspath_fallback() has to be fixed to correctly resolve drive-relative paths. For example:
def _abspath_fallback(path):
"""Return the absolute version of a path."""
path = os.fspath(path)
if isinstance(path, bytes):
sep = b'\\'
colon = b':'
cwd = os.getcwdb()
else:
sep = '\\'
colon = ':'
cwd = os.getcwd()
if not isabs(path):
# For a drive-relative path, default to the root directory
# on the drive if the process working directory is on a
# different drive.
if path[1:2] == colon and path[:2].upper() != cwd[:2].upper():
path = path[:2] + sep + path[2:]
else:
path = join(cwd, path)
return normpath(path)
Since _abspath_fallback() is no longer needed in any version of Windows, maybe it should simply assume that the working drive is "C:" and the working directory on all drives is the root directory. |
|
Date |
User |
Action |
Args |
2021-03-28 02:09:36 | eryksun | set | recipients:
+ eryksun, paul.moore, tim.golden, zach.ware, steve.dower, lazka, jainankur, Jonathan Hsu |
2021-03-28 02:09:36 | eryksun | set | messageid: <1616897376.16.0.500281736523.issue38948@roundup.psfhosted.org> |
2021-03-28 02:09:36 | eryksun | link | issue38948 messages |
2021-03-28 02:09:35 | eryksun | create | |
|