blob: 9a83a3242ed9186a2fff8274166bb652757518e6 [file] [log] [blame]
Tarek Ziadéc3399782010-02-23 05:39:18 +00001"""Utility functions for copying and archiving 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
Georg Brandl2ee470f2008-07-16 12:55:28 +000010import fnmatch
Tarek Ziadé396fad72010-02-23 05:30:31 +000011import collections
Antoine Pitrou910bd512010-03-22 20:11:09 +000012import errno
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020013
14try:
15 import zlib
16 del zlib
17 _ZLIB_SUPPORTED = True
18except ImportError:
19 _ZLIB_SUPPORTED = False
Tarek Ziadé396fad72010-02-23 05:30:31 +000020
21try:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000022 import bz2
Florent Xicluna54540ec2011-11-04 08:29:17 +010023 del bz2
Tarek Ziadéffa155a2010-04-29 13:34:35 +000024 _BZ2_SUPPORTED = True
Brett Cannoncd171c82013-07-04 17:43:24 -040025except ImportError:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000026 _BZ2_SUPPORTED = False
27
28try:
Serhiy Storchaka11213772014-08-06 18:50:19 +030029 import lzma
30 del lzma
31 _LZMA_SUPPORTED = True
32except ImportError:
33 _LZMA_SUPPORTED = False
34
35try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000036 from pwd import getpwnam
Brett Cannoncd171c82013-07-04 17:43:24 -040037except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000038 getpwnam = None
39
40try:
41 from grp import getgrnam
Brett Cannoncd171c82013-07-04 17:43:24 -040042except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000043 getgrnam = None
Guido van Rossumc6360141990-10-13 19:23:40 +000044
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070045_WINDOWS = os.name == 'nt'
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020046posix = nt = None
47if os.name == 'posix':
48 import posix
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070049elif _WINDOWS:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020050 import nt
51
Inada Naoki4f190302019-03-02 13:31:01 +090052COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
Giampaolo Rodola413d9552019-05-30 14:05:41 +080053_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070054_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020055
Tarek Ziadéc3399782010-02-23 05:39:18 +000056__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
57 "copytree", "move", "rmtree", "Error", "SpecialFileError",
58 "ExecError", "make_archive", "get_archive_formats",
Tarek Ziadé6ac91722010-04-28 17:51:36 +000059 "register_archive_format", "unregister_archive_format",
60 "get_unpack_formats", "register_unpack_format",
Éric Araujoc5efe652011-08-21 14:30:00 +020061 "unregister_unpack_format", "unpack_archive",
Berker Peksag8083cd62014-11-01 11:04:06 +020062 "ignore_patterns", "chown", "which", "get_terminal_size",
63 "SameFileError"]
Éric Araujoe4d5b8e2011-08-08 16:51:11 +020064 # disk_usage is added later, if available on the platform
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000065
Andrew Svetlov3438fa42012-12-17 23:35:18 +020066class Error(OSError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000067 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000068
Hynek Schlawack48653762012-10-07 12:49:58 +020069class SameFileError(Error):
70 """Raised when source and destination are the same file."""
71
Andrew Svetlov3438fa42012-12-17 23:35:18 +020072class SpecialFileError(OSError):
Antoine Pitrou7fff0962009-05-01 21:09:44 +000073 """Raised when trying to do a kind of operation (e.g. copying) which is
74 not supported on a special file (e.g. a named pipe)"""
75
Andrew Svetlov3438fa42012-12-17 23:35:18 +020076class ExecError(OSError):
Tarek Ziadé396fad72010-02-23 05:30:31 +000077 """Raised when a command could not be executed"""
78
Andrew Svetlov3438fa42012-12-17 23:35:18 +020079class ReadError(OSError):
Tarek Ziadé6ac91722010-04-28 17:51:36 +000080 """Raised when an archive cannot be read"""
81
82class RegistryError(Exception):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030083 """Raised when a registry operation with the archiving
Raymond Hettinger15f44ab2016-08-30 10:47:49 -070084 and unpacking registries fails"""
Tarek Ziadé6ac91722010-04-28 17:51:36 +000085
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020086class _GiveupOnFastCopy(Exception):
87 """Raised as a signal to fallback on using raw read()/write()
88 file copy when fast-copy functions fail to do so.
89 """
Tarek Ziadé6ac91722010-04-28 17:51:36 +000090
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070091def _fastcopy_fcopyfile(fsrc, fdst, flags):
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020092 """Copy a regular file content or metadata by using high-performance
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070093 fcopyfile(3) syscall (macOS).
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020094 """
95 try:
96 infd = fsrc.fileno()
97 outfd = fdst.fileno()
98 except Exception as err:
99 raise _GiveupOnFastCopy(err) # not a regular file
100
101 try:
102 posix._fcopyfile(infd, outfd, flags)
103 except OSError as err:
104 err.filename = fsrc.name
105 err.filename2 = fdst.name
106 if err.errno in {errno.EINVAL, errno.ENOTSUP}:
107 raise _GiveupOnFastCopy(err)
108 else:
109 raise err from None
110
111def _fastcopy_sendfile(fsrc, fdst):
112 """Copy data from one regular mmap-like fd to another by using
113 high-performance sendfile(2) syscall.
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800114 This should work on Linux >= 2.6.33 only.
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200115 """
116 # Note: copyfileobj() is left alone in order to not introduce any
117 # unexpected breakage. Possible risks by using zero-copy calls
118 # in copyfileobj() are:
119 # - fdst cannot be open in "a"(ppend) mode
120 # - fsrc and fdst may be open in "t"(ext) mode
121 # - fsrc may be a BufferedReader (which hides unread data in a buffer),
122 # GzipFile (which decompresses data), HTTPResponse (which decodes
123 # chunks).
124 # - possibly others (e.g. encrypted fs/partition?)
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800125 global _USE_CP_SENDFILE
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200126 try:
127 infd = fsrc.fileno()
128 outfd = fdst.fileno()
129 except Exception as err:
130 raise _GiveupOnFastCopy(err) # not a regular file
131
132 # Hopefully the whole file will be copied in a single call.
133 # sendfile() is called in a loop 'till EOF is reached (0 return)
134 # so a bufsize smaller or bigger than the actual file size
135 # should not make any difference, also in case the file content
136 # changes while being copied.
137 try:
Giampaolo Rodola94e16502019-10-01 11:40:54 +0800138 blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MiB
139 except OSError:
140 blocksize = 2 ** 27 # 128MiB
141 # On 32-bit architectures truncate to 1GiB to avoid OverflowError,
142 # see bpo-38319.
143 if sys.maxsize < 2 ** 32:
144 blocksize = min(blocksize, 2 ** 30)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200145
146 offset = 0
147 while True:
148 try:
149 sent = os.sendfile(outfd, infd, offset, blocksize)
150 except OSError as err:
151 # ...in oder to have a more informative exception.
152 err.filename = fsrc.name
153 err.filename2 = fdst.name
154
155 if err.errno == errno.ENOTSOCK:
156 # sendfile() on this platform (probably Linux < 2.6.33)
157 # does not support copies between regular files (only
158 # sockets).
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800159 _USE_CP_SENDFILE = False
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200160 raise _GiveupOnFastCopy(err)
161
162 if err.errno == errno.ENOSPC: # filesystem is full
163 raise err from None
164
165 # Give up on first call and if no data was copied.
166 if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0:
167 raise _GiveupOnFastCopy(err)
168
169 raise err
170 else:
171 if sent == 0:
172 break # EOF
173 offset += sent
174
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700175def _copyfileobj_readinto(fsrc, fdst, length=COPY_BUFSIZE):
176 """readinto()/memoryview() based variant of copyfileobj().
177 *fsrc* must support readinto() method and both files must be
178 open in binary mode.
179 """
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200180 # Localize variable access to minimize overhead.
181 fsrc_readinto = fsrc.readinto
182 fdst_write = fdst.write
183 with memoryview(bytearray(length)) as mv:
184 while True:
185 n = fsrc_readinto(mv)
186 if not n:
187 break
188 elif n < length:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700189 with mv[:n] as smv:
190 fdst.write(smv)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200191 else:
192 fdst_write(mv)
193
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800194def copyfileobj(fsrc, fdst, length=0):
Greg Stein42bb8b32000-07-12 09:55:30 +0000195 """copy data from file-like object fsrc to file-like object fdst"""
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700196 # Localize variable access to minimize overhead.
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800197 if not length:
198 length = COPY_BUFSIZE
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700199 fsrc_read = fsrc.read
200 fdst_write = fdst.write
201 while True:
202 buf = fsrc_read(length)
203 if not buf:
204 break
205 fdst_write(buf)
Greg Stein42bb8b32000-07-12 09:55:30 +0000206
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000207def _samefile(src, dst):
208 # Macintosh, Unix.
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800209 if isinstance(src, os.DirEntry) and hasattr(os.path, 'samestat'):
210 try:
211 return os.path.samestat(src.stat(), os.stat(dst))
212 except OSError:
213 return False
214
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +0000215 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +0000216 try:
217 return os.path.samefile(src, dst)
218 except OSError:
219 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000220
221 # All other platforms: check for same pathname.
222 return (os.path.normcase(os.path.abspath(src)) ==
223 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +0000224
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800225def _stat(fn):
226 return fn.stat() if isinstance(fn, os.DirEntry) else os.stat(fn)
227
228def _islink(fn):
229 return fn.is_symlink() if isinstance(fn, os.DirEntry) else os.path.islink(fn)
230
Larry Hastingsb4038062012-07-15 10:57:38 -0700231def copyfile(src, dst, *, follow_symlinks=True):
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700232 """Copy data from src to dst in the most efficient way possible.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100233
Larry Hastingsb4038062012-07-15 10:57:38 -0700234 If follow_symlinks is not set and src is a symbolic link, a new
Antoine Pitrou78091e62011-12-29 18:54:15 +0100235 symlink will be created instead of copying the file it points to.
236
237 """
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000238 if _samefile(src, dst):
Hynek Schlawack48653762012-10-07 12:49:58 +0200239 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000240
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700241 file_size = 0
242 for i, fn in enumerate([src, dst]):
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000243 try:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800244 st = _stat(fn)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000245 except OSError:
246 # File most likely does not exist
247 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000248 else:
249 # XXX What about other special files? (sockets, devices...)
250 if stat.S_ISFIFO(st.st_mode):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800251 fn = fn.path if isinstance(fn, os.DirEntry) else fn
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000252 raise SpecialFileError("`%s` is a named pipe" % fn)
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700253 if _WINDOWS and i == 0:
254 file_size = st.st_size
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000255
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800256 if not follow_symlinks and _islink(src):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100257 os.symlink(os.readlink(src), dst)
258 else:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200259 with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700260 # macOS
261 if _HAS_FCOPYFILE:
262 try:
263 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
264 return dst
265 except _GiveupOnFastCopy:
266 pass
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800267 # Linux
268 elif _USE_CP_SENDFILE:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200269 try:
270 _fastcopy_sendfile(fsrc, fdst)
271 return dst
272 except _GiveupOnFastCopy:
273 pass
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700274 # Windows, see:
275 # https://github.com/python/cpython/pull/7160#discussion_r195405230
276 elif _WINDOWS and file_size > 0:
277 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
278 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200279
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700280 copyfileobj(fsrc, fdst)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200281
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500282 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000283
Larry Hastingsb4038062012-07-15 10:57:38 -0700284def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100285 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000286
Larry Hastingsb4038062012-07-15 10:57:38 -0700287 If follow_symlinks is not set, symlinks aren't followed if and only
288 if both `src` and `dst` are symlinks. If `lchmod` isn't available
289 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100290
291 """
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800292 if not follow_symlinks and _islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100293 if hasattr(os, 'lchmod'):
294 stat_func, chmod_func = os.lstat, os.lchmod
295 else:
296 return
Antoine Pitrou78091e62011-12-29 18:54:15 +0100297 else:
Anthony Sottile8377cd42019-02-25 14:32:27 -0800298 stat_func, chmod_func = _stat, os.chmod
Antoine Pitrou78091e62011-12-29 18:54:15 +0100299
300 st = stat_func(src)
301 chmod_func(dst, stat.S_IMODE(st.st_mode))
302
Larry Hastingsad5ae042012-07-14 17:55:11 -0700303if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700304 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700305 """Copy extended filesystem attributes from `src` to `dst`.
306
307 Overwrite existing attributes.
308
Larry Hastingsb4038062012-07-15 10:57:38 -0700309 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700310
311 """
312
Hynek Schlawack0beab052013-02-05 08:22:44 +0100313 try:
314 names = os.listxattr(src, follow_symlinks=follow_symlinks)
315 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400316 if e.errno not in (errno.ENOTSUP, errno.ENODATA, errno.EINVAL):
Hynek Schlawack0beab052013-02-05 08:22:44 +0100317 raise
318 return
319 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700320 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700321 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
322 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700323 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400324 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
325 errno.EINVAL):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700326 raise
327else:
328 def _copyxattr(*args, **kwargs):
329 pass
330
Larry Hastingsb4038062012-07-15 10:57:38 -0700331def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200332 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200334 Copy the permission bits, last access time, last modification time, and
335 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
336 attributes" where possible. The file contents, owner, and group are
Boris Verhovsky9488a522019-09-09 09:51:56 -0600337 unaffected. `src` and `dst` are path-like objects or path names given as
338 strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100339
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200340 If the optional flag `follow_symlinks` is not set, symlinks aren't
341 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100342 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700343 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344 pass
345
Larry Hastings9cf065c2012-06-22 16:30:09 -0700346 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800347 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700348 if follow:
349 # use the real function if it exists
350 def lookup(name):
351 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100352 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700353 # use the real function only if it exists
354 # *and* it supports follow_symlinks
355 def lookup(name):
356 fn = getattr(os, name, _nop)
357 if fn in os.supports_follow_symlinks:
358 return fn
359 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100360
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800361 if isinstance(src, os.DirEntry):
362 st = src.stat(follow_symlinks=follow)
363 else:
364 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000365 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700366 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
367 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500368 # We must copy extended attributes before the file is (potentially)
369 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
370 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700371 try:
372 lookup("chmod")(dst, mode, follow_symlinks=follow)
373 except NotImplementedError:
374 # if we got a NotImplementedError, it's because
375 # * follow_symlinks=False,
376 # * lchown() is unavailable, and
377 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300378 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700379 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
380 # (it returned ENOSUP.)
381 # therefore we're out of options--we simply cannot chown the
382 # symlink. give up, suppress the error.
383 # (which is what shutil always did in this circumstance.)
384 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000386 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700387 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000388 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700389 for err in 'EOPNOTSUPP', 'ENOTSUP':
390 if hasattr(errno, err) and why.errno == getattr(errno, err):
391 break
392 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000393 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200394
Larry Hastingsb4038062012-07-15 10:57:38 -0700395def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500396 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000397
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000398 The destination may be a directory.
399
Larry Hastingsb4038062012-07-15 10:57:38 -0700400 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100401 resembles GNU's "cp -P src dst".
402
Hynek Schlawack48653762012-10-07 12:49:58 +0200403 If source and destination are the same file, a SameFileError will be
404 raised.
405
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000406 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000407 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700409 copyfile(src, dst, follow_symlinks=follow_symlinks)
410 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500411 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000412
Larry Hastingsb4038062012-07-15 10:57:38 -0700413def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200414 """Copy data and metadata. Return the file's destination.
415
416 Metadata is copied with copystat(). Please see the copystat function
417 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000418
419 The destination may be a directory.
420
Larry Hastingsb4038062012-07-15 10:57:38 -0700421 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100422 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000423 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000424 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000425 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700426 copyfile(src, dst, follow_symlinks=follow_symlinks)
427 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500428 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000429
Georg Brandl2ee470f2008-07-16 12:55:28 +0000430def ignore_patterns(*patterns):
431 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000432
Georg Brandl2ee470f2008-07-16 12:55:28 +0000433 Patterns is a sequence of glob-style patterns
434 that are used to exclude files"""
435 def _ignore_patterns(path, names):
436 ignored_names = []
437 for pattern in patterns:
438 ignored_names.extend(fnmatch.filter(names, pattern))
439 return set(ignored_names)
440 return _ignore_patterns
441
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800442def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500443 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800444 if ignore is not None:
mbarkhau88704332020-01-24 14:51:16 +0000445 ignored_names = ignore(os.fspath(src), [x.name for x in entries])
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800446 else:
447 ignored_names = set()
448
jab9e00d9e2018-12-28 13:03:40 -0500449 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800450 errors = []
451 use_srcentry = copy_function is copy2 or copy_function is copy
452
453 for srcentry in entries:
454 if srcentry.name in ignored_names:
455 continue
456 srcname = os.path.join(src, srcentry.name)
457 dstname = os.path.join(dst, srcentry.name)
458 srcobj = srcentry if use_srcentry else srcname
459 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700460 is_symlink = srcentry.is_symlink()
461 if is_symlink and os.name == 'nt':
462 # Special check for directory junctions, which appear as
463 # symlinks but we want to recurse.
464 lstat = srcentry.stat(follow_symlinks=False)
465 if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
466 is_symlink = False
467 if is_symlink:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800468 linkto = os.readlink(srcname)
469 if symlinks:
470 # We can't just leave it to `copy_function` because legacy
471 # code with a custom `copy_function` may rely on copytree
472 # doing the right thing.
473 os.symlink(linkto, dstname)
474 copystat(srcobj, dstname, follow_symlinks=not symlinks)
475 else:
476 # ignore dangling symlink if the flag is on
477 if not os.path.exists(linkto) and ignore_dangling_symlinks:
478 continue
jab9e00d9e2018-12-28 13:03:40 -0500479 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800480 if srcentry.is_dir():
481 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500482 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800483 else:
484 copy_function(srcobj, dstname)
485 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500486 copytree(srcobj, dstname, symlinks, ignore, copy_function,
487 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800488 else:
489 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100490 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800491 # catch the Error from the recursive copytree so that we can
492 # continue with other files
493 except Error as err:
494 errors.extend(err.args[0])
495 except OSError as why:
496 errors.append((srcname, dstname, str(why)))
497 try:
498 copystat(src, dst)
499 except OSError as why:
500 # Copying file access times may fail on Windows
501 if getattr(why, 'winerror', None) is None:
502 errors.append((src, dst, str(why)))
503 if errors:
504 raise Error(errors)
505 return dst
506
Tarek Ziadéfb437512010-04-20 08:57:33 +0000507def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500508 ignore_dangling_symlinks=False, dirs_exist_ok=False):
509 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000510
jab9e00d9e2018-12-28 13:03:40 -0500511 dirs_exist_ok dictates whether to raise an exception in case dst or any
512 missing parent directory already exists.
513
Neal Norwitza4c93b62003-02-23 21:36:32 +0000514 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000515
516 If the optional symlinks flag is true, symbolic links in the
517 source tree result in symbolic links in the destination tree; if
518 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000519 links are copied. If the file pointed by the symlink doesn't
520 exist, an exception will be added in the list of errors raised in
521 an Error exception at the end of the copy process.
522
523 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000524 want to silence this exception. Notice that this has no effect on
525 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000526
Georg Brandl2ee470f2008-07-16 12:55:28 +0000527 The optional ignore argument is a callable. If given, it
528 is called with the `src` parameter, which is the directory
529 being visited by copytree(), and `names` which is the list of
530 `src` contents, as returned by os.listdir():
531
532 callable(src, names) -> ignored_names
533
534 Since copytree() is called recursively, the callable will be
535 called once for each directory that is copied. It returns a
536 list of names relative to the `src` directory that should
537 not be copied.
538
Tarek Ziadé5340db32010-04-19 22:30:51 +0000539 The optional copy_function argument is a callable that will be used
540 to copy each file. It will be called with the source path and the
541 destination path as arguments. By default, copy2() is used, but any
542 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000543
544 """
Steve Dower60419a72019-06-24 08:42:54 -0700545 sys.audit("shutil.copytree", src, dst)
Bruno P. Kinoshita9bbcbc92019-11-27 14:10:37 +1300546 with os.scandir(src) as itr:
547 entries = list(itr)
548 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
549 ignore=ignore, copy_function=copy_function,
550 ignore_dangling_symlinks=ignore_dangling_symlinks,
551 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000552
Ned Deily7fcc2082019-08-29 17:20:03 -0400553if hasattr(os.stat_result, 'st_file_attributes'):
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700554 # Special handling for directory junctions to make them behave like
555 # symlinks for shutil.rmtree, since in general they do not appear as
556 # regular links.
557 def _rmtree_isdir(entry):
558 try:
559 st = entry.stat(follow_symlinks=False)
560 return (stat.S_ISDIR(st.st_mode) and not
561 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
562 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
563 except OSError:
564 return False
565
566 def _rmtree_islink(path):
567 try:
568 st = os.lstat(path)
569 return (stat.S_ISLNK(st.st_mode) or
570 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
571 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
572 except OSError:
573 return False
574else:
575 def _rmtree_isdir(entry):
576 try:
577 return entry.is_dir(follow_symlinks=False)
578 except OSError:
579 return False
580
581 def _rmtree_islink(path):
582 return os.path.islink(path)
583
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200584# version vulnerable to race conditions
585def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000586 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200587 with os.scandir(path) as scandir_it:
588 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000589 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200590 onerror(os.scandir, path, sys.exc_info())
591 entries = []
592 for entry in entries:
593 fullname = entry.path
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700594 if _rmtree_isdir(entry):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200595 try:
596 if entry.is_symlink():
597 # This can only happen if someone replaces
598 # a directory with a symlink after the call to
599 # os.scandir or entry.is_dir above.
600 raise OSError("Cannot call rmtree on a symbolic link")
601 except OSError:
602 onerror(os.path.islink, fullname, sys.exc_info())
603 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200604 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000605 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000606 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200607 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200608 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000610 try:
611 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200612 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000613 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000614
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200615# Version using fd-based APIs to protect against races
616def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200617 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200618 with os.scandir(topfd) as scandir_it:
619 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100620 except OSError as err:
621 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200622 onerror(os.scandir, path, sys.exc_info())
623 return
624 for entry in entries:
625 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200626 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200627 is_dir = entry.is_dir(follow_symlinks=False)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100628 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200629 is_dir = False
Serhiy Storchakae9b51c02019-05-31 11:30:37 +0300630 else:
631 if is_dir:
632 try:
633 orig_st = entry.stat(follow_symlinks=False)
634 is_dir = stat.S_ISDIR(orig_st.st_mode)
635 except OSError:
636 onerror(os.lstat, fullname, sys.exc_info())
637 continue
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200638 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200639 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200640 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100641 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200642 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200643 else:
644 try:
645 if os.path.samestat(orig_st, os.fstat(dirfd)):
646 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200647 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200648 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100649 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200650 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100651 else:
652 try:
653 # This can only happen if someone replaces
654 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200655 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100656 raise OSError("Cannot call rmtree on a symbolic "
657 "link")
658 except OSError:
659 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200660 finally:
661 os.close(dirfd)
662 else:
663 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200664 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100665 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200666 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200667
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200668_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
669 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200670 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200671 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000672
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200673def rmtree(path, ignore_errors=False, onerror=None):
674 """Recursively delete a directory tree.
675
676 If ignore_errors is set, errors are ignored; otherwise, if onerror
677 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200678 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200679 path is the argument to that function that caused it to fail; and
680 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
681 is false and onerror is None, an exception is raised.
682
683 """
Steve Dower60419a72019-06-24 08:42:54 -0700684 sys.audit("shutil.rmtree", path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200685 if ignore_errors:
686 def onerror(*args):
687 pass
688 elif onerror is None:
689 def onerror(*args):
690 raise
691 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200692 # While the unsafe rmtree works fine on bytes, the fd based does not.
693 if isinstance(path, bytes):
694 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200695 # Note: To guard against symlink races, we use the standard
696 # lstat()/open()/fstat() trick.
697 try:
698 orig_st = os.lstat(path)
699 except Exception:
700 onerror(os.lstat, path, sys.exc_info())
701 return
702 try:
703 fd = os.open(path, os.O_RDONLY)
704 except Exception:
705 onerror(os.lstat, path, sys.exc_info())
706 return
707 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100708 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200709 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200710 try:
711 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200712 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200713 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200714 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100715 try:
716 # symlinks to directories are forbidden, see bug #1669
717 raise OSError("Cannot call rmtree on a symbolic link")
718 except OSError:
719 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200720 finally:
721 os.close(fd)
722 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200723 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700724 if _rmtree_islink(path):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200725 # symlinks to directories are forbidden, see bug #1669
726 raise OSError("Cannot call rmtree on a symbolic link")
727 except OSError:
728 onerror(os.path.islink, path, sys.exc_info())
729 # can't continue even if onerror hook returns
730 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200731 return _rmtree_unsafe(path, onerror)
732
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000733# Allow introspection of whether or not the hardening against symlink
734# attacks is supported on the current platform
735rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000736
Christian Heimesada8c3b2008-03-18 18:26:33 +0000737def _basename(path):
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700738 """A basename() variant which first strips the trailing slash, if present.
739 Thus we always get the last component of the path, even for directories.
740
741 path: Union[PathLike, str]
742
743 e.g.
744 >>> os.path.basename('/bar/foo')
745 'foo'
746 >>> os.path.basename('/bar/foo/')
747 ''
748 >>> _basename('/bar/foo/')
749 'foo'
750 """
751 path = os.fspath(path)
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200752 sep = os.path.sep + (os.path.altsep or '')
753 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000754
R David Murray6ffface2014-06-11 14:40:13 -0400755def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000756 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500757 similar to the Unix "mv" command. Return the file or directory's
758 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000759
760 If the destination is a directory or a symlink to a directory, the source
761 is moved inside the directory. The destination path must not already
762 exist.
763
764 If the destination already exists but is not a directory, it may be
765 overwritten depending on os.rename() semantics.
766
767 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100768 Otherwise, src is copied to the destination and then removed. Symlinks are
769 recreated under the new name if os.rename() fails because of cross
770 filesystem renames.
771
R David Murray6ffface2014-06-11 14:40:13 -0400772 The optional `copy_function` argument is a callable that will be used
773 to copy the source or it will be delegated to `copytree`.
774 By default, copy2() is used, but any function that supports the same
775 signature (like copy()) can be used.
776
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000777 A lot more could be done here... A look at a mv.c shows a lot of
778 the issues this implementation glosses over.
779
780 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000781 real_dst = dst
782 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200783 if _samefile(src, dst):
784 # We might be on a case insensitive filesystem,
785 # perform the rename anyway.
786 os.rename(src, dst)
787 return
788
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700789 # Using _basename instead of os.path.basename is important, as we must
790 # ignore any trailing slash to avoid the basename returning ''
Christian Heimesada8c3b2008-03-18 18:26:33 +0000791 real_dst = os.path.join(dst, _basename(src))
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700792
Christian Heimesada8c3b2008-03-18 18:26:33 +0000793 if os.path.exists(real_dst):
794 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000795 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000796 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200797 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100798 if os.path.islink(src):
799 linkto = os.readlink(src)
800 os.symlink(linkto, real_dst)
801 os.unlink(src)
802 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000803 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400804 raise Error("Cannot move a directory '%s' into itself"
805 " '%s'." % (src, dst))
806 copytree(src, real_dst, copy_function=copy_function,
807 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000808 rmtree(src)
809 else:
R David Murray6ffface2014-06-11 14:40:13 -0400810 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000811 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500812 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000813
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000814def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300815 src = os.path.abspath(src)
816 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000817 if not src.endswith(os.path.sep):
818 src += os.path.sep
819 if not dst.endswith(os.path.sep):
820 dst += os.path.sep
821 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000822
823def _get_gid(name):
824 """Returns a gid, given a group name."""
825 if getgrnam is None or name is None:
826 return None
827 try:
828 result = getgrnam(name)
829 except KeyError:
830 result = None
831 if result is not None:
832 return result[2]
833 return None
834
835def _get_uid(name):
836 """Returns an uid, given a user name."""
837 if getpwnam is None or name is None:
838 return None
839 try:
840 result = getpwnam(name)
841 except KeyError:
842 result = None
843 if result is not None:
844 return result[2]
845 return None
846
847def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
848 owner=None, group=None, logger=None):
849 """Create a (possibly compressed) tar file from all the files under
850 'base_dir'.
851
Serhiy Storchaka11213772014-08-06 18:50:19 +0300852 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000853
854 'owner' and 'group' can be used to define an owner and a group for the
855 archive that is being built. If not provided, the current owner and group
856 will be used.
857
Éric Araujo4433a5f2010-12-15 20:26:30 +0000858 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300859 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000860
861 Returns the output filename.
862 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200863 if compress is None:
864 tar_compression = ''
865 elif _ZLIB_SUPPORTED and compress == 'gzip':
866 tar_compression = 'gz'
867 elif _BZ2_SUPPORTED and compress == 'bzip2':
868 tar_compression = 'bz2'
869 elif _LZMA_SUPPORTED and compress == 'xz':
870 tar_compression = 'xz'
871 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000872 raise ValueError("bad value for 'compress', or compression format not "
873 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000874
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200875 import tarfile # late import for breaking circular dependency
876
877 compress_ext = '.' + tar_compression if compress else ''
878 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000879 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000880
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200881 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000882 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200883 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000884 if not dry_run:
885 os.makedirs(archive_dir)
886
Tarek Ziadé396fad72010-02-23 05:30:31 +0000887 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000888 if logger is not None:
889 logger.info('Creating tar archive')
890
891 uid = _get_uid(owner)
892 gid = _get_gid(group)
893
894 def _set_uid_gid(tarinfo):
895 if gid is not None:
896 tarinfo.gid = gid
897 tarinfo.gname = group
898 if uid is not None:
899 tarinfo.uid = uid
900 tarinfo.uname = owner
901 return tarinfo
902
903 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200904 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000905 try:
906 tar.add(base_dir, filter=_set_uid_gid)
907 finally:
908 tar.close()
909
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 return archive_name
911
Tarek Ziadé396fad72010-02-23 05:30:31 +0000912def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
913 """Create a zip file from all the files under 'base_dir'.
914
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200915 The output zip file will be named 'base_name' + ".zip". Returns the
916 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000917 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200918 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400919
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920 zip_filename = base_name + ".zip"
921 archive_dir = os.path.dirname(base_name)
922
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200923 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000924 if logger is not None:
925 logger.info("creating %s", archive_dir)
926 if not dry_run:
927 os.makedirs(archive_dir)
928
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400929 if logger is not None:
930 logger.info("creating '%s' and adding '%s' to it",
931 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400933 if not dry_run:
934 with zipfile.ZipFile(zip_filename, "w",
935 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300936 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300937 if path != os.curdir:
938 zf.write(path, path)
939 if logger is not None:
940 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400941 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300942 for name in sorted(dirnames):
943 path = os.path.normpath(os.path.join(dirpath, name))
944 zf.write(path, path)
945 if logger is not None:
946 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400947 for name in filenames:
948 path = os.path.normpath(os.path.join(dirpath, name))
949 if os.path.isfile(path):
950 zf.write(path, path)
951 if logger is not None:
952 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000953
954 return zip_filename
955
956_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000957 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200958}
959
960if _ZLIB_SUPPORTED:
961 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
962 "gzip'ed tar-file")
963 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000964
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000965if _BZ2_SUPPORTED:
966 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
967 "bzip2'ed tar-file")
968
Serhiy Storchaka11213772014-08-06 18:50:19 +0300969if _LZMA_SUPPORTED:
970 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
971 "xz'ed tar-file")
972
Tarek Ziadé396fad72010-02-23 05:30:31 +0000973def get_archive_formats():
974 """Returns a list of supported formats for archiving and unarchiving.
975
976 Each element of the returned sequence is a tuple (name, description)
977 """
978 formats = [(name, registry[2]) for name, registry in
979 _ARCHIVE_FORMATS.items()]
980 formats.sort()
981 return formats
982
983def register_archive_format(name, function, extra_args=None, description=''):
984 """Registers an archive format.
985
986 name is the name of the format. function is the callable that will be
987 used to create archives. If provided, extra_args is a sequence of
988 (name, value) tuples that will be passed as arguments to the callable.
989 description can be provided to describe the format, and will be returned
990 by the get_archive_formats() function.
991 """
992 if extra_args is None:
993 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200994 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000995 raise TypeError('The %s object is not callable' % function)
996 if not isinstance(extra_args, (tuple, list)):
997 raise TypeError('extra_args needs to be a sequence')
998 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200999 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001000 raise TypeError('extra_args elements are : (arg_name, value)')
1001
1002 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
1003
1004def unregister_archive_format(name):
1005 del _ARCHIVE_FORMATS[name]
1006
1007def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
1008 dry_run=0, owner=None, group=None, logger=None):
1009 """Create an archive file (eg. zip or tar).
1010
1011 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001012 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
1013 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +00001014
1015 'root_dir' is a directory that will be the root directory of the
1016 archive; ie. we typically chdir into 'root_dir' before creating the
1017 archive. 'base_dir' is the directory where we start archiving from;
1018 ie. 'base_dir' will be the common prefix of all files and
1019 directories in the archive. 'root_dir' and 'base_dir' both default
1020 to the current directory. Returns the name of the archive file.
1021
1022 'owner' and 'group' are used when creating a tar archive. By default,
1023 uses the current owner and group.
1024 """
Steve Dower60419a72019-06-24 08:42:54 -07001025 sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026 save_cwd = os.getcwd()
1027 if root_dir is not None:
1028 if logger is not None:
1029 logger.debug("changing into '%s'", root_dir)
1030 base_name = os.path.abspath(base_name)
1031 if not dry_run:
1032 os.chdir(root_dir)
1033
1034 if base_dir is None:
1035 base_dir = os.curdir
1036
1037 kwargs = {'dry_run': dry_run, 'logger': logger}
1038
1039 try:
1040 format_info = _ARCHIVE_FORMATS[format]
1041 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001042 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +00001043
1044 func = format_info[0]
1045 for arg, val in format_info[1]:
1046 kwargs[arg] = val
1047
1048 if format != 'zip':
1049 kwargs['owner'] = owner
1050 kwargs['group'] = group
1051
1052 try:
1053 filename = func(base_name, base_dir, **kwargs)
1054 finally:
1055 if root_dir is not None:
1056 if logger is not None:
1057 logger.debug("changing back to '%s'", save_cwd)
1058 os.chdir(save_cwd)
1059
1060 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001061
1062
1063def get_unpack_formats():
1064 """Returns a list of supported formats for unpacking.
1065
1066 Each element of the returned sequence is a tuple
1067 (name, extensions, description)
1068 """
1069 formats = [(name, info[0], info[3]) for name, info in
1070 _UNPACK_FORMATS.items()]
1071 formats.sort()
1072 return formats
1073
1074def _check_unpack_options(extensions, function, extra_args):
1075 """Checks what gets registered as an unpacker."""
1076 # first make sure no other unpacker is registered for this extension
1077 existing_extensions = {}
1078 for name, info in _UNPACK_FORMATS.items():
1079 for ext in info[0]:
1080 existing_extensions[ext] = name
1081
1082 for extension in extensions:
1083 if extension in existing_extensions:
1084 msg = '%s is already registered for "%s"'
1085 raise RegistryError(msg % (extension,
1086 existing_extensions[extension]))
1087
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001088 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001089 raise TypeError('The registered function must be a callable')
1090
1091
1092def register_unpack_format(name, extensions, function, extra_args=None,
1093 description=''):
1094 """Registers an unpack format.
1095
1096 `name` is the name of the format. `extensions` is a list of extensions
1097 corresponding to the format.
1098
1099 `function` is the callable that will be
1100 used to unpack archives. The callable will receive archives to unpack.
1101 If it's unable to handle an archive, it needs to raise a ReadError
1102 exception.
1103
1104 If provided, `extra_args` is a sequence of
1105 (name, value) tuples that will be passed as arguments to the callable.
1106 description can be provided to describe the format, and will be returned
1107 by the get_unpack_formats() function.
1108 """
1109 if extra_args is None:
1110 extra_args = []
1111 _check_unpack_options(extensions, function, extra_args)
1112 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1113
1114def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001115 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001116 del _UNPACK_FORMATS[name]
1117
1118def _ensure_directory(path):
1119 """Ensure that the parent directory of `path` exists"""
1120 dirname = os.path.dirname(path)
1121 if not os.path.isdir(dirname):
1122 os.makedirs(dirname)
1123
1124def _unpack_zipfile(filename, extract_dir):
1125 """Unpack zip `filename` to `extract_dir`
1126 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001127 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001128
1129 if not zipfile.is_zipfile(filename):
1130 raise ReadError("%s is not a zip file" % filename)
1131
1132 zip = zipfile.ZipFile(filename)
1133 try:
1134 for info in zip.infolist():
1135 name = info.filename
1136
1137 # don't extract absolute paths or ones with .. in them
1138 if name.startswith('/') or '..' in name:
1139 continue
1140
1141 target = os.path.join(extract_dir, *name.split('/'))
1142 if not target:
1143 continue
1144
1145 _ensure_directory(target)
1146 if not name.endswith('/'):
1147 # file
1148 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001149 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001150 try:
1151 f.write(data)
1152 finally:
1153 f.close()
1154 del data
1155 finally:
1156 zip.close()
1157
1158def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001159 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001160 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001161 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001162 try:
1163 tarobj = tarfile.open(filename)
1164 except tarfile.TarError:
1165 raise ReadError(
1166 "%s is not a compressed or uncompressed tar file" % filename)
1167 try:
1168 tarobj.extractall(extract_dir)
1169 finally:
1170 tarobj.close()
1171
1172_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001173 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001174 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1175}
1176
1177if _ZLIB_SUPPORTED:
1178 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1179 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001180
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001181if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001182 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001183 "bzip2'ed tar-file")
1184
Serhiy Storchaka11213772014-08-06 18:50:19 +03001185if _LZMA_SUPPORTED:
1186 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1187 "xz'ed tar-file")
1188
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001189def _find_unpack_format(filename):
1190 for name, info in _UNPACK_FORMATS.items():
1191 for extension in info[0]:
1192 if filename.endswith(extension):
1193 return name
1194 return None
1195
1196def unpack_archive(filename, extract_dir=None, format=None):
1197 """Unpack an archive.
1198
1199 `filename` is the name of the archive.
1200
1201 `extract_dir` is the name of the target directory, where the archive
1202 is unpacked. If not provided, the current working directory is used.
1203
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001204 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1205 or "xztar". Or any other registered format. If not provided,
1206 unpack_archive will use the filename extension and see if an unpacker
1207 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001208
1209 In case none is found, a ValueError is raised.
1210 """
1211 if extract_dir is None:
1212 extract_dir = os.getcwd()
1213
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001214 extract_dir = os.fspath(extract_dir)
1215 filename = os.fspath(filename)
1216
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001217 if format is not None:
1218 try:
1219 format_info = _UNPACK_FORMATS[format]
1220 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001221 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001222
Nick Coghlanabf202d2011-03-16 13:52:20 -04001223 func = format_info[1]
1224 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001225 else:
1226 # we need to look at the registered unpackers supported extensions
1227 format = _find_unpack_format(filename)
1228 if format is None:
1229 raise ReadError("Unknown archive format '{0}'".format(filename))
1230
1231 func = _UNPACK_FORMATS[format][1]
1232 kwargs = dict(_UNPACK_FORMATS[format][2])
1233 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001234
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001235
1236if hasattr(os, 'statvfs'):
1237
1238 __all__.append('disk_usage')
1239 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001240 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1241 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1242 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001243
1244 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001245 """Return disk usage statistics about the given path.
1246
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001247 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001248 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001249 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001250 st = os.statvfs(path)
1251 free = st.f_bavail * st.f_frsize
1252 total = st.f_blocks * st.f_frsize
1253 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1254 return _ntuple_diskusage(total, used, free)
1255
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001256elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001257
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001258 __all__.append('disk_usage')
1259 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1260
1261 def disk_usage(path):
1262 """Return disk usage statistics about the given path.
1263
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001264 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001265 'free', which are the amount of total, used and free space, in bytes.
1266 """
1267 total, free = nt._getdiskusage(path)
1268 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001269 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001270
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001271
Sandro Tosid902a142011-08-22 23:28:27 +02001272def chown(path, user=None, group=None):
1273 """Change owner user and group of the given path.
1274
1275 user and group can be the uid/gid or the user/group names, and in that case,
1276 they are converted to their respective uid/gid.
1277 """
1278
1279 if user is None and group is None:
1280 raise ValueError("user and/or group must be set")
1281
1282 _user = user
1283 _group = group
1284
1285 # -1 means don't change it
1286 if user is None:
1287 _user = -1
1288 # user can either be an int (the uid) or a string (the system username)
1289 elif isinstance(user, str):
1290 _user = _get_uid(user)
1291 if _user is None:
1292 raise LookupError("no such user: {!r}".format(user))
1293
1294 if group is None:
1295 _group = -1
1296 elif not isinstance(group, int):
1297 _group = _get_gid(group)
1298 if _group is None:
1299 raise LookupError("no such group: {!r}".format(group))
1300
1301 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001302
1303def get_terminal_size(fallback=(80, 24)):
1304 """Get the size of the terminal window.
1305
1306 For each of the two dimensions, the environment variable, COLUMNS
1307 and LINES respectively, is checked. If the variable is defined and
1308 the value is a positive integer, it is used.
1309
1310 When COLUMNS or LINES is not defined, which is the common case,
1311 the terminal connected to sys.__stdout__ is queried
1312 by invoking os.get_terminal_size.
1313
1314 If the terminal size cannot be successfully queried, either because
1315 the system doesn't support querying, or because we are not
1316 connected to a terminal, the value given in fallback parameter
1317 is used. Fallback defaults to (80, 24) which is the default
1318 size used by many terminal emulators.
1319
1320 The value returned is a named tuple of type os.terminal_size.
1321 """
1322 # columns, lines are the working values
1323 try:
1324 columns = int(os.environ['COLUMNS'])
1325 except (KeyError, ValueError):
1326 columns = 0
1327
1328 try:
1329 lines = int(os.environ['LINES'])
1330 except (KeyError, ValueError):
1331 lines = 0
1332
1333 # only query if necessary
1334 if columns <= 0 or lines <= 0:
1335 try:
1336 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001337 except (AttributeError, ValueError, OSError):
1338 # stdout is None, closed, detached, or not a terminal, or
1339 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001340 size = os.terminal_size(fallback)
1341 if columns <= 0:
1342 columns = size.columns
1343 if lines <= 0:
1344 lines = size.lines
1345
1346 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001347
Cheryl Sabella5680f652019-02-13 06:25:10 -05001348
1349# Check that a given file can be accessed with the correct mode.
1350# Additionally check that `file` is not a directory, as on Windows
1351# directories pass the os.access check.
1352def _access_check(fn, mode):
1353 return (os.path.exists(fn) and os.access(fn, mode)
1354 and not os.path.isdir(fn))
1355
1356
Brian Curtinc57a3452012-06-22 16:00:30 -05001357def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001358 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001359 conforms to the given mode on the PATH, or None if there is no such
1360 file.
1361
1362 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1363 of os.environ.get("PATH"), or can be overridden with a custom search
1364 path.
1365
1366 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001367 # If we're given a path with a directory part, look it up directly rather
1368 # than referring to PATH directories. This includes checking relative to the
1369 # current directory, e.g. ./script
1370 if os.path.dirname(cmd):
1371 if _access_check(cmd, mode):
1372 return cmd
1373 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001374
Cheryl Sabella5680f652019-02-13 06:25:10 -05001375 use_bytes = isinstance(cmd, bytes)
1376
Barry Warsaw618738b2013-04-16 11:05:03 -04001377 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001378 path = os.environ.get("PATH", None)
1379 if path is None:
1380 try:
1381 path = os.confstr("CS_PATH")
1382 except (AttributeError, ValueError):
1383 # os.confstr() or CS_PATH is not available
1384 path = os.defpath
1385 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001386 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001387
1388 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001389 if not path:
1390 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001391
Cheryl Sabella5680f652019-02-13 06:25:10 -05001392 if use_bytes:
1393 path = os.fsencode(path)
1394 path = path.split(os.fsencode(os.pathsep))
1395 else:
1396 path = os.fsdecode(path)
1397 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001398
1399 if sys.platform == "win32":
1400 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001401 curdir = os.curdir
1402 if use_bytes:
1403 curdir = os.fsencode(curdir)
1404 if curdir not in path:
1405 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001406
1407 # PATHEXT is necessary to check on Windows.
1408 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
Cheryl Sabella5680f652019-02-13 06:25:10 -05001409 if use_bytes:
1410 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001411 # See if the given file matches any of the expected path extensions.
1412 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001413 # If it does match, only test that one, otherwise we have to try
1414 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001415 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1416 files = [cmd]
1417 else:
1418 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001419 else:
1420 # On other platforms you don't have things like PATHEXT to tell you
1421 # what file suffixes are executable, so just pass on cmd as-is.
1422 files = [cmd]
1423
1424 seen = set()
1425 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001426 normdir = os.path.normcase(dir)
1427 if not normdir in seen:
1428 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001429 for thefile in files:
1430 name = os.path.join(dir, thefile)
1431 if _access_check(name, mode):
1432 return name
1433 return None