python-2.5.2/win32/Lib/ntpath.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
       
     2 """Common pathname manipulations, WindowsNT/95 version.
       
     3 
       
     4 Instead of importing this module directly, import os and refer to this
       
     5 module as os.path.
       
     6 """
       
     7 
       
     8 import os
       
     9 import stat
       
    10 import sys
       
    11 
       
    12 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
       
    13            "basename","dirname","commonprefix","getsize","getmtime",
       
    14            "getatime","getctime", "islink","exists","lexists","isdir","isfile",
       
    15            "ismount","walk","expanduser","expandvars","normpath","abspath",
       
    16            "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
       
    17            "extsep","devnull","realpath","supports_unicode_filenames"]
       
    18 
       
    19 # strings representing various path-related bits and pieces
       
    20 curdir = '.'
       
    21 pardir = '..'
       
    22 extsep = '.'
       
    23 sep = '\\'
       
    24 pathsep = ';'
       
    25 altsep = '/'
       
    26 defpath = '.;C:\\bin'
       
    27 if 'ce' in sys.builtin_module_names:
       
    28     defpath = '\\Windows'
       
    29 elif 'os2' in sys.builtin_module_names:
       
    30     # OS/2 w/ VACPP
       
    31     altsep = '/'
       
    32 devnull = 'nul'
       
    33 
       
    34 # Normalize the case of a pathname and map slashes to backslashes.
       
    35 # Other normalizations (such as optimizing '../' away) are not done
       
    36 # (this is done by normpath).
       
    37 
       
    38 def normcase(s):
       
    39     """Normalize case of pathname.
       
    40 
       
    41     Makes all characters lowercase and all slashes into backslashes."""
       
    42     return s.replace("/", "\\").lower()
       
    43 
       
    44 
       
    45 # Return whether a path is absolute.
       
    46 # Trivial in Posix, harder on the Mac or MS-DOS.
       
    47 # For DOS it is absolute if it starts with a slash or backslash (current
       
    48 # volume), or if a pathname after the volume letter and colon / UNC resource
       
    49 # starts with a slash or backslash.
       
    50 
       
    51 def isabs(s):
       
    52     """Test whether a path is absolute"""
       
    53     s = splitdrive(s)[1]
       
    54     return s != '' and s[:1] in '/\\'
       
    55 
       
    56 
       
    57 # Join two (or more) paths.
       
    58 
       
    59 def join(a, *p):
       
    60     """Join two or more pathname components, inserting "\\" as needed"""
       
    61     path = a
       
    62     for b in p:
       
    63         b_wins = 0  # set to 1 iff b makes path irrelevant
       
    64         if path == "":
       
    65             b_wins = 1
       
    66 
       
    67         elif isabs(b):
       
    68             # This probably wipes out path so far.  However, it's more
       
    69             # complicated if path begins with a drive letter:
       
    70             #     1. join('c:', '/a') == 'c:/a'
       
    71             #     2. join('c:/', '/a') == 'c:/a'
       
    72             # But
       
    73             #     3. join('c:/a', '/b') == '/b'
       
    74             #     4. join('c:', 'd:/') = 'd:/'
       
    75             #     5. join('c:/', 'd:/') = 'd:/'
       
    76             if path[1:2] != ":" or b[1:2] == ":":
       
    77                 # Path doesn't start with a drive letter, or cases 4 and 5.
       
    78                 b_wins = 1
       
    79 
       
    80             # Else path has a drive letter, and b doesn't but is absolute.
       
    81             elif len(path) > 3 or (len(path) == 3 and
       
    82                                    path[-1] not in "/\\"):
       
    83                 # case 3
       
    84                 b_wins = 1
       
    85 
       
    86         if b_wins:
       
    87             path = b
       
    88         else:
       
    89             # Join, and ensure there's a separator.
       
    90             assert len(path) > 0
       
    91             if path[-1] in "/\\":
       
    92                 if b and b[0] in "/\\":
       
    93                     path += b[1:]
       
    94                 else:
       
    95                     path += b
       
    96             elif path[-1] == ":":
       
    97                 path += b
       
    98             elif b:
       
    99                 if b[0] in "/\\":
       
   100                     path += b
       
   101                 else:
       
   102                     path += "\\" + b
       
   103             else:
       
   104                 # path is not empty and does not end with a backslash,
       
   105                 # but b is empty; since, e.g., split('a/') produces
       
   106                 # ('a', ''), it's best if join() adds a backslash in
       
   107                 # this case.
       
   108                 path += '\\'
       
   109 
       
   110     return path
       
   111 
       
   112 
       
   113 # Split a path in a drive specification (a drive letter followed by a
       
   114 # colon) and the path specification.
       
   115 # It is always true that drivespec + pathspec == p
       
   116 def splitdrive(p):
       
   117     """Split a pathname into drive and path specifiers. Returns a 2-tuple
       
   118 "(drive,path)";  either part may be empty"""
       
   119     if p[1:2] == ':':
       
   120         return p[0:2], p[2:]
       
   121     return '', p
       
   122 
       
   123 
       
   124 # Parse UNC paths
       
   125 def splitunc(p):
       
   126     """Split a pathname into UNC mount point and relative path specifiers.
       
   127 
       
   128     Return a 2-tuple (unc, rest); either part may be empty.
       
   129     If unc is not empty, it has the form '//host/mount' (or similar
       
   130     using backslashes).  unc+rest is always the input path.
       
   131     Paths containing drive letters never have an UNC part.
       
   132     """
       
   133     if p[1:2] == ':':
       
   134         return '', p # Drive letter present
       
   135     firstTwo = p[0:2]
       
   136     if firstTwo == '//' or firstTwo == '\\\\':
       
   137         # is a UNC path:
       
   138         # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter
       
   139         # \\machine\mountpoint\directories...
       
   140         #           directory ^^^^^^^^^^^^^^^
       
   141         normp = normcase(p)
       
   142         index = normp.find('\\', 2)
       
   143         if index == -1:
       
   144             ##raise RuntimeError, 'illegal UNC path: "' + p + '"'
       
   145             return ("", p)
       
   146         index = normp.find('\\', index + 1)
       
   147         if index == -1:
       
   148             index = len(p)
       
   149         return p[:index], p[index:]
       
   150     return '', p
       
   151 
       
   152 
       
   153 # Split a path in head (everything up to the last '/') and tail (the
       
   154 # rest).  After the trailing '/' is stripped, the invariant
       
   155 # join(head, tail) == p holds.
       
   156 # The resulting head won't end in '/' unless it is the root.
       
   157 
       
   158 def split(p):
       
   159     """Split a pathname.
       
   160 
       
   161     Return tuple (head, tail) where tail is everything after the final slash.
       
   162     Either part may be empty."""
       
   163 
       
   164     d, p = splitdrive(p)
       
   165     # set i to index beyond p's last slash
       
   166     i = len(p)
       
   167     while i and p[i-1] not in '/\\':
       
   168         i = i - 1
       
   169     head, tail = p[:i], p[i:]  # now tail has no slashes
       
   170     # remove trailing slashes from head, unless it's all slashes
       
   171     head2 = head
       
   172     while head2 and head2[-1] in '/\\':
       
   173         head2 = head2[:-1]
       
   174     head = head2 or head
       
   175     return d + head, tail
       
   176 
       
   177 
       
   178 # Split a path in root and extension.
       
   179 # The extension is everything starting at the last dot in the last
       
   180 # pathname component; the root is everything before that.
       
   181 # It is always true that root + ext == p.
       
   182 
       
   183 def splitext(p):
       
   184     """Split the extension from a pathname.
       
   185 
       
   186     Extension is everything from the last dot to the end.
       
   187     Return (root, ext), either part may be empty."""
       
   188 
       
   189     i = p.rfind('.')
       
   190     if i<=max(p.rfind('/'), p.rfind('\\')):
       
   191         return p, ''
       
   192     else:
       
   193         return p[:i], p[i:]
       
   194 
       
   195 
       
   196 # Return the tail (basename) part of a path.
       
   197 
       
   198 def basename(p):
       
   199     """Returns the final component of a pathname"""
       
   200     return split(p)[1]
       
   201 
       
   202 
       
   203 # Return the head (dirname) part of a path.
       
   204 
       
   205 def dirname(p):
       
   206     """Returns the directory component of a pathname"""
       
   207     return split(p)[0]
       
   208 
       
   209 
       
   210 # Return the longest prefix of all list elements.
       
   211 
       
   212 def commonprefix(m):
       
   213     "Given a list of pathnames, returns the longest common leading component"
       
   214     if not m: return ''
       
   215     s1 = min(m)
       
   216     s2 = max(m)
       
   217     n = min(len(s1), len(s2))
       
   218     for i in xrange(n):
       
   219         if s1[i] != s2[i]:
       
   220             return s1[:i]
       
   221     return s1[:n]
       
   222 
       
   223 
       
   224 # Get size, mtime, atime of files.
       
   225 
       
   226 def getsize(filename):
       
   227     """Return the size of a file, reported by os.stat()"""
       
   228     return os.stat(filename).st_size
       
   229 
       
   230 def getmtime(filename):
       
   231     """Return the last modification time of a file, reported by os.stat()"""
       
   232     return os.stat(filename).st_mtime
       
   233 
       
   234 def getatime(filename):
       
   235     """Return the last access time of a file, reported by os.stat()"""
       
   236     return os.stat(filename).st_atime
       
   237 
       
   238 def getctime(filename):
       
   239     """Return the creation time of a file, reported by os.stat()."""
       
   240     return os.stat(filename).st_ctime
       
   241 
       
   242 # Is a path a symbolic link?
       
   243 # This will always return false on systems where posix.lstat doesn't exist.
       
   244 
       
   245 def islink(path):
       
   246     """Test for symbolic link.  On WindowsNT/95 always returns false"""
       
   247     return False
       
   248 
       
   249 
       
   250 # Does a path exist?
       
   251 
       
   252 def exists(path):
       
   253     """Test whether a path exists"""
       
   254     try:
       
   255         st = os.stat(path)
       
   256     except os.error:
       
   257         return False
       
   258     return True
       
   259 
       
   260 lexists = exists
       
   261 
       
   262 
       
   263 # Is a path a dos directory?
       
   264 # This follows symbolic links, so both islink() and isdir() can be true
       
   265 # for the same path.
       
   266 
       
   267 def isdir(path):
       
   268     """Test whether a path is a directory"""
       
   269     try:
       
   270         st = os.stat(path)
       
   271     except os.error:
       
   272         return False
       
   273     return stat.S_ISDIR(st.st_mode)
       
   274 
       
   275 
       
   276 # Is a path a regular file?
       
   277 # This follows symbolic links, so both islink() and isdir() can be true
       
   278 # for the same path.
       
   279 
       
   280 def isfile(path):
       
   281     """Test whether a path is a regular file"""
       
   282     try:
       
   283         st = os.stat(path)
       
   284     except os.error:
       
   285         return False
       
   286     return stat.S_ISREG(st.st_mode)
       
   287 
       
   288 
       
   289 # Is a path a mount point?  Either a root (with or without drive letter)
       
   290 # or an UNC path with at most a / or \ after the mount point.
       
   291 
       
   292 def ismount(path):
       
   293     """Test whether a path is a mount point (defined as root of drive)"""
       
   294     unc, rest = splitunc(path)
       
   295     if unc:
       
   296         return rest in ("", "/", "\\")
       
   297     p = splitdrive(path)[1]
       
   298     return len(p) == 1 and p[0] in '/\\'
       
   299 
       
   300 
       
   301 # Directory tree walk.
       
   302 # For each directory under top (including top itself, but excluding
       
   303 # '.' and '..'), func(arg, dirname, filenames) is called, where
       
   304 # dirname is the name of the directory and filenames is the list
       
   305 # of files (and subdirectories etc.) in the directory.
       
   306 # The func may modify the filenames list, to implement a filter,
       
   307 # or to impose a different order of visiting.
       
   308 
       
   309 def walk(top, func, arg):
       
   310     """Directory tree walk with callback function.
       
   311 
       
   312     For each directory in the directory tree rooted at top (including top
       
   313     itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
       
   314     dirname is the name of the directory, and fnames a list of the names of
       
   315     the files and subdirectories in dirname (excluding '.' and '..').  func
       
   316     may modify the fnames list in-place (e.g. via del or slice assignment),
       
   317     and walk will only recurse into the subdirectories whose names remain in
       
   318     fnames; this can be used to implement a filter, or to impose a specific
       
   319     order of visiting.  No semantics are defined for, or required of, arg,
       
   320     beyond that arg is always passed to func.  It can be used, e.g., to pass
       
   321     a filename pattern, or a mutable object designed to accumulate
       
   322     statistics.  Passing None for arg is common."""
       
   323 
       
   324     try:
       
   325         names = os.listdir(top)
       
   326     except os.error:
       
   327         return
       
   328     func(arg, top, names)
       
   329     exceptions = ('.', '..')
       
   330     for name in names:
       
   331         if name not in exceptions:
       
   332             name = join(top, name)
       
   333             if isdir(name):
       
   334                 walk(name, func, arg)
       
   335 
       
   336 
       
   337 # Expand paths beginning with '~' or '~user'.
       
   338 # '~' means $HOME; '~user' means that user's home directory.
       
   339 # If the path doesn't begin with '~', or if the user or $HOME is unknown,
       
   340 # the path is returned unchanged (leaving error reporting to whatever
       
   341 # function is called with the expanded path as argument).
       
   342 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
       
   343 # (A function should also be defined to do full *sh-style environment
       
   344 # variable expansion.)
       
   345 
       
   346 def expanduser(path):
       
   347     """Expand ~ and ~user constructs.
       
   348 
       
   349     If user or $HOME is unknown, do nothing."""
       
   350     if path[:1] != '~':
       
   351         return path
       
   352     i, n = 1, len(path)
       
   353     while i < n and path[i] not in '/\\':
       
   354         i = i + 1
       
   355     if i == 1:
       
   356         if 'HOME' in os.environ:
       
   357             userhome = os.environ['HOME']
       
   358         elif not 'HOMEPATH' in os.environ:
       
   359             return path
       
   360         else:
       
   361             try:
       
   362                 drive = os.environ['HOMEDRIVE']
       
   363             except KeyError:
       
   364                 drive = ''
       
   365             userhome = join(drive, os.environ['HOMEPATH'])
       
   366     else:
       
   367         return path
       
   368     return userhome + path[i:]
       
   369 
       
   370 
       
   371 # Expand paths containing shell variable substitutions.
       
   372 # The following rules apply:
       
   373 #       - no expansion within single quotes
       
   374 #       - no escape character, except for '$$' which is translated into '$'
       
   375 #       - ${varname} is accepted.
       
   376 #       - varnames can be made out of letters, digits and the character '_'
       
   377 # XXX With COMMAND.COM you can use any characters in a variable name,
       
   378 # XXX except '^|<>='.
       
   379 
       
   380 def expandvars(path):
       
   381     """Expand shell variables of form $var and ${var}.
       
   382 
       
   383     Unknown variables are left unchanged."""
       
   384     if '$' not in path:
       
   385         return path
       
   386     import string
       
   387     varchars = string.ascii_letters + string.digits + '_-'
       
   388     res = ''
       
   389     index = 0
       
   390     pathlen = len(path)
       
   391     while index < pathlen:
       
   392         c = path[index]
       
   393         if c == '\'':   # no expansion within single quotes
       
   394             path = path[index + 1:]
       
   395             pathlen = len(path)
       
   396             try:
       
   397                 index = path.index('\'')
       
   398                 res = res + '\'' + path[:index + 1]
       
   399             except ValueError:
       
   400                 res = res + path
       
   401                 index = pathlen - 1
       
   402         elif c == '$':  # variable or '$$'
       
   403             if path[index + 1:index + 2] == '$':
       
   404                 res = res + c
       
   405                 index = index + 1
       
   406             elif path[index + 1:index + 2] == '{':
       
   407                 path = path[index+2:]
       
   408                 pathlen = len(path)
       
   409                 try:
       
   410                     index = path.index('}')
       
   411                     var = path[:index]
       
   412                     if var in os.environ:
       
   413                         res = res + os.environ[var]
       
   414                 except ValueError:
       
   415                     res = res + path
       
   416                     index = pathlen - 1
       
   417             else:
       
   418                 var = ''
       
   419                 index = index + 1
       
   420                 c = path[index:index + 1]
       
   421                 while c != '' and c in varchars:
       
   422                     var = var + c
       
   423                     index = index + 1
       
   424                     c = path[index:index + 1]
       
   425                 if var in os.environ:
       
   426                     res = res + os.environ[var]
       
   427                 if c != '':
       
   428                     res = res + c
       
   429         else:
       
   430             res = res + c
       
   431         index = index + 1
       
   432     return res
       
   433 
       
   434 
       
   435 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
       
   436 # Previously, this function also truncated pathnames to 8+3 format,
       
   437 # but as this module is called "ntpath", that's obviously wrong!
       
   438 
       
   439 def normpath(path):
       
   440     """Normalize path, eliminating double slashes, etc."""
       
   441     path = path.replace("/", "\\")
       
   442     prefix, path = splitdrive(path)
       
   443     # We need to be careful here. If the prefix is empty, and the path starts
       
   444     # with a backslash, it could either be an absolute path on the current
       
   445     # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
       
   446     # is therefore imperative NOT to collapse multiple backslashes blindly in
       
   447     # that case.
       
   448     # The code below preserves multiple backslashes when there is no drive
       
   449     # letter. This means that the invalid filename \\\a\b is preserved
       
   450     # unchanged, where a\\\b is normalised to a\b. It's not clear that there
       
   451     # is any better behaviour for such edge cases.
       
   452     if prefix == '':
       
   453         # No drive letter - preserve initial backslashes
       
   454         while path[:1] == "\\":
       
   455             prefix = prefix + "\\"
       
   456             path = path[1:]
       
   457     else:
       
   458         # We have a drive letter - collapse initial backslashes
       
   459         if path.startswith("\\"):
       
   460             prefix = prefix + "\\"
       
   461             path = path.lstrip("\\")
       
   462     comps = path.split("\\")
       
   463     i = 0
       
   464     while i < len(comps):
       
   465         if comps[i] in ('.', ''):
       
   466             del comps[i]
       
   467         elif comps[i] == '..':
       
   468             if i > 0 and comps[i-1] != '..':
       
   469                 del comps[i-1:i+1]
       
   470                 i -= 1
       
   471             elif i == 0 and prefix.endswith("\\"):
       
   472                 del comps[i]
       
   473             else:
       
   474                 i += 1
       
   475         else:
       
   476             i += 1
       
   477     # If the path is now empty, substitute '.'
       
   478     if not prefix and not comps:
       
   479         comps.append('.')
       
   480     return prefix + "\\".join(comps)
       
   481 
       
   482 
       
   483 # Return an absolute path.
       
   484 try:
       
   485     from nt import _getfullpathname
       
   486 
       
   487 except ImportError: # not running on Windows - mock up something sensible
       
   488     def abspath(path):
       
   489         """Return the absolute version of a path."""
       
   490         if not isabs(path):
       
   491             path = join(os.getcwd(), path)
       
   492         return normpath(path)
       
   493 
       
   494 else:  # use native Windows method on Windows
       
   495     def abspath(path):
       
   496         """Return the absolute version of a path."""
       
   497 
       
   498         if path: # Empty path must return current working directory.
       
   499             try:
       
   500                 path = _getfullpathname(path)
       
   501             except WindowsError:
       
   502                 pass # Bad path - return unchanged.
       
   503         else:
       
   504             path = os.getcwd()
       
   505         return normpath(path)
       
   506 
       
   507 # realpath is a no-op on systems without islink support
       
   508 realpath = abspath
       
   509 # Win9x family and earlier have no Unicode filename support.
       
   510 supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
       
   511                               sys.getwindowsversion()[3] >= 2)