1*cda5da8dSAndroid Build Coastguard Worker# Module 'ntpath' -- common operations on WinNT/Win95 pathnames 2*cda5da8dSAndroid Build Coastguard Worker"""Common pathname manipulations, WindowsNT/95 version. 3*cda5da8dSAndroid Build Coastguard Worker 4*cda5da8dSAndroid Build Coastguard WorkerInstead of importing this module directly, import os and refer to this 5*cda5da8dSAndroid Build Coastguard Workermodule as os.path. 6*cda5da8dSAndroid Build Coastguard Worker""" 7*cda5da8dSAndroid Build Coastguard Worker 8*cda5da8dSAndroid Build Coastguard Worker# strings representing various path-related bits and pieces 9*cda5da8dSAndroid Build Coastguard Worker# These are primarily for export; internally, they are hardcoded. 10*cda5da8dSAndroid Build Coastguard Worker# Should be set before imports for resolving cyclic dependency. 11*cda5da8dSAndroid Build Coastguard Workercurdir = '.' 12*cda5da8dSAndroid Build Coastguard Workerpardir = '..' 13*cda5da8dSAndroid Build Coastguard Workerextsep = '.' 14*cda5da8dSAndroid Build Coastguard Workersep = '\\' 15*cda5da8dSAndroid Build Coastguard Workerpathsep = ';' 16*cda5da8dSAndroid Build Coastguard Workeraltsep = '/' 17*cda5da8dSAndroid Build Coastguard Workerdefpath = '.;C:\\bin' 18*cda5da8dSAndroid Build Coastguard Workerdevnull = 'nul' 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Workerimport os 21*cda5da8dSAndroid Build Coastguard Workerimport sys 22*cda5da8dSAndroid Build Coastguard Workerimport stat 23*cda5da8dSAndroid Build Coastguard Workerimport genericpath 24*cda5da8dSAndroid Build Coastguard Workerfrom genericpath import * 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Worker__all__ = ["normcase","isabs","join","splitdrive","split","splitext", 28*cda5da8dSAndroid Build Coastguard Worker "basename","dirname","commonprefix","getsize","getmtime", 29*cda5da8dSAndroid Build Coastguard Worker "getatime","getctime", "islink","exists","lexists","isdir","isfile", 30*cda5da8dSAndroid Build Coastguard Worker "ismount", "expanduser","expandvars","normpath","abspath", 31*cda5da8dSAndroid Build Coastguard Worker "curdir","pardir","sep","pathsep","defpath","altsep", 32*cda5da8dSAndroid Build Coastguard Worker "extsep","devnull","realpath","supports_unicode_filenames","relpath", 33*cda5da8dSAndroid Build Coastguard Worker "samefile", "sameopenfile", "samestat", "commonpath"] 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard Workerdef _get_bothseps(path): 36*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 37*cda5da8dSAndroid Build Coastguard Worker return b'\\/' 38*cda5da8dSAndroid Build Coastguard Worker else: 39*cda5da8dSAndroid Build Coastguard Worker return '\\/' 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker# Normalize the case of a pathname and map slashes to backslashes. 42*cda5da8dSAndroid Build Coastguard Worker# Other normalizations (such as optimizing '../' away) are not done 43*cda5da8dSAndroid Build Coastguard Worker# (this is done by normpath). 44*cda5da8dSAndroid Build Coastguard Worker 45*cda5da8dSAndroid Build Coastguard Workertry: 46*cda5da8dSAndroid Build Coastguard Worker from _winapi import ( 47*cda5da8dSAndroid Build Coastguard Worker LCMapStringEx as _LCMapStringEx, 48*cda5da8dSAndroid Build Coastguard Worker LOCALE_NAME_INVARIANT as _LOCALE_NAME_INVARIANT, 49*cda5da8dSAndroid Build Coastguard Worker LCMAP_LOWERCASE as _LCMAP_LOWERCASE) 50*cda5da8dSAndroid Build Coastguard Worker 51*cda5da8dSAndroid Build Coastguard Worker def normcase(s): 52*cda5da8dSAndroid Build Coastguard Worker """Normalize case of pathname. 53*cda5da8dSAndroid Build Coastguard Worker 54*cda5da8dSAndroid Build Coastguard Worker Makes all characters lowercase and all slashes into backslashes. 55*cda5da8dSAndroid Build Coastguard Worker """ 56*cda5da8dSAndroid Build Coastguard Worker s = os.fspath(s) 57*cda5da8dSAndroid Build Coastguard Worker if not s: 58*cda5da8dSAndroid Build Coastguard Worker return s 59*cda5da8dSAndroid Build Coastguard Worker if isinstance(s, bytes): 60*cda5da8dSAndroid Build Coastguard Worker encoding = sys.getfilesystemencoding() 61*cda5da8dSAndroid Build Coastguard Worker s = s.decode(encoding, 'surrogateescape').replace('/', '\\') 62*cda5da8dSAndroid Build Coastguard Worker s = _LCMapStringEx(_LOCALE_NAME_INVARIANT, 63*cda5da8dSAndroid Build Coastguard Worker _LCMAP_LOWERCASE, s) 64*cda5da8dSAndroid Build Coastguard Worker return s.encode(encoding, 'surrogateescape') 65*cda5da8dSAndroid Build Coastguard Worker else: 66*cda5da8dSAndroid Build Coastguard Worker return _LCMapStringEx(_LOCALE_NAME_INVARIANT, 67*cda5da8dSAndroid Build Coastguard Worker _LCMAP_LOWERCASE, 68*cda5da8dSAndroid Build Coastguard Worker s.replace('/', '\\')) 69*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 70*cda5da8dSAndroid Build Coastguard Worker def normcase(s): 71*cda5da8dSAndroid Build Coastguard Worker """Normalize case of pathname. 72*cda5da8dSAndroid Build Coastguard Worker 73*cda5da8dSAndroid Build Coastguard Worker Makes all characters lowercase and all slashes into backslashes. 74*cda5da8dSAndroid Build Coastguard Worker """ 75*cda5da8dSAndroid Build Coastguard Worker s = os.fspath(s) 76*cda5da8dSAndroid Build Coastguard Worker if isinstance(s, bytes): 77*cda5da8dSAndroid Build Coastguard Worker return os.fsencode(os.fsdecode(s).replace('/', '\\').lower()) 78*cda5da8dSAndroid Build Coastguard Worker return s.replace('/', '\\').lower() 79*cda5da8dSAndroid Build Coastguard Worker 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Worker# Return whether a path is absolute. 82*cda5da8dSAndroid Build Coastguard Worker# Trivial in Posix, harder on Windows. 83*cda5da8dSAndroid Build Coastguard Worker# For Windows it is absolute if it starts with a slash or backslash (current 84*cda5da8dSAndroid Build Coastguard Worker# volume), or if a pathname after the volume-letter-and-colon or UNC-resource 85*cda5da8dSAndroid Build Coastguard Worker# starts with a slash or backslash. 86*cda5da8dSAndroid Build Coastguard Worker 87*cda5da8dSAndroid Build Coastguard Workerdef isabs(s): 88*cda5da8dSAndroid Build Coastguard Worker """Test whether a path is absolute""" 89*cda5da8dSAndroid Build Coastguard Worker s = os.fspath(s) 90*cda5da8dSAndroid Build Coastguard Worker if isinstance(s, bytes): 91*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 92*cda5da8dSAndroid Build Coastguard Worker altsep = b'/' 93*cda5da8dSAndroid Build Coastguard Worker colon_sep = b':\\' 94*cda5da8dSAndroid Build Coastguard Worker else: 95*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 96*cda5da8dSAndroid Build Coastguard Worker altsep = '/' 97*cda5da8dSAndroid Build Coastguard Worker colon_sep = ':\\' 98*cda5da8dSAndroid Build Coastguard Worker s = s[:3].replace(altsep, sep) 99*cda5da8dSAndroid Build Coastguard Worker # Absolute: UNC, device, and paths with a drive and root. 100*cda5da8dSAndroid Build Coastguard Worker # LEGACY BUG: isabs("/x") should be false since the path has no drive. 101*cda5da8dSAndroid Build Coastguard Worker if s.startswith(sep) or s.startswith(colon_sep, 1): 102*cda5da8dSAndroid Build Coastguard Worker return True 103*cda5da8dSAndroid Build Coastguard Worker return False 104*cda5da8dSAndroid Build Coastguard Worker 105*cda5da8dSAndroid Build Coastguard Worker 106*cda5da8dSAndroid Build Coastguard Worker# Join two (or more) paths. 107*cda5da8dSAndroid Build Coastguard Workerdef join(path, *paths): 108*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 109*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 110*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 111*cda5da8dSAndroid Build Coastguard Worker seps = b'\\/' 112*cda5da8dSAndroid Build Coastguard Worker colon = b':' 113*cda5da8dSAndroid Build Coastguard Worker else: 114*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 115*cda5da8dSAndroid Build Coastguard Worker seps = '\\/' 116*cda5da8dSAndroid Build Coastguard Worker colon = ':' 117*cda5da8dSAndroid Build Coastguard Worker try: 118*cda5da8dSAndroid Build Coastguard Worker if not paths: 119*cda5da8dSAndroid Build Coastguard Worker path[:0] + sep #23780: Ensure compatible data type even if p is null. 120*cda5da8dSAndroid Build Coastguard Worker result_drive, result_path = splitdrive(path) 121*cda5da8dSAndroid Build Coastguard Worker for p in map(os.fspath, paths): 122*cda5da8dSAndroid Build Coastguard Worker p_drive, p_path = splitdrive(p) 123*cda5da8dSAndroid Build Coastguard Worker if p_path and p_path[0] in seps: 124*cda5da8dSAndroid Build Coastguard Worker # Second path is absolute 125*cda5da8dSAndroid Build Coastguard Worker if p_drive or not result_drive: 126*cda5da8dSAndroid Build Coastguard Worker result_drive = p_drive 127*cda5da8dSAndroid Build Coastguard Worker result_path = p_path 128*cda5da8dSAndroid Build Coastguard Worker continue 129*cda5da8dSAndroid Build Coastguard Worker elif p_drive and p_drive != result_drive: 130*cda5da8dSAndroid Build Coastguard Worker if p_drive.lower() != result_drive.lower(): 131*cda5da8dSAndroid Build Coastguard Worker # Different drives => ignore the first path entirely 132*cda5da8dSAndroid Build Coastguard Worker result_drive = p_drive 133*cda5da8dSAndroid Build Coastguard Worker result_path = p_path 134*cda5da8dSAndroid Build Coastguard Worker continue 135*cda5da8dSAndroid Build Coastguard Worker # Same drive in different case 136*cda5da8dSAndroid Build Coastguard Worker result_drive = p_drive 137*cda5da8dSAndroid Build Coastguard Worker # Second path is relative to the first 138*cda5da8dSAndroid Build Coastguard Worker if result_path and result_path[-1] not in seps: 139*cda5da8dSAndroid Build Coastguard Worker result_path = result_path + sep 140*cda5da8dSAndroid Build Coastguard Worker result_path = result_path + p_path 141*cda5da8dSAndroid Build Coastguard Worker ## add separator between UNC and non-absolute path 142*cda5da8dSAndroid Build Coastguard Worker if (result_path and result_path[0] not in seps and 143*cda5da8dSAndroid Build Coastguard Worker result_drive and result_drive[-1:] != colon): 144*cda5da8dSAndroid Build Coastguard Worker return result_drive + sep + result_path 145*cda5da8dSAndroid Build Coastguard Worker return result_drive + result_path 146*cda5da8dSAndroid Build Coastguard Worker except (TypeError, AttributeError, BytesWarning): 147*cda5da8dSAndroid Build Coastguard Worker genericpath._check_arg_types('join', path, *paths) 148*cda5da8dSAndroid Build Coastguard Worker raise 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker 151*cda5da8dSAndroid Build Coastguard Worker# Split a path in a drive specification (a drive letter followed by a 152*cda5da8dSAndroid Build Coastguard Worker# colon) and the path specification. 153*cda5da8dSAndroid Build Coastguard Worker# It is always true that drivespec + pathspec == p 154*cda5da8dSAndroid Build Coastguard Workerdef splitdrive(p): 155*cda5da8dSAndroid Build Coastguard Worker """Split a pathname into drive/UNC sharepoint and relative path specifiers. 156*cda5da8dSAndroid Build Coastguard Worker Returns a 2-tuple (drive_or_unc, path); either part may be empty. 157*cda5da8dSAndroid Build Coastguard Worker 158*cda5da8dSAndroid Build Coastguard Worker If you assign 159*cda5da8dSAndroid Build Coastguard Worker result = splitdrive(p) 160*cda5da8dSAndroid Build Coastguard Worker It is always true that: 161*cda5da8dSAndroid Build Coastguard Worker result[0] + result[1] == p 162*cda5da8dSAndroid Build Coastguard Worker 163*cda5da8dSAndroid Build Coastguard Worker If the path contained a drive letter, drive_or_unc will contain everything 164*cda5da8dSAndroid Build Coastguard Worker up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir") 165*cda5da8dSAndroid Build Coastguard Worker 166*cda5da8dSAndroid Build Coastguard Worker If the path contained a UNC path, the drive_or_unc will contain the host name 167*cda5da8dSAndroid Build Coastguard Worker and share up to but not including the fourth directory separator character. 168*cda5da8dSAndroid Build Coastguard Worker e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir") 169*cda5da8dSAndroid Build Coastguard Worker 170*cda5da8dSAndroid Build Coastguard Worker Paths cannot contain both a drive letter and a UNC path. 171*cda5da8dSAndroid Build Coastguard Worker 172*cda5da8dSAndroid Build Coastguard Worker """ 173*cda5da8dSAndroid Build Coastguard Worker p = os.fspath(p) 174*cda5da8dSAndroid Build Coastguard Worker if len(p) >= 2: 175*cda5da8dSAndroid Build Coastguard Worker if isinstance(p, bytes): 176*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 177*cda5da8dSAndroid Build Coastguard Worker altsep = b'/' 178*cda5da8dSAndroid Build Coastguard Worker colon = b':' 179*cda5da8dSAndroid Build Coastguard Worker unc_prefix = b'\\\\?\\UNC\\' 180*cda5da8dSAndroid Build Coastguard Worker else: 181*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 182*cda5da8dSAndroid Build Coastguard Worker altsep = '/' 183*cda5da8dSAndroid Build Coastguard Worker colon = ':' 184*cda5da8dSAndroid Build Coastguard Worker unc_prefix = '\\\\?\\UNC\\' 185*cda5da8dSAndroid Build Coastguard Worker normp = p.replace(altsep, sep) 186*cda5da8dSAndroid Build Coastguard Worker if normp[0:2] == sep * 2: 187*cda5da8dSAndroid Build Coastguard Worker # UNC drives, e.g. \\server\share or \\?\UNC\server\share 188*cda5da8dSAndroid Build Coastguard Worker # Device drives, e.g. \\.\device or \\?\device 189*cda5da8dSAndroid Build Coastguard Worker start = 8 if normp[:8].upper() == unc_prefix else 2 190*cda5da8dSAndroid Build Coastguard Worker index = normp.find(sep, start) 191*cda5da8dSAndroid Build Coastguard Worker if index == -1: 192*cda5da8dSAndroid Build Coastguard Worker return p, p[:0] 193*cda5da8dSAndroid Build Coastguard Worker index2 = normp.find(sep, index + 1) 194*cda5da8dSAndroid Build Coastguard Worker if index2 == -1: 195*cda5da8dSAndroid Build Coastguard Worker return p, p[:0] 196*cda5da8dSAndroid Build Coastguard Worker return p[:index2], p[index2:] 197*cda5da8dSAndroid Build Coastguard Worker if normp[1:2] == colon: 198*cda5da8dSAndroid Build Coastguard Worker # Drive-letter drives, e.g. X: 199*cda5da8dSAndroid Build Coastguard Worker return p[:2], p[2:] 200*cda5da8dSAndroid Build Coastguard Worker return p[:0], p 201*cda5da8dSAndroid Build Coastguard Worker 202*cda5da8dSAndroid Build Coastguard Worker 203*cda5da8dSAndroid Build Coastguard Worker# Split a path in head (everything up to the last '/') and tail (the 204*cda5da8dSAndroid Build Coastguard Worker# rest). After the trailing '/' is stripped, the invariant 205*cda5da8dSAndroid Build Coastguard Worker# join(head, tail) == p holds. 206*cda5da8dSAndroid Build Coastguard Worker# The resulting head won't end in '/' unless it is the root. 207*cda5da8dSAndroid Build Coastguard Worker 208*cda5da8dSAndroid Build Coastguard Workerdef split(p): 209*cda5da8dSAndroid Build Coastguard Worker """Split a pathname. 210*cda5da8dSAndroid Build Coastguard Worker 211*cda5da8dSAndroid Build Coastguard Worker Return tuple (head, tail) where tail is everything after the final slash. 212*cda5da8dSAndroid Build Coastguard Worker Either part may be empty.""" 213*cda5da8dSAndroid Build Coastguard Worker p = os.fspath(p) 214*cda5da8dSAndroid Build Coastguard Worker seps = _get_bothseps(p) 215*cda5da8dSAndroid Build Coastguard Worker d, p = splitdrive(p) 216*cda5da8dSAndroid Build Coastguard Worker # set i to index beyond p's last slash 217*cda5da8dSAndroid Build Coastguard Worker i = len(p) 218*cda5da8dSAndroid Build Coastguard Worker while i and p[i-1] not in seps: 219*cda5da8dSAndroid Build Coastguard Worker i -= 1 220*cda5da8dSAndroid Build Coastguard Worker head, tail = p[:i], p[i:] # now tail has no slashes 221*cda5da8dSAndroid Build Coastguard Worker # remove trailing slashes from head, unless it's all slashes 222*cda5da8dSAndroid Build Coastguard Worker head = head.rstrip(seps) or head 223*cda5da8dSAndroid Build Coastguard Worker return d + head, tail 224*cda5da8dSAndroid Build Coastguard Worker 225*cda5da8dSAndroid Build Coastguard Worker 226*cda5da8dSAndroid Build Coastguard Worker# Split a path in root and extension. 227*cda5da8dSAndroid Build Coastguard Worker# The extension is everything starting at the last dot in the last 228*cda5da8dSAndroid Build Coastguard Worker# pathname component; the root is everything before that. 229*cda5da8dSAndroid Build Coastguard Worker# It is always true that root + ext == p. 230*cda5da8dSAndroid Build Coastguard Worker 231*cda5da8dSAndroid Build Coastguard Workerdef splitext(p): 232*cda5da8dSAndroid Build Coastguard Worker p = os.fspath(p) 233*cda5da8dSAndroid Build Coastguard Worker if isinstance(p, bytes): 234*cda5da8dSAndroid Build Coastguard Worker return genericpath._splitext(p, b'\\', b'/', b'.') 235*cda5da8dSAndroid Build Coastguard Worker else: 236*cda5da8dSAndroid Build Coastguard Worker return genericpath._splitext(p, '\\', '/', '.') 237*cda5da8dSAndroid Build Coastguard Workersplitext.__doc__ = genericpath._splitext.__doc__ 238*cda5da8dSAndroid Build Coastguard Worker 239*cda5da8dSAndroid Build Coastguard Worker 240*cda5da8dSAndroid Build Coastguard Worker# Return the tail (basename) part of a path. 241*cda5da8dSAndroid Build Coastguard Worker 242*cda5da8dSAndroid Build Coastguard Workerdef basename(p): 243*cda5da8dSAndroid Build Coastguard Worker """Returns the final component of a pathname""" 244*cda5da8dSAndroid Build Coastguard Worker return split(p)[1] 245*cda5da8dSAndroid Build Coastguard Worker 246*cda5da8dSAndroid Build Coastguard Worker 247*cda5da8dSAndroid Build Coastguard Worker# Return the head (dirname) part of a path. 248*cda5da8dSAndroid Build Coastguard Worker 249*cda5da8dSAndroid Build Coastguard Workerdef dirname(p): 250*cda5da8dSAndroid Build Coastguard Worker """Returns the directory component of a pathname""" 251*cda5da8dSAndroid Build Coastguard Worker return split(p)[0] 252*cda5da8dSAndroid Build Coastguard Worker 253*cda5da8dSAndroid Build Coastguard Worker# Is a path a symbolic link? 254*cda5da8dSAndroid Build Coastguard Worker# This will always return false on systems where os.lstat doesn't exist. 255*cda5da8dSAndroid Build Coastguard Worker 256*cda5da8dSAndroid Build Coastguard Workerdef islink(path): 257*cda5da8dSAndroid Build Coastguard Worker """Test whether a path is a symbolic link. 258*cda5da8dSAndroid Build Coastguard Worker This will always return false for Windows prior to 6.0. 259*cda5da8dSAndroid Build Coastguard Worker """ 260*cda5da8dSAndroid Build Coastguard Worker try: 261*cda5da8dSAndroid Build Coastguard Worker st = os.lstat(path) 262*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError, AttributeError): 263*cda5da8dSAndroid Build Coastguard Worker return False 264*cda5da8dSAndroid Build Coastguard Worker return stat.S_ISLNK(st.st_mode) 265*cda5da8dSAndroid Build Coastguard Worker 266*cda5da8dSAndroid Build Coastguard Worker# Being true for dangling symbolic links is also useful. 267*cda5da8dSAndroid Build Coastguard Worker 268*cda5da8dSAndroid Build Coastguard Workerdef lexists(path): 269*cda5da8dSAndroid Build Coastguard Worker """Test whether a path exists. Returns True for broken symbolic links""" 270*cda5da8dSAndroid Build Coastguard Worker try: 271*cda5da8dSAndroid Build Coastguard Worker st = os.lstat(path) 272*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 273*cda5da8dSAndroid Build Coastguard Worker return False 274*cda5da8dSAndroid Build Coastguard Worker return True 275*cda5da8dSAndroid Build Coastguard Worker 276*cda5da8dSAndroid Build Coastguard Worker# Is a path a mount point? 277*cda5da8dSAndroid Build Coastguard Worker# Any drive letter root (eg c:\) 278*cda5da8dSAndroid Build Coastguard Worker# Any share UNC (eg \\server\share) 279*cda5da8dSAndroid Build Coastguard Worker# Any volume mounted on a filesystem folder 280*cda5da8dSAndroid Build Coastguard Worker# 281*cda5da8dSAndroid Build Coastguard Worker# No one method detects all three situations. Historically we've lexically 282*cda5da8dSAndroid Build Coastguard Worker# detected drive letter roots and share UNCs. The canonical approach to 283*cda5da8dSAndroid Build Coastguard Worker# detecting mounted volumes (querying the reparse tag) fails for the most 284*cda5da8dSAndroid Build Coastguard Worker# common case: drive letter roots. The alternative which uses GetVolumePathName 285*cda5da8dSAndroid Build Coastguard Worker# fails if the drive letter is the result of a SUBST. 286*cda5da8dSAndroid Build Coastguard Workertry: 287*cda5da8dSAndroid Build Coastguard Worker from nt import _getvolumepathname 288*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 289*cda5da8dSAndroid Build Coastguard Worker _getvolumepathname = None 290*cda5da8dSAndroid Build Coastguard Workerdef ismount(path): 291*cda5da8dSAndroid Build Coastguard Worker """Test whether a path is a mount point (a drive root, the root of a 292*cda5da8dSAndroid Build Coastguard Worker share, or a mounted volume)""" 293*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 294*cda5da8dSAndroid Build Coastguard Worker seps = _get_bothseps(path) 295*cda5da8dSAndroid Build Coastguard Worker path = abspath(path) 296*cda5da8dSAndroid Build Coastguard Worker root, rest = splitdrive(path) 297*cda5da8dSAndroid Build Coastguard Worker if root and root[0] in seps: 298*cda5da8dSAndroid Build Coastguard Worker return (not rest) or (rest in seps) 299*cda5da8dSAndroid Build Coastguard Worker if rest and rest in seps: 300*cda5da8dSAndroid Build Coastguard Worker return True 301*cda5da8dSAndroid Build Coastguard Worker 302*cda5da8dSAndroid Build Coastguard Worker if _getvolumepathname: 303*cda5da8dSAndroid Build Coastguard Worker x = path.rstrip(seps) 304*cda5da8dSAndroid Build Coastguard Worker y =_getvolumepathname(path).rstrip(seps) 305*cda5da8dSAndroid Build Coastguard Worker return x.casefold() == y.casefold() 306*cda5da8dSAndroid Build Coastguard Worker else: 307*cda5da8dSAndroid Build Coastguard Worker return False 308*cda5da8dSAndroid Build Coastguard Worker 309*cda5da8dSAndroid Build Coastguard Worker 310*cda5da8dSAndroid Build Coastguard Worker# Expand paths beginning with '~' or '~user'. 311*cda5da8dSAndroid Build Coastguard Worker# '~' means $HOME; '~user' means that user's home directory. 312*cda5da8dSAndroid Build Coastguard Worker# If the path doesn't begin with '~', or if the user or $HOME is unknown, 313*cda5da8dSAndroid Build Coastguard Worker# the path is returned unchanged (leaving error reporting to whatever 314*cda5da8dSAndroid Build Coastguard Worker# function is called with the expanded path as argument). 315*cda5da8dSAndroid Build Coastguard Worker# See also module 'glob' for expansion of *, ? and [...] in pathnames. 316*cda5da8dSAndroid Build Coastguard Worker# (A function should also be defined to do full *sh-style environment 317*cda5da8dSAndroid Build Coastguard Worker# variable expansion.) 318*cda5da8dSAndroid Build Coastguard Worker 319*cda5da8dSAndroid Build Coastguard Workerdef expanduser(path): 320*cda5da8dSAndroid Build Coastguard Worker """Expand ~ and ~user constructs. 321*cda5da8dSAndroid Build Coastguard Worker 322*cda5da8dSAndroid Build Coastguard Worker If user or $HOME is unknown, do nothing.""" 323*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 324*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 325*cda5da8dSAndroid Build Coastguard Worker tilde = b'~' 326*cda5da8dSAndroid Build Coastguard Worker else: 327*cda5da8dSAndroid Build Coastguard Worker tilde = '~' 328*cda5da8dSAndroid Build Coastguard Worker if not path.startswith(tilde): 329*cda5da8dSAndroid Build Coastguard Worker return path 330*cda5da8dSAndroid Build Coastguard Worker i, n = 1, len(path) 331*cda5da8dSAndroid Build Coastguard Worker while i < n and path[i] not in _get_bothseps(path): 332*cda5da8dSAndroid Build Coastguard Worker i += 1 333*cda5da8dSAndroid Build Coastguard Worker 334*cda5da8dSAndroid Build Coastguard Worker if 'USERPROFILE' in os.environ: 335*cda5da8dSAndroid Build Coastguard Worker userhome = os.environ['USERPROFILE'] 336*cda5da8dSAndroid Build Coastguard Worker elif not 'HOMEPATH' in os.environ: 337*cda5da8dSAndroid Build Coastguard Worker return path 338*cda5da8dSAndroid Build Coastguard Worker else: 339*cda5da8dSAndroid Build Coastguard Worker try: 340*cda5da8dSAndroid Build Coastguard Worker drive = os.environ['HOMEDRIVE'] 341*cda5da8dSAndroid Build Coastguard Worker except KeyError: 342*cda5da8dSAndroid Build Coastguard Worker drive = '' 343*cda5da8dSAndroid Build Coastguard Worker userhome = join(drive, os.environ['HOMEPATH']) 344*cda5da8dSAndroid Build Coastguard Worker 345*cda5da8dSAndroid Build Coastguard Worker if i != 1: #~user 346*cda5da8dSAndroid Build Coastguard Worker target_user = path[1:i] 347*cda5da8dSAndroid Build Coastguard Worker if isinstance(target_user, bytes): 348*cda5da8dSAndroid Build Coastguard Worker target_user = os.fsdecode(target_user) 349*cda5da8dSAndroid Build Coastguard Worker current_user = os.environ.get('USERNAME') 350*cda5da8dSAndroid Build Coastguard Worker 351*cda5da8dSAndroid Build Coastguard Worker if target_user != current_user: 352*cda5da8dSAndroid Build Coastguard Worker # Try to guess user home directory. By default all user 353*cda5da8dSAndroid Build Coastguard Worker # profile directories are located in the same place and are 354*cda5da8dSAndroid Build Coastguard Worker # named by corresponding usernames. If userhome isn't a 355*cda5da8dSAndroid Build Coastguard Worker # normal profile directory, this guess is likely wrong, 356*cda5da8dSAndroid Build Coastguard Worker # so we bail out. 357*cda5da8dSAndroid Build Coastguard Worker if current_user != basename(userhome): 358*cda5da8dSAndroid Build Coastguard Worker return path 359*cda5da8dSAndroid Build Coastguard Worker userhome = join(dirname(userhome), target_user) 360*cda5da8dSAndroid Build Coastguard Worker 361*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 362*cda5da8dSAndroid Build Coastguard Worker userhome = os.fsencode(userhome) 363*cda5da8dSAndroid Build Coastguard Worker 364*cda5da8dSAndroid Build Coastguard Worker return userhome + path[i:] 365*cda5da8dSAndroid Build Coastguard Worker 366*cda5da8dSAndroid Build Coastguard Worker 367*cda5da8dSAndroid Build Coastguard Worker# Expand paths containing shell variable substitutions. 368*cda5da8dSAndroid Build Coastguard Worker# The following rules apply: 369*cda5da8dSAndroid Build Coastguard Worker# - no expansion within single quotes 370*cda5da8dSAndroid Build Coastguard Worker# - '$$' is translated into '$' 371*cda5da8dSAndroid Build Coastguard Worker# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2% 372*cda5da8dSAndroid Build Coastguard Worker# - ${varname} is accepted. 373*cda5da8dSAndroid Build Coastguard Worker# - $varname is accepted. 374*cda5da8dSAndroid Build Coastguard Worker# - %varname% is accepted. 375*cda5da8dSAndroid Build Coastguard Worker# - varnames can be made out of letters, digits and the characters '_-' 376*cda5da8dSAndroid Build Coastguard Worker# (though is not verified in the ${varname} and %varname% cases) 377*cda5da8dSAndroid Build Coastguard Worker# XXX With COMMAND.COM you can use any characters in a variable name, 378*cda5da8dSAndroid Build Coastguard Worker# XXX except '^|<>='. 379*cda5da8dSAndroid Build Coastguard Worker 380*cda5da8dSAndroid Build Coastguard Workerdef expandvars(path): 381*cda5da8dSAndroid Build Coastguard Worker """Expand shell variables of the forms $var, ${var} and %var%. 382*cda5da8dSAndroid Build Coastguard Worker 383*cda5da8dSAndroid Build Coastguard Worker Unknown variables are left unchanged.""" 384*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 385*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 386*cda5da8dSAndroid Build Coastguard Worker if b'$' not in path and b'%' not in path: 387*cda5da8dSAndroid Build Coastguard Worker return path 388*cda5da8dSAndroid Build Coastguard Worker import string 389*cda5da8dSAndroid Build Coastguard Worker varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii') 390*cda5da8dSAndroid Build Coastguard Worker quote = b'\'' 391*cda5da8dSAndroid Build Coastguard Worker percent = b'%' 392*cda5da8dSAndroid Build Coastguard Worker brace = b'{' 393*cda5da8dSAndroid Build Coastguard Worker rbrace = b'}' 394*cda5da8dSAndroid Build Coastguard Worker dollar = b'$' 395*cda5da8dSAndroid Build Coastguard Worker environ = getattr(os, 'environb', None) 396*cda5da8dSAndroid Build Coastguard Worker else: 397*cda5da8dSAndroid Build Coastguard Worker if '$' not in path and '%' not in path: 398*cda5da8dSAndroid Build Coastguard Worker return path 399*cda5da8dSAndroid Build Coastguard Worker import string 400*cda5da8dSAndroid Build Coastguard Worker varchars = string.ascii_letters + string.digits + '_-' 401*cda5da8dSAndroid Build Coastguard Worker quote = '\'' 402*cda5da8dSAndroid Build Coastguard Worker percent = '%' 403*cda5da8dSAndroid Build Coastguard Worker brace = '{' 404*cda5da8dSAndroid Build Coastguard Worker rbrace = '}' 405*cda5da8dSAndroid Build Coastguard Worker dollar = '$' 406*cda5da8dSAndroid Build Coastguard Worker environ = os.environ 407*cda5da8dSAndroid Build Coastguard Worker res = path[:0] 408*cda5da8dSAndroid Build Coastguard Worker index = 0 409*cda5da8dSAndroid Build Coastguard Worker pathlen = len(path) 410*cda5da8dSAndroid Build Coastguard Worker while index < pathlen: 411*cda5da8dSAndroid Build Coastguard Worker c = path[index:index+1] 412*cda5da8dSAndroid Build Coastguard Worker if c == quote: # no expansion within single quotes 413*cda5da8dSAndroid Build Coastguard Worker path = path[index + 1:] 414*cda5da8dSAndroid Build Coastguard Worker pathlen = len(path) 415*cda5da8dSAndroid Build Coastguard Worker try: 416*cda5da8dSAndroid Build Coastguard Worker index = path.index(c) 417*cda5da8dSAndroid Build Coastguard Worker res += c + path[:index + 1] 418*cda5da8dSAndroid Build Coastguard Worker except ValueError: 419*cda5da8dSAndroid Build Coastguard Worker res += c + path 420*cda5da8dSAndroid Build Coastguard Worker index = pathlen - 1 421*cda5da8dSAndroid Build Coastguard Worker elif c == percent: # variable or '%' 422*cda5da8dSAndroid Build Coastguard Worker if path[index + 1:index + 2] == percent: 423*cda5da8dSAndroid Build Coastguard Worker res += c 424*cda5da8dSAndroid Build Coastguard Worker index += 1 425*cda5da8dSAndroid Build Coastguard Worker else: 426*cda5da8dSAndroid Build Coastguard Worker path = path[index+1:] 427*cda5da8dSAndroid Build Coastguard Worker pathlen = len(path) 428*cda5da8dSAndroid Build Coastguard Worker try: 429*cda5da8dSAndroid Build Coastguard Worker index = path.index(percent) 430*cda5da8dSAndroid Build Coastguard Worker except ValueError: 431*cda5da8dSAndroid Build Coastguard Worker res += percent + path 432*cda5da8dSAndroid Build Coastguard Worker index = pathlen - 1 433*cda5da8dSAndroid Build Coastguard Worker else: 434*cda5da8dSAndroid Build Coastguard Worker var = path[:index] 435*cda5da8dSAndroid Build Coastguard Worker try: 436*cda5da8dSAndroid Build Coastguard Worker if environ is None: 437*cda5da8dSAndroid Build Coastguard Worker value = os.fsencode(os.environ[os.fsdecode(var)]) 438*cda5da8dSAndroid Build Coastguard Worker else: 439*cda5da8dSAndroid Build Coastguard Worker value = environ[var] 440*cda5da8dSAndroid Build Coastguard Worker except KeyError: 441*cda5da8dSAndroid Build Coastguard Worker value = percent + var + percent 442*cda5da8dSAndroid Build Coastguard Worker res += value 443*cda5da8dSAndroid Build Coastguard Worker elif c == dollar: # variable or '$$' 444*cda5da8dSAndroid Build Coastguard Worker if path[index + 1:index + 2] == dollar: 445*cda5da8dSAndroid Build Coastguard Worker res += c 446*cda5da8dSAndroid Build Coastguard Worker index += 1 447*cda5da8dSAndroid Build Coastguard Worker elif path[index + 1:index + 2] == brace: 448*cda5da8dSAndroid Build Coastguard Worker path = path[index+2:] 449*cda5da8dSAndroid Build Coastguard Worker pathlen = len(path) 450*cda5da8dSAndroid Build Coastguard Worker try: 451*cda5da8dSAndroid Build Coastguard Worker index = path.index(rbrace) 452*cda5da8dSAndroid Build Coastguard Worker except ValueError: 453*cda5da8dSAndroid Build Coastguard Worker res += dollar + brace + path 454*cda5da8dSAndroid Build Coastguard Worker index = pathlen - 1 455*cda5da8dSAndroid Build Coastguard Worker else: 456*cda5da8dSAndroid Build Coastguard Worker var = path[:index] 457*cda5da8dSAndroid Build Coastguard Worker try: 458*cda5da8dSAndroid Build Coastguard Worker if environ is None: 459*cda5da8dSAndroid Build Coastguard Worker value = os.fsencode(os.environ[os.fsdecode(var)]) 460*cda5da8dSAndroid Build Coastguard Worker else: 461*cda5da8dSAndroid Build Coastguard Worker value = environ[var] 462*cda5da8dSAndroid Build Coastguard Worker except KeyError: 463*cda5da8dSAndroid Build Coastguard Worker value = dollar + brace + var + rbrace 464*cda5da8dSAndroid Build Coastguard Worker res += value 465*cda5da8dSAndroid Build Coastguard Worker else: 466*cda5da8dSAndroid Build Coastguard Worker var = path[:0] 467*cda5da8dSAndroid Build Coastguard Worker index += 1 468*cda5da8dSAndroid Build Coastguard Worker c = path[index:index + 1] 469*cda5da8dSAndroid Build Coastguard Worker while c and c in varchars: 470*cda5da8dSAndroid Build Coastguard Worker var += c 471*cda5da8dSAndroid Build Coastguard Worker index += 1 472*cda5da8dSAndroid Build Coastguard Worker c = path[index:index + 1] 473*cda5da8dSAndroid Build Coastguard Worker try: 474*cda5da8dSAndroid Build Coastguard Worker if environ is None: 475*cda5da8dSAndroid Build Coastguard Worker value = os.fsencode(os.environ[os.fsdecode(var)]) 476*cda5da8dSAndroid Build Coastguard Worker else: 477*cda5da8dSAndroid Build Coastguard Worker value = environ[var] 478*cda5da8dSAndroid Build Coastguard Worker except KeyError: 479*cda5da8dSAndroid Build Coastguard Worker value = dollar + var 480*cda5da8dSAndroid Build Coastguard Worker res += value 481*cda5da8dSAndroid Build Coastguard Worker if c: 482*cda5da8dSAndroid Build Coastguard Worker index -= 1 483*cda5da8dSAndroid Build Coastguard Worker else: 484*cda5da8dSAndroid Build Coastguard Worker res += c 485*cda5da8dSAndroid Build Coastguard Worker index += 1 486*cda5da8dSAndroid Build Coastguard Worker return res 487*cda5da8dSAndroid Build Coastguard Worker 488*cda5da8dSAndroid Build Coastguard Worker 489*cda5da8dSAndroid Build Coastguard Worker# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B. 490*cda5da8dSAndroid Build Coastguard Worker# Previously, this function also truncated pathnames to 8+3 format, 491*cda5da8dSAndroid Build Coastguard Worker# but as this module is called "ntpath", that's obviously wrong! 492*cda5da8dSAndroid Build Coastguard Workertry: 493*cda5da8dSAndroid Build Coastguard Worker from nt import _path_normpath 494*cda5da8dSAndroid Build Coastguard Worker 495*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 496*cda5da8dSAndroid Build Coastguard Worker def normpath(path): 497*cda5da8dSAndroid Build Coastguard Worker """Normalize path, eliminating double slashes, etc.""" 498*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 499*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 500*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 501*cda5da8dSAndroid Build Coastguard Worker altsep = b'/' 502*cda5da8dSAndroid Build Coastguard Worker curdir = b'.' 503*cda5da8dSAndroid Build Coastguard Worker pardir = b'..' 504*cda5da8dSAndroid Build Coastguard Worker else: 505*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 506*cda5da8dSAndroid Build Coastguard Worker altsep = '/' 507*cda5da8dSAndroid Build Coastguard Worker curdir = '.' 508*cda5da8dSAndroid Build Coastguard Worker pardir = '..' 509*cda5da8dSAndroid Build Coastguard Worker path = path.replace(altsep, sep) 510*cda5da8dSAndroid Build Coastguard Worker prefix, path = splitdrive(path) 511*cda5da8dSAndroid Build Coastguard Worker 512*cda5da8dSAndroid Build Coastguard Worker # collapse initial backslashes 513*cda5da8dSAndroid Build Coastguard Worker if path.startswith(sep): 514*cda5da8dSAndroid Build Coastguard Worker prefix += sep 515*cda5da8dSAndroid Build Coastguard Worker path = path.lstrip(sep) 516*cda5da8dSAndroid Build Coastguard Worker 517*cda5da8dSAndroid Build Coastguard Worker comps = path.split(sep) 518*cda5da8dSAndroid Build Coastguard Worker i = 0 519*cda5da8dSAndroid Build Coastguard Worker while i < len(comps): 520*cda5da8dSAndroid Build Coastguard Worker if not comps[i] or comps[i] == curdir: 521*cda5da8dSAndroid Build Coastguard Worker del comps[i] 522*cda5da8dSAndroid Build Coastguard Worker elif comps[i] == pardir: 523*cda5da8dSAndroid Build Coastguard Worker if i > 0 and comps[i-1] != pardir: 524*cda5da8dSAndroid Build Coastguard Worker del comps[i-1:i+1] 525*cda5da8dSAndroid Build Coastguard Worker i -= 1 526*cda5da8dSAndroid Build Coastguard Worker elif i == 0 and prefix.endswith(sep): 527*cda5da8dSAndroid Build Coastguard Worker del comps[i] 528*cda5da8dSAndroid Build Coastguard Worker else: 529*cda5da8dSAndroid Build Coastguard Worker i += 1 530*cda5da8dSAndroid Build Coastguard Worker else: 531*cda5da8dSAndroid Build Coastguard Worker i += 1 532*cda5da8dSAndroid Build Coastguard Worker # If the path is now empty, substitute '.' 533*cda5da8dSAndroid Build Coastguard Worker if not prefix and not comps: 534*cda5da8dSAndroid Build Coastguard Worker comps.append(curdir) 535*cda5da8dSAndroid Build Coastguard Worker return prefix + sep.join(comps) 536*cda5da8dSAndroid Build Coastguard Worker 537*cda5da8dSAndroid Build Coastguard Workerelse: 538*cda5da8dSAndroid Build Coastguard Worker def normpath(path): 539*cda5da8dSAndroid Build Coastguard Worker """Normalize path, eliminating double slashes, etc.""" 540*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 541*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 542*cda5da8dSAndroid Build Coastguard Worker return os.fsencode(_path_normpath(os.fsdecode(path))) or b"." 543*cda5da8dSAndroid Build Coastguard Worker return _path_normpath(path) or "." 544*cda5da8dSAndroid Build Coastguard Worker 545*cda5da8dSAndroid Build Coastguard Worker 546*cda5da8dSAndroid Build Coastguard Workerdef _abspath_fallback(path): 547*cda5da8dSAndroid Build Coastguard Worker """Return the absolute version of a path as a fallback function in case 548*cda5da8dSAndroid Build Coastguard Worker `nt._getfullpathname` is not available or raises OSError. See bpo-31047 for 549*cda5da8dSAndroid Build Coastguard Worker more. 550*cda5da8dSAndroid Build Coastguard Worker 551*cda5da8dSAndroid Build Coastguard Worker """ 552*cda5da8dSAndroid Build Coastguard Worker 553*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 554*cda5da8dSAndroid Build Coastguard Worker if not isabs(path): 555*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 556*cda5da8dSAndroid Build Coastguard Worker cwd = os.getcwdb() 557*cda5da8dSAndroid Build Coastguard Worker else: 558*cda5da8dSAndroid Build Coastguard Worker cwd = os.getcwd() 559*cda5da8dSAndroid Build Coastguard Worker path = join(cwd, path) 560*cda5da8dSAndroid Build Coastguard Worker return normpath(path) 561*cda5da8dSAndroid Build Coastguard Worker 562*cda5da8dSAndroid Build Coastguard Worker# Return an absolute path. 563*cda5da8dSAndroid Build Coastguard Workertry: 564*cda5da8dSAndroid Build Coastguard Worker from nt import _getfullpathname 565*cda5da8dSAndroid Build Coastguard Worker 566*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: # not running on Windows - mock up something sensible 567*cda5da8dSAndroid Build Coastguard Worker abspath = _abspath_fallback 568*cda5da8dSAndroid Build Coastguard Worker 569*cda5da8dSAndroid Build Coastguard Workerelse: # use native Windows method on Windows 570*cda5da8dSAndroid Build Coastguard Worker def abspath(path): 571*cda5da8dSAndroid Build Coastguard Worker """Return the absolute version of a path.""" 572*cda5da8dSAndroid Build Coastguard Worker try: 573*cda5da8dSAndroid Build Coastguard Worker return _getfullpathname(normpath(path)) 574*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 575*cda5da8dSAndroid Build Coastguard Worker return _abspath_fallback(path) 576*cda5da8dSAndroid Build Coastguard Worker 577*cda5da8dSAndroid Build Coastguard Workertry: 578*cda5da8dSAndroid Build Coastguard Worker from nt import _getfinalpathname, readlink as _nt_readlink 579*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 580*cda5da8dSAndroid Build Coastguard Worker # realpath is a no-op on systems without _getfinalpathname support. 581*cda5da8dSAndroid Build Coastguard Worker realpath = abspath 582*cda5da8dSAndroid Build Coastguard Workerelse: 583*cda5da8dSAndroid Build Coastguard Worker def _readlink_deep(path): 584*cda5da8dSAndroid Build Coastguard Worker # These error codes indicate that we should stop reading links and 585*cda5da8dSAndroid Build Coastguard Worker # return the path we currently have. 586*cda5da8dSAndroid Build Coastguard Worker # 1: ERROR_INVALID_FUNCTION 587*cda5da8dSAndroid Build Coastguard Worker # 2: ERROR_FILE_NOT_FOUND 588*cda5da8dSAndroid Build Coastguard Worker # 3: ERROR_DIRECTORY_NOT_FOUND 589*cda5da8dSAndroid Build Coastguard Worker # 5: ERROR_ACCESS_DENIED 590*cda5da8dSAndroid Build Coastguard Worker # 21: ERROR_NOT_READY (implies drive with no media) 591*cda5da8dSAndroid Build Coastguard Worker # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file) 592*cda5da8dSAndroid Build Coastguard Worker # 50: ERROR_NOT_SUPPORTED (implies no support for reparse points) 593*cda5da8dSAndroid Build Coastguard Worker # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) 594*cda5da8dSAndroid Build Coastguard Worker # 87: ERROR_INVALID_PARAMETER 595*cda5da8dSAndroid Build Coastguard Worker # 4390: ERROR_NOT_A_REPARSE_POINT 596*cda5da8dSAndroid Build Coastguard Worker # 4392: ERROR_INVALID_REPARSE_DATA 597*cda5da8dSAndroid Build Coastguard Worker # 4393: ERROR_REPARSE_TAG_INVALID 598*cda5da8dSAndroid Build Coastguard Worker allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 67, 87, 4390, 4392, 4393 599*cda5da8dSAndroid Build Coastguard Worker 600*cda5da8dSAndroid Build Coastguard Worker seen = set() 601*cda5da8dSAndroid Build Coastguard Worker while normcase(path) not in seen: 602*cda5da8dSAndroid Build Coastguard Worker seen.add(normcase(path)) 603*cda5da8dSAndroid Build Coastguard Worker try: 604*cda5da8dSAndroid Build Coastguard Worker old_path = path 605*cda5da8dSAndroid Build Coastguard Worker path = _nt_readlink(path) 606*cda5da8dSAndroid Build Coastguard Worker # Links may be relative, so resolve them against their 607*cda5da8dSAndroid Build Coastguard Worker # own location 608*cda5da8dSAndroid Build Coastguard Worker if not isabs(path): 609*cda5da8dSAndroid Build Coastguard Worker # If it's something other than a symlink, we don't know 610*cda5da8dSAndroid Build Coastguard Worker # what it's actually going to be resolved against, so 611*cda5da8dSAndroid Build Coastguard Worker # just return the old path. 612*cda5da8dSAndroid Build Coastguard Worker if not islink(old_path): 613*cda5da8dSAndroid Build Coastguard Worker path = old_path 614*cda5da8dSAndroid Build Coastguard Worker break 615*cda5da8dSAndroid Build Coastguard Worker path = normpath(join(dirname(old_path), path)) 616*cda5da8dSAndroid Build Coastguard Worker except OSError as ex: 617*cda5da8dSAndroid Build Coastguard Worker if ex.winerror in allowed_winerror: 618*cda5da8dSAndroid Build Coastguard Worker break 619*cda5da8dSAndroid Build Coastguard Worker raise 620*cda5da8dSAndroid Build Coastguard Worker except ValueError: 621*cda5da8dSAndroid Build Coastguard Worker # Stop on reparse points that are not symlinks 622*cda5da8dSAndroid Build Coastguard Worker break 623*cda5da8dSAndroid Build Coastguard Worker return path 624*cda5da8dSAndroid Build Coastguard Worker 625*cda5da8dSAndroid Build Coastguard Worker def _getfinalpathname_nonstrict(path): 626*cda5da8dSAndroid Build Coastguard Worker # These error codes indicate that we should stop resolving the path 627*cda5da8dSAndroid Build Coastguard Worker # and return the value we currently have. 628*cda5da8dSAndroid Build Coastguard Worker # 1: ERROR_INVALID_FUNCTION 629*cda5da8dSAndroid Build Coastguard Worker # 2: ERROR_FILE_NOT_FOUND 630*cda5da8dSAndroid Build Coastguard Worker # 3: ERROR_DIRECTORY_NOT_FOUND 631*cda5da8dSAndroid Build Coastguard Worker # 5: ERROR_ACCESS_DENIED 632*cda5da8dSAndroid Build Coastguard Worker # 21: ERROR_NOT_READY (implies drive with no media) 633*cda5da8dSAndroid Build Coastguard Worker # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file) 634*cda5da8dSAndroid Build Coastguard Worker # 50: ERROR_NOT_SUPPORTED 635*cda5da8dSAndroid Build Coastguard Worker # 53: ERROR_BAD_NETPATH 636*cda5da8dSAndroid Build Coastguard Worker # 65: ERROR_NETWORK_ACCESS_DENIED 637*cda5da8dSAndroid Build Coastguard Worker # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) 638*cda5da8dSAndroid Build Coastguard Worker # 87: ERROR_INVALID_PARAMETER 639*cda5da8dSAndroid Build Coastguard Worker # 123: ERROR_INVALID_NAME 640*cda5da8dSAndroid Build Coastguard Worker # 161: ERROR_BAD_PATHNAME 641*cda5da8dSAndroid Build Coastguard Worker # 1920: ERROR_CANT_ACCESS_FILE 642*cda5da8dSAndroid Build Coastguard Worker # 1921: ERROR_CANT_RESOLVE_FILENAME (implies unfollowable symlink) 643*cda5da8dSAndroid Build Coastguard Worker allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 53, 65, 67, 87, 123, 161, 1920, 1921 644*cda5da8dSAndroid Build Coastguard Worker 645*cda5da8dSAndroid Build Coastguard Worker # Non-strict algorithm is to find as much of the target directory 646*cda5da8dSAndroid Build Coastguard Worker # as we can and join the rest. 647*cda5da8dSAndroid Build Coastguard Worker tail = path[:0] 648*cda5da8dSAndroid Build Coastguard Worker while path: 649*cda5da8dSAndroid Build Coastguard Worker try: 650*cda5da8dSAndroid Build Coastguard Worker path = _getfinalpathname(path) 651*cda5da8dSAndroid Build Coastguard Worker return join(path, tail) if tail else path 652*cda5da8dSAndroid Build Coastguard Worker except OSError as ex: 653*cda5da8dSAndroid Build Coastguard Worker if ex.winerror not in allowed_winerror: 654*cda5da8dSAndroid Build Coastguard Worker raise 655*cda5da8dSAndroid Build Coastguard Worker try: 656*cda5da8dSAndroid Build Coastguard Worker # The OS could not resolve this path fully, so we attempt 657*cda5da8dSAndroid Build Coastguard Worker # to follow the link ourselves. If we succeed, join the tail 658*cda5da8dSAndroid Build Coastguard Worker # and return. 659*cda5da8dSAndroid Build Coastguard Worker new_path = _readlink_deep(path) 660*cda5da8dSAndroid Build Coastguard Worker if new_path != path: 661*cda5da8dSAndroid Build Coastguard Worker return join(new_path, tail) if tail else new_path 662*cda5da8dSAndroid Build Coastguard Worker except OSError: 663*cda5da8dSAndroid Build Coastguard Worker # If we fail to readlink(), let's keep traversing 664*cda5da8dSAndroid Build Coastguard Worker pass 665*cda5da8dSAndroid Build Coastguard Worker path, name = split(path) 666*cda5da8dSAndroid Build Coastguard Worker # TODO (bpo-38186): Request the real file name from the directory 667*cda5da8dSAndroid Build Coastguard Worker # entry using FindFirstFileW. For now, we will return the path 668*cda5da8dSAndroid Build Coastguard Worker # as best we have it 669*cda5da8dSAndroid Build Coastguard Worker if path and not name: 670*cda5da8dSAndroid Build Coastguard Worker return path + tail 671*cda5da8dSAndroid Build Coastguard Worker tail = join(name, tail) if tail else name 672*cda5da8dSAndroid Build Coastguard Worker return tail 673*cda5da8dSAndroid Build Coastguard Worker 674*cda5da8dSAndroid Build Coastguard Worker def realpath(path, *, strict=False): 675*cda5da8dSAndroid Build Coastguard Worker path = normpath(path) 676*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 677*cda5da8dSAndroid Build Coastguard Worker prefix = b'\\\\?\\' 678*cda5da8dSAndroid Build Coastguard Worker unc_prefix = b'\\\\?\\UNC\\' 679*cda5da8dSAndroid Build Coastguard Worker new_unc_prefix = b'\\\\' 680*cda5da8dSAndroid Build Coastguard Worker cwd = os.getcwdb() 681*cda5da8dSAndroid Build Coastguard Worker # bpo-38081: Special case for realpath(b'nul') 682*cda5da8dSAndroid Build Coastguard Worker if normcase(path) == normcase(os.fsencode(devnull)): 683*cda5da8dSAndroid Build Coastguard Worker return b'\\\\.\\NUL' 684*cda5da8dSAndroid Build Coastguard Worker else: 685*cda5da8dSAndroid Build Coastguard Worker prefix = '\\\\?\\' 686*cda5da8dSAndroid Build Coastguard Worker unc_prefix = '\\\\?\\UNC\\' 687*cda5da8dSAndroid Build Coastguard Worker new_unc_prefix = '\\\\' 688*cda5da8dSAndroid Build Coastguard Worker cwd = os.getcwd() 689*cda5da8dSAndroid Build Coastguard Worker # bpo-38081: Special case for realpath('nul') 690*cda5da8dSAndroid Build Coastguard Worker if normcase(path) == normcase(devnull): 691*cda5da8dSAndroid Build Coastguard Worker return '\\\\.\\NUL' 692*cda5da8dSAndroid Build Coastguard Worker had_prefix = path.startswith(prefix) 693*cda5da8dSAndroid Build Coastguard Worker if not had_prefix and not isabs(path): 694*cda5da8dSAndroid Build Coastguard Worker path = join(cwd, path) 695*cda5da8dSAndroid Build Coastguard Worker try: 696*cda5da8dSAndroid Build Coastguard Worker path = _getfinalpathname(path) 697*cda5da8dSAndroid Build Coastguard Worker initial_winerror = 0 698*cda5da8dSAndroid Build Coastguard Worker except OSError as ex: 699*cda5da8dSAndroid Build Coastguard Worker if strict: 700*cda5da8dSAndroid Build Coastguard Worker raise 701*cda5da8dSAndroid Build Coastguard Worker initial_winerror = ex.winerror 702*cda5da8dSAndroid Build Coastguard Worker path = _getfinalpathname_nonstrict(path) 703*cda5da8dSAndroid Build Coastguard Worker # The path returned by _getfinalpathname will always start with \\?\ - 704*cda5da8dSAndroid Build Coastguard Worker # strip off that prefix unless it was already provided on the original 705*cda5da8dSAndroid Build Coastguard Worker # path. 706*cda5da8dSAndroid Build Coastguard Worker if not had_prefix and path.startswith(prefix): 707*cda5da8dSAndroid Build Coastguard Worker # For UNC paths, the prefix will actually be \\?\UNC\ 708*cda5da8dSAndroid Build Coastguard Worker # Handle that case as well. 709*cda5da8dSAndroid Build Coastguard Worker if path.startswith(unc_prefix): 710*cda5da8dSAndroid Build Coastguard Worker spath = new_unc_prefix + path[len(unc_prefix):] 711*cda5da8dSAndroid Build Coastguard Worker else: 712*cda5da8dSAndroid Build Coastguard Worker spath = path[len(prefix):] 713*cda5da8dSAndroid Build Coastguard Worker # Ensure that the non-prefixed path resolves to the same path 714*cda5da8dSAndroid Build Coastguard Worker try: 715*cda5da8dSAndroid Build Coastguard Worker if _getfinalpathname(spath) == path: 716*cda5da8dSAndroid Build Coastguard Worker path = spath 717*cda5da8dSAndroid Build Coastguard Worker except OSError as ex: 718*cda5da8dSAndroid Build Coastguard Worker # If the path does not exist and originally did not exist, then 719*cda5da8dSAndroid Build Coastguard Worker # strip the prefix anyway. 720*cda5da8dSAndroid Build Coastguard Worker if ex.winerror == initial_winerror: 721*cda5da8dSAndroid Build Coastguard Worker path = spath 722*cda5da8dSAndroid Build Coastguard Worker return path 723*cda5da8dSAndroid Build Coastguard Worker 724*cda5da8dSAndroid Build Coastguard Worker 725*cda5da8dSAndroid Build Coastguard Worker# Win9x family and earlier have no Unicode filename support. 726*cda5da8dSAndroid Build Coastguard Workersupports_unicode_filenames = (hasattr(sys, "getwindowsversion") and 727*cda5da8dSAndroid Build Coastguard Worker sys.getwindowsversion()[3] >= 2) 728*cda5da8dSAndroid Build Coastguard Worker 729*cda5da8dSAndroid Build Coastguard Workerdef relpath(path, start=None): 730*cda5da8dSAndroid Build Coastguard Worker """Return a relative version of a path""" 731*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 732*cda5da8dSAndroid Build Coastguard Worker if isinstance(path, bytes): 733*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 734*cda5da8dSAndroid Build Coastguard Worker curdir = b'.' 735*cda5da8dSAndroid Build Coastguard Worker pardir = b'..' 736*cda5da8dSAndroid Build Coastguard Worker else: 737*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 738*cda5da8dSAndroid Build Coastguard Worker curdir = '.' 739*cda5da8dSAndroid Build Coastguard Worker pardir = '..' 740*cda5da8dSAndroid Build Coastguard Worker 741*cda5da8dSAndroid Build Coastguard Worker if start is None: 742*cda5da8dSAndroid Build Coastguard Worker start = curdir 743*cda5da8dSAndroid Build Coastguard Worker 744*cda5da8dSAndroid Build Coastguard Worker if not path: 745*cda5da8dSAndroid Build Coastguard Worker raise ValueError("no path specified") 746*cda5da8dSAndroid Build Coastguard Worker 747*cda5da8dSAndroid Build Coastguard Worker start = os.fspath(start) 748*cda5da8dSAndroid Build Coastguard Worker try: 749*cda5da8dSAndroid Build Coastguard Worker start_abs = abspath(normpath(start)) 750*cda5da8dSAndroid Build Coastguard Worker path_abs = abspath(normpath(path)) 751*cda5da8dSAndroid Build Coastguard Worker start_drive, start_rest = splitdrive(start_abs) 752*cda5da8dSAndroid Build Coastguard Worker path_drive, path_rest = splitdrive(path_abs) 753*cda5da8dSAndroid Build Coastguard Worker if normcase(start_drive) != normcase(path_drive): 754*cda5da8dSAndroid Build Coastguard Worker raise ValueError("path is on mount %r, start on mount %r" % ( 755*cda5da8dSAndroid Build Coastguard Worker path_drive, start_drive)) 756*cda5da8dSAndroid Build Coastguard Worker 757*cda5da8dSAndroid Build Coastguard Worker start_list = [x for x in start_rest.split(sep) if x] 758*cda5da8dSAndroid Build Coastguard Worker path_list = [x for x in path_rest.split(sep) if x] 759*cda5da8dSAndroid Build Coastguard Worker # Work out how much of the filepath is shared by start and path. 760*cda5da8dSAndroid Build Coastguard Worker i = 0 761*cda5da8dSAndroid Build Coastguard Worker for e1, e2 in zip(start_list, path_list): 762*cda5da8dSAndroid Build Coastguard Worker if normcase(e1) != normcase(e2): 763*cda5da8dSAndroid Build Coastguard Worker break 764*cda5da8dSAndroid Build Coastguard Worker i += 1 765*cda5da8dSAndroid Build Coastguard Worker 766*cda5da8dSAndroid Build Coastguard Worker rel_list = [pardir] * (len(start_list)-i) + path_list[i:] 767*cda5da8dSAndroid Build Coastguard Worker if not rel_list: 768*cda5da8dSAndroid Build Coastguard Worker return curdir 769*cda5da8dSAndroid Build Coastguard Worker return join(*rel_list) 770*cda5da8dSAndroid Build Coastguard Worker except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning): 771*cda5da8dSAndroid Build Coastguard Worker genericpath._check_arg_types('relpath', path, start) 772*cda5da8dSAndroid Build Coastguard Worker raise 773*cda5da8dSAndroid Build Coastguard Worker 774*cda5da8dSAndroid Build Coastguard Worker 775*cda5da8dSAndroid Build Coastguard Worker# Return the longest common sub-path of the sequence of paths given as input. 776*cda5da8dSAndroid Build Coastguard Worker# The function is case-insensitive and 'separator-insensitive', i.e. if the 777*cda5da8dSAndroid Build Coastguard Worker# only difference between two paths is the use of '\' versus '/' as separator, 778*cda5da8dSAndroid Build Coastguard Worker# they are deemed to be equal. 779*cda5da8dSAndroid Build Coastguard Worker# 780*cda5da8dSAndroid Build Coastguard Worker# However, the returned path will have the standard '\' separator (even if the 781*cda5da8dSAndroid Build Coastguard Worker# given paths had the alternative '/' separator) and will have the case of the 782*cda5da8dSAndroid Build Coastguard Worker# first path given in the sequence. Additionally, any trailing separator is 783*cda5da8dSAndroid Build Coastguard Worker# stripped from the returned path. 784*cda5da8dSAndroid Build Coastguard Worker 785*cda5da8dSAndroid Build Coastguard Workerdef commonpath(paths): 786*cda5da8dSAndroid Build Coastguard Worker """Given a sequence of path names, returns the longest common sub-path.""" 787*cda5da8dSAndroid Build Coastguard Worker 788*cda5da8dSAndroid Build Coastguard Worker if not paths: 789*cda5da8dSAndroid Build Coastguard Worker raise ValueError('commonpath() arg is an empty sequence') 790*cda5da8dSAndroid Build Coastguard Worker 791*cda5da8dSAndroid Build Coastguard Worker paths = tuple(map(os.fspath, paths)) 792*cda5da8dSAndroid Build Coastguard Worker if isinstance(paths[0], bytes): 793*cda5da8dSAndroid Build Coastguard Worker sep = b'\\' 794*cda5da8dSAndroid Build Coastguard Worker altsep = b'/' 795*cda5da8dSAndroid Build Coastguard Worker curdir = b'.' 796*cda5da8dSAndroid Build Coastguard Worker else: 797*cda5da8dSAndroid Build Coastguard Worker sep = '\\' 798*cda5da8dSAndroid Build Coastguard Worker altsep = '/' 799*cda5da8dSAndroid Build Coastguard Worker curdir = '.' 800*cda5da8dSAndroid Build Coastguard Worker 801*cda5da8dSAndroid Build Coastguard Worker try: 802*cda5da8dSAndroid Build Coastguard Worker drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths] 803*cda5da8dSAndroid Build Coastguard Worker split_paths = [p.split(sep) for d, p in drivesplits] 804*cda5da8dSAndroid Build Coastguard Worker 805*cda5da8dSAndroid Build Coastguard Worker try: 806*cda5da8dSAndroid Build Coastguard Worker isabs, = set(p[:1] == sep for d, p in drivesplits) 807*cda5da8dSAndroid Build Coastguard Worker except ValueError: 808*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Can't mix absolute and relative paths") from None 809*cda5da8dSAndroid Build Coastguard Worker 810*cda5da8dSAndroid Build Coastguard Worker # Check that all drive letters or UNC paths match. The check is made only 811*cda5da8dSAndroid Build Coastguard Worker # now otherwise type errors for mixing strings and bytes would not be 812*cda5da8dSAndroid Build Coastguard Worker # caught. 813*cda5da8dSAndroid Build Coastguard Worker if len(set(d for d, p in drivesplits)) != 1: 814*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Paths don't have the same drive") 815*cda5da8dSAndroid Build Coastguard Worker 816*cda5da8dSAndroid Build Coastguard Worker drive, path = splitdrive(paths[0].replace(altsep, sep)) 817*cda5da8dSAndroid Build Coastguard Worker common = path.split(sep) 818*cda5da8dSAndroid Build Coastguard Worker common = [c for c in common if c and c != curdir] 819*cda5da8dSAndroid Build Coastguard Worker 820*cda5da8dSAndroid Build Coastguard Worker split_paths = [[c for c in s if c and c != curdir] for s in split_paths] 821*cda5da8dSAndroid Build Coastguard Worker s1 = min(split_paths) 822*cda5da8dSAndroid Build Coastguard Worker s2 = max(split_paths) 823*cda5da8dSAndroid Build Coastguard Worker for i, c in enumerate(s1): 824*cda5da8dSAndroid Build Coastguard Worker if c != s2[i]: 825*cda5da8dSAndroid Build Coastguard Worker common = common[:i] 826*cda5da8dSAndroid Build Coastguard Worker break 827*cda5da8dSAndroid Build Coastguard Worker else: 828*cda5da8dSAndroid Build Coastguard Worker common = common[:len(s1)] 829*cda5da8dSAndroid Build Coastguard Worker 830*cda5da8dSAndroid Build Coastguard Worker prefix = drive + sep if isabs else drive 831*cda5da8dSAndroid Build Coastguard Worker return prefix + sep.join(common) 832*cda5da8dSAndroid Build Coastguard Worker except (TypeError, AttributeError): 833*cda5da8dSAndroid Build Coastguard Worker genericpath._check_arg_types('commonpath', *paths) 834*cda5da8dSAndroid Build Coastguard Worker raise 835*cda5da8dSAndroid Build Coastguard Worker 836*cda5da8dSAndroid Build Coastguard Worker 837*cda5da8dSAndroid Build Coastguard Workertry: 838*cda5da8dSAndroid Build Coastguard Worker # The genericpath.isdir implementation uses os.stat and checks the mode 839*cda5da8dSAndroid Build Coastguard Worker # attribute to tell whether or not the path is a directory. 840*cda5da8dSAndroid Build Coastguard Worker # This is overkill on Windows - just pass the path to GetFileAttributes 841*cda5da8dSAndroid Build Coastguard Worker # and check the attribute from there. 842*cda5da8dSAndroid Build Coastguard Worker from nt import _isdir as isdir 843*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 844*cda5da8dSAndroid Build Coastguard Worker # Use genericpath.isdir as imported above. 845*cda5da8dSAndroid Build Coastguard Worker pass 846