blob: 2befb47dd4a2445df8a115130bbedfdabe0b3c77 [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 Brandl2ee470f2008-07-16 12:55:28 +000011import fnmatch
Antoine Pitrou9f274b12010-03-22 20:12:40 +000012import errno
Guido van Rossumc6360141990-10-13 19:23:40 +000013
Skip Montanaro0de65802001-02-15 22:15:14 +000014__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
Antoine Pitrou7fff0962009-05-01 21:09:44 +000015 "copytree","move","rmtree","Error", "SpecialFileError"]
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000016
Neal Norwitz4ce69a52005-09-01 00:45:28 +000017class Error(EnvironmentError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000018 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000019
Antoine Pitrou7fff0962009-05-01 21:09:44 +000020class SpecialFileError(EnvironmentError):
21 """Raised when trying to do a kind of operation (e.g. copying) which is
22 not supported on a special file (e.g. a named pipe)"""
23
Georg Brandl6aa2d1f2008-08-12 08:35:52 +000024try:
25 WindowsError
26except NameError:
27 WindowsError = None
28
Greg Stein42bb8b32000-07-12 09:55:30 +000029def copyfileobj(fsrc, fdst, length=16*1024):
30 """copy data from file-like object fsrc to file-like object fdst"""
31 while 1:
32 buf = fsrc.read(length)
33 if not buf:
34 break
35 fdst.write(buf)
36
Johannes Gijsbers46f14592004-08-14 13:30:02 +000037def _samefile(src, dst):
38 # Macintosh, Unix.
39 if hasattr(os.path,'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +000040 try:
41 return os.path.samefile(src, dst)
42 except OSError:
43 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +000044
45 # All other platforms: check for same pathname.
46 return (os.path.normcase(os.path.abspath(src)) ==
47 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +000048
Guido van Rossumc6360141990-10-13 19:23:40 +000049def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000050 """Copy data from src to dst"""
Johannes Gijsbers46f14592004-08-14 13:30:02 +000051 if _samefile(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +000052 raise Error("`%s` and `%s` are the same file" % (src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +000053
Guido van Rossuma2baf461997-04-29 14:06:46 +000054 fsrc = None
55 fdst = None
Antoine Pitrou7fff0962009-05-01 21:09:44 +000056 for fn in [src, dst]:
57 try:
58 st = os.stat(fn)
59 except OSError:
60 # File most likely does not exist
61 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +000062 else:
63 # XXX What about other special files? (sockets, devices...)
64 if stat.S_ISFIFO(st.st_mode):
65 raise SpecialFileError("`%s` is a named pipe" % fn)
Tarek Ziadé96239802010-05-05 22:39:31 +000066
67 with open(src, 'rb') as fsrc:
68 with open(dst, 'wb') as fdst:
69 copyfileobj(fsrc, fdst)
Guido van Rossumc6360141990-10-13 19:23:40 +000070
Guido van Rossumc6360141990-10-13 19:23:40 +000071def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000072 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000073 if hasattr(os, 'chmod'):
74 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000075 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000076 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000077
Guido van Rossumc6360141990-10-13 19:23:40 +000078def copystat(src, dst):
Thomas Wouterscf297e42007-02-23 15:07:44 +000079 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000080 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000081 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000082 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000083 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000084 if hasattr(os, 'chmod'):
85 os.chmod(dst, mode)
Thomas Wouterscf297e42007-02-23 15:07:44 +000086 if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
Antoine Pitrou9f274b12010-03-22 20:12:40 +000087 try:
88 os.chflags(dst, st.st_flags)
89 except OSError as why:
90 if not hasattr(errno, 'EOPNOTSUPP') or why.errno != errno.EOPNOTSUPP:
91 raise
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 Brandl2ee470f2008-07-16 12:55:28 +0000115def ignore_patterns(*patterns):
116 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000117
Georg Brandl2ee470f2008-07-16 12:55:28 +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 Brandl2ee470f2008-07-16 12:55:28 +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 Brandl2ee470f2008-07-16 12:55:28 +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 Brandl2ee470f2008-07-16 12:55:28 +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 Brandl2ee470f2008-07-16 12:55:28 +0000171 copytree(srcname, dstname, symlinks, ignore)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +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
Guido van Rossumb940e112007-01-10 16:19:56 +0000177 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000178 errors.extend(err.args[0])
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000179 except EnvironmentError as why:
180 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000181 try:
182 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000183 except OSError as why:
Georg Brandl6aa2d1f2008-08-12 08:35:52 +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:
Collin Winterce36ad82007-08-30 01:19:48 +0000190 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
Christian Heimes9bd667a2008-01-20 15:14:11 +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)
Guido van Rossumb940e112007-01-10 16:19:56 +0000220 except os.error as err:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000221 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)
Guido van Rossumb940e112007-01-10 16:19:56 +0000233 except os.error as err:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000234 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
Christian Heimesada8c3b2008-03-18 18:26:33 +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 """
Christian Heimesada8c3b2008-03-18 18:26:33 +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:
Christian Heimesada8c3b2008-03-18 18:26:33 +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 Peterson247a9b82009-02-20 04:09:19 +0000272 if _destinsrc(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +0000273 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000274 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000275 rmtree(src)
276 else:
Christian Heimesada8c3b2008-03-18 18:26:33 +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 Peterson247a9b82009-02-20 04:09:19 +0000280def _destinsrc(src, dst):
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +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)