blob: 0056a1bc77ad84cec070f47e638f9a32d525beda [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)41d48bc2021-09-21 15:14:40 -0700254 with open(src, 'rb') as fsrc:
255 try:
256 with open(dst, 'wb') as fdst:
257 # macOS
258 if _HAS_FCOPYFILE:
259 try:
260 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
261 return dst
262 except _GiveupOnFastCopy:
263 pass
264 # Linux
265 elif _USE_CP_SENDFILE:
266 try:
267 _fastcopy_sendfile(fsrc, fdst)
268 return dst
269 except _GiveupOnFastCopy:
270 pass
271 # Windows, see:
272 # https://github.com/python/cpython/pull/7160#discussion_r195405230
273 elif _WINDOWS and file_size > 0:
274 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
Miss Islington (bot)15772592021-07-09 21:07:35 -0700275 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200276
Miss Islington (bot)41d48bc2021-09-21 15:14:40 -0700277 copyfileobj(fsrc, fdst)
Miss Islington (bot)15772592021-07-09 21:07:35 -0700278
Miss Islington (bot)41d48bc2021-09-21 15:14:40 -0700279 # Issue 43219, raise a less confusing exception
280 except IsADirectoryError as e:
281 if not os.path.exists(dst):
282 raise FileNotFoundError(f'Directory does not exist: {dst}') from e
283 else:
284 raise
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200285
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500286 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000287
Larry Hastingsb4038062012-07-15 10:57:38 -0700288def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100289 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000290
Larry Hastingsb4038062012-07-15 10:57:38 -0700291 If follow_symlinks is not set, symlinks aren't followed if and only
292 if both `src` and `dst` are symlinks. If `lchmod` isn't available
293 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100294
295 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800296 sys.audit("shutil.copymode", src, dst)
297
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800298 if not follow_symlinks and _islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100299 if hasattr(os, 'lchmod'):
300 stat_func, chmod_func = os.lstat, os.lchmod
301 else:
302 return
Antoine Pitrou78091e62011-12-29 18:54:15 +0100303 else:
Anthony Sottile8377cd42019-02-25 14:32:27 -0800304 stat_func, chmod_func = _stat, os.chmod
Antoine Pitrou78091e62011-12-29 18:54:15 +0100305
306 st = stat_func(src)
307 chmod_func(dst, stat.S_IMODE(st.st_mode))
308
Larry Hastingsad5ae042012-07-14 17:55:11 -0700309if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700310 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700311 """Copy extended filesystem attributes from `src` to `dst`.
312
313 Overwrite existing attributes.
314
Larry Hastingsb4038062012-07-15 10:57:38 -0700315 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700316
317 """
318
Hynek Schlawack0beab052013-02-05 08:22:44 +0100319 try:
320 names = os.listxattr(src, follow_symlinks=follow_symlinks)
321 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400322 if e.errno not in (errno.ENOTSUP, errno.ENODATA, errno.EINVAL):
Hynek Schlawack0beab052013-02-05 08:22:44 +0100323 raise
324 return
325 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700326 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700327 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
328 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700329 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400330 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
331 errno.EINVAL):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700332 raise
333else:
334 def _copyxattr(*args, **kwargs):
335 pass
336
Larry Hastingsb4038062012-07-15 10:57:38 -0700337def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200338 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100339
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200340 Copy the permission bits, last access time, last modification time, and
341 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
342 attributes" where possible. The file contents, owner, and group are
Boris Verhovsky9488a522019-09-09 09:51:56 -0600343 unaffected. `src` and `dst` are path-like objects or path names given as
344 strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100345
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200346 If the optional flag `follow_symlinks` is not set, symlinks aren't
347 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100348 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800349 sys.audit("shutil.copystat", src, dst)
350
Larry Hastings9cf065c2012-06-22 16:30:09 -0700351 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100352 pass
353
Larry Hastings9cf065c2012-06-22 16:30:09 -0700354 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800355 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700356 if follow:
357 # use the real function if it exists
358 def lookup(name):
359 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100360 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700361 # use the real function only if it exists
362 # *and* it supports follow_symlinks
363 def lookup(name):
364 fn = getattr(os, name, _nop)
365 if fn in os.supports_follow_symlinks:
366 return fn
367 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100368
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800369 if isinstance(src, os.DirEntry):
370 st = src.stat(follow_symlinks=follow)
371 else:
372 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000373 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
375 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500376 # We must copy extended attributes before the file is (potentially)
377 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
378 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700379 try:
380 lookup("chmod")(dst, mode, follow_symlinks=follow)
381 except NotImplementedError:
382 # if we got a NotImplementedError, it's because
383 # * follow_symlinks=False,
384 # * lchown() is unavailable, and
385 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300386 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700387 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
388 # (it returned ENOSUP.)
389 # therefore we're out of options--we simply cannot chown the
390 # symlink. give up, suppress the error.
391 # (which is what shutil always did in this circumstance.)
392 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100393 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000394 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700395 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000396 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700397 for err in 'EOPNOTSUPP', 'ENOTSUP':
398 if hasattr(errno, err) and why.errno == getattr(errno, err):
399 break
400 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000401 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200402
Larry Hastingsb4038062012-07-15 10:57:38 -0700403def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500404 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000405
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000406 The destination may be a directory.
407
Larry Hastingsb4038062012-07-15 10:57:38 -0700408 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100409 resembles GNU's "cp -P src dst".
410
Hynek Schlawack48653762012-10-07 12:49:58 +0200411 If source and destination are the same file, a SameFileError will be
412 raised.
413
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000414 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000415 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000416 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700417 copyfile(src, dst, follow_symlinks=follow_symlinks)
418 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500419 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000420
Larry Hastingsb4038062012-07-15 10:57:38 -0700421def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200422 """Copy data and metadata. Return the file's destination.
423
424 Metadata is copied with copystat(). Please see the copystat function
425 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000426
427 The destination may be a directory.
428
Larry Hastingsb4038062012-07-15 10:57:38 -0700429 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100430 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000431 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000432 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000433 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700434 copyfile(src, dst, follow_symlinks=follow_symlinks)
435 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500436 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000437
Georg Brandl2ee470f2008-07-16 12:55:28 +0000438def ignore_patterns(*patterns):
439 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000440
Georg Brandl2ee470f2008-07-16 12:55:28 +0000441 Patterns is a sequence of glob-style patterns
442 that are used to exclude files"""
443 def _ignore_patterns(path, names):
444 ignored_names = []
445 for pattern in patterns:
446 ignored_names.extend(fnmatch.filter(names, pattern))
447 return set(ignored_names)
448 return _ignore_patterns
449
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800450def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500451 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800452 if ignore is not None:
mbarkhau88704332020-01-24 14:51:16 +0000453 ignored_names = ignore(os.fspath(src), [x.name for x in entries])
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800454 else:
455 ignored_names = set()
456
jab9e00d9e2018-12-28 13:03:40 -0500457 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800458 errors = []
459 use_srcentry = copy_function is copy2 or copy_function is copy
460
461 for srcentry in entries:
462 if srcentry.name in ignored_names:
463 continue
464 srcname = os.path.join(src, srcentry.name)
465 dstname = os.path.join(dst, srcentry.name)
466 srcobj = srcentry if use_srcentry else srcname
467 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700468 is_symlink = srcentry.is_symlink()
469 if is_symlink and os.name == 'nt':
470 # Special check for directory junctions, which appear as
471 # symlinks but we want to recurse.
472 lstat = srcentry.stat(follow_symlinks=False)
473 if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
474 is_symlink = False
475 if is_symlink:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800476 linkto = os.readlink(srcname)
477 if symlinks:
478 # We can't just leave it to `copy_function` because legacy
479 # code with a custom `copy_function` may rely on copytree
480 # doing the right thing.
481 os.symlink(linkto, dstname)
482 copystat(srcobj, dstname, follow_symlinks=not symlinks)
483 else:
484 # ignore dangling symlink if the flag is on
485 if not os.path.exists(linkto) and ignore_dangling_symlinks:
486 continue
jab9e00d9e2018-12-28 13:03:40 -0500487 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800488 if srcentry.is_dir():
489 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500490 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800491 else:
492 copy_function(srcobj, dstname)
493 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500494 copytree(srcobj, dstname, symlinks, ignore, copy_function,
495 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800496 else:
497 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100498 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800499 # catch the Error from the recursive copytree so that we can
500 # continue with other files
501 except Error as err:
502 errors.extend(err.args[0])
503 except OSError as why:
504 errors.append((srcname, dstname, str(why)))
505 try:
506 copystat(src, dst)
507 except OSError as why:
508 # Copying file access times may fail on Windows
509 if getattr(why, 'winerror', None) is None:
510 errors.append((src, dst, str(why)))
511 if errors:
512 raise Error(errors)
513 return dst
514
Tarek Ziadéfb437512010-04-20 08:57:33 +0000515def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500516 ignore_dangling_symlinks=False, dirs_exist_ok=False):
517 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000518
jab9e00d9e2018-12-28 13:03:40 -0500519 dirs_exist_ok dictates whether to raise an exception in case dst or any
520 missing parent directory already exists.
521
Neal Norwitza4c93b62003-02-23 21:36:32 +0000522 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000523
524 If the optional symlinks flag is true, symbolic links in the
525 source tree result in symbolic links in the destination tree; if
526 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000527 links are copied. If the file pointed by the symlink doesn't
528 exist, an exception will be added in the list of errors raised in
529 an Error exception at the end of the copy process.
530
531 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000532 want to silence this exception. Notice that this has no effect on
533 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000534
Georg Brandl2ee470f2008-07-16 12:55:28 +0000535 The optional ignore argument is a callable. If given, it
536 is called with the `src` parameter, which is the directory
537 being visited by copytree(), and `names` which is the list of
538 `src` contents, as returned by os.listdir():
539
540 callable(src, names) -> ignored_names
541
542 Since copytree() is called recursively, the callable will be
543 called once for each directory that is copied. It returns a
544 list of names relative to the `src` directory that should
545 not be copied.
546
Tarek Ziadé5340db32010-04-19 22:30:51 +0000547 The optional copy_function argument is a callable that will be used
548 to copy each file. It will be called with the source path and the
549 destination path as arguments. By default, copy2() is used, but any
550 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000551
552 """
Steve Dower60419a72019-06-24 08:42:54 -0700553 sys.audit("shutil.copytree", src, dst)
Bruno P. Kinoshita9bbcbc92019-11-27 14:10:37 +1300554 with os.scandir(src) as itr:
555 entries = list(itr)
556 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
557 ignore=ignore, copy_function=copy_function,
558 ignore_dangling_symlinks=ignore_dangling_symlinks,
559 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000560
Ned Deily7fcc2082019-08-29 17:20:03 -0400561if hasattr(os.stat_result, 'st_file_attributes'):
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700562 # Special handling for directory junctions to make them behave like
563 # symlinks for shutil.rmtree, since in general they do not appear as
564 # regular links.
565 def _rmtree_isdir(entry):
566 try:
567 st = entry.stat(follow_symlinks=False)
568 return (stat.S_ISDIR(st.st_mode) and not
569 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
570 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
571 except OSError:
572 return False
573
574 def _rmtree_islink(path):
575 try:
576 st = os.lstat(path)
577 return (stat.S_ISLNK(st.st_mode) or
578 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
579 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
580 except OSError:
581 return False
582else:
583 def _rmtree_isdir(entry):
584 try:
585 return entry.is_dir(follow_symlinks=False)
586 except OSError:
587 return False
588
589 def _rmtree_islink(path):
590 return os.path.islink(path)
591
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200592# version vulnerable to race conditions
593def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000594 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200595 with os.scandir(path) as scandir_it:
596 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000597 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200598 onerror(os.scandir, path, sys.exc_info())
599 entries = []
600 for entry in entries:
601 fullname = entry.path
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700602 if _rmtree_isdir(entry):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200603 try:
604 if entry.is_symlink():
605 # This can only happen if someone replaces
606 # a directory with a symlink after the call to
607 # os.scandir or entry.is_dir above.
608 raise OSError("Cannot call rmtree on a symbolic link")
609 except OSError:
610 onerror(os.path.islink, fullname, sys.exc_info())
611 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200612 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000613 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000614 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200615 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200616 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200617 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000618 try:
619 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200620 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000621 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000622
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200623# Version using fd-based APIs to protect against races
624def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200625 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200626 with os.scandir(topfd) as scandir_it:
627 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100628 except OSError as err:
629 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200630 onerror(os.scandir, path, sys.exc_info())
631 return
632 for entry in entries:
633 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200634 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200635 is_dir = entry.is_dir(follow_symlinks=False)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100636 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200637 is_dir = False
Serhiy Storchakae9b51c02019-05-31 11:30:37 +0300638 else:
639 if is_dir:
640 try:
641 orig_st = entry.stat(follow_symlinks=False)
642 is_dir = stat.S_ISDIR(orig_st.st_mode)
643 except OSError:
644 onerror(os.lstat, fullname, sys.exc_info())
645 continue
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200646 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200647 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200648 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100649 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200650 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200651 else:
652 try:
653 if os.path.samestat(orig_st, os.fstat(dirfd)):
654 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200655 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200656 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100657 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200658 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100659 else:
660 try:
661 # This can only happen if someone replaces
662 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200663 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100664 raise OSError("Cannot call rmtree on a symbolic "
665 "link")
666 except OSError:
667 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200668 finally:
669 os.close(dirfd)
670 else:
671 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200672 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100673 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200674 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200675
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200676_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
677 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200678 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200679 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000680
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200681def rmtree(path, ignore_errors=False, onerror=None):
682 """Recursively delete a directory tree.
683
684 If ignore_errors is set, errors are ignored; otherwise, if onerror
685 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200686 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200687 path is the argument to that function that caused it to fail; and
688 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
689 is false and onerror is None, an exception is raised.
690
691 """
Steve Dower60419a72019-06-24 08:42:54 -0700692 sys.audit("shutil.rmtree", path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200693 if ignore_errors:
694 def onerror(*args):
695 pass
696 elif onerror is None:
697 def onerror(*args):
698 raise
699 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200700 # While the unsafe rmtree works fine on bytes, the fd based does not.
701 if isinstance(path, bytes):
702 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200703 # Note: To guard against symlink races, we use the standard
704 # lstat()/open()/fstat() trick.
705 try:
706 orig_st = os.lstat(path)
707 except Exception:
708 onerror(os.lstat, path, sys.exc_info())
709 return
710 try:
711 fd = os.open(path, os.O_RDONLY)
712 except Exception:
Michal Čihaře59b2de2020-11-10 17:06:02 +0100713 onerror(os.open, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200714 return
715 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100716 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200717 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200718 try:
719 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200720 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200721 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200722 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100723 try:
724 # symlinks to directories are forbidden, see bug #1669
725 raise OSError("Cannot call rmtree on a symbolic link")
726 except OSError:
727 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200728 finally:
729 os.close(fd)
730 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200731 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700732 if _rmtree_islink(path):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200733 # symlinks to directories are forbidden, see bug #1669
734 raise OSError("Cannot call rmtree on a symbolic link")
735 except OSError:
736 onerror(os.path.islink, path, sys.exc_info())
737 # can't continue even if onerror hook returns
738 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200739 return _rmtree_unsafe(path, onerror)
740
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000741# Allow introspection of whether or not the hardening against symlink
742# attacks is supported on the current platform
743rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000744
Christian Heimesada8c3b2008-03-18 18:26:33 +0000745def _basename(path):
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700746 """A basename() variant which first strips the trailing slash, if present.
747 Thus we always get the last component of the path, even for directories.
748
749 path: Union[PathLike, str]
750
751 e.g.
752 >>> os.path.basename('/bar/foo')
753 'foo'
754 >>> os.path.basename('/bar/foo/')
755 ''
756 >>> _basename('/bar/foo/')
757 'foo'
758 """
759 path = os.fspath(path)
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200760 sep = os.path.sep + (os.path.altsep or '')
761 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000762
R David Murray6ffface2014-06-11 14:40:13 -0400763def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000764 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500765 similar to the Unix "mv" command. Return the file or directory's
766 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000767
768 If the destination is a directory or a symlink to a directory, the source
769 is moved inside the directory. The destination path must not already
770 exist.
771
772 If the destination already exists but is not a directory, it may be
773 overwritten depending on os.rename() semantics.
774
775 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100776 Otherwise, src is copied to the destination and then removed. Symlinks are
777 recreated under the new name if os.rename() fails because of cross
778 filesystem renames.
779
R David Murray6ffface2014-06-11 14:40:13 -0400780 The optional `copy_function` argument is a callable that will be used
781 to copy the source or it will be delegated to `copytree`.
782 By default, copy2() is used, but any function that supports the same
783 signature (like copy()) can be used.
784
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000785 A lot more could be done here... A look at a mv.c shows a lot of
786 the issues this implementation glosses over.
787
788 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800789 sys.audit("shutil.move", src, dst)
Christian Heimesada8c3b2008-03-18 18:26:33 +0000790 real_dst = dst
791 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200792 if _samefile(src, dst):
793 # We might be on a case insensitive filesystem,
794 # perform the rename anyway.
795 os.rename(src, dst)
796 return
797
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700798 # Using _basename instead of os.path.basename is important, as we must
799 # ignore any trailing slash to avoid the basename returning ''
Christian Heimesada8c3b2008-03-18 18:26:33 +0000800 real_dst = os.path.join(dst, _basename(src))
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700801
Christian Heimesada8c3b2008-03-18 18:26:33 +0000802 if os.path.exists(real_dst):
803 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000804 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000805 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200806 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100807 if os.path.islink(src):
808 linkto = os.readlink(src)
809 os.symlink(linkto, real_dst)
810 os.unlink(src)
811 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000812 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400813 raise Error("Cannot move a directory '%s' into itself"
814 " '%s'." % (src, dst))
Winson Luk132131b2021-03-02 15:53:15 -0500815 if (_is_immutable(src)
816 or (not os.access(src, os.W_OK) and os.listdir(src)
817 and sys.platform == 'darwin')):
818 raise PermissionError("Cannot move the non-empty directory "
819 "'%s': Lacking write permission to '%s'."
820 % (src, src))
R David Murray6ffface2014-06-11 14:40:13 -0400821 copytree(src, real_dst, copy_function=copy_function,
822 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000823 rmtree(src)
824 else:
R David Murray6ffface2014-06-11 14:40:13 -0400825 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000826 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500827 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000828
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000829def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300830 src = os.path.abspath(src)
831 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000832 if not src.endswith(os.path.sep):
833 src += os.path.sep
834 if not dst.endswith(os.path.sep):
835 dst += os.path.sep
836 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000837
Winson Luk132131b2021-03-02 15:53:15 -0500838def _is_immutable(src):
839 st = _stat(src)
840 immutable_states = [stat.UF_IMMUTABLE, stat.SF_IMMUTABLE]
841 return hasattr(st, 'st_flags') and st.st_flags in immutable_states
842
Tarek Ziadé396fad72010-02-23 05:30:31 +0000843def _get_gid(name):
844 """Returns a gid, given a group name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100845 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000846 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100847
848 try:
849 from grp import getgrnam
850 except ImportError:
851 return None
852
Tarek Ziadé396fad72010-02-23 05:30:31 +0000853 try:
854 result = getgrnam(name)
855 except KeyError:
856 result = None
857 if result is not None:
858 return result[2]
859 return None
860
861def _get_uid(name):
862 """Returns an uid, given a user name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100863 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000864 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100865
866 try:
867 from pwd import getpwnam
868 except ImportError:
869 return None
870
Tarek Ziadé396fad72010-02-23 05:30:31 +0000871 try:
872 result = getpwnam(name)
873 except KeyError:
874 result = None
875 if result is not None:
876 return result[2]
877 return None
878
879def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
880 owner=None, group=None, logger=None):
881 """Create a (possibly compressed) tar file from all the files under
882 'base_dir'.
883
Serhiy Storchaka11213772014-08-06 18:50:19 +0300884 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000885
886 'owner' and 'group' can be used to define an owner and a group for the
887 archive that is being built. If not provided, the current owner and group
888 will be used.
889
Éric Araujo4433a5f2010-12-15 20:26:30 +0000890 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300891 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000892
893 Returns the output filename.
894 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200895 if compress is None:
896 tar_compression = ''
897 elif _ZLIB_SUPPORTED and compress == 'gzip':
898 tar_compression = 'gz'
899 elif _BZ2_SUPPORTED and compress == 'bzip2':
900 tar_compression = 'bz2'
901 elif _LZMA_SUPPORTED and compress == 'xz':
902 tar_compression = 'xz'
903 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000904 raise ValueError("bad value for 'compress', or compression format not "
905 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000906
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200907 import tarfile # late import for breaking circular dependency
908
909 compress_ext = '.' + tar_compression if compress else ''
910 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000911 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000912
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200913 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000914 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200915 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000916 if not dry_run:
917 os.makedirs(archive_dir)
918
Tarek Ziadé396fad72010-02-23 05:30:31 +0000919 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920 if logger is not None:
921 logger.info('Creating tar archive')
922
923 uid = _get_uid(owner)
924 gid = _get_gid(group)
925
926 def _set_uid_gid(tarinfo):
927 if gid is not None:
928 tarinfo.gid = gid
929 tarinfo.gname = group
930 if uid is not None:
931 tarinfo.uid = uid
932 tarinfo.uname = owner
933 return tarinfo
934
935 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200936 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000937 try:
938 tar.add(base_dir, filter=_set_uid_gid)
939 finally:
940 tar.close()
941
Tarek Ziadé396fad72010-02-23 05:30:31 +0000942 return archive_name
943
Tarek Ziadé396fad72010-02-23 05:30:31 +0000944def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
945 """Create a zip file from all the files under 'base_dir'.
946
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200947 The output zip file will be named 'base_name' + ".zip". Returns the
948 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000949 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200950 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400951
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952 zip_filename = base_name + ".zip"
953 archive_dir = os.path.dirname(base_name)
954
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200955 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000956 if logger is not None:
957 logger.info("creating %s", archive_dir)
958 if not dry_run:
959 os.makedirs(archive_dir)
960
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400961 if logger is not None:
962 logger.info("creating '%s' and adding '%s' to it",
963 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000964
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400965 if not dry_run:
966 with zipfile.ZipFile(zip_filename, "w",
967 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300968 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300969 if path != os.curdir:
970 zf.write(path, path)
971 if logger is not None:
972 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400973 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300974 for name in sorted(dirnames):
975 path = os.path.normpath(os.path.join(dirpath, name))
976 zf.write(path, path)
977 if logger is not None:
978 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400979 for name in filenames:
980 path = os.path.normpath(os.path.join(dirpath, name))
981 if os.path.isfile(path):
982 zf.write(path, path)
983 if logger is not None:
984 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000985
986 return zip_filename
987
988_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000989 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200990}
991
992if _ZLIB_SUPPORTED:
993 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
994 "gzip'ed tar-file")
995 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000996
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000997if _BZ2_SUPPORTED:
998 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
999 "bzip2'ed tar-file")
1000
Serhiy Storchaka11213772014-08-06 18:50:19 +03001001if _LZMA_SUPPORTED:
1002 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
1003 "xz'ed tar-file")
1004
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005def get_archive_formats():
1006 """Returns a list of supported formats for archiving and unarchiving.
1007
1008 Each element of the returned sequence is a tuple (name, description)
1009 """
1010 formats = [(name, registry[2]) for name, registry in
1011 _ARCHIVE_FORMATS.items()]
1012 formats.sort()
1013 return formats
1014
1015def register_archive_format(name, function, extra_args=None, description=''):
1016 """Registers an archive format.
1017
1018 name is the name of the format. function is the callable that will be
1019 used to create archives. If provided, extra_args is a sequence of
1020 (name, value) tuples that will be passed as arguments to the callable.
1021 description can be provided to describe the format, and will be returned
1022 by the get_archive_formats() function.
1023 """
1024 if extra_args is None:
1025 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001026 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001027 raise TypeError('The %s object is not callable' % function)
1028 if not isinstance(extra_args, (tuple, list)):
1029 raise TypeError('extra_args needs to be a sequence')
1030 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001031 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032 raise TypeError('extra_args elements are : (arg_name, value)')
1033
1034 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
1035
1036def unregister_archive_format(name):
1037 del _ARCHIVE_FORMATS[name]
1038
1039def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
1040 dry_run=0, owner=None, group=None, logger=None):
1041 """Create an archive file (eg. zip or tar).
1042
1043 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001044 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
1045 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +00001046
1047 'root_dir' is a directory that will be the root directory of the
1048 archive; ie. we typically chdir into 'root_dir' before creating the
1049 archive. 'base_dir' is the directory where we start archiving from;
1050 ie. 'base_dir' will be the common prefix of all files and
1051 directories in the archive. 'root_dir' and 'base_dir' both default
1052 to the current directory. Returns the name of the archive file.
1053
1054 'owner' and 'group' are used when creating a tar archive. By default,
1055 uses the current owner and group.
1056 """
Steve Dower60419a72019-06-24 08:42:54 -07001057 sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001058 save_cwd = os.getcwd()
1059 if root_dir is not None:
1060 if logger is not None:
1061 logger.debug("changing into '%s'", root_dir)
1062 base_name = os.path.abspath(base_name)
1063 if not dry_run:
1064 os.chdir(root_dir)
1065
1066 if base_dir is None:
1067 base_dir = os.curdir
1068
1069 kwargs = {'dry_run': dry_run, 'logger': logger}
1070
1071 try:
1072 format_info = _ARCHIVE_FORMATS[format]
1073 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001074 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +00001075
1076 func = format_info[0]
1077 for arg, val in format_info[1]:
1078 kwargs[arg] = val
1079
1080 if format != 'zip':
1081 kwargs['owner'] = owner
1082 kwargs['group'] = group
1083
1084 try:
1085 filename = func(base_name, base_dir, **kwargs)
1086 finally:
1087 if root_dir is not None:
1088 if logger is not None:
1089 logger.debug("changing back to '%s'", save_cwd)
1090 os.chdir(save_cwd)
1091
1092 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001093
1094
1095def get_unpack_formats():
1096 """Returns a list of supported formats for unpacking.
1097
1098 Each element of the returned sequence is a tuple
1099 (name, extensions, description)
1100 """
1101 formats = [(name, info[0], info[3]) for name, info in
1102 _UNPACK_FORMATS.items()]
1103 formats.sort()
1104 return formats
1105
1106def _check_unpack_options(extensions, function, extra_args):
1107 """Checks what gets registered as an unpacker."""
1108 # first make sure no other unpacker is registered for this extension
1109 existing_extensions = {}
1110 for name, info in _UNPACK_FORMATS.items():
1111 for ext in info[0]:
1112 existing_extensions[ext] = name
1113
1114 for extension in extensions:
1115 if extension in existing_extensions:
1116 msg = '%s is already registered for "%s"'
1117 raise RegistryError(msg % (extension,
1118 existing_extensions[extension]))
1119
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001120 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001121 raise TypeError('The registered function must be a callable')
1122
1123
1124def register_unpack_format(name, extensions, function, extra_args=None,
1125 description=''):
1126 """Registers an unpack format.
1127
1128 `name` is the name of the format. `extensions` is a list of extensions
1129 corresponding to the format.
1130
1131 `function` is the callable that will be
1132 used to unpack archives. The callable will receive archives to unpack.
1133 If it's unable to handle an archive, it needs to raise a ReadError
1134 exception.
1135
1136 If provided, `extra_args` is a sequence of
1137 (name, value) tuples that will be passed as arguments to the callable.
1138 description can be provided to describe the format, and will be returned
1139 by the get_unpack_formats() function.
1140 """
1141 if extra_args is None:
1142 extra_args = []
1143 _check_unpack_options(extensions, function, extra_args)
1144 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1145
1146def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001147 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001148 del _UNPACK_FORMATS[name]
1149
1150def _ensure_directory(path):
1151 """Ensure that the parent directory of `path` exists"""
1152 dirname = os.path.dirname(path)
1153 if not os.path.isdir(dirname):
1154 os.makedirs(dirname)
1155
1156def _unpack_zipfile(filename, extract_dir):
1157 """Unpack zip `filename` to `extract_dir`
1158 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001159 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001160
1161 if not zipfile.is_zipfile(filename):
1162 raise ReadError("%s is not a zip file" % filename)
1163
1164 zip = zipfile.ZipFile(filename)
1165 try:
1166 for info in zip.infolist():
1167 name = info.filename
1168
1169 # don't extract absolute paths or ones with .. in them
1170 if name.startswith('/') or '..' in name:
1171 continue
1172
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001173 targetpath = os.path.join(extract_dir, *name.split('/'))
1174 if not targetpath:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001175 continue
1176
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001177 _ensure_directory(targetpath)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001178 if not name.endswith('/'):
1179 # file
Miss Islington (bot)7a588622021-05-17 10:35:30 -07001180 with zip.open(name, 'r') as source, \
1181 open(targetpath, 'wb') as target:
1182 copyfileobj(source, target)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001183 finally:
1184 zip.close()
1185
1186def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001187 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001188 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001189 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001190 try:
1191 tarobj = tarfile.open(filename)
1192 except tarfile.TarError:
1193 raise ReadError(
1194 "%s is not a compressed or uncompressed tar file" % filename)
1195 try:
1196 tarobj.extractall(extract_dir)
1197 finally:
1198 tarobj.close()
1199
1200_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001201 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001202 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1203}
1204
1205if _ZLIB_SUPPORTED:
1206 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1207 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001208
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001209if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001210 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001211 "bzip2'ed tar-file")
1212
Serhiy Storchaka11213772014-08-06 18:50:19 +03001213if _LZMA_SUPPORTED:
1214 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1215 "xz'ed tar-file")
1216
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001217def _find_unpack_format(filename):
1218 for name, info in _UNPACK_FORMATS.items():
1219 for extension in info[0]:
1220 if filename.endswith(extension):
1221 return name
1222 return None
1223
1224def unpack_archive(filename, extract_dir=None, format=None):
1225 """Unpack an archive.
1226
1227 `filename` is the name of the archive.
1228
1229 `extract_dir` is the name of the target directory, where the archive
1230 is unpacked. If not provided, the current working directory is used.
1231
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001232 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1233 or "xztar". Or any other registered format. If not provided,
1234 unpack_archive will use the filename extension and see if an unpacker
1235 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001236
1237 In case none is found, a ValueError is raised.
1238 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001239 sys.audit("shutil.unpack_archive", filename, extract_dir, format)
1240
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001241 if extract_dir is None:
1242 extract_dir = os.getcwd()
1243
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001244 extract_dir = os.fspath(extract_dir)
1245 filename = os.fspath(filename)
1246
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001247 if format is not None:
1248 try:
1249 format_info = _UNPACK_FORMATS[format]
1250 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001251 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001252
Nick Coghlanabf202d2011-03-16 13:52:20 -04001253 func = format_info[1]
1254 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001255 else:
1256 # we need to look at the registered unpackers supported extensions
1257 format = _find_unpack_format(filename)
1258 if format is None:
1259 raise ReadError("Unknown archive format '{0}'".format(filename))
1260
1261 func = _UNPACK_FORMATS[format][1]
1262 kwargs = dict(_UNPACK_FORMATS[format][2])
1263 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001264
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001265
1266if hasattr(os, 'statvfs'):
1267
1268 __all__.append('disk_usage')
1269 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001270 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1271 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1272 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001273
1274 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001275 """Return disk usage statistics about the given path.
1276
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001277 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001278 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001279 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001280 st = os.statvfs(path)
1281 free = st.f_bavail * st.f_frsize
1282 total = st.f_blocks * st.f_frsize
1283 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1284 return _ntuple_diskusage(total, used, free)
1285
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001286elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001287
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001288 __all__.append('disk_usage')
1289 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1290
1291 def disk_usage(path):
1292 """Return disk usage statistics about the given path.
1293
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001294 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001295 'free', which are the amount of total, used and free space, in bytes.
1296 """
1297 total, free = nt._getdiskusage(path)
1298 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001299 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001300
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001301
Sandro Tosid902a142011-08-22 23:28:27 +02001302def chown(path, user=None, group=None):
1303 """Change owner user and group of the given path.
1304
1305 user and group can be the uid/gid or the user/group names, and in that case,
1306 they are converted to their respective uid/gid.
1307 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001308 sys.audit('shutil.chown', path, user, group)
Sandro Tosid902a142011-08-22 23:28:27 +02001309
1310 if user is None and group is None:
1311 raise ValueError("user and/or group must be set")
1312
1313 _user = user
1314 _group = group
1315
1316 # -1 means don't change it
1317 if user is None:
1318 _user = -1
1319 # user can either be an int (the uid) or a string (the system username)
1320 elif isinstance(user, str):
1321 _user = _get_uid(user)
1322 if _user is None:
1323 raise LookupError("no such user: {!r}".format(user))
1324
1325 if group is None:
1326 _group = -1
1327 elif not isinstance(group, int):
1328 _group = _get_gid(group)
1329 if _group is None:
1330 raise LookupError("no such group: {!r}".format(group))
1331
1332 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001333
1334def get_terminal_size(fallback=(80, 24)):
1335 """Get the size of the terminal window.
1336
1337 For each of the two dimensions, the environment variable, COLUMNS
1338 and LINES respectively, is checked. If the variable is defined and
1339 the value is a positive integer, it is used.
1340
1341 When COLUMNS or LINES is not defined, which is the common case,
1342 the terminal connected to sys.__stdout__ is queried
1343 by invoking os.get_terminal_size.
1344
1345 If the terminal size cannot be successfully queried, either because
1346 the system doesn't support querying, or because we are not
1347 connected to a terminal, the value given in fallback parameter
1348 is used. Fallback defaults to (80, 24) which is the default
1349 size used by many terminal emulators.
1350
1351 The value returned is a named tuple of type os.terminal_size.
1352 """
1353 # columns, lines are the working values
1354 try:
1355 columns = int(os.environ['COLUMNS'])
1356 except (KeyError, ValueError):
1357 columns = 0
1358
1359 try:
1360 lines = int(os.environ['LINES'])
1361 except (KeyError, ValueError):
1362 lines = 0
1363
1364 # only query if necessary
1365 if columns <= 0 or lines <= 0:
1366 try:
1367 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001368 except (AttributeError, ValueError, OSError):
1369 # stdout is None, closed, detached, or not a terminal, or
1370 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001371 size = os.terminal_size(fallback)
1372 if columns <= 0:
1373 columns = size.columns
1374 if lines <= 0:
1375 lines = size.lines
1376
1377 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001378
Cheryl Sabella5680f652019-02-13 06:25:10 -05001379
1380# Check that a given file can be accessed with the correct mode.
1381# Additionally check that `file` is not a directory, as on Windows
1382# directories pass the os.access check.
1383def _access_check(fn, mode):
1384 return (os.path.exists(fn) and os.access(fn, mode)
1385 and not os.path.isdir(fn))
1386
1387
Brian Curtinc57a3452012-06-22 16:00:30 -05001388def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001389 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001390 conforms to the given mode on the PATH, or None if there is no such
1391 file.
1392
1393 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1394 of os.environ.get("PATH"), or can be overridden with a custom search
1395 path.
1396
1397 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001398 # If we're given a path with a directory part, look it up directly rather
1399 # than referring to PATH directories. This includes checking relative to the
1400 # current directory, e.g. ./script
1401 if os.path.dirname(cmd):
1402 if _access_check(cmd, mode):
1403 return cmd
1404 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001405
Cheryl Sabella5680f652019-02-13 06:25:10 -05001406 use_bytes = isinstance(cmd, bytes)
1407
Barry Warsaw618738b2013-04-16 11:05:03 -04001408 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001409 path = os.environ.get("PATH", None)
1410 if path is None:
1411 try:
1412 path = os.confstr("CS_PATH")
1413 except (AttributeError, ValueError):
1414 # os.confstr() or CS_PATH is not available
1415 path = os.defpath
1416 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001417 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001418
1419 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001420 if not path:
1421 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001422
Cheryl Sabella5680f652019-02-13 06:25:10 -05001423 if use_bytes:
1424 path = os.fsencode(path)
1425 path = path.split(os.fsencode(os.pathsep))
1426 else:
1427 path = os.fsdecode(path)
1428 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001429
1430 if sys.platform == "win32":
1431 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001432 curdir = os.curdir
1433 if use_bytes:
1434 curdir = os.fsencode(curdir)
1435 if curdir not in path:
1436 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001437
1438 # PATHEXT is necessary to check on Windows.
Christopher Marchfelderda6f0982020-10-23 12:08:24 +02001439 pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
1440 pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
1441
Cheryl Sabella5680f652019-02-13 06:25:10 -05001442 if use_bytes:
1443 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001444 # See if the given file matches any of the expected path extensions.
1445 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001446 # If it does match, only test that one, otherwise we have to try
1447 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001448 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1449 files = [cmd]
1450 else:
1451 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001452 else:
1453 # On other platforms you don't have things like PATHEXT to tell you
1454 # what file suffixes are executable, so just pass on cmd as-is.
1455 files = [cmd]
1456
1457 seen = set()
1458 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001459 normdir = os.path.normcase(dir)
1460 if not normdir in seen:
1461 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001462 for thefile in files:
1463 name = os.path.join(dir, thefile)
1464 if _access_check(name, mode):
1465 return name
1466 return None