xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/ntpath.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
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