blob: dfde2361369ff0d7fbdf8f4909c3d13cb4ce6341 [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
Guido van Rossumc6360141990-10-13 19:23:40 +000010
Guido van Rossumc6360141990-10-13 19:23:40 +000011
Greg Stein42bb8b32000-07-12 09:55:30 +000012def copyfileobj(fsrc, fdst, length=16*1024):
13 """copy data from file-like object fsrc to file-like object fdst"""
14 while 1:
15 buf = fsrc.read(length)
16 if not buf:
17 break
18 fdst.write(buf)
19
20
Guido van Rossumc6360141990-10-13 19:23:40 +000021def copyfile(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000022 """Copy data from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000023 fsrc = None
24 fdst = None
25 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000026 fsrc = open(src, 'rb')
27 fdst = open(dst, 'wb')
Greg Stein42bb8b32000-07-12 09:55:30 +000028 copyfileobj(fsrc, fdst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000029 finally:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000030 if fdst:
31 fdst.close()
32 if fsrc:
33 fsrc.close()
Guido van Rossumc6360141990-10-13 19:23:40 +000034
Guido van Rossumc6360141990-10-13 19:23:40 +000035def copymode(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000036 """Copy mode bits from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000037 st = os.stat(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000038 mode = stat.S_IMODE(st[stat.ST_MODE])
Guido van Rossuma2baf461997-04-29 14:06:46 +000039 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000040
Guido van Rossumc6360141990-10-13 19:23:40 +000041def copystat(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000042 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
Guido van Rossuma2baf461997-04-29 14:06:46 +000043 st = os.stat(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000044 mode = stat.S_IMODE(st[stat.ST_MODE])
Guido van Rossum96372a21998-10-02 03:16:08 +000045 os.utime(dst, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
Guido van Rossume1bf7e81999-01-14 00:42:00 +000046 os.chmod(dst, mode)
Guido van Rossumc6360141990-10-13 19:23:40 +000047
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000048
Guido van Rossumc6360141990-10-13 19:23:40 +000049def copy(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000050 """Copy data and mode bits ("cp src dst").
51
52 The destination may be a directory.
53
54 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000055 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000056 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000057 copyfile(src, dst)
58 copymode(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000059
Guido van Rossumc6360141990-10-13 19:23:40 +000060def copy2(src, dst):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000061 """Copy data and all stat info ("cp -p src dst").
62
63 The destination may be a directory.
64
65 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000066 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000067 dst = os.path.join(dst, os.path.basename(src))
Guido van Rossuma2baf461997-04-29 14:06:46 +000068 copyfile(src, dst)
69 copystat(src, dst)
Guido van Rossumc6360141990-10-13 19:23:40 +000070
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000071
72def copytree(src, dst, symlinks=0):
73 """Recursively copy a directory tree using copy2().
74
75 The destination directory must not already exist.
76 Error are reported to standard output.
77
78 If the optional symlinks flag is true, symbolic links in the
79 source tree result in symbolic links in the destination tree; if
80 it is false, the contents of the files pointed to by symbolic
81 links are copied.
82
83 XXX Consider this example code rather than the ultimate tool.
84
85 """
Guido van Rossuma2baf461997-04-29 14:06:46 +000086 names = os.listdir(src)
Guido van Rossum9d0a3df1997-04-29 14:45:19 +000087 os.mkdir(dst)
Guido van Rossuma2baf461997-04-29 14:06:46 +000088 for name in names:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000089 srcname = os.path.join(src, name)
90 dstname = os.path.join(dst, name)
91 try:
92 if symlinks and os.path.islink(srcname):
93 linkto = os.readlink(srcname)
94 os.symlink(linkto, dstname)
95 elif os.path.isdir(srcname):
Fred Drake5fa38862000-04-07 14:34:50 +000096 copytree(srcname, dstname, symlinks)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000097 else:
98 copy2(srcname, dstname)
99 # XXX What about devices, sockets etc.?
100 except (IOError, os.error), why:
101 print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))
Guido van Rossumd7673291998-02-06 21:38:09 +0000102
103def rmtree(path, ignore_errors=0, onerror=None):
104 """Recursively delete a directory tree.
105
106 If ignore_errors is set, errors are ignored; otherwise, if
107 onerror is set, it is called to handle the error; otherwise, an
108 exception is raised.
109
110 """
111 cmdtuples = []
112 _build_cmdtuple(path, cmdtuples)
113 for cmd in cmdtuples:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 try:
115 apply(cmd[0], (cmd[1],))
116 except:
117 exc = sys.exc_info()
118 if ignore_errors:
119 pass
120 elif onerror:
121 onerror(cmd[0], cmd[1], exc)
122 else:
123 raise exc[0], (exc[1][0], exc[1][1] + ' removing '+cmd[1])
Guido van Rossumd7673291998-02-06 21:38:09 +0000124
125# Helper for rmtree()
126def _build_cmdtuple(path, cmdtuples):
127 for f in os.listdir(path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 real_f = os.path.join(path,f)
129 if os.path.isdir(real_f) and not os.path.islink(real_f):
130 _build_cmdtuple(real_f, cmdtuples)
131 else:
Guido van Rossumd832f9e1998-10-07 13:18:17 +0000132 cmdtuples.append((os.remove, real_f))
133 cmdtuples.append((os.rmdir, path))