blob: 21fadd0eb9bdfdaab624c5c67261c468332376ad [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
9import stat
Skip Montanaro4d5d5bf2000-07-13 01:01:03 +000010
Skip Montanaro269b83b2001-02-06 01:07:02 +000011__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
12 "basename","dirname","commonprefix","getsize","getmtime",
13 "getatime","islink","exists","isdir","isfile","ismount",
14 "walk","expanduser","expandvars","normpath","abspath","splitunc"]
Guido van Rossum555915a1994-02-24 11:32:59 +000015
Guido van Rossume2ad88c1997-08-12 14:46:58 +000016# Normalize the case of a pathname and map slashes to backslashes.
17# Other normalizations (such as optimizing '../' away) are not done
Guido van Rossum555915a1994-02-24 11:32:59 +000018# (this is done by normpath).
Guido van Rossume2ad88c1997-08-12 14:46:58 +000019
Guido van Rossum555915a1994-02-24 11:32:59 +000020def normcase(s):
Guido van Rossum16a0bc21998-02-18 13:48:31 +000021 """Normalize case of pathname.
22
Guido van Rossum534972b1999-02-03 17:20:50 +000023 Makes all characters lowercase and all slashes into backslashes."""
Fred Drakeb4e460a2000-09-28 16:25:20 +000024 return s.replace("/", "\\").lower()
Guido van Rossum555915a1994-02-24 11:32:59 +000025
Guido van Rossum77e1db31997-06-02 23:11:57 +000026
Fred Drakeef0b5dd2000-02-17 17:30:40 +000027# Return whether a path is absolute.
Guido van Rossum555915a1994-02-24 11:32:59 +000028# Trivial in Posix, harder on the Mac or MS-DOS.
29# For DOS it is absolute if it starts with a slash or backslash (current
Guido van Rossum534972b1999-02-03 17:20:50 +000030# volume), or if a pathname after the volume letter and colon / UNC resource
31# starts with a slash or backslash.
Guido van Rossum555915a1994-02-24 11:32:59 +000032
33def isabs(s):
Guido van Rossum15e22e11997-12-05 19:03:01 +000034 """Test whether a path is absolute"""
35 s = splitdrive(s)[1]
36 return s != '' and s[:1] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +000037
38
Guido van Rossum77e1db31997-06-02 23:11:57 +000039# Join two (or more) paths.
40
Barry Warsaw384d2491997-02-18 21:53:25 +000041def join(a, *p):
Guido van Rossum15e22e11997-12-05 19:03:01 +000042 """Join two or more pathname components, inserting "\\" as needed"""
43 path = a
44 for b in p:
Tim Peters33dc0a12001-07-27 08:09:54 +000045 b_wins = 0 # set to 1 iff b makes path irrelevant
46 if path == "":
47 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000048
Tim Peters33dc0a12001-07-27 08:09:54 +000049 elif isabs(b):
50 # This probably wipes out path so far. However, it's more
51 # complicated if path begins with a drive letter:
52 # 1. join('c:', '/a') == 'c:/a'
53 # 2. join('c:/', '/a') == 'c:/a'
54 # But
55 # 3. join('c:/a', '/b') == '/b'
56 # 4. join('c:', 'd:/') = 'd:/'
57 # 5. join('c:/', 'd:/') = 'd:/'
58 if path[1:2] != ":" or b[1:2] == ":":
59 # Path doesn't start with a drive letter, or cases 4 and 5.
60 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000061
Tim Peters33dc0a12001-07-27 08:09:54 +000062 # Else path has a drive letter, and b doesn't but is absolute.
63 elif len(path) > 3 or (len(path) == 3 and
64 path[-1] not in "/\\"):
65 # case 3
66 b_wins = 1
Tim Peters1bdd0f22001-07-19 17:18:18 +000067
Tim Peters33dc0a12001-07-27 08:09:54 +000068 if b_wins:
69 path = b
70 else:
71 # Join, and ensure there's a separator.
72 assert len(path) > 0
73 if path[-1] in "/\\":
74 if b and b[0] in "/\\":
75 path += b[1:]
76 else:
77 path += b
78 elif path[-1] == ":":
79 path += b
80 elif b:
81 if b[0] in "/\\":
82 path += b
83 else:
84 path += "\\" + b
Tim Peters6a3e5f12001-11-05 21:25:02 +000085 else:
86 # path is not empty and does not end with a backslash,
87 # but b is empty; since, e.g., split('a/') produces
88 # ('a', ''), it's best if join() adds a backslash in
89 # this case.
90 path += '\\'
Tim Peters1bdd0f22001-07-19 17:18:18 +000091
Guido van Rossum15e22e11997-12-05 19:03:01 +000092 return path
Guido van Rossum555915a1994-02-24 11:32:59 +000093
94
95# Split a path in a drive specification (a drive letter followed by a
Guido van Rossumf3c695c1999-04-06 19:32:19 +000096# colon) and the path specification.
Guido van Rossum555915a1994-02-24 11:32:59 +000097# It is always true that drivespec + pathspec == p
98def splitdrive(p):
Guido van Rossumf3c695c1999-04-06 19:32:19 +000099 """Split a pathname into drive and path specifiers. Returns a 2-tuple
100"(drive,path)"; either part may be empty"""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000101 if p[1:2] == ':':
102 return p[0:2], p[2:]
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000103 return '', p
104
105
106# Parse UNC paths
107def splitunc(p):
108 """Split a pathname into UNC mount point and relative path specifiers.
109
110 Return a 2-tuple (unc, rest); either part may be empty.
111 If unc is not empty, it has the form '//host/mount' (or similar
112 using backslashes). unc+rest is always the input path.
113 Paths containing drive letters never have an UNC part.
114 """
115 if p[1:2] == ':':
116 return '', p # Drive letter present
Guido van Rossum534972b1999-02-03 17:20:50 +0000117 firstTwo = p[0:2]
118 if firstTwo == '//' or firstTwo == '\\\\':
119 # is a UNC path:
120 # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
121 # \\machine\mountpoint\directories...
122 # directory ^^^^^^^^^^^^^^^
123 normp = normcase(p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000124 index = normp.find('\\', 2)
Guido van Rossum534972b1999-02-03 17:20:50 +0000125 if index == -1:
126 ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
127 return ("", p)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000128 index = normp.find('\\', index + 1)
Guido van Rossum534972b1999-02-03 17:20:50 +0000129 if index == -1:
130 index = len(p)
131 return p[:index], p[index:]
Guido van Rossum15e22e11997-12-05 19:03:01 +0000132 return '', p
Guido van Rossum555915a1994-02-24 11:32:59 +0000133
134
135# Split a path in head (everything up to the last '/') and tail (the
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000136# rest). After the trailing '/' is stripped, the invariant
Guido van Rossum555915a1994-02-24 11:32:59 +0000137# join(head, tail) == p holds.
138# The resulting head won't end in '/' unless it is the root.
139
140def split(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000141 """Split a pathname.
142
143 Return tuple (head, tail) where tail is everything after the final slash.
144 Either part may be empty."""
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000145
Guido van Rossum15e22e11997-12-05 19:03:01 +0000146 d, p = splitdrive(p)
Guido van Rossum8f0fa9e1999-03-19 21:05:12 +0000147 # set i to index beyond p's last slash
148 i = len(p)
149 while i and p[i-1] not in '/\\':
150 i = i - 1
151 head, tail = p[:i], p[i:] # now tail has no slashes
152 # remove trailing slashes from head, unless it's all slashes
153 head2 = head
154 while head2 and head2[-1] in '/\\':
155 head2 = head2[:-1]
156 head = head2 or head
Guido van Rossum15e22e11997-12-05 19:03:01 +0000157 return d + head, tail
Guido van Rossum555915a1994-02-24 11:32:59 +0000158
159
160# Split a path in root and extension.
Guido van Rossum73e122f1997-01-22 00:17:26 +0000161# The extension is everything starting at the last dot in the last
Guido van Rossum555915a1994-02-24 11:32:59 +0000162# pathname component; the root is everything before that.
163# It is always true that root + ext == p.
164
165def splitext(p):
Guido van Rossum534972b1999-02-03 17:20:50 +0000166 """Split the extension from a pathname.
167
168 Extension is everything from the last dot to the end.
169 Return (root, ext), either part may be empty."""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000170 root, ext = '', ''
171 for c in p:
172 if c in ['/','\\']:
173 root, ext = root + ext + c, ''
174 elif c == '.':
175 if ext:
176 root, ext = root + ext, c
177 else:
178 ext = c
179 elif ext:
180 ext = ext + c
181 else:
182 root = root + c
183 return root, ext
Guido van Rossum555915a1994-02-24 11:32:59 +0000184
185
186# Return the tail (basename) part of a path.
187
188def basename(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000189 """Returns the final component of a pathname"""
190 return split(p)[1]
Guido van Rossum555915a1994-02-24 11:32:59 +0000191
192
193# Return the head (dirname) part of a path.
194
195def dirname(p):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000196 """Returns the directory component of a pathname"""
197 return split(p)[0]
Guido van Rossum555915a1994-02-24 11:32:59 +0000198
199
200# Return the longest prefix of all list elements.
201
202def commonprefix(m):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000203 "Given a list of pathnames, returns the longest common leading component"
204 if not m: return ''
Skip Montanaro62358312000-08-22 13:01:53 +0000205 prefix = m[0]
206 for item in m:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000207 for i in range(len(prefix)):
Fred Drake8152d322000-12-12 23:20:45 +0000208 if prefix[:i+1] != item[:i+1]:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000209 prefix = prefix[:i]
210 if i == 0: return ''
211 break
Skip Montanaro62358312000-08-22 13:01:53 +0000212 return prefix
Guido van Rossum555915a1994-02-24 11:32:59 +0000213
214
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000215# Get size, mtime, atime of files.
216
217def getsize(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000218 """Return the size of a file, reported by os.stat()"""
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000219 st = os.stat(filename)
220 return st[stat.ST_SIZE]
221
222def getmtime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000223 """Return the last modification time of a file, reported by os.stat()"""
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000224 st = os.stat(filename)
225 return st[stat.ST_MTIME]
226
227def getatime(filename):
Guido van Rossum534972b1999-02-03 17:20:50 +0000228 """Return the last access time of a file, reported by os.stat()"""
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000229 st = os.stat(filename)
Fred Drake162bd852000-07-01 06:36:51 +0000230 return st[stat.ST_ATIME]
Guido van Rossum2bc1f8f1998-07-24 20:49:26 +0000231
232
Guido van Rossum555915a1994-02-24 11:32:59 +0000233# Is a path a symbolic link?
234# This will always return false on systems where posix.lstat doesn't exist.
235
236def islink(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000237 """Test for symbolic link. On WindowsNT/95 always returns false"""
238 return 0
Guido van Rossum555915a1994-02-24 11:32:59 +0000239
240
241# Does a path exist?
242# This is false for dangling symbolic links.
243
244def exists(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000245 """Test whether a path exists"""
246 try:
247 st = os.stat(path)
248 except os.error:
249 return 0
250 return 1
Guido van Rossum555915a1994-02-24 11:32:59 +0000251
252
253# Is a path a dos directory?
254# This follows symbolic links, so both islink() and isdir() can be true
255# for the same path.
256
257def isdir(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000258 """Test whether a path is a directory"""
259 try:
260 st = os.stat(path)
261 except os.error:
262 return 0
263 return stat.S_ISDIR(st[stat.ST_MODE])
Guido van Rossum555915a1994-02-24 11:32:59 +0000264
265
266# Is a path a regular file?
267# This follows symbolic links, so both islink() and isdir() can be true
268# for the same path.
269
270def isfile(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000271 """Test whether a path is a regular file"""
272 try:
273 st = os.stat(path)
274 except os.error:
275 return 0
276 return stat.S_ISREG(st[stat.ST_MODE])
Guido van Rossum555915a1994-02-24 11:32:59 +0000277
278
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000279# Is a path a mount point? Either a root (with or without drive letter)
280# or an UNC path with at most a / or \ after the mount point.
Guido van Rossum555915a1994-02-24 11:32:59 +0000281
282def ismount(path):
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000283 """Test whether a path is a mount point (defined as root of drive)"""
Guido van Rossumf3c695c1999-04-06 19:32:19 +0000284 unc, rest = splitunc(path)
285 if unc:
286 return rest in ("", "/", "\\")
Guido van Rossumca99c2c1998-01-19 22:25:59 +0000287 p = splitdrive(path)[1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000288 return len(p) == 1 and p[0] in '/\\'
Guido van Rossum555915a1994-02-24 11:32:59 +0000289
290
291# Directory tree walk.
292# For each directory under top (including top itself, but excluding
293# '.' and '..'), func(arg, dirname, filenames) is called, where
294# dirname is the name of the directory and filenames is the list
295# files files (and subdirectories etc.) in the directory.
296# The func may modify the filenames list, to implement a filter,
297# or to impose a different order of visiting.
298
299def walk(top, func, arg):
Tim Peterscf5e6a42001-10-10 04:16:20 +0000300 """Directory tree walk with callback function.
Guido van Rossum534972b1999-02-03 17:20:50 +0000301
Tim Peterscf5e6a42001-10-10 04:16:20 +0000302 For each directory in the directory tree rooted at top (including top
303 itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
304 dirname is the name of the directory, and fnames a list of the names of
305 the files and subdirectories in dirname (excluding '.' and '..'). func
306 may modify the fnames list in-place (e.g. via del or slice assignment),
307 and walk will only recurse into the subdirectories whose names remain in
308 fnames; this can be used to implement a filter, or to impose a specific
309 order of visiting. No semantics are defined for, or required of, arg,
310 beyond that arg is always passed to func. It can be used, e.g., to pass
311 a filename pattern, or a mutable object designed to accumulate
312 statistics. Passing None for arg is common."""
313
Guido van Rossum15e22e11997-12-05 19:03:01 +0000314 try:
315 names = os.listdir(top)
316 except os.error:
317 return
318 func(arg, top, names)
319 exceptions = ('.', '..')
320 for name in names:
321 if name not in exceptions:
322 name = join(top, name)
323 if isdir(name):
324 walk(name, func, arg)
Guido van Rossum555915a1994-02-24 11:32:59 +0000325
326
327# Expand paths beginning with '~' or '~user'.
328# '~' means $HOME; '~user' means that user's home directory.
329# If the path doesn't begin with '~', or if the user or $HOME is unknown,
330# the path is returned unchanged (leaving error reporting to whatever
331# function is called with the expanded path as argument).
332# See also module 'glob' for expansion of *, ? and [...] in pathnames.
333# (A function should also be defined to do full *sh-style environment
334# variable expansion.)
335
336def expanduser(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000337 """Expand ~ and ~user constructs.
338
339 If user or $HOME is unknown, do nothing."""
Fred Drake8152d322000-12-12 23:20:45 +0000340 if path[:1] != '~':
Guido van Rossum15e22e11997-12-05 19:03:01 +0000341 return path
342 i, n = 1, len(path)
343 while i < n and path[i] not in '/\\':
Fred Drakeb4e460a2000-09-28 16:25:20 +0000344 i = i + 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000345 if i == 1:
346 if os.environ.has_key('HOME'):
347 userhome = os.environ['HOME']
348 elif not os.environ.has_key('HOMEPATH'):
349 return path
350 else:
351 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000352 drive = os.environ['HOMEDRIVE']
Guido van Rossum15e22e11997-12-05 19:03:01 +0000353 except KeyError:
354 drive = ''
355 userhome = join(drive, os.environ['HOMEPATH'])
356 else:
357 return path
358 return userhome + path[i:]
Guido van Rossum555915a1994-02-24 11:32:59 +0000359
360
361# Expand paths containing shell variable substitutions.
362# The following rules apply:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000363# - no expansion within single quotes
364# - no escape character, except for '$$' which is translated into '$'
365# - ${varname} is accepted.
366# - varnames can be made out of letters, digits and the character '_'
Guido van Rossum555915a1994-02-24 11:32:59 +0000367# XXX With COMMAND.COM you can use any characters in a variable name,
368# XXX except '^|<>='.
369
Tim Peters2344fae2001-01-15 00:50:52 +0000370def expandvars(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000371 """Expand shell variables of form $var and ${var}.
372
373 Unknown variables are left unchanged."""
Guido van Rossum15e22e11997-12-05 19:03:01 +0000374 if '$' not in path:
375 return path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000376 import string
Fred Drake79e75e12001-07-20 19:05:50 +0000377 varchars = string.ascii_letters + string.digits + '_-'
Guido van Rossum15e22e11997-12-05 19:03:01 +0000378 res = ''
379 index = 0
380 pathlen = len(path)
381 while index < pathlen:
382 c = path[index]
383 if c == '\'': # no expansion within single quotes
384 path = path[index + 1:]
385 pathlen = len(path)
386 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000387 index = path.index('\'')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000388 res = res + '\'' + path[:index + 1]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000389 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000390 res = res + path
Fred Drakeb4e460a2000-09-28 16:25:20 +0000391 index = pathlen - 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000392 elif c == '$': # variable or '$$'
393 if path[index + 1:index + 2] == '$':
394 res = res + c
395 index = index + 1
396 elif path[index + 1:index + 2] == '{':
397 path = path[index+2:]
398 pathlen = len(path)
399 try:
Fred Drakeb4e460a2000-09-28 16:25:20 +0000400 index = path.index('}')
Guido van Rossum15e22e11997-12-05 19:03:01 +0000401 var = path[:index]
402 if os.environ.has_key(var):
403 res = res + os.environ[var]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000404 except ValueError:
Guido van Rossum15e22e11997-12-05 19:03:01 +0000405 res = res + path
406 index = pathlen - 1
407 else:
408 var = ''
409 index = index + 1
410 c = path[index:index + 1]
411 while c != '' and c in varchars:
412 var = var + c
413 index = index + 1
414 c = path[index:index + 1]
415 if os.environ.has_key(var):
416 res = res + os.environ[var]
417 if c != '':
418 res = res + c
419 else:
420 res = res + c
421 index = index + 1
422 return res
Guido van Rossum555915a1994-02-24 11:32:59 +0000423
424
Tim Peters54a14a32001-08-30 22:05:26 +0000425# 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 +0000426# Previously, this function also truncated pathnames to 8+3 format,
427# but as this module is called "ntpath", that's obviously wrong!
Guido van Rossum555915a1994-02-24 11:32:59 +0000428
429def normpath(path):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000430 """Normalize path, eliminating double slashes, etc."""
Fred Drakeb4e460a2000-09-28 16:25:20 +0000431 path = path.replace("/", "\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000432 prefix, path = splitdrive(path)
Fred Drakeb4e460a2000-09-28 16:25:20 +0000433 while path[:1] == "\\":
434 prefix = prefix + "\\"
Guido van Rossum15e22e11997-12-05 19:03:01 +0000435 path = path[1:]
Fred Drakeb4e460a2000-09-28 16:25:20 +0000436 comps = path.split("\\")
Guido van Rossum15e22e11997-12-05 19:03:01 +0000437 i = 0
438 while i < len(comps):
Tim Peters54a14a32001-08-30 22:05:26 +0000439 if comps[i] in ('.', ''):
Guido van Rossum15e22e11997-12-05 19:03:01 +0000440 del comps[i]
Tim Peters54a14a32001-08-30 22:05:26 +0000441 elif comps[i] == '..':
442 if i > 0 and comps[i-1] != '..':
443 del comps[i-1:i+1]
444 i -= 1
445 elif i == 0 and prefix.endswith("\\"):
446 del comps[i]
447 else:
448 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000449 else:
Tim Peters54a14a32001-08-30 22:05:26 +0000450 i += 1
Guido van Rossum15e22e11997-12-05 19:03:01 +0000451 # If the path is now empty, substitute '.'
452 if not prefix and not comps:
453 comps.append('.')
Fred Drakeb4e460a2000-09-28 16:25:20 +0000454 return prefix + "\\".join(comps)
Guido van Rossume294cf61999-01-29 18:05:18 +0000455
456
457# Return an absolute path.
458def abspath(path):
Guido van Rossum534972b1999-02-03 17:20:50 +0000459 """Return the absolute version of a path"""
Mark Hammond647d2fe2000-08-14 06:20:32 +0000460 if path: # Empty path must return current working directory.
Mark Hammondef8b6542001-05-13 08:04:26 +0000461 from nt import _getfullpathname
Mark Hammond647d2fe2000-08-14 06:20:32 +0000462 try:
Mark Hammondef8b6542001-05-13 08:04:26 +0000463 path = _getfullpathname(path)
464 except WindowsError:
Fred Drakeda05e972001-05-15 15:23:01 +0000465 pass # Bad path - return unchanged.
Mark Hammond647d2fe2000-08-14 06:20:32 +0000466 else:
467 path = os.getcwd()
Guido van Rossum6dfc7921999-11-30 15:00:00 +0000468 return normpath(path)
Guido van Rossum83eeef42001-09-17 15:16:09 +0000469
470# realpath is a no-op on systems without islink support
471realpath = abspath