blob: de7a247db09b12e9f9f09abd91cd273e442dabf7 [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",
Brian Curtinae57cec2012-12-26 08:22:00 -060020 "samefile", "sameopenfile", "samestat",]
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
Mark Hammond5a607a32009-05-06 08:04:54 +000035def _get_empty(path):
36 if isinstance(path, bytes):
37 return b''
38 else:
39 return ''
40
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000041def _get_sep(path):
42 if isinstance(path, bytes):
43 return b'\\'
44 else:
45 return '\\'
46
47def _get_altsep(path):
48 if isinstance(path, bytes):
49 return b'/'
50 else:
51 return '/'
52
53def _get_bothseps(path):
54 if isinstance(path, bytes):
55 return b'\\/'
56 else:
57 return '\\/'
58
59def _get_dot(path):
60 if isinstance(path, bytes):
61 return b'.'
62 else:
63 return '.'
64
65def _get_colon(path):
66 if isinstance(path, bytes):
67 return b':'
68 else:
69 return ':'
70
Georg Brandlcfb68212010-07-31 21:40:15 +000071def _get_special(path):
72 if isinstance(path, bytes):
73 return (b'\\\\.\\', b'\\\\?\\')
74 else:
75 return ('\\\\.\\', '\\\\?\\')
76
Guido van Rossume2ad88c1997-08-12 14:46:58 +000077# Normalize the case of a pathname and map slashes to backslashes.
78# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000079# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000080
Guido van Rossum555915a1994-02-24 11:32:59 +000081def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000082 """Normalize case of pathname.
83
Guido van Rossum534972b1999-02-03 17:20:50 +000084 Makes all characters lowercase and all slashes into backslashes."""
Ezio Melotti5a3ef5b2010-06-25 10:56:11 +000085 if not isinstance(s, (bytes, str)):
86 raise TypeError("normcase() argument must be str or bytes, "
87 "not '{}'".format(s.__class__.__name__))
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +000088 return s.replace(_get_altsep(s), _get_sep(s)).lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000089
Guido van Rossum77e1db31997-06-02 23:11:57 +000090
Fred Drakeef0b5dd2000-02-17 17:30:40 +000091# Return whether a path is absolute.
Mark Hammond5a607a32009-05-06 08:04:54 +000092# Trivial in Posix, harder on Windows.
93# For Windows it is absolute if it starts with a slash or backslash (current
94# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
Guido van Rossum534972b1999-02-03 17:20:50 +000095# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000096
97def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000098 """Test whether a path is absolute"""
99 s = splitdrive(s)[1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000100 return len(s) > 0 and s[:1] in _get_bothseps(s)
Guido van Rossum555915a1994-02-24 11:32:59 +0000101
102
Guido van Rossum77e1db31997-06-02 23:11:57 +0000103# Join two (or more) paths.
Serhiy Storchakac369c2c2014-01-27 23:15:14 +0200104def join(path, *paths):
105 sep = _get_sep(path)
106 seps = _get_bothseps(path)
107 colon = _get_colon(path)
108 result_drive, result_path = splitdrive(path)
109 for p in paths:
110 p_drive, p_path = splitdrive(p)
111 if p_path and p_path[0] in seps:
112 # Second path is absolute
113 if p_drive or not result_drive:
114 result_drive = p_drive
115 result_path = p_path
116 continue
117 elif p_drive and p_drive != result_drive:
118 if p_drive.lower() != result_drive.lower():
119 # Different drives => ignore the first path entirely
120 result_drive = p_drive
121 result_path = p_path
122 continue
123 # Same drive in different case
124 result_drive = p_drive
125 # Second path is relative to the first
126 if result_path and result_path[-1] not in seps:
127 result_path = result_path + sep
128 result_path = result_path + p_path
129 ## add separator between UNC and non-absolute path
130 if (result_path and result_path[0] not in seps and
131 result_drive and result_drive[-1:] != colon):
132 return result_drive + sep + result_path
133 return result_drive + result_path
Guido van Rossum555915a1994-02-24 11:32:59 +0000134
135
136# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000137# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +0000138# It is always true that drivespec + pathspec == p
139def splitdrive(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000140 """Split a pathname into drive/UNC sharepoint and relative path specifiers.
141 Returns a 2-tuple (drive_or_unc, path); either part may be empty.
142
143 If you assign
144 result = splitdrive(p)
145 It is always true that:
146 result[0] + result[1] == p
147
148 If the path contained a drive letter, drive_or_unc will contain everything
149 up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
150
151 If the path contained a UNC path, the drive_or_unc will contain the host name
152 and share up to but not including the fourth directory separator character.
153 e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
154
155 Paths cannot contain both a drive letter and a UNC path.
156
157 """
158 empty = _get_empty(p)
159 if len(p) > 1:
160 sep = _get_sep(p)
Serhiy Storchaka3d7e1152013-12-16 14:34:55 +0200161 normp = p.replace(_get_altsep(p), sep)
Mark Hammond5a607a32009-05-06 08:04:54 +0000162 if (normp[0:2] == sep*2) and (normp[2:3] != sep):
163 # is a UNC path:
164 # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
165 # \\machine\mountpoint\directory\etc\...
166 # directory ^^^^^^^^^^^^^^^
167 index = normp.find(sep, 2)
168 if index == -1:
169 return empty, p
170 index2 = normp.find(sep, index + 1)
171 # a UNC path can't have two slashes in a row
172 # (after the initial two)
173 if index2 == index + 1:
174 return empty, p
175 if index2 == -1:
176 index2 = len(p)
177 return p[:index2], p[index2:]
178 if normp[1:2] == _get_colon(p):
179 return p[:2], p[2:]
180 return empty, p
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000181
182
183# Parse UNC paths
184def splitunc(p):
Mark Hammond5a607a32009-05-06 08:04:54 +0000185 """Deprecated since Python 3.1. Please use splitdrive() instead;
186 it now handles UNC paths.
187
188 Split a pathname into UNC mount point and relative path specifiers.
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000189
190 Return a 2-tuple (unc, rest); either part may be empty.
191 If unc is not empty, it has the form '//host/mount' (or similar
192 using backslashes). unc+rest is always the input path.
193 Paths containing drive letters never have an UNC part.
194 """
Mark Hammond5a607a32009-05-06 08:04:54 +0000195 import warnings
196 warnings.warn("ntpath.splitunc is deprecated, use ntpath.splitdrive instead",
Serhiy Storchaka593568b2013-12-16 15:13:28 +0200197 DeprecationWarning, 2)
198 drive, path = splitdrive(p)
199 if len(drive) == 2:
200 # Drive letter present
201 return p[:0], p
202 return drive, path
Guido van Rossum555915a1994-02-24 11:32:59 +0000203
204
205# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000206# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000207# join(head, tail) == p holds.
208# The resulting head won't end in '/' unless it is the root.
209
210def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000211 """Split a pathname.
212
213 Return tuple (head, tail) where tail is everything after the final slash.
214 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000215
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000216 seps = _get_bothseps(p)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000217 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000218 # set i to index beyond p's last slash
219 i = len(p)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000220 while i and p[i-1] not in seps:
Georg Brandl599b65d2010-07-23 08:46:35 +0000221 i -= 1
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000222 head, tail = p[:i], p[i:] # now tail has no slashes
223 # remove trailing slashes from head, unless it's all slashes
224 head2 = head
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000225 while head2 and head2[-1:] in seps:
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000226 head2 = head2[:-1]
227 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000228 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000229
230
231# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000232# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000233# pathname component; the root is everything before that.
234# It is always true that root + ext == p.
235
236def splitext(p):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000237 return genericpath._splitext(p, _get_sep(p), _get_altsep(p),
238 _get_dot(p))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000239splitext.__doc__ = genericpath._splitext.__doc__
Guido van Rossum555915a1994-02-24 11:32:59 +0000240
241
242# Return the tail (basename) part of a path.
243
244def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000245 """Returns the final component of a pathname"""
246 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000247
248
249# Return the head (dirname) part of a path.
250
251def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000252 """Returns the directory component of a pathname"""
253 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000254
Guido van Rossum555915a1994-02-24 11:32:59 +0000255# Is a path a symbolic link?
Brian Curtind40e6f72010-07-08 21:39:08 +0000256# This will always return false on systems where os.lstat doesn't exist.
Guido van Rossum555915a1994-02-24 11:32:59 +0000257
258def islink(path):
Brian Curtind40e6f72010-07-08 21:39:08 +0000259 """Test whether a path is a symbolic link.
Jesus Ceaf1af7052012-10-05 02:48:46 +0200260 This will always return false for Windows prior to 6.0.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000261 """
Brian Curtind40e6f72010-07-08 21:39:08 +0000262 try:
263 st = os.lstat(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200264 except (OSError, AttributeError):
Brian Curtind40e6f72010-07-08 21:39:08 +0000265 return False
266 return stat.S_ISLNK(st.st_mode)
Guido van Rossum555915a1994-02-24 11:32:59 +0000267
Brian Curtind40e6f72010-07-08 21:39:08 +0000268# Being true for dangling symbolic links is also useful.
269
270def lexists(path):
271 """Test whether a path exists. Returns True for broken symbolic links"""
272 try:
273 st = os.lstat(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200274 except OSError:
Brian Curtind40e6f72010-07-08 21:39:08 +0000275 return False
276 return True
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000277
Tim Golden6b528062013-08-01 12:44:00 +0100278# Is a path a mount point?
279# Any drive letter root (eg c:\)
280# Any share UNC (eg \\server\share)
281# Any volume mounted on a filesystem folder
282#
283# No one method detects all three situations. Historically we've lexically
284# detected drive letter roots and share UNCs. The canonical approach to
285# detecting mounted volumes (querying the reparse tag) fails for the most
286# common case: drive letter roots. The alternative which uses GetVolumePathName
287# fails if the drive letter is the result of a SUBST.
288try:
289 from nt import _getvolumepathname
290except ImportError:
291 _getvolumepathname = None
Guido van Rossum555915a1994-02-24 11:32:59 +0000292def ismount(path):
Tim Golden6b528062013-08-01 12:44:00 +0100293 """Test whether a path is a mount point (a drive root, the root of a
294 share, or a mounted volume)"""
Benjamin Peterson48e24782009-03-29 13:02:52 +0000295 seps = _get_bothseps(path)
Tim Golden6b528062013-08-01 12:44:00 +0100296 path = abspath(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000297 root, rest = splitdrive(path)
298 if root and root[0] in seps:
299 return (not rest) or (rest in seps)
Tim Golden6b528062013-08-01 12:44:00 +0100300 if rest in seps:
301 return True
302
303 if _getvolumepathname:
304 return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
305 else:
306 return False
Guido van Rossum555915a1994-02-24 11:32:59 +0000307
308
Guido van Rossum555915a1994-02-24 11:32:59 +0000309# Expand paths beginning with '~' or '~user'.
310# '~' means $HOME; '~user' means that user's home directory.
311# If the path doesn't begin with '~', or if the user or $HOME is unknown,
312# the path is returned unchanged (leaving error reporting to whatever
313# function is called with the expanded path as argument).
314# See also module 'glob' for expansion of *, ? and [...] in pathnames.
315# (A function should also be defined to do full *sh-style environment
316# variable expansion.)
317
318def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000319 """Expand ~ and ~user constructs.
320
321 If user or $HOME is unknown, do nothing."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000322 if isinstance(path, bytes):
323 tilde = b'~'
324 else:
325 tilde = '~'
326 if not path.startswith(tilde):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000327 return path
328 i, n = 1, len(path)
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000329 while i < n and path[i] not in _get_bothseps(path):
Georg Brandl599b65d2010-07-23 08:46:35 +0000330 i += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000331
332 if 'HOME' in os.environ:
333 userhome = os.environ['HOME']
334 elif 'USERPROFILE' in os.environ:
335 userhome = os.environ['USERPROFILE']
336 elif not 'HOMEPATH' in os.environ:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000337 return path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000338 else:
339 try:
340 drive = os.environ['HOMEDRIVE']
341 except KeyError:
342 drive = ''
343 userhome = join(drive, os.environ['HOMEPATH'])
344
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000345 if isinstance(path, bytes):
346 userhome = userhome.encode(sys.getfilesystemencoding())
347
Guido van Rossumd8faa362007-04-27 19:54:29 +0000348 if i != 1: #~user
349 userhome = join(dirname(userhome), path[1:i])
350
Guido van Rossum15e22e11997-12-05 19:03:01 +0000351 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000352
353
354# Expand paths containing shell variable substitutions.
355# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000356# - no expansion within single quotes
Guido van Rossumd8faa362007-04-27 19:54:29 +0000357# - '$$' is translated into '$'
358# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
Guido van Rossum15e22e11997-12-05 19:03:01 +0000359# - ${varname} is accepted.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000360# - $varname is accepted.
361# - %varname% is accepted.
362# - varnames can be made out of letters, digits and the characters '_-'
Ezio Melotti13925002011-03-16 11:05:33 +0200363# (though is not verified in the ${varname} and %varname% cases)
Guido van Rossum555915a1994-02-24 11:32:59 +0000364# XXX With COMMAND.COM you can use any characters in a variable name,
365# XXX except '^|<>='.
366
Tim Peters2344fae2001-01-15 00:50:52 +0000367def expandvars(path):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000368 """Expand shell variables of the forms $var, ${var} and %var%.
Guido van Rossum534972b1999-02-03 17:20:50 +0000369
370 Unknown variables are left unchanged."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000371 if isinstance(path, bytes):
372 if ord('$') not in path and ord('%') not in path:
373 return path
374 import string
375 varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000376 quote = b'\''
377 percent = b'%'
378 brace = b'{'
379 dollar = b'$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000380 else:
381 if '$' not in path and '%' not in path:
382 return path
383 import string
384 varchars = string.ascii_letters + string.digits + '_-'
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000385 quote = '\''
386 percent = '%'
387 brace = '{'
388 dollar = '$'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000389 res = path[:0]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000390 index = 0
391 pathlen = len(path)
392 while index < pathlen:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000393 c = path[index:index+1]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000394 if c == quote: # no expansion within single quotes
Guido van Rossum15e22e11997-12-05 19:03:01 +0000395 path = path[index + 1:]
396 pathlen = len(path)
397 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000398 index = path.index(c)
Georg Brandl599b65d2010-07-23 08:46:35 +0000399 res += c + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000400 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000401 res += path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000402 index = pathlen - 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000403 elif c == percent: # variable or '%'
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000404 if path[index + 1:index + 2] == percent:
Georg Brandl599b65d2010-07-23 08:46:35 +0000405 res += c
406 index += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000407 else:
408 path = path[index+1:]
409 pathlen = len(path)
410 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000411 index = path.index(percent)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000412 except ValueError:
Georg Brandl599b65d2010-07-23 08:46:35 +0000413 res += percent + path
Guido van Rossumd8faa362007-04-27 19:54:29 +0000414 index = pathlen - 1
415 else:
416 var = path[:index]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000417 if isinstance(path, bytes):
418 var = var.decode('ascii')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000419 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000420 value = os.environ[var]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000421 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000422 value = '%' + var + '%'
423 if isinstance(path, bytes):
424 value = value.encode('ascii')
Georg Brandl599b65d2010-07-23 08:46:35 +0000425 res += value
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000426 elif c == dollar: # variable or '$$'
427 if path[index + 1:index + 2] == dollar:
Georg Brandl599b65d2010-07-23 08:46:35 +0000428 res += c
429 index += 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000430 elif path[index + 1:index + 2] == brace:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000431 path = path[index+2:]
432 pathlen = len(path)
433 try:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000434 if isinstance(path, bytes):
435 index = path.index(b'}')
Thomas Woutersb2137042007-02-01 18:02:27 +0000436 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000437 index = path.index('}')
438 var = path[:index]
439 if isinstance(path, bytes):
440 var = var.decode('ascii')
441 if var in os.environ:
442 value = os.environ[var]
443 else:
444 value = '${' + var + '}'
445 if isinstance(path, bytes):
446 value = value.encode('ascii')
Georg Brandl599b65d2010-07-23 08:46:35 +0000447 res += value
Fred Drakeb4e460a2000-09-28 16:25:20 +0000448 except ValueError:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000449 if isinstance(path, bytes):
Georg Brandl599b65d2010-07-23 08:46:35 +0000450 res += b'${' + path
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000451 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000452 res += '${' + path
Guido van Rossum15e22e11997-12-05 19:03:01 +0000453 index = pathlen - 1
454 else:
455 var = ''
Georg Brandl599b65d2010-07-23 08:46:35 +0000456 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000457 c = path[index:index + 1]
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000458 while c and c in varchars:
459 if isinstance(path, bytes):
Georg Brandl599b65d2010-07-23 08:46:35 +0000460 var += c.decode('ascii')
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000461 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000462 var += c
463 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000464 c = path[index:index + 1]
Raymond Hettinger54f02222002-06-01 14:18:47 +0000465 if var in os.environ:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000466 value = os.environ[var]
Thomas Woutersb2137042007-02-01 18:02:27 +0000467 else:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000468 value = '$' + var
469 if isinstance(path, bytes):
470 value = value.encode('ascii')
Georg Brandl599b65d2010-07-23 08:46:35 +0000471 res += value
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000472 if c:
Georg Brandl599b65d2010-07-23 08:46:35 +0000473 index -= 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000474 else:
Georg Brandl599b65d2010-07-23 08:46:35 +0000475 res += c
476 index += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000477 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000478
479
Tim Peters54a14a32001-08-30 22:05:26 +0000480# 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 +0000481# Previously, this function also truncated pathnames to 8+3 format,
482# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000483
484def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000485 """Normalize path, eliminating double slashes, etc."""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000486 sep = _get_sep(path)
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000487 dotdot = _get_dot(path) * 2
Georg Brandlcfb68212010-07-31 21:40:15 +0000488 special_prefixes = _get_special(path)
489 if path.startswith(special_prefixes):
490 # in the case of paths with these prefixes:
491 # \\.\ -> device names
492 # \\?\ -> literal paths
493 # do not do any normalization, but return the path unchanged
494 return path
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000495 path = path.replace(_get_altsep(path), sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000496 prefix, path = splitdrive(path)
Mark Hammond5a607a32009-05-06 08:04:54 +0000497
498 # collapse initial backslashes
499 if path.startswith(sep):
Georg Brandl599b65d2010-07-23 08:46:35 +0000500 prefix += sep
Mark Hammond5a607a32009-05-06 08:04:54 +0000501 path = path.lstrip(sep)
502
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000503 comps = path.split(sep)
Guido van Rossum15e22e11997-12-05 19:03:01 +0000504 i = 0
505 while i < len(comps):
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000506 if not comps[i] or comps[i] == _get_dot(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000507 del comps[i]
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000508 elif comps[i] == dotdot:
509 if i > 0 and comps[i-1] != dotdot:
Tim Peters54a14a32001-08-30 22:05:26 +0000510 del comps[i-1:i+1]
511 i -= 1
Amaury Forgeot d'Arc3b44e612008-10-03 20:32:33 +0000512 elif i == 0 and prefix.endswith(_get_sep(path)):
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000513 del comps[i]
514 else:
515 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000516 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000517 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000518 # If the path is now empty, substitute '.'
519 if not prefix and not comps:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000520 comps.append(_get_dot(path))
521 return prefix + sep.join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000522
523
524# Return an absolute path.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000525try:
526 from nt import _getfullpathname
Mark Hammondf717f052002-01-17 00:44:26 +0000527
Brett Cannoncd171c82013-07-04 17:43:24 -0400528except ImportError: # not running on Windows - mock up something sensible
Thomas Wouters477c8d52006-05-27 19:21:47 +0000529 def abspath(path):
530 """Return the absolute version of a path."""
531 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.
544 try:
545 path = _getfullpathname(path)
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200546 except OSError:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000547 pass # Bad path - return unchanged.
Florent Xiclunaad8c5ca2010-03-08 14:44:41 +0000548 elif isinstance(path, bytes):
549 path = os.getcwdb()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000550 else:
551 path = os.getcwd()
552 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000553
554# realpath is a no-op on systems without islink support
555realpath = abspath
Mark Hammond8696ebc2002-10-08 02:44:31 +0000556# Win9x family and earlier have no Unicode filename support.
Tim Peters26bc25a2002-10-09 07:56:04 +0000557supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
558 sys.getwindowsversion()[3] >= 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000559
560def relpath(path, start=curdir):
561 """Return a relative version of a path"""
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000562 sep = _get_sep(path)
563
564 if start is curdir:
565 start = _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000566
567 if not path:
568 raise ValueError("no path specified")
Mark Hammond5a607a32009-05-06 08:04:54 +0000569
570 start_abs = abspath(normpath(start))
571 path_abs = abspath(normpath(path))
572 start_drive, start_rest = splitdrive(start_abs)
573 path_drive, path_rest = splitdrive(path_abs)
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000574 if normcase(start_drive) != normcase(path_drive):
Mark Hammond5a607a32009-05-06 08:04:54 +0000575 error = "path is on mount '{0}', start on mount '{1}'".format(
576 path_drive, start_drive)
577 raise ValueError(error)
578
579 start_list = [x for x in start_rest.split(sep) if x]
580 path_list = [x for x in path_rest.split(sep) if x]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000581 # Work out how much of the filepath is shared by start and path.
Mark Hammond5a607a32009-05-06 08:04:54 +0000582 i = 0
583 for e1, e2 in zip(start_list, path_list):
Hirokazu Yamamotob08820a2010-10-18 12:13:18 +0000584 if normcase(e1) != normcase(e2):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000585 break
Guido van Rossumd8faa362007-04-27 19:54:29 +0000586 i += 1
587
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000588 if isinstance(path, bytes):
589 pardir = b'..'
590 else:
591 pardir = '..'
Guido van Rossumd8faa362007-04-27 19:54:29 +0000592 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
Christian Heimesfaf2f632008-01-06 16:59:19 +0000593 if not rel_list:
Amaury Forgeot d'Arcc72ef8b2008-10-03 18:38:26 +0000594 return _get_dot(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595 return join(*rel_list)
Brian Curtind40e6f72010-07-08 21:39:08 +0000596
597
598# determine if two files are in fact the same file
Brian Curtin0dac8082010-09-23 20:38:14 +0000599try:
Brian Curtine8e80422010-09-24 13:56:34 +0000600 # GetFinalPathNameByHandle is available starting with Windows 6.0.
601 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
602 if sys.getwindowsversion()[:2] >= (6, 0):
603 from nt import _getfinalpathname
604 else:
605 raise ImportError
606except (AttributeError, ImportError):
Brian Curtin0dac8082010-09-23 20:38:14 +0000607 # On Windows XP and earlier, two files are the same if their absolute
608 # pathnames are the same.
Brian Curtine8e80422010-09-24 13:56:34 +0000609 # Non-Windows operating systems fake this method with an XP
610 # approximation.
Brian Curtin0dac8082010-09-23 20:38:14 +0000611 def _getfinalpathname(f):
Ronald Oussoren6355c162011-05-06 17:11:07 +0200612 return normcase(abspath(f))
Brian Curtin0dac8082010-09-23 20:38:14 +0000613
Brian Curtin9c669cc2011-06-08 18:17:18 -0500614
615try:
616 # The genericpath.isdir implementation uses os.stat and checks the mode
617 # attribute to tell whether or not the path is a directory.
618 # This is overkill on Windows - just pass the path to GetFileAttributes
619 # and check the attribute from there.
Brian Curtin95d028f2011-06-09 09:10:38 -0500620 from nt import _isdir as isdir
Brett Cannoncd171c82013-07-04 17:43:24 -0400621except ImportError:
Brian Curtin95d028f2011-06-09 09:10:38 -0500622 # Use genericpath.isdir as imported above.
623 pass