Skip to content

Commit c97bfbf

Browse files
committed
pythongh-81790: support "UNC" device paths in ntpath.splitdrive()
1 parent 0907217 commit c97bfbf

File tree

2 files changed

+21
-53
lines changed

2 files changed

+21
-53
lines changed

Lib/ntpath.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,30 @@ def splitdrive(p):
146146
sep = b'\\'
147147
altsep = b'/'
148148
colon = b':'
149+
unc2 = b'\\\\'
150+
unc4 = b'\\\\?\\'
151+
unc8 = b'\\\\?\\UNC\\'
149152
else:
150153
sep = '\\'
151154
altsep = '/'
152155
colon = ':'
156+
unc2 = '\\\\'
157+
unc4 = '\\\\?\\'
158+
unc8 = '\\\\?\\UNC\\'
153159
normp = p.replace(altsep, sep)
154-
if (normp[0:2] == sep*2) and (normp[2:3] != sep):
160+
if normp[:8] == unc8:
161+
normp = sep * 8 + normp[8:]
162+
offset = 6
163+
elif normp[:4] == unc4:
164+
offset = 4
165+
else:
166+
offset = 0
167+
if (normp[offset:offset + 2] == unc2) and (normp[offset + 2:offset + 3] != sep):
155168
# is a UNC path:
156169
# vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
157170
# \\machine\mountpoint\directory\etc\...
158171
# directory ^^^^^^^^^^^^^^^
159-
index = normp.find(sep, 2)
172+
index = normp.find(sep, offset + 2)
160173
if index == -1:
161174
return p[:0], p
162175
index2 = normp.find(sep, index + 1)
@@ -167,8 +180,8 @@ def splitdrive(p):
167180
if index2 == -1:
168181
index2 = len(p)
169182
return p[:index2], p[index2:]
170-
if normp[1:2] == colon:
171-
return p[:2], p[2:]
183+
if normp[offset + 1:offset + 2] == colon:
184+
return p[:offset + 2], p[offset + 2:]
172185
return p[:0], p
173186

174187

Lib/pathlib.py

+4-49
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ class _WindowsFlavour(_Flavour):
120120

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

123-
drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
124-
ext_namespace_prefix = '\\\\?\\'
125-
126123
reserved_names = (
127124
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
128125
{'COM%s' % c for c in '123456789\xb9\xb2\xb3'} |
@@ -145,43 +142,11 @@ class _WindowsFlavour(_Flavour):
145142
# even with the '\\?\' prefix.
146143

147144
def splitroot(self, part, sep=sep):
148-
first = part[0:1]
149-
second = part[1:2]
150-
if (second == sep and first == sep):
151-
# XXX extended paths should also disable the collapsing of "."
152-
# components (according to MSDN docs).
153-
prefix, part = self._split_extended_path(part)
154-
first = part[0:1]
155-
second = part[1:2]
145+
drv, rest = self.pathmod.splitdrive(part)
146+
if drv[:1] == sep or rest[:1] == sep:
147+
return drv, sep, rest.lstrip(sep)
156148
else:
157-
prefix = ''
158-
third = part[2:3]
159-
if (second == sep and first == sep and third != sep):
160-
# is a UNC path:
161-
# vvvvvvvvvvvvvvvvvvvvv root
162-
# \\machine\mountpoint\directory\etc\...
163-
# directory ^^^^^^^^^^^^^^
164-
index = part.find(sep, 2)
165-
if index != -1:
166-
index2 = part.find(sep, index + 1)
167-
# a UNC path can't have two slashes in a row
168-
# (after the initial two)
169-
if index2 != index + 1:
170-
if index2 == -1:
171-
index2 = len(part)
172-
if prefix:
173-
return prefix + part[1:index2], sep, part[index2+1:]
174-
else:
175-
return part[:index2], sep, part[index2+1:]
176-
drv = root = ''
177-
if second == ':' and first in self.drive_letters:
178-
drv = part[:2]
179-
part = part[2:]
180-
first = third
181-
if first == sep:
182-
root = first
183-
part = part.lstrip(sep)
184-
return prefix + drv, root, part
149+
return drv, '', rest
185150

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

195-
def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
196-
prefix = ''
197-
if s.startswith(ext_prefix):
198-
prefix = s[:4]
199-
s = s[4:]
200-
if s.startswith('UNC\\'):
201-
prefix += s[:3]
202-
s = '\\' + s[3:]
203-
return prefix, s
204-
205160
def is_reserved(self, parts):
206161
# NOTE: the rules for reserved names seem somewhat complicated
207162
# (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not

0 commit comments

Comments
 (0)