blob: 2182ec776cc50357ee1c17732fdb9be765768ca0 [file] [log] [blame]
Guido van Rossum15e22e11997-12-05 19:03:01 +00001# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
Tim Peters2344fae2001-01-15 00:50:52 +00002"""Common pathname manipulations, WindowsNT/95 version.
Guido van Rossum534972b1999-02-03 17:20:50 +00003
4Instead of importing this module directly, import os and refer to this
5module as os.path.
Guido van Rossum15e22e11997-12-05 19:03:01 +00006"""
Guido van Rossum555915a1994-02-24 11:32:59 +00007
Serhiy Storchaka34601982018-01-07 17:54:31 +02008# strings representing various path-related bits and pieces
9# These are primarily for export; internally, they are hardcoded.
10# Should be set before imports for resolving cyclic dependency.
11curdir = '.'
12pardir = '..'
13extsep = '.'
14sep = '\\'
15pathsep = ';'
16altsep = '/'
17defpath = '.;C:\\bin'
18devnull = 'nul'
19
Guido van Rossum555915a1994-02-24 11:32:59 +000020import os
Mark Hammond8696ebc2002-10-08 02:44:31 +000021import sys
Christian Heimes05e8be12008-02-23 18:30:17 +000022import stat
Guido van Rossumd8faa362007-04-27 19:54:29 +000023import genericpath
Thomas Wouters89f507f2006-12-13 04:49:30 +000024from genericpath import *
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000025
Skip Montanaro269b83b2001-02-06 01:07:02 +000026__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
27 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000028 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
Benjamin Petersond71ca412008-05-08 23:44:58 +000029 "ismount", "expanduser","expandvars","normpath","abspath",
Serhiy Storchaka9ed707e2017-01-13 20:55:05 +020030 "curdir","pardir","sep","pathsep","defpath","altsep",
Brian Curtind40e6f72010-07-08 21:39:08 +000031 "extsep","devnull","realpath","supports_unicode_filenames","relpath",
Serhiy Storchaka38220932015-03-31 15:31:53 +030032 "samefile", "sameopenfile", "samestat", "commonpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000033
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000034def _get_bothseps(path):
35 if isinstance(path, bytes):
36 return b'\\/'
37 else:
38 return '\\/'
39
Guido van Rossume2ad88c1997-08-12 14:46:58 +000040# Normalize the case of a pathname and map slashes to backslashes.
41# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000042# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000043
Guido van Rossum555915a1994-02-24 11:32:59 +000044def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000045 """Normalize case of pathname.
46
Guido van Rossum534972b1999-02-03 17:20:50 +000047 Makes all characters lowercase and all slashes into backslashes."""
Brett Cannon3f9183b2016-08-26 14:44:48 -070048 s = os.fspath(s)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030049 try:
50 if isinstance(s, bytes):
51 return s.replace(b'/', b'\\').lower()
52 else:
53 return s.replace('/', '\\').lower()
54 except (TypeError, AttributeError):
55 if not isinstance(s, (bytes, str)):
56 raise TypeError("normcase() argument must be str or bytes, "
57 "not %r" % s.__class__.__name__) from None
58 raise
Guido van Rossum555915a1994-02-24 11:32:59 +000059
Guido van Rossum77e1db31997-06-02 23:11:57 +000060
Fred Drakeef0b5dd2000-02-17 17:30:40 +000061# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000062# Trivial in Posix, harder on Windows.
63# For Windows it is absolute if it starts with a slash or backslash (current
64# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000065# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000066
67def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000068 """Test whether a path is absolute"""
Brett Cannon3f9183b2016-08-26 14:44:48 -070069 s = os.fspath(s)
Guido van Rossum15e22e11997-12-05 19:03:01 +000070 s = splitdrive(s)[1]
Serhiy Storchaka8518b792014-07-23 20:43:13 +030071 return len(s) > 0 and s[0] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000072
73
Guido van Rossum77e1db31997-06-02 23:11:57 +000074# Join two (or more) paths.
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020075def join(path, *paths):
Brett Cannon3f9183b2016-08-26 14:44:48 -070076 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030077 if isinstance(path, bytes):
78 sep = b'\\'
79 seps = b'\\/'
80 colon = b':'
81 else:
82 sep = '\\'
83 seps = '\\/'
84 colon = ':'
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030085 try:
Serhiy Storchaka5bfc03f2015-05-19 11:00:07 +030086 if not paths:
87 path[:0] + sep #23780: Ensure compatible data type even if p is null.
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030088 result_drive, result_path = splitdrive(path)
Brett Cannon3f9183b2016-08-26 14:44:48 -070089 for p in map(os.fspath, paths):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030090 p_drive, p_path = splitdrive(p)
91 if p_path and p_path[0] in seps:
92 # Second path is absolute
93 if p_drive or not result_drive:
94 result_drive = p_drive
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020095 result_path = p_path
96 continue
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030097 elif p_drive and p_drive != result_drive:
98 if p_drive.lower() != result_drive.lower():
99 # Different drives => ignore the first path entirely
100 result_drive = p_drive
101 result_path = p_path
102 continue
103 # Same drive in different case
104 result_drive = p_drive
105 # Second path is relative to the first
106 if result_path and result_path[-1] not in seps:
107 result_path = result_path + sep
108 result_path = result_path + p_path
109 ## add separator between UNC and non-absolute path
110 if (result_path and result_path[0] not in seps and
111 result_drive and result_drive[-1:] != colon):
112 return result_drive + sep + result_path
113 return result_drive + result_path
114 except (TypeError, AttributeError, BytesWarning):
115 genericpath._check_arg_types('join', path, *paths)
116 raise
Guido van Rossum555915a1994-02-24 11:32:59 +0000117
118
119# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000120# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000121# It is always true that drivespec + pathspec == p
122def splitdrive(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000123 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
124 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
125
126 If you assign
127 result = splitdrive(p)
128 It is always true that:
129 result[0] + result[1] == p
130
131 If the path contained a drive letter, drive_or_unc will contain everything
132 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
133
134 If the path contained a UNC path, the drive_or_unc will contain the host name
135 and share up to but not including the fourth directory separator character.
136 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
137
138 Paths cannot contain both a drive letter and a UNC path.
139
140 """
Brett Cannon3f9183b2016-08-26 14:44:48 -0700141 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300142 if len(p) >= 2:
143 if isinstance(p, bytes):
144 sep = b'\\'
145 altsep = b'/'
146 colon = b':'
147 else:
148 sep = '\\'
149 altsep = '/'
150 colon = ':'
151 normp = p.replace(altsep, sep)
Mark Hammond5a607a32009-05-06 08:04:54 +0000152 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
153 # is a UNC path:
154 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
155 # \\machine\mountpoint\directory\etc\...
156 # directory ^^^^^^^^^^^^^^^
157 index = normp.find(sep, 2)
158 if index == -1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300159 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000160 index2 = normp.find(sep, index + 1)
161 # a UNC path can't have two slashes in a row
162 # (after the initial two)
163 if index2 == index + 1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300164 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000165 if index2 == -1:
166 index2 = len(p)
167 return p[:index2], p[index2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300168 if normp[1:2] == colon:
Mark Hammond5a607a32009-05-06 08:04:54 +0000169 return p[:2], p[2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300170 return p[:0], p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000171
172
Guido van Rossum555915a1994-02-24 11:32:59 +0000173# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000174# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000175# join(head, tail) == p holds.
176# The resulting head won't end in '/' unless it is the root.
177
178def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000179 """Split a pathname.
180
181 Return tuple (head, tail) where tail is everything after the final slash.
182 Either part may be empty."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700183 p = os.fspath(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000184 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000185 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000186 # set i to index beyond p's last slash
187 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000188 while i and p[i-1] not in seps:
Georg Brandl599b65d2010-07-23 08:46:35 +0000189 i -= 1
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000190 head, tail = p[:i], p[i:] # now tail has no slashes
191 # remove trailing slashes from head, unless it's all slashes
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300192 head = head.rstrip(seps) or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000193 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000194
195
196# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000197# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000198# pathname component; the root is everything before that.
199# It is always true that root + ext == p.
200
201def splitext(p):
Brett Cannon3f9183b2016-08-26 14:44:48 -0700202 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300203 if isinstance(p, bytes):
204 return genericpath._splitext(p, b'\\', b'/', b'.')
205 else:
206 return genericpath._splitext(p, '\\', '/', '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000207splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000208
209
210# Return the tail (basename) part of a path.
211
212def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000213 """Returns the final component of a pathname"""
214 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000215
216
217# Return the head (dirname) part of a path.
218
219def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000220 """Returns the directory component of a pathname"""
221 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000222
Guido van Rossum555915a1994-02-24 11:32:59 +0000223# Is a path a symbolic link?
Brian Curtind40e6f72010-07-08 21:39:08 +0000224# This will always return false on systems where os.lstat doesn't exist.
Guido van Rossum555915a1994-02-24 11:32:59 +0000225
226def islink(path):
Brian Curtind40e6f72010-07-08 21:39:08 +0000227 """Test whether a path is a symbolic link.
Jesus Ceaf1af7052012-10-05 02:48:46 +0200228 This will always return false for Windows prior to 6.0.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000229 """
Brian Curtind40e6f72010-07-08 21:39:08 +0000230 try:
231 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200232 except (OSError, AttributeError):
Brian Curtind40e6f72010-07-08 21:39:08 +0000233 return False
234 return stat.S_ISLNK(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000235
Brian Curtind40e6f72010-07-08 21:39:08 +0000236# Being true for dangling symbolic links is also useful.
237
238def lexists(path):
239 """Test whether a path exists. Returns True for broken symbolic links"""
240 try:
241 st = os.lstat(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200242 except OSError:
Brian Curtind40e6f72010-07-08 21:39:08 +0000243 return False
244 return True
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000245
Tim Golden6b528062013-08-01 12:44:00 +0100246# Is a path a mount point?
247# Any drive letter root (eg c:\)
248# Any share UNC (eg \\server\share)
249# Any volume mounted on a filesystem folder
250#
251# No one method detects all three situations. Historically we've lexically
252# detected drive letter roots and share UNCs. The canonical approach to
253# detecting mounted volumes (querying the reparse tag) fails for the most
254# common case: drive letter roots. The alternative which uses GetVolumePathName
255# fails if the drive letter is the result of a SUBST.
256try:
257 from nt import _getvolumepathname
258except ImportError:
259 _getvolumepathname = None
Guido van Rossum555915a1994-02-24 11:32:59 +0000260def ismount(path):
Tim Golden6b528062013-08-01 12:44:00 +0100261 """Test whether a path is a mount point (a drive root, the root of a
262 share, or a mounted volume)"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700263 path = os.fspath(path)
Benjamin Peterson48e24782009-03-29 13:02:52 +0000264 seps = _get_bothseps(path)
Tim Golden6b528062013-08-01 12:44:00 +0100265 path = abspath(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000266 root, rest = splitdrive(path)
267 if root and root[0] in seps:
268 return (not rest) or (rest in seps)
Tim Golden6b528062013-08-01 12:44:00 +0100269 if rest in seps:
270 return True
271
272 if _getvolumepathname:
273 return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
274 else:
275 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000276
277
Guido van Rossum555915a1994-02-24 11:32:59 +0000278# Expand paths beginning with '~' or '~user'.
279# '~' means $HOME; '~user' means that user's home directory.
280# If the path doesn't begin with '~', or if the user or $HOME is unknown,
281# the path is returned unchanged (leaving error reporting to whatever
282# function is called with the expanded path as argument).
283# See also module 'glob' for expansion of *, ? and [...] in pathnames.
284# (A function should also be defined to do full *sh-style environment
285# variable expansion.)
286
287def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000288 """Expand ~ and ~user constructs.
289
290 If user or $HOME is unknown, do nothing."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700291 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000292 if isinstance(path, bytes):
293 tilde = b'~'
294 else:
295 tilde = '~'
296 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000297 return path
298 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000299 while i < n and path[i] not in _get_bothseps(path):
Georg Brandl599b65d2010-07-23 08:46:35 +0000300 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301
302 if 'HOME' in os.environ:
303 userhome = os.environ['HOME']
304 elif 'USERPROFILE' in os.environ:
305 userhome = os.environ['USERPROFILE']
306 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000307 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000308 else:
309 try:
310 drive = os.environ['HOMEDRIVE']
311 except KeyError:
312 drive = ''
313 userhome = join(drive, os.environ['HOMEPATH'])
314
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000315 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300316 userhome = os.fsencode(userhome)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000317
Guido van Rossumd8faa362007-04-27 19:54:29 +0000318 if i != 1: #~user
319 userhome = join(dirname(userhome), path[1:i])
320
Guido van Rossum15e22e11997-12-05 19:03:01 +0000321 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000322
323
324# Expand paths containing shell variable substitutions.
325# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000326# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000327# - '$$' is translated into '$'
328# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000329# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000330# - $varname is accepted.
331# - %varname% is accepted.
332# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melotti13925002011-03-16 11:05:33 +0200333# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000334# XXX With COMMAND.COM you can use any characters in a variable name,
335# XXX except '^|<>='.
336
Tim Peters2344fae2001-01-15 00:50:52 +0000337def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000338 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000339
340 Unknown variables are left unchanged."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700341 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000342 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300343 if b'$' not in path and b'%' not in path:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000344 return path
345 import string
346 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000347 quote = b'\''
348 percent = b'%'
349 brace = b'{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300350 rbrace = b'}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000351 dollar = b'$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200352 environ = getattr(os, 'environb', None)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000353 else:
354 if '$' not in path and '%' not in path:
355 return path
356 import string
357 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000358 quote = '\''
359 percent = '%'
360 brace = '{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300361 rbrace = '}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000362 dollar = '$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200363 environ = os.environ
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000364 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000365 index = 0
366 pathlen = len(path)
367 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000368 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000369 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000370 path = path[index + 1:]
371 pathlen = len(path)
372 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000373 index = path.index(c)
Georg Brandl599b65d2010-07-23 08:46:35 +0000374 res += c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000375 except ValueError:
Serhiy Storchaka1b87ae02015-03-25 16:40:15 +0200376 res += c + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000377 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000378 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000379 if path[index + 1:index + 2] == percent:
Georg Brandl599b65d2010-07-23 08:46:35 +0000380 res += c
381 index += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000382 else:
383 path = path[index+1:]
384 pathlen = len(path)
385 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000386 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000387 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000388 res += percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000389 index = pathlen - 1
390 else:
391 var = path[:index]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200392 try:
393 if environ is None:
394 value = os.fsencode(os.environ[os.fsdecode(var)])
395 else:
396 value = environ[var]
397 except KeyError:
398 value = percent + var + percent
Georg Brandl599b65d2010-07-23 08:46:35 +0000399 res += value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000400 elif c == dollar: # variable or '$$'
401 if path[index + 1:index + 2] == dollar:
Georg Brandl599b65d2010-07-23 08:46:35 +0000402 res += c
403 index += 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000404 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000405 path = path[index+2:]
406 pathlen = len(path)
407 try:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300408 index = path.index(rbrace)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000409 except ValueError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300410 res += dollar + brace + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000411 index = pathlen - 1
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200412 else:
413 var = path[:index]
414 try:
415 if environ is None:
416 value = os.fsencode(os.environ[os.fsdecode(var)])
417 else:
418 value = environ[var]
419 except KeyError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300420 value = dollar + brace + var + rbrace
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200421 res += value
Guido van Rossum15e22e11997-12-05 19:03:01 +0000422 else:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200423 var = path[:0]
Georg Brandl599b65d2010-07-23 08:46:35 +0000424 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000425 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000426 while c and c in varchars:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200427 var += c
Georg Brandl599b65d2010-07-23 08:46:35 +0000428 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000429 c = path[index:index + 1]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200430 try:
431 if environ is None:
432 value = os.fsencode(os.environ[os.fsdecode(var)])
433 else:
434 value = environ[var]
435 except KeyError:
436 value = dollar + var
Georg Brandl599b65d2010-07-23 08:46:35 +0000437 res += value
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000438 if c:
Georg Brandl599b65d2010-07-23 08:46:35 +0000439 index -= 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000440 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000441 res += c
442 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000443 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000444
445
Tim Peters54a14a32001-08-30 22:05:26 +0000446# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
Guido van Rossum3df7b5a1996-08-26 16:35:26 +0000447# Previously, this function also truncated pathnames to 8+3 format,
448# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000449
450def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000451 """Normalize path, eliminating double slashes, etc."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700452 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300453 if isinstance(path, bytes):
454 sep = b'\\'
455 altsep = b'/'
456 curdir = b'.'
457 pardir = b'..'
458 special_prefixes = (b'\\\\.\\', b'\\\\?\\')
459 else:
460 sep = '\\'
461 altsep = '/'
462 curdir = '.'
463 pardir = '..'
464 special_prefixes = ('\\\\.\\', '\\\\?\\')
Georg Brandlcfb68212010-07-31 21:40:15 +0000465 if path.startswith(special_prefixes):
466 # in the case of paths with these prefixes:
467 # \\.\ -> device names
468 # \\?\ -> literal paths
469 # do not do any normalization, but return the path unchanged
470 return path
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300471 path = path.replace(altsep, sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000472 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000473
474 # collapse initial backslashes
475 if path.startswith(sep):
Georg Brandl599b65d2010-07-23 08:46:35 +0000476 prefix += sep
Mark Hammond5a607a32009-05-06 08:04:54 +0000477 path = path.lstrip(sep)
478
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000479 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000480 i = 0
481 while i < len(comps):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300482 if not comps[i] or comps[i] == curdir:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000483 del comps[i]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300484 elif comps[i] == pardir:
485 if i > 0 and comps[i-1] != pardir:
Tim Peters54a14a32001-08-30 22:05:26 +0000486 del comps[i-1:i+1]
487 i -= 1
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300488 elif i == 0 and prefix.endswith(sep):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000489 del comps[i]
490 else:
491 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000492 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000493 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000494 # If the path is now empty, substitute '.'
495 if not prefix and not comps:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300496 comps.append(curdir)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000497 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000498
499
500# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501try:
502 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000503
Brett Cannoncd171c82013-07-04 17:43:24 -0400504except ImportError: # not running on Windows - mock up something sensible
Thomas Wouters477c8d52006-05-27 19:21:47 +0000505 def abspath(path):
506 """Return the absolute version of a path."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700507 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000508 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000509 if isinstance(path, bytes):
510 cwd = os.getcwdb()
511 else:
512 cwd = os.getcwd()
513 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000514 return normpath(path)
515
516else: # use native Windows method on Windows
517 def abspath(path):
518 """Return the absolute version of a path."""
519
520 if path: # Empty path must return current working directory.
Brett Cannon3f9183b2016-08-26 14:44:48 -0700521 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000522 try:
523 path = _getfullpathname(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200524 except OSError:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000525 pass # Bad path - return unchanged.
Florent Xiclunaad8c5ca2010-03-08 14:44:41 +0000526 elif isinstance(path, bytes):
527 path = os.getcwdb()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000528 else:
529 path = os.getcwd()
530 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000531
532# realpath is a no-op on systems without islink support
533realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000534# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000535supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
536 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000537
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300538def relpath(path, start=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000539 """Return a relative version of a path"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700540 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300541 if isinstance(path, bytes):
542 sep = b'\\'
543 curdir = b'.'
544 pardir = b'..'
545 else:
546 sep = '\\'
547 curdir = '.'
548 pardir = '..'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000549
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300550 if start is None:
551 start = curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000552
553 if not path:
554 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000555
Brett Cannon3f9183b2016-08-26 14:44:48 -0700556 start = os.fspath(start)
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300557 try:
558 start_abs = abspath(normpath(start))
559 path_abs = abspath(normpath(path))
560 start_drive, start_rest = splitdrive(start_abs)
561 path_drive, path_rest = splitdrive(path_abs)
562 if normcase(start_drive) != normcase(path_drive):
563 raise ValueError("path is on mount %r, start on mount %r" % (
564 path_drive, start_drive))
Mark Hammond5a607a32009-05-06 08:04:54 +0000565
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300566 start_list = [x for x in start_rest.split(sep) if x]
567 path_list = [x for x in path_rest.split(sep) if x]
568 # Work out how much of the filepath is shared by start and path.
569 i = 0
570 for e1, e2 in zip(start_list, path_list):
571 if normcase(e1) != normcase(e2):
572 break
573 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000574
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300575 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
576 if not rel_list:
577 return curdir
578 return join(*rel_list)
Serhiy Storchakae4f47082014-10-04 16:09:02 +0300579 except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300580 genericpath._check_arg_types('relpath', path, start)
581 raise
Brian Curtind40e6f72010-07-08 21:39:08 +0000582
583
Serhiy Storchaka38220932015-03-31 15:31:53 +0300584# Return the longest common sub-path of the sequence of paths given as input.
585# The function is case-insensitive and 'separator-insensitive', i.e. if the
586# only difference between two paths is the use of '\' versus '/' as separator,
587# they are deemed to be equal.
588#
589# However, the returned path will have the standard '\' separator (even if the
590# given paths had the alternative '/' separator) and will have the case of the
591# first path given in the sequence. Additionally, any trailing separator is
592# stripped from the returned path.
593
594def commonpath(paths):
595 """Given a sequence of path names, returns the longest common sub-path."""
596
597 if not paths:
598 raise ValueError('commonpath() arg is an empty sequence')
599
Brett Cannon3f9183b2016-08-26 14:44:48 -0700600 paths = tuple(map(os.fspath, paths))
Serhiy Storchaka38220932015-03-31 15:31:53 +0300601 if isinstance(paths[0], bytes):
602 sep = b'\\'
603 altsep = b'/'
604 curdir = b'.'
605 else:
606 sep = '\\'
607 altsep = '/'
608 curdir = '.'
609
610 try:
611 drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
612 split_paths = [p.split(sep) for d, p in drivesplits]
613
614 try:
615 isabs, = set(p[:1] == sep for d, p in drivesplits)
616 except ValueError:
617 raise ValueError("Can't mix absolute and relative paths") from None
618
619 # Check that all drive letters or UNC paths match. The check is made only
620 # now otherwise type errors for mixing strings and bytes would not be
621 # caught.
622 if len(set(d for d, p in drivesplits)) != 1:
623 raise ValueError("Paths don't have the same drive")
624
625 drive, path = splitdrive(paths[0].replace(altsep, sep))
626 common = path.split(sep)
627 common = [c for c in common if c and c != curdir]
628
629 split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
630 s1 = min(split_paths)
631 s2 = max(split_paths)
632 for i, c in enumerate(s1):
633 if c != s2[i]:
634 common = common[:i]
635 break
636 else:
637 common = common[:len(s1)]
638
639 prefix = drive + sep if isabs else drive
640 return prefix + sep.join(common)
641 except (TypeError, AttributeError):
642 genericpath._check_arg_types('commonpath', *paths)
643 raise
644
645
Brian Curtind40e6f72010-07-08 21:39:08 +0000646# determine if two files are in fact the same file
Brian Curtin0dac8082010-09-23 20:38:14 +0000647try:
Brian Curtine8e80422010-09-24 13:56:34 +0000648 # GetFinalPathNameByHandle is available starting with Windows 6.0.
649 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
650 if sys.getwindowsversion()[:2] >= (6, 0):
651 from nt import _getfinalpathname
652 else:
653 raise ImportError
654except (AttributeError, ImportError):
Brian Curtin0dac8082010-09-23 20:38:14 +0000655 # On Windows XP and earlier, two files are the same if their absolute
656 # pathnames are the same.
Brian Curtine8e80422010-09-24 13:56:34 +0000657 # Non-Windows operating systems fake this method with an XP
658 # approximation.
Brian Curtin0dac8082010-09-23 20:38:14 +0000659 def _getfinalpathname(f):
Ronald Oussoren6355c162011-05-06 17:11:07 +0200660 return normcase(abspath(f))
Brian Curtin0dac8082010-09-23 20:38:14 +0000661
Brian Curtin9c669cc2011-06-08 18:17:18 -0500662
663try:
664 # The genericpath.isdir implementation uses os.stat and checks the mode
665 # attribute to tell whether or not the path is a directory.
666 # This is overkill on Windows - just pass the path to GetFileAttributes
667 # and check the attribute from there.
Brian Curtin95d028f2011-06-09 09:10:38 -0500668 from nt import _isdir as isdir
Brett Cannoncd171c82013-07-04 17:43:24 -0400669except ImportError:
Brian Curtin95d028f2011-06-09 09:10:38 -0500670 # Use genericpath.isdir as imported above.
671 pass