blob: 4862ae6a13eebd05f7f2bab8341d3cafeabdb660 [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
Antoine Pitrou7fff0962009-05-01 21:09:44 +000054 for fn in [src, dst]:
55 try:
56 st = os.stat(fn)
57 except OSError:
58 # File most likely does not exist
59 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +000060 else:
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)
Tarek Ziadé96239802010-05-05 22:39:31 +000064
65 with open(src, 'rb') as fsrc:
66 with open(dst, 'wb') as fdst:
67 copyfileobj(fsrc, fdst)
Guido van Rossumc6360141990-10-13 19:23:40 +000068
Guido van Rossumc6360141990-10-13 19:23:40 +000069def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000070 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000071 if hasattr(os, 'chmod'):
72 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000073 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000074 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000075
Guido van Rossumc6360141990-10-13 19:23:40 +000076def copystat(src, dst):
Thomas Wouterscf297e42007-02-23 15:07:44 +000077 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000078 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000079 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000080 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000081 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000082 if hasattr(os, 'chmod'):
83 os.chmod(dst, mode)
Thomas Wouterscf297e42007-02-23 15:07:44 +000084 if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
Antoine Pitrou9f274b12010-03-22 20:12:40 +000085 try:
86 os.chflags(dst, st.st_flags)
87 except OSError as why:
88 if not hasattr(errno, 'EOPNOTSUPP') or why.errno != errno.EOPNOTSUPP:
89 raise
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000090
Guido van Rossumc6360141990-10-13 19:23:40 +000091def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000092 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000093
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000094 The destination may be a directory.
95
96 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000097 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000098 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000099 copyfile(src, dst)
100 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +0000101
Guido van Rossumc6360141990-10-13 19:23:40 +0000102def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000103 """Copy data and all stat info ("cp -p src dst").
104
105 The destination may be a directory.
106
107 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000108 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000109 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +0000110 copyfile(src, dst)
111 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +0000112
Georg Brandl2ee470f2008-07-16 12:55:28 +0000113def ignore_patterns(*patterns):
114 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000115
Georg Brandl2ee470f2008-07-16 12:55:28 +0000116 Patterns is a sequence of glob-style patterns
117 that are used to exclude files"""
118 def _ignore_patterns(path, names):
119 ignored_names = []
120 for pattern in patterns:
121 ignored_names.extend(fnmatch.filter(names, pattern))
122 return set(ignored_names)
123 return _ignore_patterns
124
125def copytree(src, dst, symlinks=False, ignore=None):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000126 """Recursively copy a directory tree using copy2().
127
128 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000129 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000130
131 If the optional symlinks flag is true, symbolic links in the
132 source tree result in symbolic links in the destination tree; if
133 it is false, the contents of the files pointed to by symbolic
134 links are copied.
135
Georg Brandl2ee470f2008-07-16 12:55:28 +0000136 The optional ignore argument is a callable. If given, it
137 is called with the `src` parameter, which is the directory
138 being visited by copytree(), and `names` which is the list of
139 `src` contents, as returned by os.listdir():
140
141 callable(src, names) -> ignored_names
142
143 Since copytree() is called recursively, the callable will be
144 called once for each directory that is copied. It returns a
145 list of names relative to the `src` directory that should
146 not be copied.
147
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000148 XXX Consider this example code rather than the ultimate tool.
149
150 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000151 names = os.listdir(src)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000152 if ignore is not None:
153 ignored_names = ignore(src, names)
154 else:
155 ignored_names = set()
156
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000157 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000158 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000159 for name in names:
Georg Brandl2ee470f2008-07-16 12:55:28 +0000160 if name in ignored_names:
161 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000162 srcname = os.path.join(src, name)
163 dstname = os.path.join(dst, name)
164 try:
165 if symlinks and os.path.islink(srcname):
166 linkto = os.readlink(srcname)
167 os.symlink(linkto, dstname)
168 elif os.path.isdir(srcname):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000169 copytree(srcname, dstname, symlinks, ignore)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000170 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000171 # Will raise a SpecialFileError for unsupported file types
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 copy2(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000173 # catch the Error from the recursive copytree so that we can
174 # continue with other files
Guido van Rossumb940e112007-01-10 16:19:56 +0000175 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000176 errors.extend(err.args[0])
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000177 except EnvironmentError as why:
178 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000179 try:
180 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000181 except OSError as why:
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000182 if WindowsError is not None and isinstance(why, WindowsError):
183 # Copying file access times may fail on Windows
184 pass
185 else:
186 errors.extend((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000187 if errors:
Collin Winterce36ad82007-08-30 01:19:48 +0000188 raise Error(errors)
Guido van Rossumd7673291998-02-06 21:38:09 +0000189
Barry Warsaw234d9a92003-01-24 17:36:15 +0000190def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000191 """Recursively delete a directory tree.
192
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000193 If ignore_errors is set, errors are ignored; otherwise, if onerror
194 is set, it is called to handle the error with arguments (func,
195 path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
196 path is the argument to that function that caused it to fail; and
197 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
198 is false and onerror is None, an exception is raised.
199
Guido van Rossumd7673291998-02-06 21:38:09 +0000200 """
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000201 if ignore_errors:
202 def onerror(*args):
Barry Warsaw234d9a92003-01-24 17:36:15 +0000203 pass
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000204 elif onerror is None:
205 def onerror(*args):
206 raise
Christian Heimes9bd667a2008-01-20 15:14:11 +0000207 try:
208 if os.path.islink(path):
209 # symlinks to directories are forbidden, see bug #1669
210 raise OSError("Cannot call rmtree on a symbolic link")
211 except OSError:
212 onerror(os.path.islink, path, sys.exc_info())
213 # can't continue even if onerror hook returns
214 return
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000215 names = []
216 try:
217 names = os.listdir(path)
Guido van Rossumb940e112007-01-10 16:19:56 +0000218 except os.error as err:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000219 onerror(os.listdir, path, sys.exc_info())
220 for name in names:
221 fullname = os.path.join(path, name)
222 try:
223 mode = os.lstat(fullname).st_mode
224 except os.error:
225 mode = 0
226 if stat.S_ISDIR(mode):
227 rmtree(fullname, ignore_errors, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000228 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229 try:
230 os.remove(fullname)
Guido van Rossumb940e112007-01-10 16:19:56 +0000231 except os.error as err:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000232 onerror(os.remove, fullname, sys.exc_info())
233 try:
234 os.rmdir(path)
235 except os.error:
236 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000237
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000238
Christian Heimesada8c3b2008-03-18 18:26:33 +0000239def _basename(path):
240 # A basename() variant which first strips the trailing slash, if present.
241 # Thus we always get the last component of the path, even for directories.
242 return os.path.basename(path.rstrip(os.path.sep))
243
244def move(src, dst):
245 """Recursively move a file or directory to another location. This is
246 similar to the Unix "mv" command.
247
248 If the destination is a directory or a symlink to a directory, the source
249 is moved inside the directory. The destination path must not already
250 exist.
251
252 If the destination already exists but is not a directory, it may be
253 overwritten depending on os.rename() semantics.
254
255 If the destination is on our current filesystem, then rename() is used.
256 Otherwise, src is copied to the destination and then removed.
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000257 A lot more could be done here... A look at a mv.c shows a lot of
258 the issues this implementation glosses over.
259
260 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000261 real_dst = dst
262 if os.path.isdir(dst):
263 real_dst = os.path.join(dst, _basename(src))
264 if os.path.exists(real_dst):
265 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000266 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000267 os.rename(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000268 except OSError:
269 if os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000270 if _destinsrc(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +0000271 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000272 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000273 rmtree(src)
274 else:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000275 copy2(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000276 os.unlink(src)
Brett Cannon1c3fa182004-06-19 21:11:35 +0000277
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000278def _destinsrc(src, dst):
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000279 src = abspath(src)
280 dst = abspath(dst)
281 if not src.endswith(os.path.sep):
282 src += os.path.sep
283 if not dst.endswith(os.path.sep):
284 dst += os.path.sep
285 return dst.startswith(src)