blob: e0539179454474813965ea03c4d688bc868c4e44 [file] [log] [blame]
Guido van Rossume7b146f2000-02-04 15:28:42 +00001"""Utility functions for copying files and directory trees.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00002
Guido van Rossum959fa011999-08-18 20:03:17 +00003XXX The functions here don't copy the resource fork or other metadata on Mac.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00004
5"""
Guido van Rossumc6360141990-10-13 19:23:40 +00006
Guido van Rossumc96207a1992-03-31 18:55:40 +00007import os
Guido van Rossum83c03e21999-02-23 23:07:51 +00008import sys
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00009import stat
Guido van Rossumc6360141990-10-13 19:23:40 +000010
Guido van Rossumc6360141990-10-13 19:23:40 +000011
Greg Stein42bb8b32000-07-12 09:55:30 +000012def copyfileobj(fsrc, fdst, length=16*1024):
13 """copy data from file-like object fsrc to file-like object fdst"""
14 while 1:
15 buf = fsrc.read(length)
16 if not buf:
17 break
18 fdst.write(buf)
19
Tim Peters495ad3c2001-01-15 01:36:40 +000020
Guido van Rossumc6360141990-10-13 19:23:40 +000021def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000022 """Copy data from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000023 fsrc = None
24 fdst = None
25 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000026 fsrc = open(src, 'rb')
27 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000028 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000029 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000030 if fdst:
31 fdst.close()
32 if fsrc:
33 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000034
Guido van Rossumc6360141990-10-13 19:23:40 +000035def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000036 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000037 if hasattr(os, 'chmod'):
38 st = os.stat(src)
39 mode = stat.S_IMODE(st[stat.ST_MODE])
40 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000041
Guido van Rossumc6360141990-10-13 19:23:40 +000042def copystat(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000043 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000044 st = os.stat(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000045 mode = stat.S_IMODE(st[stat.ST_MODE])
Tim Peters0c947242001-01-21 20:00:00 +000046 if hasattr(os, 'utime'):
47 os.utime(dst, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
48 if hasattr(os, 'chmod'):
49 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000050
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000051
Guido van Rossumc6360141990-10-13 19:23:40 +000052def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000053 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000054
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000055 The destination may be a directory.
56
57 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000058 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000059 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000060 copyfile(src, dst)
61 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000062
Guido van Rossumc6360141990-10-13 19:23:40 +000063def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000064 """Copy data and all stat info ("cp -p src dst").
65
66 The destination may be a directory.
67
68 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000069 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000070 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000071 copyfile(src, dst)
72 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000073
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000074
75def copytree(src, dst, symlinks=0):
76 """Recursively copy a directory tree using copy2().
77
78 The destination directory must not already exist.
79 Error are reported to standard output.
80
81 If the optional symlinks flag is true, symbolic links in the
82 source tree result in symbolic links in the destination tree; if
83 it is false, the contents of the files pointed to by symbolic
84 links are copied.
85
86 XXX Consider this example code rather than the ultimate tool.
87
88 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000089 names = os.listdir(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000090 os.mkdir(dst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000091 for name in names:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000092 srcname = os.path.join(src, name)
93 dstname = os.path.join(dst, name)
94 try:
95 if symlinks and os.path.islink(srcname):
96 linkto = os.readlink(srcname)
97 os.symlink(linkto, dstname)
98 elif os.path.isdir(srcname):
Fred Drake5fa38862000-04-07 14:34:50 +000099 copytree(srcname, dstname, symlinks)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000100 else:
101 copy2(srcname, dstname)
102 # XXX What about devices, sockets etc.?
103 except (IOError, os.error), why:
104 print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))
Guido van Rossumd7673291998-02-06 21:38:09 +0000105
106def rmtree(path, ignore_errors=0, onerror=None):
107 """Recursively delete a directory tree.
108
109 If ignore_errors is set, errors are ignored; otherwise, if
110 onerror is set, it is called to handle the error; otherwise, an
111 exception is raised.
112
113 """
114 cmdtuples = []
115 _build_cmdtuple(path, cmdtuples)
116 for cmd in cmdtuples:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 try:
118 apply(cmd[0], (cmd[1],))
119 except:
120 exc = sys.exc_info()
121 if ignore_errors:
122 pass
123 elif onerror:
124 onerror(cmd[0], cmd[1], exc)
125 else:
126 raise exc[0], (exc[1][0], exc[1][1] + ' removing '+cmd[1])
Guido van Rossumd7673291998-02-06 21:38:09 +0000127
128# Helper for rmtree()
129def _build_cmdtuple(path, cmdtuples):
130 for f in os.listdir(path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000131 real_f = os.path.join(path,f)
132 if os.path.isdir(real_f) and not os.path.islink(real_f):
133 _build_cmdtuple(real_f, cmdtuples)
134 else:
Guido van Rossumd832f9e1998-10-07 13:18:17 +0000135 cmdtuples.append((os.remove, real_f))
136 cmdtuples.append((os.rmdir, path))