Skip to content
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ class _WindowsFlavour(_Flavour):
is_supported = (os.name == 'nt')

drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
ext_namespace_prefix = '\\\\?\\'
# See https://bugs.python.org/issue33898
ext_namespace_prefix = ('\\\\?\\','\\\\.\\')

reserved_names = (
{'CON', 'PRN', 'AUX', 'NUL'} |
Expand All @@ -142,7 +143,7 @@ def splitroot(self, part, sep=sep):
prefix = ''
third = part[2:3]
if (second == sep and first == sep and third != sep):
# is a UNC path:
# is a UNC and/or Global path:
# vvvvvvvvvvvvvvvvvvvvv root
# \\machine\mountpoint\directory\etc\...
# directory ^^^^^^^^^^^^^^
Expand All @@ -163,12 +164,27 @@ def splitroot(self, part, sep=sep):
drv = part[:2]
part = part[2:]
first = third
# Except for UNC and Global paths, the drive should be
# the first component after the local-device prefix.
# See https://bugs.python.org/issue33898
# All UNC and some of Global paths are parsed in if-condition above.
elif part != sep and prefix and 'global' not in self.casefold(prefix):
index = part.find(sep)
if index != -1:
drv = part[:index]
part = part[index:]
first = part[0:1]
else:
drv = part
part = ''
first = ''
if first == sep:
root = first
part = part.lstrip(sep)
return prefix + drv, root, part

def casefold(self, s):
# .lower() is not recommended. See https://bugs.python.org/issue32612
return s.lower()

def casefold_parts(self, parts):
Expand Down Expand Up @@ -199,13 +215,32 @@ def resolve(self, path, strict=False):
return None

def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
# See https://bugs.python.org/issue33898
prefix = ''
if s.startswith(ext_prefix):
prefix = s[:4]
s = s[4:]
if s.startswith('UNC\\'):
prefix += s[:3]
s = '\\' + s[3:]
index = s.find('\\')
if index != -1:
# Do not assume case sensitivity.
# See https://docs.microsoft.com/ru-ru/windows/desktop/FileIO/naming-a-file
Comment thread
zooba marked this conversation as resolved.
Outdated
# But .lower() is not recommended. See https://bugs.python.org/issue32612
s1 = self.casefold(s[:index])
if s1 == 'global':
Comment thread
zooba marked this conversation as resolved.
Outdated
prefix += s[:6]
# For example, Path('//?/Global/Z:/').drive
Comment thread
zooba marked this conversation as resolved.
Outdated
if s[8:9] == ':':
prefix += s[6:7]
s = s[7:]
# For example, r'\\?\Global\UNC\server\share'
Comment thread
zooba marked this conversation as resolved.
Outdated
elif self.casefold(s[7:11]) == 'unc\\':
prefix += s[6:10]
s = '\\' + s[10:]
else:
s = '\\' + s[6:]
if s1 == 'unc':
Comment thread
zooba marked this conversation as resolved.
Outdated
prefix += s[:3]
s = '\\' + s[3:]
return prefix, s

def _ext_to_normal(self, s):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix pathlib issues with parsing Windows device paths
starting with //?/ or //./. Patch by Albina Giliazova.