python-2.5.2/win32/Lib/shutil.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Utility functions for copying files and directory trees.
       
     2 
       
     3 XXX The functions here don't copy the resource fork or other metadata on Mac.
       
     4 
       
     5 """
       
     6 
       
     7 import os
       
     8 import sys
       
     9 import stat
       
    10 from os.path import abspath
       
    11 
       
    12 __all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
       
    13            "copytree","move","rmtree","Error"]
       
    14 
       
    15 class Error(EnvironmentError):
       
    16     pass
       
    17 
       
    18 def copyfileobj(fsrc, fdst, length=16*1024):
       
    19     """copy data from file-like object fsrc to file-like object fdst"""
       
    20     while 1:
       
    21         buf = fsrc.read(length)
       
    22         if not buf:
       
    23             break
       
    24         fdst.write(buf)
       
    25 
       
    26 def _samefile(src, dst):
       
    27     # Macintosh, Unix.
       
    28     if hasattr(os.path,'samefile'):
       
    29         try:
       
    30             return os.path.samefile(src, dst)
       
    31         except OSError:
       
    32             return False
       
    33 
       
    34     # All other platforms: check for same pathname.
       
    35     return (os.path.normcase(os.path.abspath(src)) ==
       
    36             os.path.normcase(os.path.abspath(dst)))
       
    37 
       
    38 def copyfile(src, dst):
       
    39     """Copy data from src to dst"""
       
    40     if _samefile(src, dst):
       
    41         raise Error, "`%s` and `%s` are the same file" % (src, dst)
       
    42 
       
    43     fsrc = None
       
    44     fdst = None
       
    45     try:
       
    46         fsrc = open(src, 'rb')
       
    47         fdst = open(dst, 'wb')
       
    48         copyfileobj(fsrc, fdst)
       
    49     finally:
       
    50         if fdst:
       
    51             fdst.close()
       
    52         if fsrc:
       
    53             fsrc.close()
       
    54 
       
    55 def copymode(src, dst):
       
    56     """Copy mode bits from src to dst"""
       
    57     if hasattr(os, 'chmod'):
       
    58         st = os.stat(src)
       
    59         mode = stat.S_IMODE(st.st_mode)
       
    60         os.chmod(dst, mode)
       
    61 
       
    62 def copystat(src, dst):
       
    63     """Copy all stat info (mode bits, atime and mtime) from src to dst"""
       
    64     st = os.stat(src)
       
    65     mode = stat.S_IMODE(st.st_mode)
       
    66     if hasattr(os, 'utime'):
       
    67         os.utime(dst, (st.st_atime, st.st_mtime))
       
    68     if hasattr(os, 'chmod'):
       
    69         os.chmod(dst, mode)
       
    70 
       
    71 
       
    72 def copy(src, dst):
       
    73     """Copy data and mode bits ("cp src dst").
       
    74 
       
    75     The destination may be a directory.
       
    76 
       
    77     """
       
    78     if os.path.isdir(dst):
       
    79         dst = os.path.join(dst, os.path.basename(src))
       
    80     copyfile(src, dst)
       
    81     copymode(src, dst)
       
    82 
       
    83 def copy2(src, dst):
       
    84     """Copy data and all stat info ("cp -p src dst").
       
    85 
       
    86     The destination may be a directory.
       
    87 
       
    88     """
       
    89     if os.path.isdir(dst):
       
    90         dst = os.path.join(dst, os.path.basename(src))
       
    91     copyfile(src, dst)
       
    92     copystat(src, dst)
       
    93 
       
    94 
       
    95 def copytree(src, dst, symlinks=False):
       
    96     """Recursively copy a directory tree using copy2().
       
    97 
       
    98     The destination directory must not already exist.
       
    99     If exception(s) occur, an Error is raised with a list of reasons.
       
   100 
       
   101     If the optional symlinks flag is true, symbolic links in the
       
   102     source tree result in symbolic links in the destination tree; if
       
   103     it is false, the contents of the files pointed to by symbolic
       
   104     links are copied.
       
   105 
       
   106     XXX Consider this example code rather than the ultimate tool.
       
   107 
       
   108     """
       
   109     names = os.listdir(src)
       
   110     os.makedirs(dst)
       
   111     errors = []
       
   112     for name in names:
       
   113         srcname = os.path.join(src, name)
       
   114         dstname = os.path.join(dst, name)
       
   115         try:
       
   116             if symlinks and os.path.islink(srcname):
       
   117                 linkto = os.readlink(srcname)
       
   118                 os.symlink(linkto, dstname)
       
   119             elif os.path.isdir(srcname):
       
   120                 copytree(srcname, dstname, symlinks)
       
   121             else:
       
   122                 copy2(srcname, dstname)
       
   123             # XXX What about devices, sockets etc.?
       
   124         except (IOError, os.error), why:
       
   125             errors.append((srcname, dstname, str(why)))
       
   126         # catch the Error from the recursive copytree so that we can
       
   127         # continue with other files
       
   128         except Error, err:
       
   129             errors.extend(err.args[0])
       
   130     try:
       
   131         copystat(src, dst)
       
   132     except WindowsError:
       
   133         # can't copy file access times on Windows
       
   134         pass
       
   135     except OSError, why:
       
   136         errors.extend((src, dst, str(why)))
       
   137     if errors:
       
   138         raise Error, errors
       
   139 
       
   140 def rmtree(path, ignore_errors=False, onerror=None):
       
   141     """Recursively delete a directory tree.
       
   142 
       
   143     If ignore_errors is set, errors are ignored; otherwise, if onerror
       
   144     is set, it is called to handle the error with arguments (func,
       
   145     path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
       
   146     path is the argument to that function that caused it to fail; and
       
   147     exc_info is a tuple returned by sys.exc_info().  If ignore_errors
       
   148     is false and onerror is None, an exception is raised.
       
   149 
       
   150     """
       
   151     if ignore_errors:
       
   152         def onerror(*args):
       
   153             pass
       
   154     elif onerror is None:
       
   155         def onerror(*args):
       
   156             raise
       
   157     names = []
       
   158     try:
       
   159         names = os.listdir(path)
       
   160     except os.error, err:
       
   161         onerror(os.listdir, path, sys.exc_info())
       
   162     for name in names:
       
   163         fullname = os.path.join(path, name)
       
   164         try:
       
   165             mode = os.lstat(fullname).st_mode
       
   166         except os.error:
       
   167             mode = 0
       
   168         if stat.S_ISDIR(mode):
       
   169             rmtree(fullname, ignore_errors, onerror)
       
   170         else:
       
   171             try:
       
   172                 os.remove(fullname)
       
   173             except os.error, err:
       
   174                 onerror(os.remove, fullname, sys.exc_info())
       
   175     try:
       
   176         os.rmdir(path)
       
   177     except os.error:
       
   178         onerror(os.rmdir, path, sys.exc_info())
       
   179 
       
   180 def move(src, dst):
       
   181     """Recursively move a file or directory to another location.
       
   182 
       
   183     If the destination is on our current filesystem, then simply use
       
   184     rename.  Otherwise, copy src to the dst and then remove src.
       
   185     A lot more could be done here...  A look at a mv.c shows a lot of
       
   186     the issues this implementation glosses over.
       
   187 
       
   188     """
       
   189 
       
   190     try:
       
   191         os.rename(src, dst)
       
   192     except OSError:
       
   193         if os.path.isdir(src):
       
   194             if destinsrc(src, dst):
       
   195                 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
       
   196             copytree(src, dst, symlinks=True)
       
   197             rmtree(src)
       
   198         else:
       
   199             copy2(src,dst)
       
   200             os.unlink(src)
       
   201 
       
   202 def destinsrc(src, dst):
       
   203     return abspath(dst).startswith(abspath(src))