diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 1d22d5f1dc2ab5..5496ef8e112fc8 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -134,16 +134,9 @@ def splitdrive(p): """ p = os.fspath(p) if len(p) >= 2: - if isinstance(p, bytes): - sep = b'\\' - altsep = b'/' - colon = b':' - else: - sep = '\\' - altsep = '/' - colon = ':' + sep, altsep, colon = get_separator(p) normp = p.replace(altsep, sep) - if (normp[0:2] == sep*2) and (normp[2:3] != sep): + if is_unc_path(normp, sep): # is a UNC path: # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path # \\machine\mountpoint\directory\etc\... @@ -151,6 +144,11 @@ def splitdrive(p): index = normp.find(sep, 2) if index == -1: return p[:0], p + if is_extended_unc(normp, colon): + start = normp.find(sep, index + 1) + drive_colon = normp.find(colon, index + 1) + if drive_colon == -1 or drive_colon > start: + index = normp.find(sep, start + 1) index2 = normp.find(sep, index + 1) # a UNC path can't have two slashes in a row # (after the initial two) @@ -159,11 +157,30 @@ def splitdrive(p): if index2 == -1: index2 = len(p) return p[:index2], p[index2:] - if normp[1:2] == colon: + if is_drive_path(normp, colon): return p[:2], p[2:] return p[:0], p +def is_unc_path(path, sep): + return (path[0:2] == sep*2) and (path[2:3] != sep) + + +def is_drive_path(path, colon): + return path[1:2] == colon + + +def is_extended_unc(path, colon): + return path[2] in ['?', '.'] and path[-2] != colon and path[4:7] == 'UNC' + + +def get_separator(path): + sep, altsep, colon = ['\\', '/', ':'] + if isinstance(path, bytes): + sep, altsep, colon = [b'\\', b'/', b':'] + return sep, altsep, colon + + # Split a path in head (everything up to the last '/') and tail (the # rest). After the trailing '/' is stripped, the invariant # join(head, tail) == p holds. diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 285fb69dc1e88f..4a12efd5df5d54 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -84,6 +84,11 @@ def test_splitdrive(self): # Issue #19911: UNC part containing U+0130 self.assertEqual(ntpath.splitdrive('//conky/MOUNTPOİNT/foo/bar'), ('//conky/MOUNTPOİNT', '/foo/bar')) + # Issue #37609: UNC device path + self.assertEqual(ntpath.splitdrive('//?/UNC/localhost/C$/foo/bar'), + ('//?/UNC/localhost/C$', '/foo/bar')) + self.assertEqual(ntpath.splitdrive('//./UNC/localhost/C$/foo/bar'), + ('//./UNC/localhost/C$', '/foo/bar')) def test_split(self): tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) diff --git a/Misc/NEWS.d/next/Library/2019-07-18-14-39-59.bpo-37609.1ZYNbG.rst b/Misc/NEWS.d/next/Library/2019-07-18-14-39-59.bpo-37609.1ZYNbG.rst new file mode 100644 index 00000000000000..37430f1bb0f4e0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-07-18-14-39-59.bpo-37609.1ZYNbG.rst @@ -0,0 +1 @@ +Add support for unc device path in :func:`ntpath.splitdrive`
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: