blob: 1fa4448426f890a774f5b2f7dd36066e86309e69 [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",
Georg Brandlf0de6a12005-08-22 18:02:59 +000018 "splitunc","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'
Skip Montanaro117910d2003-02-14 19:35:31 +000031if 'ce' in sys.builtin_module_names:
32 defpath = '\\Windows'
Martin v. Löwisbdec50f2004-06-08 08:29:33 +000033devnull = 'nul'
Skip Montanaro117910d2003-02-14 19:35:31 +000034
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000035def _get_bothseps(path):
36 if isinstance(path, bytes):
37 return b'\\/'
38 else:
39 return '\\/'
40
Guido van Rossume2ad88c1997-08-12 14:46:58 +000041# Normalize the case of a pathname and map slashes to backslashes.
42# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000043# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000044
Guido van Rossum555915a1994-02-24 11:32:59 +000045def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000046 """Normalize case of pathname.
47
Guido van Rossum534972b1999-02-03 17:20:50 +000048 Makes all characters lowercase and all slashes into backslashes."""
Brett Cannon3f9183b2016-08-26 14:44:48 -070049 s = os.fspath(s)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030050 try:
51 if isinstance(s, bytes):
52 return s.replace(b'/', b'\\').lower()
53 else:
54 return s.replace('/', '\\').lower()
55 except (TypeError, AttributeError):
56 if not isinstance(s, (bytes, str)):
57 raise TypeError("normcase() argument must be str or bytes, "
58 "not %r" % s.__class__.__name__) from None
59 raise
Guido van Rossum555915a1994-02-24 11:32:59 +000060
Guido van Rossum77e1db31997-06-02 23:11:57 +000061
Fred Drakeef0b5dd2000-02-17 17:30:40 +000062# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000063# Trivial in Posix, harder on Windows.
64# For Windows it is absolute if it starts with a slash or backslash (current
65# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000066# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000067
68def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000069 """Test whether a path is absolute"""
Brett Cannon3f9183b2016-08-26 14:44:48 -070070 s = os.fspath(s)
Guido van Rossum15e22e11997-12-05 19:03:01 +000071 s = splitdrive(s)[1]
Serhiy Storchaka8518b792014-07-23 20:43:13 +030072 return len(s) > 0 and s[0] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +000073
74
Guido van Rossum77e1db31997-06-02 23:11:57 +000075# Join two (or more) paths.
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020076def join(path, *paths):
Brett Cannon3f9183b2016-08-26 14:44:48 -070077 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +030078 if isinstance(path, bytes):
79 sep = b'\\'
80 seps = b'\\/'
81 colon = b':'
82 else:
83 sep = '\\'
84 seps = '\\/'
85 colon = ':'
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030086 try:
Serhiy Storchaka5bfc03f2015-05-19 11:00:07 +030087 if not paths:
88 path[:0] + sep #23780: Ensure compatible data type even if p is null.
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030089 result_drive, result_path = splitdrive(path)
Brett Cannon3f9183b2016-08-26 14:44:48 -070090 for p in map(os.fspath, paths):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030091 p_drive, p_path = splitdrive(p)
92 if p_path and p_path[0] in seps:
93 # Second path is absolute
94 if p_drive or not result_drive:
95 result_drive = p_drive
Serhiy Storchakac369c2c2014-01-27 23:15:14 +020096 result_path = p_path
97 continue
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +030098 elif p_drive and p_drive != result_drive:
99 if p_drive.lower() != result_drive.lower():
100 # Different drives => ignore the first path entirely
101 result_drive = p_drive
102 result_path = p_path
103 continue
104 # Same drive in different case
105 result_drive = p_drive
106 # Second path is relative to the first
107 if result_path and result_path[-1] not in seps:
108 result_path = result_path + sep
109 result_path = result_path + p_path
110 ## add separator between UNC and non-absolute path
111 if (result_path and result_path[0] not in seps and
112 result_drive and result_drive[-1:] != colon):
113 return result_drive + sep + result_path
114 return result_drive + result_path
115 except (TypeError, AttributeError, BytesWarning):
116 genericpath._check_arg_types('join', path, *paths)
117 raise
Guido van Rossum555915a1994-02-24 11:32:59 +0000118
119
120# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000121# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000122# It is always true that drivespec + pathspec == p
123def splitdrive(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000124 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
125 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
126
127 If you assign
128 result = splitdrive(p)
129 It is always true that:
130 result[0] + result[1] == p
131
132 If the path contained a drive letter, drive_or_unc will contain everything
133 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
134
135 If the path contained a UNC path, the drive_or_unc will contain the host name
136 and share up to but not including the fourth directory separator character.
137 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
138
139 Paths cannot contain both a drive letter and a UNC path.
140
141 """
Brett Cannon3f9183b2016-08-26 14:44:48 -0700142 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300143 if len(p) >= 2:
144 if isinstance(p, bytes):
145 sep = b'\\'
146 altsep = b'/'
147 colon = b':'
148 else:
149 sep = '\\'
150 altsep = '/'
151 colon = ':'
152 normp = p.replace(altsep, sep)
Mark Hammond5a607a32009-05-06 08:04:54 +0000153 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
154 # is a UNC path:
155 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
156 # \\machine\mountpoint\directory\etc\...
157 # directory ^^^^^^^^^^^^^^^
158 index = normp.find(sep, 2)
159 if index == -1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300160 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000161 index2 = normp.find(sep, index + 1)
162 # a UNC path can't have two slashes in a row
163 # (after the initial two)
164 if index2 == index + 1:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300165 return p[:0], p
Mark Hammond5a607a32009-05-06 08:04:54 +0000166 if index2 == -1:
167 index2 = len(p)
168 return p[:index2], p[index2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300169 if normp[1:2] == colon:
Mark Hammond5a607a32009-05-06 08:04:54 +0000170 return p[:2], p[2:]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300171 return p[:0], p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000172
173
174# Parse UNC paths
175def splitunc(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000176 """Deprecated since Python 3.1. Please use splitdrive() instead;
177 it now handles UNC paths.
178
179 Split a pathname into UNC mount point and relative path specifiers.
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000180
181 Return a 2-tuple (unc, rest); either part may be empty.
182 If unc is not empty, it has the form '//host/mount' (or similar
183 using backslashes). unc+rest is always the input path.
Martin Panter6245cb32016-04-15 02:14:19 +0000184 Paths containing drive letters never have a UNC part.
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000185 """
Mark Hammond5a607a32009-05-06 08:04:54 +0000186 import warnings
187 warnings.warn("ntpath.splitunc is deprecated, use ntpath.splitdrive instead",
Serhiy Storchaka593568b2013-12-16 15:13:28 +0200188 DeprecationWarning, 2)
189 drive, path = splitdrive(p)
190 if len(drive) == 2:
191 # Drive letter present
192 return p[:0], p
193 return drive, path
Guido van Rossum555915a1994-02-24 11:32:59 +0000194
195
196# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000197# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000198# join(head, tail) == p holds.
199# The resulting head won't end in '/' unless it is the root.
200
201def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000202 """Split a pathname.
203
204 Return tuple (head, tail) where tail is everything after the final slash.
205 Either part may be empty."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700206 p = os.fspath(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000207 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000208 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000209 # set i to index beyond p's last slash
210 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000211 while i and p[i-1] not in seps:
Georg Brandl599b65d2010-07-23 08:46:35 +0000212 i -= 1
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000213 head, tail = p[:i], p[i:] # now tail has no slashes
214 # remove trailing slashes from head, unless it's all slashes
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300215 head = head.rstrip(seps) or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000216 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000217
218
219# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000220# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000221# pathname component; the root is everything before that.
222# It is always true that root + ext == p.
223
224def splitext(p):
Brett Cannon3f9183b2016-08-26 14:44:48 -0700225 p = os.fspath(p)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300226 if isinstance(p, bytes):
227 return genericpath._splitext(p, b'\\', b'/', b'.')
228 else:
229 return genericpath._splitext(p, '\\', '/', '.')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000230splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000231
232
233# Return the tail (basename) part of a path.
234
235def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000236 """Returns the final component of a pathname"""
237 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000238
239
240# Return the head (dirname) part of a path.
241
242def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000243 """Returns the directory component of a pathname"""
244 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000245
Guido van Rossum555915a1994-02-24 11:32:59 +0000246# Is a path a symbolic link?
Brian Curtind40e6f72010-07-08 21:39:08 +0000247# This will always return false on systems where os.lstat doesn't exist.
Guido van Rossum555915a1994-02-24 11:32:59 +0000248
249def islink(path):
Brian Curtind40e6f72010-07-08 21:39:08 +0000250 """Test whether a path is a symbolic link.
Jesus Ceaf1af7052012-10-05 02:48:46 +0200251 This will always return false for Windows prior to 6.0.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000252 """
Brian Curtind40e6f72010-07-08 21:39:08 +0000253 try:
254 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200255 except (OSError, AttributeError):
Brian Curtind40e6f72010-07-08 21:39:08 +0000256 return False
257 return stat.S_ISLNK(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000258
Brian Curtind40e6f72010-07-08 21:39:08 +0000259# Being true for dangling symbolic links is also useful.
260
261def lexists(path):
262 """Test whether a path exists. Returns True for broken symbolic links"""
263 try:
264 st = os.lstat(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200265 except OSError:
Brian Curtind40e6f72010-07-08 21:39:08 +0000266 return False
267 return True
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000268
Tim Golden6b528062013-08-01 12:44:00 +0100269# Is a path a mount point?
270# Any drive letter root (eg c:\)
271# Any share UNC (eg \\server\share)
272# Any volume mounted on a filesystem folder
273#
274# No one method detects all three situations. Historically we've lexically
275# detected drive letter roots and share UNCs. The canonical approach to
276# detecting mounted volumes (querying the reparse tag) fails for the most
277# common case: drive letter roots. The alternative which uses GetVolumePathName
278# fails if the drive letter is the result of a SUBST.
279try:
280 from nt import _getvolumepathname
281except ImportError:
282 _getvolumepathname = None
Guido van Rossum555915a1994-02-24 11:32:59 +0000283def ismount(path):
Tim Golden6b528062013-08-01 12:44:00 +0100284 """Test whether a path is a mount point (a drive root, the root of a
285 share, or a mounted volume)"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700286 path = os.fspath(path)
Benjamin Peterson48e24782009-03-29 13:02:52 +0000287 seps = _get_bothseps(path)
Tim Golden6b528062013-08-01 12:44:00 +0100288 path = abspath(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000289 root, rest = splitdrive(path)
290 if root and root[0] in seps:
291 return (not rest) or (rest in seps)
Tim Golden6b528062013-08-01 12:44:00 +0100292 if rest in seps:
293 return True
294
295 if _getvolumepathname:
296 return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
297 else:
298 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000299
300
Guido van Rossum555915a1994-02-24 11:32:59 +0000301# Expand paths beginning with '~' or '~user'.
302# '~' means $HOME; '~user' means that user's home directory.
303# If the path doesn't begin with '~', or if the user or $HOME is unknown,
304# the path is returned unchanged (leaving error reporting to whatever
305# function is called with the expanded path as argument).
306# See also module 'glob' for expansion of *, ? and [...] in pathnames.
307# (A function should also be defined to do full *sh-style environment
308# variable expansion.)
309
310def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000311 """Expand ~ and ~user constructs.
312
313 If user or $HOME is unknown, do nothing."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700314 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000315 if isinstance(path, bytes):
316 tilde = b'~'
317 else:
318 tilde = '~'
319 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000320 return path
321 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000322 while i < n and path[i] not in _get_bothseps(path):
Georg Brandl599b65d2010-07-23 08:46:35 +0000323 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000324
325 if 'HOME' in os.environ:
326 userhome = os.environ['HOME']
327 elif 'USERPROFILE' in os.environ:
328 userhome = os.environ['USERPROFILE']
329 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000330 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000331 else:
332 try:
333 drive = os.environ['HOMEDRIVE']
334 except KeyError:
335 drive = ''
336 userhome = join(drive, os.environ['HOMEPATH'])
337
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000338 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300339 userhome = os.fsencode(userhome)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000340
Guido van Rossumd8faa362007-04-27 19:54:29 +0000341 if i != 1: #~user
342 userhome = join(dirname(userhome), path[1:i])
343
Guido van Rossum15e22e11997-12-05 19:03:01 +0000344 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000345
346
347# Expand paths containing shell variable substitutions.
348# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000349# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000350# - '$$' is translated into '$'
351# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000352# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000353# - $varname is accepted.
354# - %varname% is accepted.
355# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melotti13925002011-03-16 11:05:33 +0200356# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000357# XXX With COMMAND.COM you can use any characters in a variable name,
358# XXX except '^|<>='.
359
Tim Peters2344fae2001-01-15 00:50:52 +0000360def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000361 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000362
363 Unknown variables are left unchanged."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700364 path = os.fspath(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000365 if isinstance(path, bytes):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300366 if b'$' not in path and b'%' not in path:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000367 return path
368 import string
369 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000370 quote = b'\''
371 percent = b'%'
372 brace = b'{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300373 rbrace = b'}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000374 dollar = b'$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200375 environ = getattr(os, 'environb', None)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000376 else:
377 if '$' not in path and '%' not in path:
378 return path
379 import string
380 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000381 quote = '\''
382 percent = '%'
383 brace = '{'
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300384 rbrace = '}'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000385 dollar = '$'
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200386 environ = os.environ
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000387 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 index = 0
389 pathlen = len(path)
390 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000391 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000392 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000393 path = path[index + 1:]
394 pathlen = len(path)
395 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000396 index = path.index(c)
Georg Brandl599b65d2010-07-23 08:46:35 +0000397 res += c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000398 except ValueError:
Serhiy Storchaka1b87ae02015-03-25 16:40:15 +0200399 res += c + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000400 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000401 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000402 if path[index + 1:index + 2] == percent:
Georg Brandl599b65d2010-07-23 08:46:35 +0000403 res += c
404 index += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000405 else:
406 path = path[index+1:]
407 pathlen = len(path)
408 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000409 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000410 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000411 res += percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000412 index = pathlen - 1
413 else:
414 var = path[:index]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200415 try:
416 if environ is None:
417 value = os.fsencode(os.environ[os.fsdecode(var)])
418 else:
419 value = environ[var]
420 except KeyError:
421 value = percent + var + percent
Georg Brandl599b65d2010-07-23 08:46:35 +0000422 res += value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000423 elif c == dollar: # variable or '$$'
424 if path[index + 1:index + 2] == dollar:
Georg Brandl599b65d2010-07-23 08:46:35 +0000425 res += c
426 index += 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000427 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000428 path = path[index+2:]
429 pathlen = len(path)
430 try:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300431 index = path.index(rbrace)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000432 except ValueError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300433 res += dollar + brace + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000434 index = pathlen - 1
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200435 else:
436 var = path[:index]
437 try:
438 if environ is None:
439 value = os.fsencode(os.environ[os.fsdecode(var)])
440 else:
441 value = environ[var]
442 except KeyError:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300443 value = dollar + brace + var + rbrace
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200444 res += value
Guido van Rossum15e22e11997-12-05 19:03:01 +0000445 else:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200446 var = path[:0]
Georg Brandl599b65d2010-07-23 08:46:35 +0000447 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000448 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000449 while c and c in varchars:
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200450 var += c
Georg Brandl599b65d2010-07-23 08:46:35 +0000451 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000452 c = path[index:index + 1]
Serhiy Storchakadbb10192014-02-13 10:13:53 +0200453 try:
454 if environ is None:
455 value = os.fsencode(os.environ[os.fsdecode(var)])
456 else:
457 value = environ[var]
458 except KeyError:
459 value = dollar + var
Georg Brandl599b65d2010-07-23 08:46:35 +0000460 res += value
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000461 if c:
Georg Brandl599b65d2010-07-23 08:46:35 +0000462 index -= 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000463 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000464 res += c
465 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000466 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000467
468
Tim Peters54a14a32001-08-30 22:05:26 +0000469# 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 +0000470# Previously, this function also truncated pathnames to 8+3 format,
471# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000472
473def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000474 """Normalize path, eliminating double slashes, etc."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700475 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300476 if isinstance(path, bytes):
477 sep = b'\\'
478 altsep = b'/'
479 curdir = b'.'
480 pardir = b'..'
481 special_prefixes = (b'\\\\.\\', b'\\\\?\\')
482 else:
483 sep = '\\'
484 altsep = '/'
485 curdir = '.'
486 pardir = '..'
487 special_prefixes = ('\\\\.\\', '\\\\?\\')
Georg Brandlcfb68212010-07-31 21:40:15 +0000488 if path.startswith(special_prefixes):
489 # in the case of paths with these prefixes:
490 # \\.\ -> device names
491 # \\?\ -> literal paths
492 # do not do any normalization, but return the path unchanged
493 return path
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300494 path = path.replace(altsep, sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000495 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000496
497 # collapse initial backslashes
498 if path.startswith(sep):
Georg Brandl599b65d2010-07-23 08:46:35 +0000499 prefix += sep
Mark Hammond5a607a32009-05-06 08:04:54 +0000500 path = path.lstrip(sep)
501
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000502 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000503 i = 0
504 while i < len(comps):
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300505 if not comps[i] or comps[i] == curdir:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000506 del comps[i]
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300507 elif comps[i] == pardir:
508 if i > 0 and comps[i-1] != pardir:
Tim Peters54a14a32001-08-30 22:05:26 +0000509 del comps[i-1:i+1]
510 i -= 1
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300511 elif i == 0 and prefix.endswith(sep):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000512 del comps[i]
513 else:
514 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000515 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000516 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000517 # If the path is now empty, substitute '.'
518 if not prefix and not comps:
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300519 comps.append(curdir)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000520 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000521
522
523# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000524try:
525 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000526
Brett Cannoncd171c82013-07-04 17:43:24 -0400527except ImportError: # not running on Windows - mock up something sensible
Thomas Wouters477c8d52006-05-27 19:21:47 +0000528 def abspath(path):
529 """Return the absolute version of a path."""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700530 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000531 if not isabs(path):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000532 if isinstance(path, bytes):
533 cwd = os.getcwdb()
534 else:
535 cwd = os.getcwd()
536 path = join(cwd, path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537 return normpath(path)
538
539else: # use native Windows method on Windows
540 def abspath(path):
541 """Return the absolute version of a path."""
542
543 if path: # Empty path must return current working directory.
Brett Cannon3f9183b2016-08-26 14:44:48 -0700544 path = os.fspath(path)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000545 try:
546 path = _getfullpathname(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200547 except OSError:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000548 pass # Bad path - return unchanged.
Florent Xiclunaad8c5ca2010-03-08 14:44:41 +0000549 elif isinstance(path, bytes):
550 path = os.getcwdb()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000551 else:
552 path = os.getcwd()
553 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000554
555# realpath is a no-op on systems without islink support
556realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000557# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000558supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
559 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000560
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300561def relpath(path, start=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000562 """Return a relative version of a path"""
Brett Cannon3f9183b2016-08-26 14:44:48 -0700563 path = os.fspath(path)
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300564 if isinstance(path, bytes):
565 sep = b'\\'
566 curdir = b'.'
567 pardir = b'..'
568 else:
569 sep = '\\'
570 curdir = '.'
571 pardir = '..'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000572
Serhiy Storchaka8518b792014-07-23 20:43:13 +0300573 if start is None:
574 start = curdir
Guido van Rossumd8faa362007-04-27 19:54:29 +0000575
576 if not path:
577 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000578
Brett Cannon3f9183b2016-08-26 14:44:48 -0700579 start = os.fspath(start)
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300580 try:
581 start_abs = abspath(normpath(start))
582 path_abs = abspath(normpath(path))
583 start_drive, start_rest = splitdrive(start_abs)
584 path_drive, path_rest = splitdrive(path_abs)
585 if normcase(start_drive) != normcase(path_drive):
586 raise ValueError("path is on mount %r, start on mount %r" % (
587 path_drive, start_drive))
Mark Hammond5a607a32009-05-06 08:04:54 +0000588
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300589 start_list = [x for x in start_rest.split(sep) if x]
590 path_list = [x for x in path_rest.split(sep) if x]
591 # Work out how much of the filepath is shared by start and path.
592 i = 0
593 for e1, e2 in zip(start_list, path_list):
594 if normcase(e1) != normcase(e2):
595 break
596 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000597
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300598 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
599 if not rel_list:
600 return curdir
601 return join(*rel_list)
Serhiy Storchakae4f47082014-10-04 16:09:02 +0300602 except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
Serhiy Storchaka3deeeb02014-10-04 14:58:43 +0300603 genericpath._check_arg_types('relpath', path, start)
604 raise
Brian Curtind40e6f72010-07-08 21:39:08 +0000605
606
Serhiy Storchaka38220932015-03-31 15:31:53 +0300607# Return the longest common sub-path of the sequence of paths given as input.
608# The function is case-insensitive and 'separator-insensitive', i.e. if the
609# only difference between two paths is the use of '\' versus '/' as separator,
610# they are deemed to be equal.
611#
612# However, the returned path will have the standard '\' separator (even if the
613# given paths had the alternative '/' separator) and will have the case of the
614# first path given in the sequence. Additionally, any trailing separator is
615# stripped from the returned path.
616
617def commonpath(paths):
618 """Given a sequence of path names, returns the longest common sub-path."""
619
620 if not paths:
621 raise ValueError('commonpath() arg is an empty sequence')
622
Brett Cannon3f9183b2016-08-26 14:44:48 -0700623 paths = tuple(map(os.fspath, paths))
Serhiy Storchaka38220932015-03-31 15:31:53 +0300624 if isinstance(paths[0], bytes):
625 sep = b'\\'
626 altsep = b'/'
627 curdir = b'.'
628 else:
629 sep = '\\'
630 altsep = '/'
631 curdir = '.'
632
633 try:
634 drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
635 split_paths = [p.split(sep) for d, p in drivesplits]
636
637 try:
638 isabs, = set(p[:1] == sep for d, p in drivesplits)
639 except ValueError:
640 raise ValueError("Can't mix absolute and relative paths") from None
641
642 # Check that all drive letters or UNC paths match. The check is made only
643 # now otherwise type errors for mixing strings and bytes would not be
644 # caught.
645 if len(set(d for d, p in drivesplits)) != 1:
646 raise ValueError("Paths don't have the same drive")
647
648 drive, path = splitdrive(paths[0].replace(altsep, sep))
649 common = path.split(sep)
650 common = [c for c in common if c and c != curdir]
651
652 split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
653 s1 = min(split_paths)
654 s2 = max(split_paths)
655 for i, c in enumerate(s1):
656 if c != s2[i]:
657 common = common[:i]
658 break
659 else:
660 common = common[:len(s1)]
661
662 prefix = drive + sep if isabs else drive
663 return prefix + sep.join(common)
664 except (TypeError, AttributeError):
665 genericpath._check_arg_types('commonpath', *paths)
666 raise
667
668
Brian Curtind40e6f72010-07-08 21:39:08 +0000669# determine if two files are in fact the same file
Brian Curtin0dac8082010-09-23 20:38:14 +0000670try:
Brian Curtine8e80422010-09-24 13:56:34 +0000671 # GetFinalPathNameByHandle is available starting with Windows 6.0.
672 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
673 if sys.getwindowsversion()[:2] >= (6, 0):
674 from nt import _getfinalpathname
675 else:
676 raise ImportError
677except (AttributeError, ImportError):
Brian Curtin0dac8082010-09-23 20:38:14 +0000678 # On Windows XP and earlier, two files are the same if their absolute
679 # pathnames are the same.
Brian Curtine8e80422010-09-24 13:56:34 +0000680 # Non-Windows operating systems fake this method with an XP
681 # approximation.
Brian Curtin0dac8082010-09-23 20:38:14 +0000682 def _getfinalpathname(f):
Ronald Oussoren6355c162011-05-06 17:11:07 +0200683 return normcase(abspath(f))
Brian Curtin0dac8082010-09-23 20:38:14 +0000684
Brian Curtin9c669cc2011-06-08 18:17:18 -0500685
686try:
687 # The genericpath.isdir implementation uses os.stat and checks the mode
688 # attribute to tell whether or not the path is a directory.
689 # This is overkill on Windows - just pass the path to GetFileAttributes
690 # and check the attribute from there.
Brian Curtin95d028f2011-06-09 09:10:38 -0500691 from nt import _isdir as isdir
Brett Cannoncd171c82013-07-04 17:43:24 -0400692except ImportError:
Brian Curtin95d028f2011-06-09 09:10:38 -0500693 # Use genericpath.isdir as imported above.
694 pass