blob: 10d3f2dc35ba8834311b2820f91670869e2d1a2d [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
8import os
Mark Hammond8696ebc2002-10-08 02:44:31 +00009import sys
Christian Heimes05e8be12008-02-23 18:30:17 +000010import stat
Guido van Rossumd8faa362007-04-27 19:54:29 +000011import genericpath
Thomas Wouters89f507f2006-12-13 04:49:30 +000012from genericpath import *
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000013
Skip Montanaro269b83b2001-02-06 01:07:02 +000014__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
15 "basename","dirname","commonprefix","getsize","getmtime",
Georg Brandlf0de6a12005-08-22 18:02:59 +000016 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
Benjamin Petersond71ca412008-05-08 23:44:58 +000017 "ismount", "expanduser","expandvars","normpath","abspath",
Serhiy Storchaka9ed707e2017-01-13 20:55:05 +020018 "curdir","pardir","sep","pathsep","defpath","altsep",
Brian Curtind40e6f72010-07-08 21:39:08 +000019 "extsep","devnull","realpath","supports_unicode_filenames","relpath",
Serhiy Storchaka38220932015-03-31 15:31:53 +030020 "samefile", "sameopenfile", "samestat", "commonpath"]
Guido van Rossum555915a1994-02-24 11:32:59 +000021
Skip Montanaro117910d2003-02-14 19:35:31 +000022# strings representing various path-related bits and pieces
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000023# These are primarily for export; internally, they are hardcoded.
Skip Montanaro117910d2003-02-14 19:35:31 +000024curdir = '.'
25pardir = '..'
26extsep = '.'
27sep = '\\'
28pathsep = ';'
Skip Montanaro9ddac3e2003-03-28 22:23:24 +000029altsep = '/'
Andrew MacIntyre437966c2003-02-17 09:17:50 +000030defpath = '.;C:\\bin'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000031devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000032
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000033def _get_bothseps(path):
34 if isinstance(path, bytes):
35 return b'\\/'
36 else:
37 return '\\/'
38
Guido van Rossume2ad88c1997-08-12 14:46:58 +000039# Normalize the case of a pathname and map slashes to backslashes.
40# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000041# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000042
Guido van Rossum555915a1994-02-24 11:32:59 +000043def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000044 """Normalize case of pathname.
45
Guido van Rossum534972b1999-02-03 17:20:50 +000046 Makes all characters lowercase and all slashes into backslashes."""
Brett Cannon3f9183b2016-08-26 14:44:48 -070047 s = os.fspath(s)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030048 try:
49 if isinstance(s, bytes):
50 return s.replace(b'/', b'\\').lower()
51 else:
52 return s.replace('/', '\\').lower()
53 except (TypeError, AttributeError):
54 if not isinstance(s, (bytes, str)):
55 raise TypeError("normcase() argument must be str or bytes, "
56 "not %r" % s.__class__.__name__) from None
57 raise
Guido van Rossum555915a1994-02-24 11:32:59 +000058
Guido van Rossum77e1db31997-06-02 23:11:57 +000059
Fred Drakeef0b5dd2000-02-17 17:30:40 +000060# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000061# Trivial in Posix, harder on Windows.
62# For Windows it is absolute if it starts with a slash or backslash (current
63# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000064# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000065
66def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000067 """Test whether a path is absolute"""
Brett Cannon3f9183b2016-08-26 14:44:48 -070068 s = os.fspath(s)
Guido van Rossum15e22e11997-12-05 19:03:01 +000069 s = splitdrive(s)[1]
Serhiy Storchaka8518b792014-07-23 20:43:13 +030070 return len(s) > 0 and s[0] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000071
72
Guido van Rossum77e1db31997-06-02 23:11:57 +000073# Join two (or more) paths.
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020074def join(path, *paths):
Brett Cannon3f9183b2016-08-26 14:44:48 -070075 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030076 if isinstance(path, bytes):
77 sep = b'\\'
78 seps = b'\\/'
79 colon = b':'
80 else:
81 sep = '\\'
82 seps = '\\/'
83 colon = ':'
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030084 try:
Serhiy Storchaka5bfc03f2015-05-19 11:00:07 +030085 if not paths:
86 path[:0] + sep #23780: Ensure compatible data type even if p is null.
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030087 result_drive, result_path = splitdrive(path)
Brett Cannon3f9183b2016-08-26 14:44:48 -070088 for p in map(os.fspath, paths):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030089 p_drive, p_path = splitdrive(p)
90 if p_path and p_path[0] in seps:
91 # Second path is absolute
92 if p_drive or not result_drive:
93 result_drive = p_drive
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020094 result_path = p_path
95 continue
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030096 elif p_drive and p_drive != result_drive:
97 if p_drive.lower() != result_drive.lower():
98 # Different drives => ignore the first path entirely
99 result_drive = p_drive
100 result_path = p_path
101 continue
102 # Same drive in different case
103 result_drive = p_drive
104 # Second path is relative to the first
105 if result_path and result_path[-1] not in seps:
106 result_path = result_path + sep
107 result_path = result_path + p_path
108 ## add separator between UNC and non-absolute path
109 if (result_path and result_path[0] not in seps and
110 result_drive and result_drive[-1:] != colon):
111 return result_drive + sep + result_path
112 return result_drive + result_path
113 except (TypeError, AttributeError, BytesWarning):
114 genericpath._check_arg_types('join', path, *paths)
115 raise
Guido van Rossum555915a1994-02-24 11:32:59 +0000116
117
118# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000119# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000120# It is always true that drivespec + pathspec == p
121def splitdrive(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000122 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
123 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
124
125 If you assign
126 result = splitdrive(p)
127 It is always true that:
128 result[0] + result[1] == p
129
130 If the path contained a drive letter, drive_or_unc will contain everything
131 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
132
133 If the path contained a UNC path, the drive_or_unc will contain the host name
134 and share up to but not including the fourth directory separator character.
135 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
136
137 Paths cannot contain both a drive letter and a UNC path.
138
139 """
Brett Cannon3f9183b2016-08-26 14:44:48 -0700140 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300141 if len(p) >= 2:
142 if isinstance(p, bytes):
143 sep = b'\\'
144 altsep = b'/'
145 colon = b':'
146 else:
147 sep = '\\'
148 altsep = '/'
149 colon = ':'
150 normp = p.replace(altsep, sep)
Mark Hammond5a607a32009-05-06 08:04:54 +0000151 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
152 # is a UNC path:
153 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
154 # \\machine\mountpoint\directory\etc\...
155 # directory ^^^^^^^^^^^^^^^
156 index = normp.find(sep, 2)
157 if index == -1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300158 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000159 index2 = normp.find(sep, index + 1)
160 # a UNC path can't have two slashes in a row
161 # (after the initial two)
162 if index2 == index + 1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300163 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000164 if index2 == -1:
165 index2 = len(p)
166 return p[:index2], p[index2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300167 if normp[1:2] == colon:
Mark Hammond5a607a32009-05-06 08:04:54 +0000168 return p[:2], p[2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300169 return p[:0], p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000170
171
Guido van Rossum555915a1994-02-24 11:32:59 +0000172# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000173# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000174# join(head, tail) == p holds.
175# The resulting head won't end in '/' unless it is the root.
176
177def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000178 """Split a pathname.
179
180 Return tuple (head, tail) where tail is everything after the final slash.
181 Either part may be empty."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700182 p = os.fspath(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000183 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000184 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000185 # set i to index beyond p's last slash
186 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000187 while i and p[i-1] not in seps:
Georg Brandl599b65d2010-07-23 08:46:35 +0000188 i -= 1
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000189 head, tail = p[:i], p[i:] # now tail has no slashes
190 # remove trailing slashes from head, unless it's all slashes
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300191 head = head.rstrip(seps) or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000192 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000193
194
195# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000196# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000197# pathname component; the root is everything before that.
198# It is always true that root + ext == p.
199
200def splitext(p):
Brett Cannon3f9183b2016-08-26 14:44:48 -0700201 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300202 if isinstance(p, bytes):
203 return genericpath._splitext(p, b'\\', b'/', b'.')
204 else:
205 return genericpath._splitext(p, '\\', '/', '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000206splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000207
208
209# Return the tail (basename) part of a path.
210
211def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000212 """Returns the final component of a pathname"""
213 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000214
215
216# Return the head (dirname) part of a path.
217
218def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000219 """Returns the directory component of a pathname"""
220 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000221
Guido van Rossum555915a1994-02-24 11:32:59 +0000222# Is a path a symbolic link?
Brian Curtind40e6f72010-07-08 21:39:08 +0000223# This will always return false on systems where os.lstat doesn't exist.
Guido van Rossum555915a1994-02-24 11:32:59 +0000224
225def islink(path):
Brian Curtind40e6f72010-07-08 21:39:08 +0000226 """Test whether a path is a symbolic link.
Jesus Ceaf1af7052012-10-05 02:48:46 +0200227 This will always return false for Windows prior to 6.0.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000228 """
Brian Curtind40e6f72010-07-08 21:39:08 +0000229 try:
230 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200231 except (OSError, AttributeError):
Brian Curtind40e6f72010-07-08 21:39:08 +0000232 return False
233 return stat.S_ISLNK(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000234
Brian Curtind40e6f72010-07-08 21:39:08 +0000235# Being true for dangling symbolic links is also useful.
236
237def lexists(path):
238 """Test whether a path exists. Returns True for broken symbolic links"""
239 try:
240 st = os.lstat(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200241 except OSError:
Brian Curtind40e6f72010-07-08 21:39:08 +0000242 return False
243 return True
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000244
Tim Golden6b528062013-08-01 12:44:00 +0100245# Is a path a mount point?
246# Any drive letter root (eg c:\)
247# Any share UNC (eg \\server\share)
248# Any volume mounted on a filesystem folder
249#
250# No one method detects all three situations. Historically we've lexically
251# detected drive letter roots and share UNCs. The canonical approach to
252# detecting mounted volumes (querying the reparse tag) fails for the most
253# common case: drive letter roots. The alternative which uses GetVolumePathName
254# fails if the drive letter is the result of a SUBST.
255try:
256 from nt import _getvolumepathname
257except ImportError:
258 _getvolumepathname = None
Guido van Rossum555915a1994-02-24 11:32:59 +0000259def ismount(path):
Tim Golden6b528062013-08-01 12:44:00 +0100260 """Test whether a path is a mount point (a drive root, the root of a
261 share, or a mounted volume)"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700262 path = os.fspath(path)
Benjamin Peterson48e24782009-03-29 13:02:52 +0000263 seps = _get_bothseps(path)
Tim Golden6b528062013-08-01 12:44:00 +0100264 path = abspath(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000265 root, rest = splitdrive(path)
266 if root and root[0] in seps:
267 return (not rest) or (rest in seps)
Tim Golden6b528062013-08-01 12:44:00 +0100268 if rest in seps:
269 return True
270
271 if _getvolumepathname:
272 return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
273 else:
274 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000275
276
Guido van Rossum555915a1994-02-24 11:32:59 +0000277# Expand paths beginning with '~' or '~user'.
278# '~' means $HOME; '~user' means that user's home directory.
279# If the path doesn't begin with '~', or if the user or $HOME is unknown,
280# the path is returned unchanged (leaving error reporting to whatever
281# function is called with the expanded path as argument).
282# See also module 'glob' for expansion of *, ? and [...] in pathnames.
283# (A function should also be defined to do full *sh-style environment
284# variable expansion.)
285
286def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000287 """Expand ~ and ~user constructs.
288
289 If user or $HOME is unknown, do nothing."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700290 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000291 if isinstance(path, bytes):
292 tilde = b'~'
293 else:
294 tilde = '~'
295 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000296 return path
297 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000298 while i < n and path[i] not in _get_bothseps(path):
Georg Brandl599b65d2010-07-23 08:46:35 +0000299 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000300
301 if 'HOME' in os.environ:
302 userhome = os.environ['HOME']
303 elif 'USERPROFILE' in os.environ:
304 userhome = os.environ['USERPROFILE']
305 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000306 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000307 else:
308 try:
309 drive = os.environ['HOMEDRIVE']
310 except KeyError:
311 drive = ''
312 userhome = join(drive, os.environ['HOMEPATH'])
313
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000314 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300315 userhome = os.fsencode(userhome)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000316
Guido van Rossumd8faa362007-04-27 19:54:29 +0000317 if i != 1: #~user
318 userhome = join(dirname(userhome), path[1:i])
319
Guido van Rossum15e22e11997-12-05 19:03:01 +0000320 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000321
322
323# Expand paths containing shell variable substitutions.
324# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000325# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000326# - '$$' is translated into '$'
327# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000328# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000329# - $varname is accepted.
330# - %varname% is accepted.
331# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melotti13925002011-03-16 11:05:33 +0200332# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000333# XXX With COMMAND.COM you can use any characters in a variable name,
334# XXX except '^|<>='.
335
Tim Peters2344fae2001-01-15 00:50:52 +0000336def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000337 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000338
339 Unknown variables are left unchanged."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700340 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000341 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300342 if b'$' not in path and b'%' not in path:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000343 return path
344 import string
345 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000346 quote = b'\''
347 percent = b'%'
348 brace = b'{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300349 rbrace = b'}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000350 dollar = b'$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200351 environ = getattr(os, 'environb', None)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000352 else:
353 if '$' not in path and '%' not in path:
354 return path
355 import string
356 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000357 quote = '\''
358 percent = '%'
359 brace = '{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300360 rbrace = '}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000361 dollar = '$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200362 environ = os.environ
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000363 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000364 index = 0
365 pathlen = len(path)
366 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000367 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000368 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000369 path = path[index + 1:]
370 pathlen = len(path)
371 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000372 index = path.index(c)
Georg Brandl599b65d2010-07-23 08:46:35 +0000373 res += c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000374 except ValueError:
Serhiy Storchaka1b87ae02015-03-25 16:40:15 +0200375 res += c + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000376 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000377 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000378 if path[index + 1:index + 2] == percent:
Georg Brandl599b65d2010-07-23 08:46:35 +0000379 res += c
380 index += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000381 else:
382 path = path[index+1:]
383 pathlen = len(path)
384 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000385 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000386 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000387 res += percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000388 index = pathlen - 1
389 else:
390 var = path[:index]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200391 try:
392 if environ is None:
393 value = os.fsencode(os.environ[os.fsdecode(var)])
394 else:
395 value = environ[var]
396 except KeyError:
397 value = percent + var + percent
Georg Brandl599b65d2010-07-23 08:46:35 +0000398 res += value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000399 elif c == dollar: # variable or '$$'
400 if path[index + 1:index + 2] == dollar:
Georg Brandl599b65d2010-07-23 08:46:35 +0000401 res += c
402 index += 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000403 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000404 path = path[index+2:]
405 pathlen = len(path)
406 try:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300407 index = path.index(rbrace)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000408 except ValueError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300409 res += dollar + brace + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000410 index = pathlen - 1
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200411 else:
412 var = path[:index]
413 try:
414 if environ is None:
415 value = os.fsencode(os.environ[os.fsdecode(var)])
416 else:
417 value = environ[var]
418 except KeyError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300419 value = dollar + brace + var + rbrace
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200420 res += value
Guido van Rossum15e22e11997-12-05 19:03:01 +0000421 else:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200422 var = path[:0]
Georg Brandl599b65d2010-07-23 08:46:35 +0000423 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000424 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000425 while c and c in varchars:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200426 var += c
Georg Brandl599b65d2010-07-23 08:46:35 +0000427 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000428 c = path[index:index + 1]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200429 try:
430 if environ is None:
431 value = os.fsencode(os.environ[os.fsdecode(var)])
432 else:
433 value = environ[var]
434 except KeyError:
435 value = dollar + var
Georg Brandl599b65d2010-07-23 08:46:35 +0000436 res += value
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000437 if c:
Georg Brandl599b65d2010-07-23 08:46:35 +0000438 index -= 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000439 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000440 res += c
441 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000442 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000443
444
Tim Peters54a14a32001-08-30 22:05:26 +0000445# 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 +0000446# Previously, this function also truncated pathnames to 8+3 format,
447# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000448
449def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000450 """Normalize path, eliminating double slashes, etc."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700451 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300452 if isinstance(path, bytes):
453 sep = b'\\'
454 altsep = b'/'
455 curdir = b'.'
456 pardir = b'..'
457 special_prefixes = (b'\\\\.\\', b'\\\\?\\')
458 else:
459 sep = '\\'
460 altsep = '/'
461 curdir = '.'
462 pardir = '..'
463 special_prefixes = ('\\\\.\\', '\\\\?\\')
Georg Brandlcfb68212010-07-31 21:40:15 +0000464 if path.startswith(special_prefixes):
465 # in the case of paths with these prefixes:
466 # \\.\ -> device names
467 # \\?\ -> literal paths
468 # do not do any normalization, but return the path unchanged
469 return path
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300470 path = path.replace(altsep, sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000471 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000472
473 # collapse initial backslashes
474 if path.startswith(sep):
Georg Brandl599b65d2010-07-23 08:46:35 +0000475 prefix += sep
Mark Hammond5a607a32009-05-06 08:04:54 +0000476 path = path.lstrip(sep)
477
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000478 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000479 i = 0
480 while i < len(comps):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300481 if not comps[i] or comps[i] == curdir:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000482 del comps[i]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300483 elif comps[i] == pardir:
484 if i > 0 and comps[i-1] != pardir:
Tim Peters54a14a32001-08-30 22:05:26 +0000485 del comps[i-1:i+1]
486 i -= 1
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300487 elif i == 0 and prefix.endswith(sep):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000488 del comps[i]
489 else:
490 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000491 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000492 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000493 # If the path is now empty, substitute '.'
494 if not prefix and not comps:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300495 comps.append(curdir)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000496 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000497
498
499# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500try:
501 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000502
Brett Cannoncd171c82013-07-04 17:43:24 -0400503except ImportError: # not running on Windows - mock up something sensible
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504 def abspath(path):
505 """Return the absolute version of a path."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700506 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000507 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000508 if isinstance(path, bytes):
509 cwd = os.getcwdb()
510 else:
511 cwd = os.getcwd()
512 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000513 return normpath(path)
514
515else: # use native Windows method on Windows
516 def abspath(path):
517 """Return the absolute version of a path."""
518
519 if path: # Empty path must return current working directory.
Brett Cannon3f9183b2016-08-26 14:44:48 -0700520 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000521 try:
522 path = _getfullpathname(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200523 except OSError:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000524 pass # Bad path - return unchanged.
Florent Xiclunaad8c5ca2010-03-08 14:44:41 +0000525 elif isinstance(path, bytes):
526 path = os.getcwdb()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527 else:
528 path = os.getcwd()
529 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000530
531# realpath is a no-op on systems without islink support
532realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000533# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000534supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
535 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000536
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300537def relpath(path, start=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000538 """Return a relative version of a path"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700539 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300540 if isinstance(path, bytes):
541 sep = b'\\'
542 curdir = b'.'
543 pardir = b'..'
544 else:
545 sep = '\\'
546 curdir = '.'
547 pardir = '..'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000548
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300549 if start is None:
550 start = curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000551
552 if not path:
553 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000554
Brett Cannon3f9183b2016-08-26 14:44:48 -0700555 start = os.fspath(start)
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300556 try:
557 start_abs = abspath(normpath(start))
558 path_abs = abspath(normpath(path))
559 start_drive, start_rest = splitdrive(start_abs)
560 path_drive, path_rest = splitdrive(path_abs)
561 if normcase(start_drive) != normcase(path_drive):
562 raise ValueError("path is on mount %r, start on mount %r" % (
563 path_drive, start_drive))
Mark Hammond5a607a32009-05-06 08:04:54 +0000564
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300565 start_list = [x for x in start_rest.split(sep) if x]
566 path_list = [x for x in path_rest.split(sep) if x]
567 # Work out how much of the filepath is shared by start and path.
568 i = 0
569 for e1, e2 in zip(start_list, path_list):
570 if normcase(e1) != normcase(e2):
571 break
572 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000573
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300574 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
575 if not rel_list:
576 return curdir
577 return join(*rel_list)
Serhiy Storchakae4f47082014-10-04 16:09:02 +0300578 except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300579 genericpath._check_arg_types('relpath', path, start)
580 raise
Brian Curtind40e6f72010-07-08 21:39:08 +0000581
582
Serhiy Storchaka38220932015-03-31 15:31:53 +0300583# Return the longest common sub-path of the sequence of paths given as input.
584# The function is case-insensitive and 'separator-insensitive', i.e. if the
585# only difference between two paths is the use of '\' versus '/' as separator,
586# they are deemed to be equal.
587#
588# However, the returned path will have the standard '\' separator (even if the
589# given paths had the alternative '/' separator) and will have the case of the
590# first path given in the sequence. Additionally, any trailing separator is
591# stripped from the returned path.
592
593def commonpath(paths):
594 """Given a sequence of path names, returns the longest common sub-path."""
595
596 if not paths:
597 raise ValueError('commonpath() arg is an empty sequence')
598
Brett Cannon3f9183b2016-08-26 14:44:48 -0700599 paths = tuple(map(os.fspath, paths))
Serhiy Storchaka38220932015-03-31 15:31:53 +0300600 if isinstance(paths[0], bytes):
601 sep = b'\\'
602 altsep = b'/'
603 curdir = b'.'
604 else:
605 sep = '\\'
606 altsep = '/'
607 curdir = '.'
608
609 try:
610 drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
611 split_paths = [p.split(sep) for d, p in drivesplits]
612
613 try:
614 isabs, = set(p[:1] == sep for d, p in drivesplits)
615 except ValueError:
616 raise ValueError("Can't mix absolute and relative paths") from None
617
618 # Check that all drive letters or UNC paths match. The check is made only
619 # now otherwise type errors for mixing strings and bytes would not be
620 # caught.
621 if len(set(d for d, p in drivesplits)) != 1:
622 raise ValueError("Paths don't have the same drive")
623
624 drive, path = splitdrive(paths[0].replace(altsep, sep))
625 common = path.split(sep)
626 common = [c for c in common if c and c != curdir]
627
628 split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
629 s1 = min(split_paths)
630 s2 = max(split_paths)
631 for i, c in enumerate(s1):
632 if c != s2[i]:
633 common = common[:i]
634 break
635 else:
636 common = common[:len(s1)]
637
638 prefix = drive + sep if isabs else drive
639 return prefix + sep.join(common)
640 except (TypeError, AttributeError):
641 genericpath._check_arg_types('commonpath', *paths)
642 raise
643
644
Brian Curtind40e6f72010-07-08 21:39:08 +0000645# determine if two files are in fact the same file
Brian Curtin0dac8082010-09-23 20:38:14 +0000646try:
Brian Curtine8e80422010-09-24 13:56:34 +0000647 # GetFinalPathNameByHandle is available starting with Windows 6.0.
648 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
649 if sys.getwindowsversion()[:2] >= (6, 0):
650 from nt import _getfinalpathname
651 else:
652 raise ImportError
653except (AttributeError, ImportError):
Brian Curtin0dac8082010-09-23 20:38:14 +0000654 # On Windows XP and earlier, two files are the same if their absolute
655 # pathnames are the same.
Brian Curtine8e80422010-09-24 13:56:34 +0000656 # Non-Windows operating systems fake this method with an XP
657 # approximation.
Brian Curtin0dac8082010-09-23 20:38:14 +0000658 def _getfinalpathname(f):
Ronald Oussoren6355c162011-05-06 17:11:07 +0200659 return normcase(abspath(f))
Brian Curtin0dac8082010-09-23 20:38:14 +0000660
Brian Curtin9c669cc2011-06-08 18:17:18 -0500661
662try:
663 # The genericpath.isdir implementation uses os.stat and checks the mode
664 # attribute to tell whether or not the path is a directory.
665 # This is overkill on Windows - just pass the path to GetFileAttributes
666 # and check the attribute from there.
Brian Curtin95d028f2011-06-09 09:10:38 -0500667 from nt import _isdir as isdir
Brett Cannoncd171c82013-07-04 17:43:24 -0400668except ImportError:
Brian Curtin95d028f2011-06-09 09:10:38 -0500669 # Use genericpath.isdir as imported above.
670 pass