Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / shutil.py
CommitLineData
920dae64
AT
1"""Utility functions for copying files and directory trees.
2
3XXX The functions here don't copy the resource fork or other metadata on Mac.
4
5"""
6
7import os
8import sys
9import stat
10import exceptions
11from os.path import abspath
12
13__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
14 "copytree","move","rmtree","Error"]
15
16class Error(exceptions.EnvironmentError):
17 pass
18
19def 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
27def _samefile(src, dst):
28 # Macintosh, Unix.
29 if hasattr(os.path,'samefile'):
30 try:
31 return os.path.samefile(src, dst)
32 except OSError:
33 return False
34
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)))
38
39def copyfile(src, dst):
40 """Copy data from src to dst"""
41 if _samefile(src, dst):
42 raise Error, "`%s` and `%s` are the same file" % (src, dst)
43
44 fsrc = None
45 fdst = None
46 try:
47 fsrc = open(src, 'rb')
48 fdst = open(dst, 'wb')
49 copyfileobj(fsrc, fdst)
50 finally:
51 if fdst:
52 fdst.close()
53 if fsrc:
54 fsrc.close()
55
56def copymode(src, dst):
57 """Copy mode bits from src to dst"""
58 if hasattr(os, 'chmod'):
59 st = os.stat(src)
60 mode = stat.S_IMODE(st.st_mode)
61 os.chmod(dst, mode)
62
63def copystat(src, dst):
64 """Copy all stat info (mode bits, atime and mtime) from src to dst"""
65 st = os.stat(src)
66 mode = stat.S_IMODE(st.st_mode)
67 if hasattr(os, 'utime'):
68 os.utime(dst, (st.st_atime, st.st_mtime))
69 if hasattr(os, 'chmod'):
70 os.chmod(dst, mode)
71
72
73def copy(src, dst):
74 """Copy data and mode bits ("cp src dst").
75
76 The destination may be a directory.
77
78 """
79 if os.path.isdir(dst):
80 dst = os.path.join(dst, os.path.basename(src))
81 copyfile(src, dst)
82 copymode(src, dst)
83
84def copy2(src, dst):
85 """Copy data and all stat info ("cp -p src dst").
86
87 The destination may be a directory.
88
89 """
90 if os.path.isdir(dst):
91 dst = os.path.join(dst, os.path.basename(src))
92 copyfile(src, dst)
93 copystat(src, dst)
94
95
96def copytree(src, dst, symlinks=False):
97 """Recursively copy a directory tree using copy2().
98
99 The destination directory must not already exist.
100 If exception(s) occur, an Error is raised with a list of reasons.
101
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 """
110 names = os.listdir(src)
111 os.mkdir(dst)
112 errors = []
113 for name in names:
114 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):
121 copytree(srcname, dstname, symlinks)
122 else:
123 copy2(srcname, dstname)
124 # XXX What about devices, sockets etc.?
125 except (IOError, os.error), why:
126 errors.append((srcname, dstname, why))
127 # catch the Error from the recursive copytree so that we can
128 # continue with other files
129 except Error, err:
130 errors.extend(err.args[0])
131 if errors:
132 raise Error, errors
133
134def rmtree(path, ignore_errors=False, onerror=None):
135 """Recursively delete a directory tree.
136
137 If ignore_errors is set, errors are ignored; otherwise, if onerror
138 is set, it is called to handle the error with arguments (func,
139 path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
140 path is the argument to that function that caused it to fail; and
141 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
142 is false and onerror is None, an exception is raised.
143
144 """
145 if ignore_errors:
146 def onerror(*args):
147 pass
148 elif onerror is None:
149 def onerror(*args):
150 raise
151 names = []
152 try:
153 names = os.listdir(path)
154 except os.error, err:
155 onerror(os.listdir, path, sys.exc_info())
156 for name in names:
157 fullname = os.path.join(path, name)
158 try:
159 mode = os.lstat(fullname).st_mode
160 except os.error:
161 mode = 0
162 if stat.S_ISDIR(mode):
163 rmtree(fullname, ignore_errors, onerror)
164 else:
165 try:
166 os.remove(fullname)
167 except os.error, err:
168 onerror(os.remove, fullname, sys.exc_info())
169 try:
170 os.rmdir(path)
171 except os.error:
172 onerror(os.rmdir, path, sys.exc_info())
173
174def move(src, dst):
175 """Recursively move a file or directory to another location.
176
177 If the destination is on our current filesystem, then simply use
178 rename. Otherwise, copy src to the dst and then remove src.
179 A lot more could be done here... A look at a mv.c shows a lot of
180 the issues this implementation glosses over.
181
182 """
183
184 try:
185 os.rename(src, dst)
186 except OSError:
187 if os.path.isdir(src):
188 if destinsrc(src, dst):
189 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
190 copytree(src, dst, symlinks=True)
191 rmtree(src)
192 else:
193 copy2(src,dst)
194 os.unlink(src)
195
196def destinsrc(src, dst):
197 return abspath(dst).startswith(abspath(src))