blob: c46ec47fd3b32371efe598ec6a2636c9e3ab861a [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
Brett Cannon1c3fa182004-06-19 21:11:35 +000010from os.path import abspath
Georg Brandle78fbcc2008-07-05 10:13:36 +000011import fnmatch
Guido van Rossumc6360141990-10-13 19:23:40 +000012
Skip Montanaro0de65802001-02-15 22:15:14 +000013__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
Antoine Pitrou1fc02312009-05-01 20:55:35 +000014 "copytree","move","rmtree","Error", "SpecialFileError"]
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000015
Neal Norwitz4ce69a52005-09-01 00:45:28 +000016class Error(EnvironmentError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000017 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000018
Antoine Pitrou1fc02312009-05-01 20:55:35 +000019class SpecialFileError(EnvironmentError):
20 """Raised when trying to do a kind of operation (e.g. copying) which is
21 not supported on a special file (e.g. a named pipe)"""
22
Antoine Pitrou9fcd4b32008-08-11 17:21:36 +000023try:
24 WindowsError
25except NameError:
26 WindowsError = None
27
Greg Stein42bb8b32000-07-12 09:55:30 +000028def copyfileobj(fsrc, fdst, length=16*1024):
29 """copy data from file-like object fsrc to file-like object fdst"""
30 while 1:
31 buf = fsrc.read(length)
32 if not buf:
33 break
34 fdst.write(buf)
35
Johannes Gijsbers46f14592004-08-14 13:30:02 +000036def _samefile(src, dst):
37 # Macintosh, Unix.
38 if hasattr(os.path,'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +000039 try:
40 return os.path.samefile(src, dst)
41 except OSError:
42 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +000043
44 # All other platforms: check for same pathname.
45 return (os.path.normcase(os.path.abspath(src)) ==
46 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +000047
Guido van Rossumc6360141990-10-13 19:23:40 +000048def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000049 """Copy data from src to dst"""
Johannes Gijsbers46f14592004-08-14 13:30:02 +000050 if _samefile(src, dst):
51 raise Error, "`%s` and `%s` are the same file" % (src, dst)
52
Guido van Rossuma2baf461997-04-29 14:06:46 +000053 fsrc = None
54 fdst = None
Antoine Pitrou1fc02312009-05-01 20:55:35 +000055 for fn in [src, dst]:
56 try:
57 st = os.stat(fn)
58 except OSError:
59 # File most likely does not exist
60 pass
61 # XXX What about other special files? (sockets, devices...)
62 if stat.S_ISFIFO(st.st_mode):
63 raise SpecialFileError("`%s` is a named pipe" % fn)
Guido van Rossuma2baf461997-04-29 14:06:46 +000064 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000065 fsrc = open(src, 'rb')
66 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000067 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000068 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000069 if fdst:
70 fdst.close()
71 if fsrc:
72 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000073
Guido van Rossumc6360141990-10-13 19:23:40 +000074def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000075 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000076 if hasattr(os, 'chmod'):
77 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000078 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000079 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000080
Guido van Rossumc6360141990-10-13 19:23:40 +000081def copystat(src, dst):
Martin v. Löwis382abef2007-02-19 10:55:19 +000082 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000083 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000084 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000085 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000086 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000087 if hasattr(os, 'chmod'):
88 os.chmod(dst, mode)
Martin v. Löwis382abef2007-02-19 10:55:19 +000089 if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
90 os.chflags(dst, st.st_flags)
Guido van Rossumc6360141990-10-13 19:23:40 +000091
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000092
Guido van Rossumc6360141990-10-13 19:23:40 +000093def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000094 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000095
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000096 The destination may be a directory.
97
98 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000099 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000100 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +0000101 copyfile(src, dst)
102 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +0000103
Guido van Rossumc6360141990-10-13 19:23:40 +0000104def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000105 """Copy data and all stat info ("cp -p src dst").
106
107 The destination may be a directory.
108
109 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000110 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000111 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +0000112 copyfile(src, dst)
113 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +0000114
Georg Brandle78fbcc2008-07-05 10:13:36 +0000115def ignore_patterns(*patterns):
116 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000117
Georg Brandle78fbcc2008-07-05 10:13:36 +0000118 Patterns is a sequence of glob-style patterns
119 that are used to exclude files"""
120 def _ignore_patterns(path, names):
121 ignored_names = []
122 for pattern in patterns:
123 ignored_names.extend(fnmatch.filter(names, pattern))
124 return set(ignored_names)
125 return _ignore_patterns
126
127def copytree(src, dst, symlinks=False, ignore=None):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000128 """Recursively copy a directory tree using copy2().
129
130 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000131 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000132
133 If the optional symlinks flag is true, symbolic links in the
134 source tree result in symbolic links in the destination tree; if
135 it is false, the contents of the files pointed to by symbolic
136 links are copied.
137
Georg Brandle78fbcc2008-07-05 10:13:36 +0000138 The optional ignore argument is a callable. If given, it
139 is called with the `src` parameter, which is the directory
140 being visited by copytree(), and `names` which is the list of
141 `src` contents, as returned by os.listdir():
142
143 callable(src, names) -> ignored_names
144
145 Since copytree() is called recursively, the callable will be
146 called once for each directory that is copied. It returns a
147 list of names relative to the `src` directory that should
148 not be copied.
149
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000150 XXX Consider this example code rather than the ultimate tool.
151
152 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000153 names = os.listdir(src)
Georg Brandle78fbcc2008-07-05 10:13:36 +0000154 if ignore is not None:
155 ignored_names = ignore(src, names)
156 else:
157 ignored_names = set()
158
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000159 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000160 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000161 for name in names:
Georg Brandle78fbcc2008-07-05 10:13:36 +0000162 if name in ignored_names:
163 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 srcname = os.path.join(src, name)
165 dstname = os.path.join(dst, name)
166 try:
167 if symlinks and os.path.islink(srcname):
168 linkto = os.readlink(srcname)
169 os.symlink(linkto, dstname)
170 elif os.path.isdir(srcname):
Georg Brandle78fbcc2008-07-05 10:13:36 +0000171 copytree(srcname, dstname, symlinks, ignore)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 else:
Antoine Pitrou1fc02312009-05-01 20:55:35 +0000173 # Will raise a SpecialFileError for unsupported file types
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000174 copy2(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000175 # catch the Error from the recursive copytree so that we can
176 # continue with other files
177 except Error, err:
178 errors.extend(err.args[0])
Antoine Pitrou1fc02312009-05-01 20:55:35 +0000179 except EnvironmentError, why:
180 errors.append((srcname, dstname, str(why)))
Martin v. Löwis4e678382006-07-30 13:00:31 +0000181 try:
182 copystat(src, dst)
Martin v. Löwis4e678382006-07-30 13:00:31 +0000183 except OSError, why:
Antoine Pitrou9fcd4b32008-08-11 17:21:36 +0000184 if WindowsError is not None and isinstance(why, WindowsError):
185 # Copying file access times may fail on Windows
186 pass
187 else:
188 errors.extend((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000189 if errors:
190 raise Error, errors
Guido van Rossumd7673291998-02-06 21:38:09 +0000191
Barry Warsaw234d9a92003-01-24 17:36:15 +0000192def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000193 """Recursively delete a directory tree.
194
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195 If ignore_errors is set, errors are ignored; otherwise, if onerror
196 is set, it is called to handle the error with arguments (func,
197 path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
198 path is the argument to that function that caused it to fail; and
199 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
200 is false and onerror is None, an exception is raised.
201
Guido van Rossumd7673291998-02-06 21:38:09 +0000202 """
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000203 if ignore_errors:
204 def onerror(*args):
Barry Warsaw234d9a92003-01-24 17:36:15 +0000205 pass
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000206 elif onerror is None:
207 def onerror(*args):
208 raise
Georg Brandl52353982008-01-20 14:17:42 +0000209 try:
210 if os.path.islink(path):
211 # symlinks to directories are forbidden, see bug #1669
212 raise OSError("Cannot call rmtree on a symbolic link")
213 except OSError:
214 onerror(os.path.islink, path, sys.exc_info())
215 # can't continue even if onerror hook returns
216 return
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000217 names = []
218 try:
219 names = os.listdir(path)
220 except os.error, err:
221 onerror(os.listdir, path, sys.exc_info())
222 for name in names:
223 fullname = os.path.join(path, name)
224 try:
225 mode = os.lstat(fullname).st_mode
226 except os.error:
227 mode = 0
228 if stat.S_ISDIR(mode):
229 rmtree(fullname, ignore_errors, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000230 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000231 try:
232 os.remove(fullname)
233 except os.error, err:
234 onerror(os.remove, fullname, sys.exc_info())
235 try:
236 os.rmdir(path)
237 except os.error:
238 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000239
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000240
Sean Reifscheider493894c2008-03-18 17:24:12 +0000241def _basename(path):
242 # A basename() variant which first strips the trailing slash, if present.
243 # Thus we always get the last component of the path, even for directories.
244 return os.path.basename(path.rstrip(os.path.sep))
245
246def move(src, dst):
247 """Recursively move a file or directory to another location. This is
248 similar to the Unix "mv" command.
249
250 If the destination is a directory or a symlink to a directory, the source
251 is moved inside the directory. The destination path must not already
252 exist.
253
254 If the destination already exists but is not a directory, it may be
255 overwritten depending on os.rename() semantics.
256
257 If the destination is on our current filesystem, then rename() is used.
258 Otherwise, src is copied to the destination and then removed.
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000259 A lot more could be done here... A look at a mv.c shows a lot of
260 the issues this implementation glosses over.
261
262 """
Sean Reifscheider493894c2008-03-18 17:24:12 +0000263 real_dst = dst
264 if os.path.isdir(dst):
265 real_dst = os.path.join(dst, _basename(src))
266 if os.path.exists(real_dst):
267 raise Error, "Destination path '%s' already exists" % real_dst
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000268 try:
Sean Reifscheider493894c2008-03-18 17:24:12 +0000269 os.rename(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000270 except OSError:
271 if os.path.isdir(src):
Benjamin Peterson096c3ad2009-02-07 19:08:22 +0000272 if _destinsrc(src, dst):
Brett Cannon1c3fa182004-06-19 21:11:35 +0000273 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
Sean Reifscheider493894c2008-03-18 17:24:12 +0000274 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000275 rmtree(src)
276 else:
Sean Reifscheider493894c2008-03-18 17:24:12 +0000277 copy2(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000278 os.unlink(src)
Brett Cannon1c3fa182004-06-19 21:11:35 +0000279
Benjamin Peterson096c3ad2009-02-07 19:08:22 +0000280def _destinsrc(src, dst):
Antoine Pitrou707c5932009-01-29 20:19:34 +0000281 src = abspath(src)
282 dst = abspath(dst)
283 if not src.endswith(os.path.sep):
284 src += os.path.sep
285 if not dst.endswith(os.path.sep):
286 dst += os.path.sep
287 return dst.startswith(src)