blob: 5341786d528d6487be7d282fdcc6bdd1f90cdcc9 [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
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000010import exceptions
Guido van Rossumc6360141990-10-13 19:23:40 +000011
Skip Montanaro0de65802001-02-15 22:15:14 +000012__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
Raymond Hettinger2b9bfb32002-10-30 05:44:50 +000013 "copytree","move","rmtree","Error"]
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000014
15class Error(exceptions.EnvironmentError):
16 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000017
Greg Stein42bb8b32000-07-12 09:55:30 +000018def 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
Tim Peters495ad3c2001-01-15 01:36:40 +000026
Guido van Rossumc6360141990-10-13 19:23:40 +000027def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000028 """Copy data from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000029 fsrc = None
30 fdst = None
Raymond Hettinger57e79452002-09-08 20:43:59 +000031 # check for same pathname; all platforms
32 _src = os.path.normcase(os.path.abspath(src))
33 _dst = os.path.normcase(os.path.abspath(dst))
34 if _src == _dst:
35 return
Guido van Rossuma2baf461997-04-29 14:06:46 +000036 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000037 fsrc = open(src, 'rb')
38 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000039 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000040 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000041 if fdst:
42 fdst.close()
43 if fsrc:
44 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000045
Guido van Rossumc6360141990-10-13 19:23:40 +000046def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000047 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000048 if hasattr(os, 'chmod'):
49 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000050 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000051 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000052
Guido van Rossumc6360141990-10-13 19:23:40 +000053def copystat(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000054 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000055 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000056 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000057 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000058 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000059 if hasattr(os, 'chmod'):
60 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000061
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000062
Guido van Rossumc6360141990-10-13 19:23:40 +000063def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000064 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000065
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000066 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 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000073
Guido van Rossumc6360141990-10-13 19:23:40 +000074def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000075 """Copy data and all stat info ("cp -p src dst").
76
77 The destination may be a directory.
78
79 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000080 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000081 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000082 copyfile(src, dst)
83 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000084
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000085
Neal Norwitza4c93b62003-02-23 21:36:32 +000086def copytree(src, dst, symlinks=False):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000087 """Recursively copy a directory tree using copy2().
88
89 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +000090 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000091
92 If the optional symlinks flag is true, symbolic links in the
93 source tree result in symbolic links in the destination tree; if
94 it is false, the contents of the files pointed to by symbolic
95 links are copied.
96
97 XXX Consider this example code rather than the ultimate tool.
98
99 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000100 names = os.listdir(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000101 os.mkdir(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000102 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000103 for name in names:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 srcname = os.path.join(src, name)
105 dstname = os.path.join(dst, name)
106 try:
107 if symlinks and os.path.islink(srcname):
108 linkto = os.readlink(srcname)
109 os.symlink(linkto, dstname)
110 elif os.path.isdir(srcname):
Fred Drake5fa38862000-04-07 14:34:50 +0000111 copytree(srcname, dstname, symlinks)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 else:
113 copy2(srcname, dstname)
114 # XXX What about devices, sockets etc.?
115 except (IOError, os.error), why:
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000116 errors.append((srcname, dstname, why))
117 if errors:
118 raise Error, errors
Guido van Rossumd7673291998-02-06 21:38:09 +0000119
Barry Warsaw234d9a92003-01-24 17:36:15 +0000120def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000121 """Recursively delete a directory tree.
122
123 If ignore_errors is set, errors are ignored; otherwise, if
124 onerror is set, it is called to handle the error; otherwise, an
125 exception is raised.
Guido van Rossumd7673291998-02-06 21:38:09 +0000126 """
127 cmdtuples = []
Barry Warsaw234d9a92003-01-24 17:36:15 +0000128 arg = path
129 try:
130 _build_cmdtuple(path, cmdtuples)
131 for func, arg in cmdtuples:
Just van Rossum66d16ba2003-01-05 19:44:11 +0000132 func(arg)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000133 except OSError:
134 exc = sys.exc_info()
135 if ignore_errors:
136 pass
137 elif onerror is not None:
138 onerror(func, arg, exc)
139 else:
140 raise exc[0], (exc[1][0], exc[1][1] + ' removing '+arg)
Guido van Rossumd7673291998-02-06 21:38:09 +0000141
142# Helper for rmtree()
143def _build_cmdtuple(path, cmdtuples):
144 for f in os.listdir(path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000145 real_f = os.path.join(path,f)
146 if os.path.isdir(real_f) and not os.path.islink(real_f):
147 _build_cmdtuple(real_f, cmdtuples)
148 else:
Guido van Rossumd832f9e1998-10-07 13:18:17 +0000149 cmdtuples.append((os.remove, real_f))
150 cmdtuples.append((os.rmdir, path))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000151
152
153def move(src, dst):
154 """Recursively move a file or directory to another location.
155
156 If the destination is on our current filesystem, then simply use
157 rename. Otherwise, copy src to the dst and then remove src.
158 A lot more could be done here... A look at a mv.c shows a lot of
159 the issues this implementation glosses over.
160
161 """
162
163 try:
164 os.rename(src, dst)
165 except OSError:
166 if os.path.isdir(src):
Neal Norwitza4c93b62003-02-23 21:36:32 +0000167 copytree(src, dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000168 rmtree(src)
169 else:
170 copy2(src,dst)
171 os.unlink(src)