blob: 10b7a277674a3e34cf3e4e0e8bcb14e62b9dc27f [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
Tim Peters495ad3c2001-01-15 01:36:40 +000027
Guido van Rossumc6360141990-10-13 19:23:40 +000028def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000029 """Copy data from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000030 fsrc = None
31 fdst = None
Raymond Hettinger57e79452002-09-08 20:43:59 +000032 # check for same pathname; all platforms
33 _src = os.path.normcase(os.path.abspath(src))
34 _dst = os.path.normcase(os.path.abspath(dst))
35 if _src == _dst:
36 return
Guido van Rossuma2baf461997-04-29 14:06:46 +000037 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000038 fsrc = open(src, 'rb')
39 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000040 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000041 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 if fdst:
43 fdst.close()
44 if fsrc:
45 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000046
Guido van Rossumc6360141990-10-13 19:23:40 +000047def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000048 """Copy mode bits from src to dst"""
Tim Peters0c947242001-01-21 20:00:00 +000049 if hasattr(os, 'chmod'):
50 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000051 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000052 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000053
Guido van Rossumc6360141990-10-13 19:23:40 +000054def copystat(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000055 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000056 st = os.stat(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +000057 mode = stat.S_IMODE(st.st_mode)
Tim Peters0c947242001-01-21 20:00:00 +000058 if hasattr(os, 'utime'):
Walter Dörwald294bbf32002-06-06 09:48:13 +000059 os.utime(dst, (st.st_atime, st.st_mtime))
Tim Peters0c947242001-01-21 20:00:00 +000060 if hasattr(os, 'chmod'):
61 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000062
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000063
Guido van Rossumc6360141990-10-13 19:23:40 +000064def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000065 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +000066
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000067 The destination may be a directory.
68
69 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000070 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000071 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000072 copyfile(src, dst)
73 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000074
Guido van Rossumc6360141990-10-13 19:23:40 +000075def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000076 """Copy data and all stat info ("cp -p src dst").
77
78 The destination may be a directory.
79
80 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000081 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000082 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000083 copyfile(src, dst)
84 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000085
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000086
Neal Norwitza4c93b62003-02-23 21:36:32 +000087def copytree(src, dst, symlinks=False):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000088 """Recursively copy a directory tree using copy2().
89
90 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +000091 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000092
93 If the optional symlinks flag is true, symbolic links in the
94 source tree result in symbolic links in the destination tree; if
95 it is false, the contents of the files pointed to by symbolic
96 links are copied.
97
98 XXX Consider this example code rather than the ultimate tool.
99
100 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000101 names = os.listdir(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000102 os.mkdir(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000103 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000104 for name in names:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000105 srcname = os.path.join(src, name)
106 dstname = os.path.join(dst, name)
107 try:
108 if symlinks and os.path.islink(srcname):
109 linkto = os.readlink(srcname)
110 os.symlink(linkto, dstname)
111 elif os.path.isdir(srcname):
Fred Drake5fa38862000-04-07 14:34:50 +0000112 copytree(srcname, dstname, symlinks)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 else:
114 copy2(srcname, dstname)
115 # XXX What about devices, sockets etc.?
116 except (IOError, os.error), why:
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000117 errors.append((srcname, dstname, why))
118 if errors:
119 raise Error, errors
Guido van Rossumd7673291998-02-06 21:38:09 +0000120
Barry Warsaw234d9a92003-01-24 17:36:15 +0000121def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000122 """Recursively delete a directory tree.
123
124 If ignore_errors is set, errors are ignored; otherwise, if
125 onerror is set, it is called to handle the error; otherwise, an
126 exception is raised.
Guido van Rossumd7673291998-02-06 21:38:09 +0000127 """
128 cmdtuples = []
Barry Warsaw234d9a92003-01-24 17:36:15 +0000129 arg = path
130 try:
131 _build_cmdtuple(path, cmdtuples)
132 for func, arg in cmdtuples:
Just van Rossum66d16ba2003-01-05 19:44:11 +0000133 func(arg)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000134 except OSError:
135 exc = sys.exc_info()
136 if ignore_errors:
137 pass
138 elif onerror is not None:
139 onerror(func, arg, exc)
140 else:
141 raise exc[0], (exc[1][0], exc[1][1] + ' removing '+arg)
Guido van Rossumd7673291998-02-06 21:38:09 +0000142
143# Helper for rmtree()
144def _build_cmdtuple(path, cmdtuples):
145 for f in os.listdir(path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000146 real_f = os.path.join(path,f)
147 if os.path.isdir(real_f) and not os.path.islink(real_f):
148 _build_cmdtuple(real_f, cmdtuples)
149 else:
Guido van Rossumd832f9e1998-10-07 13:18:17 +0000150 cmdtuples.append((os.remove, real_f))
151 cmdtuples.append((os.rmdir, path))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000152
153
154def move(src, dst):
155 """Recursively move a file or directory to another location.
156
157 If the destination is on our current filesystem, then simply use
158 rename. Otherwise, copy src to the dst and then remove src.
159 A lot more could be done here... A look at a mv.c shows a lot of
160 the issues this implementation glosses over.
161
162 """
163
164 try:
165 os.rename(src, dst)
166 except OSError:
167 if os.path.isdir(src):
Brett Cannon1c3fa182004-06-19 21:11:35 +0000168 if destinsrc(src, dst):
169 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
Neal Norwitza4c93b62003-02-23 21:36:32 +0000170 copytree(src, dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000171 rmtree(src)
172 else:
173 copy2(src,dst)
174 os.unlink(src)
Brett Cannon1c3fa182004-06-19 21:11:35 +0000175
176def destinsrc(src, dst):
177 return abspath(dst).startswith(abspath(src))