blob: baedd4cd9625c5da87623fb3831a44c2ab788d5c [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
Brett Cannon1c3fa182004-06-19 21:11:35 +000011from os.path import abspath
Guido van Rossumc6360141990-10-13 19:23:40 +000012
Skip Montanaro0de65802001-02-15 22:15:14 +000013__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
Raymond Hettinger2b9bfb32002-10-30 05:44:50 +000014 "copytree","move","rmtree","Error"]
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000015
16class Error(exceptions.EnvironmentError):
17 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000018
Greg Stein42bb8b32000-07-12 09:55:30 +000019def copyfileobj(fsrc, fdst, length=16*1024):
20 """copy data from file-like object fsrc to file-like object fdst"""
21 while 1:
22 buf = fsrc.read(length)
23 if not buf:
24 break
25 fdst.write(buf)
26
Johannes Gijsbers46f14592004-08-14 13:30:02 +000027def _samefile(src, dst):
28 # Macintosh, Unix.
29 if hasattr(os.path,'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +000030 try:
31 return os.path.samefile(src, dst)
32 except OSError:
33 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +000034
35 # All other platforms: check for same pathname.
36 return (os.path.normcase(os.path.abspath(src)) ==
37 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +000038
Guido van Rossumc6360141990-10-13 19:23:40 +000039def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000040 """Copy data from src to dst"""
Johannes Gijsbers46f14592004-08-14 13:30:02 +000041 if _samefile(src, dst):
42 raise Error, "`%s` and `%s` are the same file" % (src, dst)
43
Guido van Rossuma2baf461997-04-29 14:06:46 +000044 fsrc = None
45 fdst = None
46 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000047 fsrc = open(src, 'rb')
48 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000049 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000050 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000051 if fdst:
52 fdst.close()
53 if fsrc:
54 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000055
Guido van Rossumc6360141990-10-13 19:23:40 +000056def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000057 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000058 if hasattr(os, 'chmod'):
59 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000060 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000061 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000062
Guido van Rossumc6360141990-10-13 19:23:40 +000063def copystat(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000064 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000065 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000066 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000067 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000068 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000069 if hasattr(os, 'chmod'):
70 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000071
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000072
Guido van Rossumc6360141990-10-13 19:23:40 +000073def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000074 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000075
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000076 The destination may be a directory.
77
78 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000079 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000080 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000081 copyfile(src, dst)
82 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000083
Guido van Rossumc6360141990-10-13 19:23:40 +000084def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000085 """Copy data and all stat info ("cp -p src dst").
86
87 The destination may be a directory.
88
89 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000090 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000091 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000092 copyfile(src, dst)
93 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000094
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000095
Neal Norwitza4c93b62003-02-23 21:36:32 +000096def copytree(src, dst, symlinks=False):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000097 """Recursively copy a directory tree using copy2().
98
99 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000100 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000101
102 If the optional symlinks flag is true, symbolic links in the
103 source tree result in symbolic links in the destination tree; if
104 it is false, the contents of the files pointed to by symbolic
105 links are copied.
106
107 XXX Consider this example code rather than the ultimate tool.
108
109 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000110 names = os.listdir(src)
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000111 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000112 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000113 for name in names:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 srcname = os.path.join(src, name)
115 dstname = os.path.join(dst, name)
116 try:
117 if symlinks and os.path.islink(srcname):
118 linkto = os.readlink(srcname)
119 os.symlink(linkto, dstname)
120 elif os.path.isdir(srcname):
Fred Drake5fa38862000-04-07 14:34:50 +0000121 copytree(srcname, dstname, symlinks)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 else:
123 copy2(srcname, dstname)
124 # XXX What about devices, sockets etc.?
125 except (IOError, os.error), why:
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000126 errors.append((srcname, dstname, why))
Johannes Gijsbers926d45b2005-01-23 12:20:15 +0000127 copystat(src, dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000128 if errors:
129 raise Error, errors
Guido van Rossumd7673291998-02-06 21:38:09 +0000130
Barry Warsaw234d9a92003-01-24 17:36:15 +0000131def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000132 """Recursively delete a directory tree.
133
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000134 If ignore_errors is set, errors are ignored; otherwise, if onerror
135 is set, it is called to handle the error with arguments (func,
136 path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
137 path is the argument to that function that caused it to fail; and
138 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
139 is false and onerror is None, an exception is raised.
140
Guido van Rossumd7673291998-02-06 21:38:09 +0000141 """
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000142 if ignore_errors:
143 def onerror(*args):
Barry Warsaw234d9a92003-01-24 17:36:15 +0000144 pass
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000145 elif onerror is None:
146 def onerror(*args):
147 raise
148 names = []
149 try:
150 names = os.listdir(path)
151 except os.error, err:
152 onerror(os.listdir, path, sys.exc_info())
153 for name in names:
154 fullname = os.path.join(path, name)
155 try:
156 mode = os.lstat(fullname).st_mode
157 except os.error:
158 mode = 0
159 if stat.S_ISDIR(mode):
160 rmtree(fullname, ignore_errors, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000161 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 try:
163 os.remove(fullname)
164 except os.error, err:
165 onerror(os.remove, fullname, sys.exc_info())
166 try:
167 os.rmdir(path)
168 except os.error:
169 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000170
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000171def move(src, dst):
172 """Recursively move a file or directory to another location.
173
174 If the destination is on our current filesystem, then simply use
175 rename. Otherwise, copy src to the dst and then remove src.
176 A lot more could be done here... A look at a mv.c shows a lot of
177 the issues this implementation glosses over.
178
179 """
180
181 try:
182 os.rename(src, dst)
183 except OSError:
184 if os.path.isdir(src):
Brett Cannon1c3fa182004-06-19 21:11:35 +0000185 if destinsrc(src, dst):
186 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
Neal Norwitza4c93b62003-02-23 21:36:32 +0000187 copytree(src, dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000188 rmtree(src)
189 else:
190 copy2(src,dst)
191 os.unlink(src)
Brett Cannon1c3fa182004-06-19 21:11:35 +0000192
193def destinsrc(src, dst):
194 return abspath(dst).startswith(abspath(src))