blob: d749b843cb450dfc52fb512208b6fd5171919c36 [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
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070035_WINDOWS = os.name == 'nt'
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020036posix = nt = None
37if os.name == 'posix':
38 import posix
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070039elif _WINDOWS:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020040 import nt
41
Inada Naoki4f190302019-03-02 13:31:01 +090042COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
Giampaolo Rodola413d9552019-05-30 14:05:41 +080043_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070044_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020045
Christopher Marchfelderda6f0982020-10-23 12:08:24 +020046# CMD defaults in Windows 10
47_WIN_DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC"
48
Tarek Ziadéc3399782010-02-23 05:39:18 +000049__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
50 "copytree", "move", "rmtree", "Error", "SpecialFileError",
51 "ExecError", "make_archive", "get_archive_formats",
Tarek Ziadé6ac91722010-04-28 17:51:36 +000052 "register_archive_format", "unregister_archive_format",
53 "get_unpack_formats", "register_unpack_format",
Éric Araujoc5efe652011-08-21 14:30:00 +020054 "unregister_unpack_format", "unpack_archive",
Berker Peksag8083cd62014-11-01 11:04:06 +020055 "ignore_patterns", "chown", "which", "get_terminal_size",
56 "SameFileError"]
Éric Araujoe4d5b8e2011-08-08 16:51:11 +020057 # disk_usage is added later, if available on the platform
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000058
Andrew Svetlov3438fa42012-12-17 23:35:18 +020059class Error(OSError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000060 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000061
Hynek Schlawack48653762012-10-07 12:49:58 +020062class SameFileError(Error):
63 """Raised when source and destination are the same file."""
64
Andrew Svetlov3438fa42012-12-17 23:35:18 +020065class SpecialFileError(OSError):
Antoine Pitrou7fff0962009-05-01 21:09:44 +000066 """Raised when trying to do a kind of operation (e.g. copying) which is
67 not supported on a special file (e.g. a named pipe)"""
68
Andrew Svetlov3438fa42012-12-17 23:35:18 +020069class ExecError(OSError):
Tarek Ziadé396fad72010-02-23 05:30:31 +000070 """Raised when a command could not be executed"""
71
Andrew Svetlov3438fa42012-12-17 23:35:18 +020072class ReadError(OSError):
Tarek Ziadé6ac91722010-04-28 17:51:36 +000073 """Raised when an archive cannot be read"""
74
75class RegistryError(Exception):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030076 """Raised when a registry operation with the archiving
Raymond Hettinger15f44ab2016-08-30 10:47:49 -070077 and unpacking registries fails"""
Tarek Ziadé6ac91722010-04-28 17:51:36 +000078
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020079class _GiveupOnFastCopy(Exception):
80 """Raised as a signal to fallback on using raw read()/write()
81 file copy when fast-copy functions fail to do so.
82 """
Tarek Ziadé6ac91722010-04-28 17:51:36 +000083
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070084def _fastcopy_fcopyfile(fsrc, fdst, flags):
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020085 """Copy a regular file content or metadata by using high-performance
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070086 fcopyfile(3) syscall (macOS).
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020087 """
88 try:
89 infd = fsrc.fileno()
90 outfd = fdst.fileno()
91 except Exception as err:
92 raise _GiveupOnFastCopy(err) # not a regular file
93
94 try:
95 posix._fcopyfile(infd, outfd, flags)
96 except OSError as err:
97 err.filename = fsrc.name
98 err.filename2 = fdst.name
99 if err.errno in {errno.EINVAL, errno.ENOTSUP}:
100 raise _GiveupOnFastCopy(err)
101 else:
102 raise err from None
103
104def _fastcopy_sendfile(fsrc, fdst):
105 """Copy data from one regular mmap-like fd to another by using
106 high-performance sendfile(2) syscall.
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800107 This should work on Linux >= 2.6.33 only.
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200108 """
109 # Note: copyfileobj() is left alone in order to not introduce any
110 # unexpected breakage. Possible risks by using zero-copy calls
111 # in copyfileobj() are:
112 # - fdst cannot be open in "a"(ppend) mode
113 # - fsrc and fdst may be open in "t"(ext) mode
114 # - fsrc may be a BufferedReader (which hides unread data in a buffer),
115 # GzipFile (which decompresses data), HTTPResponse (which decodes
116 # chunks).
117 # - possibly others (e.g. encrypted fs/partition?)
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800118 global _USE_CP_SENDFILE
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200119 try:
120 infd = fsrc.fileno()
121 outfd = fdst.fileno()
122 except Exception as err:
123 raise _GiveupOnFastCopy(err) # not a regular file
124
125 # Hopefully the whole file will be copied in a single call.
126 # sendfile() is called in a loop 'till EOF is reached (0 return)
127 # so a bufsize smaller or bigger than the actual file size
128 # should not make any difference, also in case the file content
129 # changes while being copied.
130 try:
Giampaolo Rodola94e16502019-10-01 11:40:54 +0800131 blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MiB
132 except OSError:
133 blocksize = 2 ** 27 # 128MiB
134 # On 32-bit architectures truncate to 1GiB to avoid OverflowError,
135 # see bpo-38319.
136 if sys.maxsize < 2 ** 32:
137 blocksize = min(blocksize, 2 ** 30)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200138
139 offset = 0
140 while True:
141 try:
142 sent = os.sendfile(outfd, infd, offset, blocksize)
143 except OSError as err:
144 # ...in oder to have a more informative exception.
145 err.filename = fsrc.name
146 err.filename2 = fdst.name
147
148 if err.errno == errno.ENOTSOCK:
149 # sendfile() on this platform (probably Linux < 2.6.33)
150 # does not support copies between regular files (only
151 # sockets).
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800152 _USE_CP_SENDFILE = False
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200153 raise _GiveupOnFastCopy(err)
154
155 if err.errno == errno.ENOSPC: # filesystem is full
156 raise err from None
157
158 # Give up on first call and if no data was copied.
159 if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0:
160 raise _GiveupOnFastCopy(err)
161
162 raise err
163 else:
164 if sent == 0:
165 break # EOF
166 offset += sent
167
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700168def _copyfileobj_readinto(fsrc, fdst, length=COPY_BUFSIZE):
169 """readinto()/memoryview() based variant of copyfileobj().
170 *fsrc* must support readinto() method and both files must be
171 open in binary mode.
172 """
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200173 # Localize variable access to minimize overhead.
174 fsrc_readinto = fsrc.readinto
175 fdst_write = fdst.write
176 with memoryview(bytearray(length)) as mv:
177 while True:
178 n = fsrc_readinto(mv)
179 if not n:
180 break
181 elif n < length:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700182 with mv[:n] as smv:
183 fdst.write(smv)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200184 else:
185 fdst_write(mv)
186
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800187def copyfileobj(fsrc, fdst, length=0):
Greg Stein42bb8b32000-07-12 09:55:30 +0000188 """copy data from file-like object fsrc to file-like object fdst"""
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700189 # Localize variable access to minimize overhead.
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800190 if not length:
191 length = COPY_BUFSIZE
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700192 fsrc_read = fsrc.read
193 fdst_write = fdst.write
194 while True:
195 buf = fsrc_read(length)
196 if not buf:
197 break
198 fdst_write(buf)
Greg Stein42bb8b32000-07-12 09:55:30 +0000199
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000200def _samefile(src, dst):
201 # Macintosh, Unix.
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800202 if isinstance(src, os.DirEntry) and hasattr(os.path, 'samestat'):
203 try:
204 return os.path.samestat(src.stat(), os.stat(dst))
205 except OSError:
206 return False
207
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +0000208 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +0000209 try:
210 return os.path.samefile(src, dst)
211 except OSError:
212 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000213
214 # All other platforms: check for same pathname.
215 return (os.path.normcase(os.path.abspath(src)) ==
216 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +0000217
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800218def _stat(fn):
219 return fn.stat() if isinstance(fn, os.DirEntry) else os.stat(fn)
220
221def _islink(fn):
222 return fn.is_symlink() if isinstance(fn, os.DirEntry) else os.path.islink(fn)
223
Larry Hastingsb4038062012-07-15 10:57:38 -0700224def copyfile(src, dst, *, follow_symlinks=True):
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700225 """Copy data from src to dst in the most efficient way possible.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100226
Larry Hastingsb4038062012-07-15 10:57:38 -0700227 If follow_symlinks is not set and src is a symbolic link, a new
Antoine Pitrou78091e62011-12-29 18:54:15 +0100228 symlink will be created instead of copying the file it points to.
229
230 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800231 sys.audit("shutil.copyfile", src, dst)
232
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000233 if _samefile(src, dst):
Hynek Schlawack48653762012-10-07 12:49:58 +0200234 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000235
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700236 file_size = 0
237 for i, fn in enumerate([src, dst]):
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000238 try:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800239 st = _stat(fn)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000240 except OSError:
241 # File most likely does not exist
242 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000243 else:
244 # XXX What about other special files? (sockets, devices...)
245 if stat.S_ISFIFO(st.st_mode):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800246 fn = fn.path if isinstance(fn, os.DirEntry) else fn
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000247 raise SpecialFileError("`%s` is a named pipe" % fn)
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700248 if _WINDOWS and i == 0:
249 file_size = st.st_size
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000250
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800251 if not follow_symlinks and _islink(src):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100252 os.symlink(os.readlink(src), dst)
253 else:
Miss Islington (bot)15772592021-07-09 21:07:35 -0700254 try:
255 with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
256 # macOS
257 if _HAS_FCOPYFILE:
258 try:
259 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
260 return dst
261 except _GiveupOnFastCopy:
262 pass
263 # Linux
264 elif _USE_CP_SENDFILE:
265 try:
266 _fastcopy_sendfile(fsrc, fdst)
267 return dst
268 except _GiveupOnFastCopy:
269 pass
270 # Windows, see:
271 # https://github.com/python/cpython/pull/7160#discussion_r195405230
272 elif _WINDOWS and file_size > 0:
273 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700274 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200275
Miss Islington (bot)15772592021-07-09 21:07:35 -0700276 copyfileobj(fsrc, fdst)
277
278 # Issue 43219, raise a less confusing exception
279 except IsADirectoryError as e:
280 if os.path.exists(dst):
281 raise
282 else:
283 raise FileNotFoundError(f'Directory does not exist: {dst}') from e
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200284
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500285 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000286
Larry Hastingsb4038062012-07-15 10:57:38 -0700287def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100288 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000289
Larry Hastingsb4038062012-07-15 10:57:38 -0700290 If follow_symlinks is not set, symlinks aren't followed if and only
291 if both `src` and `dst` are symlinks. If `lchmod` isn't available
292 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100293
294 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800295 sys.audit("shutil.copymode", src, dst)
296
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800297 if not follow_symlinks and _islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100298 if hasattr(os, 'lchmod'):
299 stat_func, chmod_func = os.lstat, os.lchmod
300 else:
301 return
Antoine Pitrou78091e62011-12-29 18:54:15 +0100302 else:
Anthony Sottile8377cd42019-02-25 14:32:27 -0800303 stat_func, chmod_func = _stat, os.chmod
Antoine Pitrou78091e62011-12-29 18:54:15 +0100304
305 st = stat_func(src)
306 chmod_func(dst, stat.S_IMODE(st.st_mode))
307
Larry Hastingsad5ae042012-07-14 17:55:11 -0700308if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700309 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700310 """Copy extended filesystem attributes from `src` to `dst`.
311
312 Overwrite existing attributes.
313
Larry Hastingsb4038062012-07-15 10:57:38 -0700314 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700315
316 """
317
Hynek Schlawack0beab052013-02-05 08:22:44 +0100318 try:
319 names = os.listxattr(src, follow_symlinks=follow_symlinks)
320 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400321 if e.errno not in (errno.ENOTSUP, errno.ENODATA, errno.EINVAL):
Hynek Schlawack0beab052013-02-05 08:22:44 +0100322 raise
323 return
324 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700325 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
327 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700328 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400329 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
330 errno.EINVAL):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700331 raise
332else:
333 def _copyxattr(*args, **kwargs):
334 pass
335
Larry Hastingsb4038062012-07-15 10:57:38 -0700336def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200337 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100338
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200339 Copy the permission bits, last access time, last modification time, and
340 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
341 attributes" where possible. The file contents, owner, and group are
Boris Verhovsky9488a522019-09-09 09:51:56 -0600342 unaffected. `src` and `dst` are path-like objects or path names given as
343 strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200345 If the optional flag `follow_symlinks` is not set, symlinks aren't
346 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100347 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800348 sys.audit("shutil.copystat", src, dst)
349
Larry Hastings9cf065c2012-06-22 16:30:09 -0700350 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100351 pass
352
Larry Hastings9cf065c2012-06-22 16:30:09 -0700353 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800354 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700355 if follow:
356 # use the real function if it exists
357 def lookup(name):
358 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100359 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700360 # use the real function only if it exists
361 # *and* it supports follow_symlinks
362 def lookup(name):
363 fn = getattr(os, name, _nop)
364 if fn in os.supports_follow_symlinks:
365 return fn
366 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100367
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800368 if isinstance(src, os.DirEntry):
369 st = src.stat(follow_symlinks=follow)
370 else:
371 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000372 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700373 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
374 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500375 # We must copy extended attributes before the file is (potentially)
376 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
377 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700378 try:
379 lookup("chmod")(dst, mode, follow_symlinks=follow)
380 except NotImplementedError:
381 # if we got a NotImplementedError, it's because
382 # * follow_symlinks=False,
383 # * lchown() is unavailable, and
384 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300385 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700386 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
387 # (it returned ENOSUP.)
388 # therefore we're out of options--we simply cannot chown the
389 # symlink. give up, suppress the error.
390 # (which is what shutil always did in this circumstance.)
391 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100392 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000393 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700394 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000395 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700396 for err in 'EOPNOTSUPP', 'ENOTSUP':
397 if hasattr(errno, err) and why.errno == getattr(errno, err):
398 break
399 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000400 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200401
Larry Hastingsb4038062012-07-15 10:57:38 -0700402def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500403 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000404
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000405 The destination may be a directory.
406
Larry Hastingsb4038062012-07-15 10:57:38 -0700407 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100408 resembles GNU's "cp -P src dst".
409
Hynek Schlawack48653762012-10-07 12:49:58 +0200410 If source and destination are the same file, a SameFileError will be
411 raised.
412
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000413 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000414 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000415 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700416 copyfile(src, dst, follow_symlinks=follow_symlinks)
417 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500418 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000419
Larry Hastingsb4038062012-07-15 10:57:38 -0700420def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200421 """Copy data and metadata. Return the file's destination.
422
423 Metadata is copied with copystat(). Please see the copystat function
424 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000425
426 The destination may be a directory.
427
Larry Hastingsb4038062012-07-15 10:57:38 -0700428 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100429 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000430 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000431 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000432 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700433 copyfile(src, dst, follow_symlinks=follow_symlinks)
434 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500435 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000436
Georg Brandl2ee470f2008-07-16 12:55:28 +0000437def ignore_patterns(*patterns):
438 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000439
Georg Brandl2ee470f2008-07-16 12:55:28 +0000440 Patterns is a sequence of glob-style patterns
441 that are used to exclude files"""
442 def _ignore_patterns(path, names):
443 ignored_names = []
444 for pattern in patterns:
445 ignored_names.extend(fnmatch.filter(names, pattern))
446 return set(ignored_names)
447 return _ignore_patterns
448
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800449def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500450 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800451 if ignore is not None:
mbarkhau88704332020-01-24 14:51:16 +0000452 ignored_names = ignore(os.fspath(src), [x.name for x in entries])
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800453 else:
454 ignored_names = set()
455
jab9e00d9e2018-12-28 13:03:40 -0500456 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800457 errors = []
458 use_srcentry = copy_function is copy2 or copy_function is copy
459
460 for srcentry in entries:
461 if srcentry.name in ignored_names:
462 continue
463 srcname = os.path.join(src, srcentry.name)
464 dstname = os.path.join(dst, srcentry.name)
465 srcobj = srcentry if use_srcentry else srcname
466 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700467 is_symlink = srcentry.is_symlink()
468 if is_symlink and os.name == 'nt':
469 # Special check for directory junctions, which appear as
470 # symlinks but we want to recurse.
471 lstat = srcentry.stat(follow_symlinks=False)
472 if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
473 is_symlink = False
474 if is_symlink:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800475 linkto = os.readlink(srcname)
476 if symlinks:
477 # We can't just leave it to `copy_function` because legacy
478 # code with a custom `copy_function` may rely on copytree
479 # doing the right thing.
480 os.symlink(linkto, dstname)
481 copystat(srcobj, dstname, follow_symlinks=not symlinks)
482 else:
483 # ignore dangling symlink if the flag is on
484 if not os.path.exists(linkto) and ignore_dangling_symlinks:
485 continue
jab9e00d9e2018-12-28 13:03:40 -0500486 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800487 if srcentry.is_dir():
488 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500489 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800490 else:
491 copy_function(srcobj, dstname)
492 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500493 copytree(srcobj, dstname, symlinks, ignore, copy_function,
494 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800495 else:
496 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100497 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800498 # catch the Error from the recursive copytree so that we can
499 # continue with other files
500 except Error as err:
501 errors.extend(err.args[0])
502 except OSError as why:
503 errors.append((srcname, dstname, str(why)))
504 try:
505 copystat(src, dst)
506 except OSError as why:
507 # Copying file access times may fail on Windows
508 if getattr(why, 'winerror', None) is None:
509 errors.append((src, dst, str(why)))
510 if errors:
511 raise Error(errors)
512 return dst
513
Tarek Ziadéfb437512010-04-20 08:57:33 +0000514def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500515 ignore_dangling_symlinks=False, dirs_exist_ok=False):
516 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000517
jab9e00d9e2018-12-28 13:03:40 -0500518 dirs_exist_ok dictates whether to raise an exception in case dst or any
519 missing parent directory already exists.
520
Neal Norwitza4c93b62003-02-23 21:36:32 +0000521 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000522
523 If the optional symlinks flag is true, symbolic links in the
524 source tree result in symbolic links in the destination tree; if
525 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000526 links are copied. If the file pointed by the symlink doesn't
527 exist, an exception will be added in the list of errors raised in
528 an Error exception at the end of the copy process.
529
530 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000531 want to silence this exception. Notice that this has no effect on
532 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000533
Georg Brandl2ee470f2008-07-16 12:55:28 +0000534 The optional ignore argument is a callable. If given, it
535 is called with the `src` parameter, which is the directory
536 being visited by copytree(), and `names` which is the list of
537 `src` contents, as returned by os.listdir():
538
539 callable(src, names) -> ignored_names
540
541 Since copytree() is called recursively, the callable will be
542 called once for each directory that is copied. It returns a
543 list of names relative to the `src` directory that should
544 not be copied.
545
Tarek Ziadé5340db32010-04-19 22:30:51 +0000546 The optional copy_function argument is a callable that will be used
547 to copy each file. It will be called with the source path and the
548 destination path as arguments. By default, copy2() is used, but any
549 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000550
551 """
Steve Dower60419a72019-06-24 08:42:54 -0700552 sys.audit("shutil.copytree", src, dst)
Bruno P. Kinoshita9bbcbc92019-11-27 14:10:37 +1300553 with os.scandir(src) as itr:
554 entries = list(itr)
555 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
556 ignore=ignore, copy_function=copy_function,
557 ignore_dangling_symlinks=ignore_dangling_symlinks,
558 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000559
Ned Deily7fcc2082019-08-29 17:20:03 -0400560if hasattr(os.stat_result, 'st_file_attributes'):
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700561 # Special handling for directory junctions to make them behave like
562 # symlinks for shutil.rmtree, since in general they do not appear as
563 # regular links.
564 def _rmtree_isdir(entry):
565 try:
566 st = entry.stat(follow_symlinks=False)
567 return (stat.S_ISDIR(st.st_mode) and not
568 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
569 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
570 except OSError:
571 return False
572
573 def _rmtree_islink(path):
574 try:
575 st = os.lstat(path)
576 return (stat.S_ISLNK(st.st_mode) or
577 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
578 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
579 except OSError:
580 return False
581else:
582 def _rmtree_isdir(entry):
583 try:
584 return entry.is_dir(follow_symlinks=False)
585 except OSError:
586 return False
587
588 def _rmtree_islink(path):
589 return os.path.islink(path)
590
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200591# version vulnerable to race conditions
592def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000593 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200594 with os.scandir(path) as scandir_it:
595 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000596 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200597 onerror(os.scandir, path, sys.exc_info())
598 entries = []
599 for entry in entries:
600 fullname = entry.path
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700601 if _rmtree_isdir(entry):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200602 try:
603 if entry.is_symlink():
604 # This can only happen if someone replaces
605 # a directory with a symlink after the call to
606 # os.scandir or entry.is_dir above.
607 raise OSError("Cannot call rmtree on a symbolic link")
608 except OSError:
609 onerror(os.path.islink, fullname, sys.exc_info())
610 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200611 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000612 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000613 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200614 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200615 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200616 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000617 try:
618 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200619 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000620 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000621
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200622# Version using fd-based APIs to protect against races
623def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200624 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200625 with os.scandir(topfd) as scandir_it:
626 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100627 except OSError as err:
628 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200629 onerror(os.scandir, path, sys.exc_info())
630 return
631 for entry in entries:
632 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200633 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200634 is_dir = entry.is_dir(follow_symlinks=False)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100635 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200636 is_dir = False
Serhiy Storchakae9b51c02019-05-31 11:30:37 +0300637 else:
638 if is_dir:
639 try:
640 orig_st = entry.stat(follow_symlinks=False)
641 is_dir = stat.S_ISDIR(orig_st.st_mode)
642 except OSError:
643 onerror(os.lstat, fullname, sys.exc_info())
644 continue
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200645 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200646 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200647 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100648 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200649 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200650 else:
651 try:
652 if os.path.samestat(orig_st, os.fstat(dirfd)):
653 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200654 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200655 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100656 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200657 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100658 else:
659 try:
660 # This can only happen if someone replaces
661 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200662 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100663 raise OSError("Cannot call rmtree on a symbolic "
664 "link")
665 except OSError:
666 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200667 finally:
668 os.close(dirfd)
669 else:
670 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200671 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100672 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200673 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200674
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200675_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
676 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200677 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200678 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000679
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200680def rmtree(path, ignore_errors=False, onerror=None):
681 """Recursively delete a directory tree.
682
683 If ignore_errors is set, errors are ignored; otherwise, if onerror
684 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200685 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200686 path is the argument to that function that caused it to fail; and
687 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
688 is false and onerror is None, an exception is raised.
689
690 """
Steve Dower60419a72019-06-24 08:42:54 -0700691 sys.audit("shutil.rmtree", path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200692 if ignore_errors:
693 def onerror(*args):
694 pass
695 elif onerror is None:
696 def onerror(*args):
697 raise
698 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200699 # While the unsafe rmtree works fine on bytes, the fd based does not.
700 if isinstance(path, bytes):
701 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200702 # Note: To guard against symlink races, we use the standard
703 # lstat()/open()/fstat() trick.
704 try:
705 orig_st = os.lstat(path)
706 except Exception:
707 onerror(os.lstat, path, sys.exc_info())
708 return
709 try:
710 fd = os.open(path, os.O_RDONLY)
711 except Exception:
Michal Čihaře59b2de2020-11-10 17:06:02 +0100712 onerror(os.open, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200713 return
714 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100715 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200716 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200717 try:
718 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200719 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200720 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200721 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100722 try:
723 # symlinks to directories are forbidden, see bug #1669
724 raise OSError("Cannot call rmtree on a symbolic link")
725 except OSError:
726 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200727 finally:
728 os.close(fd)
729 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200730 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700731 if _rmtree_islink(path):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200732 # symlinks to directories are forbidden, see bug #1669
733 raise OSError("Cannot call rmtree on a symbolic link")
734 except OSError:
735 onerror(os.path.islink, path, sys.exc_info())
736 # can't continue even if onerror hook returns
737 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200738 return _rmtree_unsafe(path, onerror)
739
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000740# Allow introspection of whether or not the hardening against symlink
741# attacks is supported on the current platform
742rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000743
Christian Heimesada8c3b2008-03-18 18:26:33 +0000744def _basename(path):
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700745 """A basename() variant which first strips the trailing slash, if present.
746 Thus we always get the last component of the path, even for directories.
747
748 path: Union[PathLike, str]
749
750 e.g.
751 >>> os.path.basename('/bar/foo')
752 'foo'
753 >>> os.path.basename('/bar/foo/')
754 ''
755 >>> _basename('/bar/foo/')
756 'foo'
757 """
758 path = os.fspath(path)
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200759 sep = os.path.sep + (os.path.altsep or '')
760 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000761
R David Murray6ffface2014-06-11 14:40:13 -0400762def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000763 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500764 similar to the Unix "mv" command. Return the file or directory's
765 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000766
767 If the destination is a directory or a symlink to a directory, the source
768 is moved inside the directory. The destination path must not already
769 exist.
770
771 If the destination already exists but is not a directory, it may be
772 overwritten depending on os.rename() semantics.
773
774 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100775 Otherwise, src is copied to the destination and then removed. Symlinks are
776 recreated under the new name if os.rename() fails because of cross
777 filesystem renames.
778
R David Murray6ffface2014-06-11 14:40:13 -0400779 The optional `copy_function` argument is a callable that will be used
780 to copy the source or it will be delegated to `copytree`.
781 By default, copy2() is used, but any function that supports the same
782 signature (like copy()) can be used.
783
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000784 A lot more could be done here... A look at a mv.c shows a lot of
785 the issues this implementation glosses over.
786
787 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800788 sys.audit("shutil.move", src, dst)
Christian Heimesada8c3b2008-03-18 18:26:33 +0000789 real_dst = dst
790 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200791 if _samefile(src, dst):
792 # We might be on a case insensitive filesystem,
793 # perform the rename anyway.
794 os.rename(src, dst)
795 return
796
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700797 # Using _basename instead of os.path.basename is important, as we must
798 # ignore any trailing slash to avoid the basename returning ''
Christian Heimesada8c3b2008-03-18 18:26:33 +0000799 real_dst = os.path.join(dst, _basename(src))
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700800
Christian Heimesada8c3b2008-03-18 18:26:33 +0000801 if os.path.exists(real_dst):
802 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000803 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000804 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200805 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100806 if os.path.islink(src):
807 linkto = os.readlink(src)
808 os.symlink(linkto, real_dst)
809 os.unlink(src)
810 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000811 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400812 raise Error("Cannot move a directory '%s' into itself"
813 " '%s'." % (src, dst))
Winson Luk132131b2021-03-02 15:53:15 -0500814 if (_is_immutable(src)
815 or (not os.access(src, os.W_OK) and os.listdir(src)
816 and sys.platform == 'darwin')):
817 raise PermissionError("Cannot move the non-empty directory "
818 "'%s': Lacking write permission to '%s'."
819 % (src, src))
R David Murray6ffface2014-06-11 14:40:13 -0400820 copytree(src, real_dst, copy_function=copy_function,
821 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000822 rmtree(src)
823 else:
R David Murray6ffface2014-06-11 14:40:13 -0400824 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000825 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500826 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000827
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000828def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300829 src = os.path.abspath(src)
830 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000831 if not src.endswith(os.path.sep):
832 src += os.path.sep
833 if not dst.endswith(os.path.sep):
834 dst += os.path.sep
835 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000836
Winson Luk132131b2021-03-02 15:53:15 -0500837def _is_immutable(src):
838 st = _stat(src)
839 immutable_states = [stat.UF_IMMUTABLE, stat.SF_IMMUTABLE]
840 return hasattr(st, 'st_flags') and st.st_flags in immutable_states
841
Tarek Ziadé396fad72010-02-23 05:30:31 +0000842def _get_gid(name):
843 """Returns a gid, given a group name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100844 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000845 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100846
847 try:
848 from grp import getgrnam
849 except ImportError:
850 return None
851
Tarek Ziadé396fad72010-02-23 05:30:31 +0000852 try:
853 result = getgrnam(name)
854 except KeyError:
855 result = None
856 if result is not None:
857 return result[2]
858 return None
859
860def _get_uid(name):
861 """Returns an uid, given a user name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100862 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000863 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100864
865 try:
866 from pwd import getpwnam
867 except ImportError:
868 return None
869
Tarek Ziadé396fad72010-02-23 05:30:31 +0000870 try:
871 result = getpwnam(name)
872 except KeyError:
873 result = None
874 if result is not None:
875 return result[2]
876 return None
877
878def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
879 owner=None, group=None, logger=None):
880 """Create a (possibly compressed) tar file from all the files under
881 'base_dir'.
882
Serhiy Storchaka11213772014-08-06 18:50:19 +0300883 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000884
885 'owner' and 'group' can be used to define an owner and a group for the
886 archive that is being built. If not provided, the current owner and group
887 will be used.
888
Éric Araujo4433a5f2010-12-15 20:26:30 +0000889 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300890 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000891
892 Returns the output filename.
893 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200894 if compress is None:
895 tar_compression = ''
896 elif _ZLIB_SUPPORTED and compress == 'gzip':
897 tar_compression = 'gz'
898 elif _BZ2_SUPPORTED and compress == 'bzip2':
899 tar_compression = 'bz2'
900 elif _LZMA_SUPPORTED and compress == 'xz':
901 tar_compression = 'xz'
902 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000903 raise ValueError("bad value for 'compress', or compression format not "
904 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000905
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200906 import tarfile # late import for breaking circular dependency
907
908 compress_ext = '.' + tar_compression if compress else ''
909 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000911
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200912 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000913 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200914 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000915 if not dry_run:
916 os.makedirs(archive_dir)
917
Tarek Ziadé396fad72010-02-23 05:30:31 +0000918 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000919 if logger is not None:
920 logger.info('Creating tar archive')
921
922 uid = _get_uid(owner)
923 gid = _get_gid(group)
924
925 def _set_uid_gid(tarinfo):
926 if gid is not None:
927 tarinfo.gid = gid
928 tarinfo.gname = group
929 if uid is not None:
930 tarinfo.uid = uid
931 tarinfo.uname = owner
932 return tarinfo
933
934 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200935 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000936 try:
937 tar.add(base_dir, filter=_set_uid_gid)
938 finally:
939 tar.close()
940
Tarek Ziadé396fad72010-02-23 05:30:31 +0000941 return archive_name
942
Tarek Ziadé396fad72010-02-23 05:30:31 +0000943def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
944 """Create a zip file from all the files under 'base_dir'.
945
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200946 The output zip file will be named 'base_name' + ".zip". Returns the
947 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000948 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200949 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400950
Tarek Ziadé396fad72010-02-23 05:30:31 +0000951 zip_filename = base_name + ".zip"
952 archive_dir = os.path.dirname(base_name)
953
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200954 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000955 if logger is not None:
956 logger.info("creating %s", archive_dir)
957 if not dry_run:
958 os.makedirs(archive_dir)
959
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400960 if logger is not None:
961 logger.info("creating '%s' and adding '%s' to it",
962 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000963
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400964 if not dry_run:
965 with zipfile.ZipFile(zip_filename, "w",
966 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300967 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300968 if path != os.curdir:
969 zf.write(path, path)
970 if logger is not None:
971 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400972 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300973 for name in sorted(dirnames):
974 path = os.path.normpath(os.path.join(dirpath, name))
975 zf.write(path, path)
976 if logger is not None:
977 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400978 for name in filenames:
979 path = os.path.normpath(os.path.join(dirpath, name))
980 if os.path.isfile(path):
981 zf.write(path, path)
982 if logger is not None:
983 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000984
985 return zip_filename
986
987_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000988 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200989}
990
991if _ZLIB_SUPPORTED:
992 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
993 "gzip'ed tar-file")
994 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000995
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000996if _BZ2_SUPPORTED:
997 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
998 "bzip2'ed tar-file")
999
Serhiy Storchaka11213772014-08-06 18:50:19 +03001000if _LZMA_SUPPORTED:
1001 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
1002 "xz'ed tar-file")
1003
Tarek Ziadé396fad72010-02-23 05:30:31 +00001004def get_archive_formats():
1005 """Returns a list of supported formats for archiving and unarchiving.
1006
1007 Each element of the returned sequence is a tuple (name, description)
1008 """
1009 formats = [(name, registry[2]) for name, registry in
1010 _ARCHIVE_FORMATS.items()]
1011 formats.sort()
1012 return formats
1013
1014def register_archive_format(name, function, extra_args=None, description=''):
1015 """Registers an archive format.
1016
1017 name is the name of the format. function is the callable that will be
1018 used to create archives. If provided, extra_args is a sequence of
1019 (name, value) tuples that will be passed as arguments to the callable.
1020 description can be provided to describe the format, and will be returned
1021 by the get_archive_formats() function.
1022 """
1023 if extra_args is None:
1024 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001025 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026 raise TypeError('The %s object is not callable' % function)
1027 if not isinstance(extra_args, (tuple, list)):
1028 raise TypeError('extra_args needs to be a sequence')
1029 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001030 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031 raise TypeError('extra_args elements are : (arg_name, value)')
1032
1033 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
1034
1035def unregister_archive_format(name):
1036 del _ARCHIVE_FORMATS[name]
1037
1038def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
1039 dry_run=0, owner=None, group=None, logger=None):
1040 """Create an archive file (eg. zip or tar).
1041
1042 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001043 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
1044 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +00001045
1046 'root_dir' is a directory that will be the root directory of the
1047 archive; ie. we typically chdir into 'root_dir' before creating the
1048 archive. 'base_dir' is the directory where we start archiving from;
1049 ie. 'base_dir' will be the common prefix of all files and
1050 directories in the archive. 'root_dir' and 'base_dir' both default
1051 to the current directory. Returns the name of the archive file.
1052
1053 'owner' and 'group' are used when creating a tar archive. By default,
1054 uses the current owner and group.
1055 """
Steve Dower60419a72019-06-24 08:42:54 -07001056 sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001057 save_cwd = os.getcwd()
1058 if root_dir is not None:
1059 if logger is not None:
1060 logger.debug("changing into '%s'", root_dir)
1061 base_name = os.path.abspath(base_name)
1062 if not dry_run:
1063 os.chdir(root_dir)
1064
1065 if base_dir is None:
1066 base_dir = os.curdir
1067
1068 kwargs = {'dry_run': dry_run, 'logger': logger}
1069
1070 try:
1071 format_info = _ARCHIVE_FORMATS[format]
1072 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001073 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +00001074
1075 func = format_info[0]
1076 for arg, val in format_info[1]:
1077 kwargs[arg] = val
1078
1079 if format != 'zip':
1080 kwargs['owner'] = owner
1081 kwargs['group'] = group
1082
1083 try:
1084 filename = func(base_name, base_dir, **kwargs)
1085 finally:
1086 if root_dir is not None:
1087 if logger is not None:
1088 logger.debug("changing back to '%s'", save_cwd)
1089 os.chdir(save_cwd)
1090
1091 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001092
1093
1094def get_unpack_formats():
1095 """Returns a list of supported formats for unpacking.
1096
1097 Each element of the returned sequence is a tuple
1098 (name, extensions, description)
1099 """
1100 formats = [(name, info[0], info[3]) for name, info in
1101 _UNPACK_FORMATS.items()]
1102 formats.sort()
1103 return formats
1104
1105def _check_unpack_options(extensions, function, extra_args):
1106 """Checks what gets registered as an unpacker."""
1107 # first make sure no other unpacker is registered for this extension
1108 existing_extensions = {}
1109 for name, info in _UNPACK_FORMATS.items():
1110 for ext in info[0]:
1111 existing_extensions[ext] = name
1112
1113 for extension in extensions:
1114 if extension in existing_extensions:
1115 msg = '%s is already registered for "%s"'
1116 raise RegistryError(msg % (extension,
1117 existing_extensions[extension]))
1118
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001119 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001120 raise TypeError('The registered function must be a callable')
1121
1122
1123def register_unpack_format(name, extensions, function, extra_args=None,
1124 description=''):
1125 """Registers an unpack format.
1126
1127 `name` is the name of the format. `extensions` is a list of extensions
1128 corresponding to the format.
1129
1130 `function` is the callable that will be
1131 used to unpack archives. The callable will receive archives to unpack.
1132 If it's unable to handle an archive, it needs to raise a ReadError
1133 exception.
1134
1135 If provided, `extra_args` is a sequence of
1136 (name, value) tuples that will be passed as arguments to the callable.
1137 description can be provided to describe the format, and will be returned
1138 by the get_unpack_formats() function.
1139 """
1140 if extra_args is None:
1141 extra_args = []
1142 _check_unpack_options(extensions, function, extra_args)
1143 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1144
1145def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001146 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001147 del _UNPACK_FORMATS[name]
1148
1149def _ensure_directory(path):
1150 """Ensure that the parent directory of `path` exists"""
1151 dirname = os.path.dirname(path)
1152 if not os.path.isdir(dirname):
1153 os.makedirs(dirname)
1154
1155def _unpack_zipfile(filename, extract_dir):
1156 """Unpack zip `filename` to `extract_dir`
1157 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001158 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001159
1160 if not zipfile.is_zipfile(filename):
1161 raise ReadError("%s is not a zip file" % filename)
1162
1163 zip = zipfile.ZipFile(filename)
1164 try:
1165 for info in zip.infolist():
1166 name = info.filename
1167
1168 # don't extract absolute paths or ones with .. in them
1169 if name.startswith('/') or '..' in name:
1170 continue
1171
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001172 targetpath = os.path.join(extract_dir, *name.split('/'))
1173 if not targetpath:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001174 continue
1175
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001176 _ensure_directory(targetpath)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001177 if not name.endswith('/'):
1178 # file
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001179 with zip.open(name, 'r') as source, \
1180 open(targetpath, 'wb') as target:
1181 copyfileobj(source, target)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001182 finally:
1183 zip.close()
1184
1185def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001186 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001187 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001188 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001189 try:
1190 tarobj = tarfile.open(filename)
1191 except tarfile.TarError:
1192 raise ReadError(
1193 "%s is not a compressed or uncompressed tar file" % filename)
1194 try:
1195 tarobj.extractall(extract_dir)
1196 finally:
1197 tarobj.close()
1198
1199_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001200 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001201 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1202}
1203
1204if _ZLIB_SUPPORTED:
1205 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1206 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001207
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001208if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001209 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001210 "bzip2'ed tar-file")
1211
Serhiy Storchaka11213772014-08-06 18:50:19 +03001212if _LZMA_SUPPORTED:
1213 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1214 "xz'ed tar-file")
1215
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001216def _find_unpack_format(filename):
1217 for name, info in _UNPACK_FORMATS.items():
1218 for extension in info[0]:
1219 if filename.endswith(extension):
1220 return name
1221 return None
1222
1223def unpack_archive(filename, extract_dir=None, format=None):
1224 """Unpack an archive.
1225
1226 `filename` is the name of the archive.
1227
1228 `extract_dir` is the name of the target directory, where the archive
1229 is unpacked. If not provided, the current working directory is used.
1230
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001231 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1232 or "xztar". Or any other registered format. If not provided,
1233 unpack_archive will use the filename extension and see if an unpacker
1234 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001235
1236 In case none is found, a ValueError is raised.
1237 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001238 sys.audit("shutil.unpack_archive", filename, extract_dir, format)
1239
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001240 if extract_dir is None:
1241 extract_dir = os.getcwd()
1242
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001243 extract_dir = os.fspath(extract_dir)
1244 filename = os.fspath(filename)
1245
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001246 if format is not None:
1247 try:
1248 format_info = _UNPACK_FORMATS[format]
1249 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001250 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001251
Nick Coghlanabf202d2011-03-16 13:52:20 -04001252 func = format_info[1]
1253 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001254 else:
1255 # we need to look at the registered unpackers supported extensions
1256 format = _find_unpack_format(filename)
1257 if format is None:
1258 raise ReadError("Unknown archive format '{0}'".format(filename))
1259
1260 func = _UNPACK_FORMATS[format][1]
1261 kwargs = dict(_UNPACK_FORMATS[format][2])
1262 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001263
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001264
1265if hasattr(os, 'statvfs'):
1266
1267 __all__.append('disk_usage')
1268 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001269 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1270 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1271 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001272
1273 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001274 """Return disk usage statistics about the given path.
1275
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001276 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001277 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001278 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001279 st = os.statvfs(path)
1280 free = st.f_bavail * st.f_frsize
1281 total = st.f_blocks * st.f_frsize
1282 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1283 return _ntuple_diskusage(total, used, free)
1284
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001285elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001286
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001287 __all__.append('disk_usage')
1288 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1289
1290 def disk_usage(path):
1291 """Return disk usage statistics about the given path.
1292
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001293 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001294 'free', which are the amount of total, used and free space, in bytes.
1295 """
1296 total, free = nt._getdiskusage(path)
1297 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001298 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001299
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001300
Sandro Tosid902a142011-08-22 23:28:27 +02001301def chown(path, user=None, group=None):
1302 """Change owner user and group of the given path.
1303
1304 user and group can be the uid/gid or the user/group names, and in that case,
1305 they are converted to their respective uid/gid.
1306 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001307 sys.audit('shutil.chown', path, user, group)
Sandro Tosid902a142011-08-22 23:28:27 +02001308
1309 if user is None and group is None:
1310 raise ValueError("user and/or group must be set")
1311
1312 _user = user
1313 _group = group
1314
1315 # -1 means don't change it
1316 if user is None:
1317 _user = -1
1318 # user can either be an int (the uid) or a string (the system username)
1319 elif isinstance(user, str):
1320 _user = _get_uid(user)
1321 if _user is None:
1322 raise LookupError("no such user: {!r}".format(user))
1323
1324 if group is None:
1325 _group = -1
1326 elif not isinstance(group, int):
1327 _group = _get_gid(group)
1328 if _group is None:
1329 raise LookupError("no such group: {!r}".format(group))
1330
1331 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001332
1333def get_terminal_size(fallback=(80, 24)):
1334 """Get the size of the terminal window.
1335
1336 For each of the two dimensions, the environment variable, COLUMNS
1337 and LINES respectively, is checked. If the variable is defined and
1338 the value is a positive integer, it is used.
1339
1340 When COLUMNS or LINES is not defined, which is the common case,
1341 the terminal connected to sys.__stdout__ is queried
1342 by invoking os.get_terminal_size.
1343
1344 If the terminal size cannot be successfully queried, either because
1345 the system doesn't support querying, or because we are not
1346 connected to a terminal, the value given in fallback parameter
1347 is used. Fallback defaults to (80, 24) which is the default
1348 size used by many terminal emulators.
1349
1350 The value returned is a named tuple of type os.terminal_size.
1351 """
1352 # columns, lines are the working values
1353 try:
1354 columns = int(os.environ['COLUMNS'])
1355 except (KeyError, ValueError):
1356 columns = 0
1357
1358 try:
1359 lines = int(os.environ['LINES'])
1360 except (KeyError, ValueError):
1361 lines = 0
1362
1363 # only query if necessary
1364 if columns <= 0 or lines <= 0:
1365 try:
1366 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001367 except (AttributeError, ValueError, OSError):
1368 # stdout is None, closed, detached, or not a terminal, or
1369 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001370 size = os.terminal_size(fallback)
1371 if columns <= 0:
1372 columns = size.columns
1373 if lines <= 0:
1374 lines = size.lines
1375
1376 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001377
Cheryl Sabella5680f652019-02-13 06:25:10 -05001378
1379# Check that a given file can be accessed with the correct mode.
1380# Additionally check that `file` is not a directory, as on Windows
1381# directories pass the os.access check.
1382def _access_check(fn, mode):
1383 return (os.path.exists(fn) and os.access(fn, mode)
1384 and not os.path.isdir(fn))
1385
1386
Brian Curtinc57a3452012-06-22 16:00:30 -05001387def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001388 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001389 conforms to the given mode on the PATH, or None if there is no such
1390 file.
1391
1392 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1393 of os.environ.get("PATH"), or can be overridden with a custom search
1394 path.
1395
1396 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001397 # If we're given a path with a directory part, look it up directly rather
1398 # than referring to PATH directories. This includes checking relative to the
1399 # current directory, e.g. ./script
1400 if os.path.dirname(cmd):
1401 if _access_check(cmd, mode):
1402 return cmd
1403 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001404
Cheryl Sabella5680f652019-02-13 06:25:10 -05001405 use_bytes = isinstance(cmd, bytes)
1406
Barry Warsaw618738b2013-04-16 11:05:03 -04001407 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001408 path = os.environ.get("PATH", None)
1409 if path is None:
1410 try:
1411 path = os.confstr("CS_PATH")
1412 except (AttributeError, ValueError):
1413 # os.confstr() or CS_PATH is not available
1414 path = os.defpath
1415 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001416 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001417
1418 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001419 if not path:
1420 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001421
Cheryl Sabella5680f652019-02-13 06:25:10 -05001422 if use_bytes:
1423 path = os.fsencode(path)
1424 path = path.split(os.fsencode(os.pathsep))
1425 else:
1426 path = os.fsdecode(path)
1427 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001428
1429 if sys.platform == "win32":
1430 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001431 curdir = os.curdir
1432 if use_bytes:
1433 curdir = os.fsencode(curdir)
1434 if curdir not in path:
1435 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001436
1437 # PATHEXT is necessary to check on Windows.
Christopher Marchfelderda6f0982020-10-23 12:08:24 +02001438 pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
1439 pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
1440
Cheryl Sabella5680f652019-02-13 06:25:10 -05001441 if use_bytes:
1442 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001443 # See if the given file matches any of the expected path extensions.
1444 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001445 # If it does match, only test that one, otherwise we have to try
1446 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001447 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1448 files = [cmd]
1449 else:
1450 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001451 else:
1452 # On other platforms you don't have things like PATHEXT to tell you
1453 # what file suffixes are executable, so just pass on cmd as-is.
1454 files = [cmd]
1455
1456 seen = set()
1457 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001458 normdir = os.path.normcase(dir)
1459 if not normdir in seen:
1460 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001461 for thefile in files:
1462 name = os.path.join(dir, thefile)
1463 if _access_check(name, mode):
1464 return name
1465 return None