Skip to content

Commit

Permalink
pythongh-81790: support "UNC" device paths in ntpath.splitdrive()
Browse files Browse the repository at this point in the history
  • Loading branch information
barneygale committed Apr 24, 2022
1 parent 0907217 commit c97bfbf
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 53 deletions.
21 changes: 17 additions & 4 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,30 @@ def splitdrive(p):
sep = b'\\'
altsep = b'/'
colon = b':'
unc2 = b'\\\\'
unc4 = b'\\\\?\\'
unc8 = b'\\\\?\\UNC\\'
else:
sep = '\\'
altsep = '/'
colon = ':'
unc2 = '\\\\'
unc4 = '\\\\?\\'
unc8 = '\\\\?\\UNC\\'
normp = p.replace(altsep, sep)
if (normp[0:2] == sep*2) and (normp[2:3] != sep):
if normp[:8] == unc8:
normp = sep * 8 + normp[8:]
offset = 6
elif normp[:4] == unc4:
offset = 4
else:
offset = 0
if (normp[offset:offset + 2] == unc2) and (normp[offset + 2:offset + 3] != sep):
# is a UNC path:
# vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
# \\machine\mountpoint\directory\etc\...
# directory ^^^^^^^^^^^^^^^
index = normp.find(sep, 2)
index = normp.find(sep, offset + 2)
if index == -1:
return p[:0], p
index2 = normp.find(sep, index + 1)
Expand All @@ -167,8 +180,8 @@ def splitdrive(p):
if index2 == -1:
index2 = len(p)
return p[:index2], p[index2:]
if normp[1:2] == colon:
return p[:2], p[2:]
if normp[offset + 1:offset + 2] == colon:
return p[:offset + 2], p[offset + 2:]
return p[:0], p


Expand Down
53 changes: 4 additions & 49 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ class _WindowsFlavour(_Flavour):

is_supported = (os.name == 'nt')

drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
ext_namespace_prefix = '\\\\?\\'

reserved_names = (
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
{'COM%s' % c for c in '123456789\xb9\xb2\xb3'} |
Expand All @@ -145,43 +142,11 @@ class _WindowsFlavour(_Flavour):
# even with the '\\?\' prefix.

def splitroot(self, part, sep=sep):
first = part[0:1]
second = part[1:2]
if (second == sep and first == sep):
# XXX extended paths should also disable the collapsing of "."
# components (according to MSDN docs).
prefix, part = self._split_extended_path(part)
first = part[0:1]
second = part[1:2]
drv, rest = self.pathmod.splitdrive(part)
if drv[:1] == sep or rest[:1] == sep:
return drv, sep, rest.lstrip(sep)
else:
prefix = ''
third = part[2:3]
if (second == sep and first == sep and third != sep):
# is a UNC path:
# vvvvvvvvvvvvvvvvvvvvv root
# \\machine\mountpoint\directory\etc\...
# directory ^^^^^^^^^^^^^^
index = part.find(sep, 2)
if index != -1:
index2 = part.find(sep, index + 1)
# a UNC path can't have two slashes in a row
# (after the initial two)
if index2 != index + 1:
if index2 == -1:
index2 = len(part)
if prefix:
return prefix + part[1:index2], sep, part[index2+1:]
else:
return part[:index2], sep, part[index2+1:]
drv = root = ''
if second == ':' and first in self.drive_letters:
drv = part[:2]
part = part[2:]
first = third
if first == sep:
root = first
part = part.lstrip(sep)
return prefix + drv, root, part
return drv, '', rest

def casefold(self, s):
return s.lower()
Expand All @@ -192,16 +157,6 @@ def casefold_parts(self, parts):
def compile_pattern(self, pattern):
return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch

def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
prefix = ''
if s.startswith(ext_prefix):
prefix = s[:4]
s = s[4:]
if s.startswith('UNC\\'):
prefix += s[:3]
s = '\\' + s[3:]
return prefix, s

def is_reserved(self, parts):
# NOTE: the rules for reserved names seem somewhat complicated
# (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
Expand Down

0 comments on commit c97bfbf

Please sign in to comment.