blob: e29fe4d83e927790558f0d542e8e9ae392ac397a [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:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200254 with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700255 # macOS
256 if _HAS_FCOPYFILE:
257 try:
258 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
259 return dst
260 except _GiveupOnFastCopy:
261 pass
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800262 # Linux
263 elif _USE_CP_SENDFILE:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200264 try:
265 _fastcopy_sendfile(fsrc, fdst)
266 return dst
267 except _GiveupOnFastCopy:
268 pass
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700269 # Windows, see:
270 # https://github.com/python/cpython/pull/7160#discussion_r195405230
271 elif _WINDOWS and file_size > 0:
272 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
273 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200274
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700275 copyfileobj(fsrc, fdst)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200276
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500277 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000278
Larry Hastingsb4038062012-07-15 10:57:38 -0700279def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100280 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000281
Larry Hastingsb4038062012-07-15 10:57:38 -0700282 If follow_symlinks is not set, symlinks aren't followed if and only
283 if both `src` and `dst` are symlinks. If `lchmod` isn't available
284 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100285
286 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800287 sys.audit("shutil.copymode", src, dst)
288
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800289 if not follow_symlinks and _islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100290 if hasattr(os, 'lchmod'):
291 stat_func, chmod_func = os.lstat, os.lchmod
292 else:
293 return
Antoine Pitrou78091e62011-12-29 18:54:15 +0100294 else:
Anthony Sottile8377cd42019-02-25 14:32:27 -0800295 stat_func, chmod_func = _stat, os.chmod
Antoine Pitrou78091e62011-12-29 18:54:15 +0100296
297 st = stat_func(src)
298 chmod_func(dst, stat.S_IMODE(st.st_mode))
299
Larry Hastingsad5ae042012-07-14 17:55:11 -0700300if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700301 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700302 """Copy extended filesystem attributes from `src` to `dst`.
303
304 Overwrite existing attributes.
305
Larry Hastingsb4038062012-07-15 10:57:38 -0700306 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700307
308 """
309
Hynek Schlawack0beab052013-02-05 08:22:44 +0100310 try:
311 names = os.listxattr(src, follow_symlinks=follow_symlinks)
312 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400313 if e.errno not in (errno.ENOTSUP, errno.ENODATA, errno.EINVAL):
Hynek Schlawack0beab052013-02-05 08:22:44 +0100314 raise
315 return
316 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700317 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700318 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
319 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700320 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400321 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
322 errno.EINVAL):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700323 raise
324else:
325 def _copyxattr(*args, **kwargs):
326 pass
327
Larry Hastingsb4038062012-07-15 10:57:38 -0700328def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200329 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100330
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200331 Copy the permission bits, last access time, last modification time, and
332 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
333 attributes" where possible. The file contents, owner, and group are
Boris Verhovsky9488a522019-09-09 09:51:56 -0600334 unaffected. `src` and `dst` are path-like objects or path names given as
335 strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100336
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200337 If the optional flag `follow_symlinks` is not set, symlinks aren't
338 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100339 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800340 sys.audit("shutil.copystat", src, dst)
341
Larry Hastings9cf065c2012-06-22 16:30:09 -0700342 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100343 pass
344
Larry Hastings9cf065c2012-06-22 16:30:09 -0700345 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800346 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700347 if follow:
348 # use the real function if it exists
349 def lookup(name):
350 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100351 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700352 # use the real function only if it exists
353 # *and* it supports follow_symlinks
354 def lookup(name):
355 fn = getattr(os, name, _nop)
356 if fn in os.supports_follow_symlinks:
357 return fn
358 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100359
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800360 if isinstance(src, os.DirEntry):
361 st = src.stat(follow_symlinks=follow)
362 else:
363 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000364 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700365 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
366 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500367 # We must copy extended attributes before the file is (potentially)
368 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
369 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700370 try:
371 lookup("chmod")(dst, mode, follow_symlinks=follow)
372 except NotImplementedError:
373 # if we got a NotImplementedError, it's because
374 # * follow_symlinks=False,
375 # * lchown() is unavailable, and
376 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300377 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700378 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
379 # (it returned ENOSUP.)
380 # therefore we're out of options--we simply cannot chown the
381 # symlink. give up, suppress the error.
382 # (which is what shutil always did in this circumstance.)
383 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100384 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000385 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700386 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000387 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700388 for err in 'EOPNOTSUPP', 'ENOTSUP':
389 if hasattr(errno, err) and why.errno == getattr(errno, err):
390 break
391 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000392 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200393
Larry Hastingsb4038062012-07-15 10:57:38 -0700394def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500395 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000396
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000397 The destination may be a directory.
398
Larry Hastingsb4038062012-07-15 10:57:38 -0700399 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100400 resembles GNU's "cp -P src dst".
401
Hynek Schlawack48653762012-10-07 12:49:58 +0200402 If source and destination are the same file, a SameFileError will be
403 raised.
404
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000405 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000406 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000407 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700408 copyfile(src, dst, follow_symlinks=follow_symlinks)
409 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500410 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000411
Larry Hastingsb4038062012-07-15 10:57:38 -0700412def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200413 """Copy data and metadata. Return the file's destination.
414
415 Metadata is copied with copystat(). Please see the copystat function
416 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000417
418 The destination may be a directory.
419
Larry Hastingsb4038062012-07-15 10:57:38 -0700420 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100421 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000422 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000423 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000424 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700425 copyfile(src, dst, follow_symlinks=follow_symlinks)
426 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500427 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000428
Georg Brandl2ee470f2008-07-16 12:55:28 +0000429def ignore_patterns(*patterns):
430 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000431
Georg Brandl2ee470f2008-07-16 12:55:28 +0000432 Patterns is a sequence of glob-style patterns
433 that are used to exclude files"""
434 def _ignore_patterns(path, names):
435 ignored_names = []
436 for pattern in patterns:
437 ignored_names.extend(fnmatch.filter(names, pattern))
438 return set(ignored_names)
439 return _ignore_patterns
440
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800441def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500442 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800443 if ignore is not None:
mbarkhau88704332020-01-24 14:51:16 +0000444 ignored_names = ignore(os.fspath(src), [x.name for x in entries])
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800445 else:
446 ignored_names = set()
447
jab9e00d9e2018-12-28 13:03:40 -0500448 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800449 errors = []
450 use_srcentry = copy_function is copy2 or copy_function is copy
451
452 for srcentry in entries:
453 if srcentry.name in ignored_names:
454 continue
455 srcname = os.path.join(src, srcentry.name)
456 dstname = os.path.join(dst, srcentry.name)
457 srcobj = srcentry if use_srcentry else srcname
458 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700459 is_symlink = srcentry.is_symlink()
460 if is_symlink and os.name == 'nt':
461 # Special check for directory junctions, which appear as
462 # symlinks but we want to recurse.
463 lstat = srcentry.stat(follow_symlinks=False)
464 if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
465 is_symlink = False
466 if is_symlink:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800467 linkto = os.readlink(srcname)
468 if symlinks:
469 # We can't just leave it to `copy_function` because legacy
470 # code with a custom `copy_function` may rely on copytree
471 # doing the right thing.
472 os.symlink(linkto, dstname)
473 copystat(srcobj, dstname, follow_symlinks=not symlinks)
474 else:
475 # ignore dangling symlink if the flag is on
476 if not os.path.exists(linkto) and ignore_dangling_symlinks:
477 continue
jab9e00d9e2018-12-28 13:03:40 -0500478 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800479 if srcentry.is_dir():
480 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500481 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800482 else:
483 copy_function(srcobj, dstname)
484 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500485 copytree(srcobj, dstname, symlinks, ignore, copy_function,
486 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800487 else:
488 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100489 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800490 # catch the Error from the recursive copytree so that we can
491 # continue with other files
492 except Error as err:
493 errors.extend(err.args[0])
494 except OSError as why:
495 errors.append((srcname, dstname, str(why)))
496 try:
497 copystat(src, dst)
498 except OSError as why:
499 # Copying file access times may fail on Windows
500 if getattr(why, 'winerror', None) is None:
501 errors.append((src, dst, str(why)))
502 if errors:
503 raise Error(errors)
504 return dst
505
Tarek Ziadéfb437512010-04-20 08:57:33 +0000506def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500507 ignore_dangling_symlinks=False, dirs_exist_ok=False):
508 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000509
jab9e00d9e2018-12-28 13:03:40 -0500510 dirs_exist_ok dictates whether to raise an exception in case dst or any
511 missing parent directory already exists.
512
Neal Norwitza4c93b62003-02-23 21:36:32 +0000513 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000514
515 If the optional symlinks flag is true, symbolic links in the
516 source tree result in symbolic links in the destination tree; if
517 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000518 links are copied. If the file pointed by the symlink doesn't
519 exist, an exception will be added in the list of errors raised in
520 an Error exception at the end of the copy process.
521
522 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000523 want to silence this exception. Notice that this has no effect on
524 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000525
Georg Brandl2ee470f2008-07-16 12:55:28 +0000526 The optional ignore argument is a callable. If given, it
527 is called with the `src` parameter, which is the directory
528 being visited by copytree(), and `names` which is the list of
529 `src` contents, as returned by os.listdir():
530
531 callable(src, names) -> ignored_names
532
533 Since copytree() is called recursively, the callable will be
534 called once for each directory that is copied. It returns a
535 list of names relative to the `src` directory that should
536 not be copied.
537
Tarek Ziadé5340db32010-04-19 22:30:51 +0000538 The optional copy_function argument is a callable that will be used
539 to copy each file. It will be called with the source path and the
540 destination path as arguments. By default, copy2() is used, but any
541 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000542
543 """
Steve Dower60419a72019-06-24 08:42:54 -0700544 sys.audit("shutil.copytree", src, dst)
Bruno P. Kinoshita9bbcbc92019-11-27 14:10:37 +1300545 with os.scandir(src) as itr:
546 entries = list(itr)
547 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
548 ignore=ignore, copy_function=copy_function,
549 ignore_dangling_symlinks=ignore_dangling_symlinks,
550 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000551
Ned Deily7fcc2082019-08-29 17:20:03 -0400552if hasattr(os.stat_result, 'st_file_attributes'):
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700553 # Special handling for directory junctions to make them behave like
554 # symlinks for shutil.rmtree, since in general they do not appear as
555 # regular links.
556 def _rmtree_isdir(entry):
557 try:
558 st = entry.stat(follow_symlinks=False)
559 return (stat.S_ISDIR(st.st_mode) and not
560 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
561 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
562 except OSError:
563 return False
564
565 def _rmtree_islink(path):
566 try:
567 st = os.lstat(path)
568 return (stat.S_ISLNK(st.st_mode) or
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
573else:
574 def _rmtree_isdir(entry):
575 try:
576 return entry.is_dir(follow_symlinks=False)
577 except OSError:
578 return False
579
580 def _rmtree_islink(path):
581 return os.path.islink(path)
582
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200583# version vulnerable to race conditions
584def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000585 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200586 with os.scandir(path) as scandir_it:
587 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000588 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200589 onerror(os.scandir, path, sys.exc_info())
590 entries = []
591 for entry in entries:
592 fullname = entry.path
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700593 if _rmtree_isdir(entry):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200594 try:
595 if entry.is_symlink():
596 # This can only happen if someone replaces
597 # a directory with a symlink after the call to
598 # os.scandir or entry.is_dir above.
599 raise OSError("Cannot call rmtree on a symbolic link")
600 except OSError:
601 onerror(os.path.islink, fullname, sys.exc_info())
602 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200603 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000604 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000605 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200606 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200607 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200608 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000609 try:
610 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200611 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000612 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000613
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200614# Version using fd-based APIs to protect against races
615def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200616 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200617 with os.scandir(topfd) as scandir_it:
618 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100619 except OSError as err:
620 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200621 onerror(os.scandir, path, sys.exc_info())
622 return
623 for entry in entries:
624 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200625 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200626 is_dir = entry.is_dir(follow_symlinks=False)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100627 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200628 is_dir = False
Serhiy Storchakae9b51c02019-05-31 11:30:37 +0300629 else:
630 if is_dir:
631 try:
632 orig_st = entry.stat(follow_symlinks=False)
633 is_dir = stat.S_ISDIR(orig_st.st_mode)
634 except OSError:
635 onerror(os.lstat, fullname, sys.exc_info())
636 continue
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200637 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200638 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200639 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100640 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200641 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200642 else:
643 try:
644 if os.path.samestat(orig_st, os.fstat(dirfd)):
645 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200646 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200647 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100648 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200649 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100650 else:
651 try:
652 # This can only happen if someone replaces
653 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200654 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100655 raise OSError("Cannot call rmtree on a symbolic "
656 "link")
657 except OSError:
658 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200659 finally:
660 os.close(dirfd)
661 else:
662 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200663 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100664 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200665 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200666
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200667_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
668 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200669 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200670 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000671
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200672def rmtree(path, ignore_errors=False, onerror=None):
673 """Recursively delete a directory tree.
674
675 If ignore_errors is set, errors are ignored; otherwise, if onerror
676 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200677 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200678 path is the argument to that function that caused it to fail; and
679 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
680 is false and onerror is None, an exception is raised.
681
682 """
Steve Dower60419a72019-06-24 08:42:54 -0700683 sys.audit("shutil.rmtree", path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200684 if ignore_errors:
685 def onerror(*args):
686 pass
687 elif onerror is None:
688 def onerror(*args):
689 raise
690 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200691 # While the unsafe rmtree works fine on bytes, the fd based does not.
692 if isinstance(path, bytes):
693 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200694 # Note: To guard against symlink races, we use the standard
695 # lstat()/open()/fstat() trick.
696 try:
697 orig_st = os.lstat(path)
698 except Exception:
699 onerror(os.lstat, path, sys.exc_info())
700 return
701 try:
702 fd = os.open(path, os.O_RDONLY)
703 except Exception:
Michal Čihaře59b2de2020-11-10 17:06:02 +0100704 onerror(os.open, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200705 return
706 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100707 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200708 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200709 try:
710 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200711 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200712 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200713 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100714 try:
715 # symlinks to directories are forbidden, see bug #1669
716 raise OSError("Cannot call rmtree on a symbolic link")
717 except OSError:
718 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200719 finally:
720 os.close(fd)
721 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200722 try:
Steve Dowerdf2d4a62019-08-21 15:27:33 -0700723 if _rmtree_islink(path):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200724 # 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())
728 # can't continue even if onerror hook returns
729 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200730 return _rmtree_unsafe(path, onerror)
731
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000732# Allow introspection of whether or not the hardening against symlink
733# attacks is supported on the current platform
734rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000735
Christian Heimesada8c3b2008-03-18 18:26:33 +0000736def _basename(path):
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700737 """A basename() variant which first strips the trailing slash, if present.
738 Thus we always get the last component of the path, even for directories.
739
740 path: Union[PathLike, str]
741
742 e.g.
743 >>> os.path.basename('/bar/foo')
744 'foo'
745 >>> os.path.basename('/bar/foo/')
746 ''
747 >>> _basename('/bar/foo/')
748 'foo'
749 """
750 path = os.fspath(path)
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200751 sep = os.path.sep + (os.path.altsep or '')
752 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000753
R David Murray6ffface2014-06-11 14:40:13 -0400754def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000755 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500756 similar to the Unix "mv" command. Return the file or directory's
757 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000758
759 If the destination is a directory or a symlink to a directory, the source
760 is moved inside the directory. The destination path must not already
761 exist.
762
763 If the destination already exists but is not a directory, it may be
764 overwritten depending on os.rename() semantics.
765
766 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100767 Otherwise, src is copied to the destination and then removed. Symlinks are
768 recreated under the new name if os.rename() fails because of cross
769 filesystem renames.
770
R David Murray6ffface2014-06-11 14:40:13 -0400771 The optional `copy_function` argument is a callable that will be used
772 to copy the source or it will be delegated to `copytree`.
773 By default, copy2() is used, but any function that supports the same
774 signature (like copy()) can be used.
775
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000776 A lot more could be done here... A look at a mv.c shows a lot of
777 the issues this implementation glosses over.
778
779 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -0800780 sys.audit("shutil.move", src, dst)
Christian Heimesada8c3b2008-03-18 18:26:33 +0000781 real_dst = dst
782 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200783 if _samefile(src, dst):
784 # We might be on a case insensitive filesystem,
785 # perform the rename anyway.
786 os.rename(src, dst)
787 return
788
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700789 # Using _basename instead of os.path.basename is important, as we must
790 # ignore any trailing slash to avoid the basename returning ''
Christian Heimesada8c3b2008-03-18 18:26:33 +0000791 real_dst = os.path.join(dst, _basename(src))
Maxwell A McKinnoncf57cab2019-09-30 19:41:16 -0700792
Christian Heimesada8c3b2008-03-18 18:26:33 +0000793 if os.path.exists(real_dst):
794 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000795 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000796 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200797 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100798 if os.path.islink(src):
799 linkto = os.readlink(src)
800 os.symlink(linkto, real_dst)
801 os.unlink(src)
802 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000803 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400804 raise Error("Cannot move a directory '%s' into itself"
805 " '%s'." % (src, dst))
Winson Luk132131b2021-03-02 15:53:15 -0500806 if (_is_immutable(src)
807 or (not os.access(src, os.W_OK) and os.listdir(src)
808 and sys.platform == 'darwin')):
809 raise PermissionError("Cannot move the non-empty directory "
810 "'%s': Lacking write permission to '%s'."
811 % (src, src))
R David Murray6ffface2014-06-11 14:40:13 -0400812 copytree(src, real_dst, copy_function=copy_function,
813 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000814 rmtree(src)
815 else:
R David Murray6ffface2014-06-11 14:40:13 -0400816 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000817 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500818 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000819
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000820def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300821 src = os.path.abspath(src)
822 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000823 if not src.endswith(os.path.sep):
824 src += os.path.sep
825 if not dst.endswith(os.path.sep):
826 dst += os.path.sep
827 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000828
Winson Luk132131b2021-03-02 15:53:15 -0500829def _is_immutable(src):
830 st = _stat(src)
831 immutable_states = [stat.UF_IMMUTABLE, stat.SF_IMMUTABLE]
832 return hasattr(st, 'st_flags') and st.st_flags in immutable_states
833
Tarek Ziadé396fad72010-02-23 05:30:31 +0000834def _get_gid(name):
835 """Returns a gid, given a group name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100836 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000837 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100838
839 try:
840 from grp import getgrnam
841 except ImportError:
842 return None
843
Tarek Ziadé396fad72010-02-23 05:30:31 +0000844 try:
845 result = getgrnam(name)
846 except KeyError:
847 result = None
848 if result is not None:
849 return result[2]
850 return None
851
852def _get_uid(name):
853 """Returns an uid, given a user name."""
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100854 if name is None:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000855 return None
Victor Stinnerd72e8d42021-03-23 17:42:51 +0100856
857 try:
858 from pwd import getpwnam
859 except ImportError:
860 return None
861
Tarek Ziadé396fad72010-02-23 05:30:31 +0000862 try:
863 result = getpwnam(name)
864 except KeyError:
865 result = None
866 if result is not None:
867 return result[2]
868 return None
869
870def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
871 owner=None, group=None, logger=None):
872 """Create a (possibly compressed) tar file from all the files under
873 'base_dir'.
874
Serhiy Storchaka11213772014-08-06 18:50:19 +0300875 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000876
877 'owner' and 'group' can be used to define an owner and a group for the
878 archive that is being built. If not provided, the current owner and group
879 will be used.
880
Éric Araujo4433a5f2010-12-15 20:26:30 +0000881 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300882 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000883
884 Returns the output filename.
885 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200886 if compress is None:
887 tar_compression = ''
888 elif _ZLIB_SUPPORTED and compress == 'gzip':
889 tar_compression = 'gz'
890 elif _BZ2_SUPPORTED and compress == 'bzip2':
891 tar_compression = 'bz2'
892 elif _LZMA_SUPPORTED and compress == 'xz':
893 tar_compression = 'xz'
894 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000895 raise ValueError("bad value for 'compress', or compression format not "
896 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000897
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200898 import tarfile # late import for breaking circular dependency
899
900 compress_ext = '.' + tar_compression if compress else ''
901 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000902 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000903
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200904 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000905 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200906 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000907 if not dry_run:
908 os.makedirs(archive_dir)
909
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000911 if logger is not None:
912 logger.info('Creating tar archive')
913
914 uid = _get_uid(owner)
915 gid = _get_gid(group)
916
917 def _set_uid_gid(tarinfo):
918 if gid is not None:
919 tarinfo.gid = gid
920 tarinfo.gname = group
921 if uid is not None:
922 tarinfo.uid = uid
923 tarinfo.uname = owner
924 return tarinfo
925
926 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200927 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000928 try:
929 tar.add(base_dir, filter=_set_uid_gid)
930 finally:
931 tar.close()
932
Tarek Ziadé396fad72010-02-23 05:30:31 +0000933 return archive_name
934
Tarek Ziadé396fad72010-02-23 05:30:31 +0000935def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
936 """Create a zip file from all the files under 'base_dir'.
937
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200938 The output zip file will be named 'base_name' + ".zip". Returns the
939 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000940 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200941 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400942
Tarek Ziadé396fad72010-02-23 05:30:31 +0000943 zip_filename = base_name + ".zip"
944 archive_dir = os.path.dirname(base_name)
945
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200946 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000947 if logger is not None:
948 logger.info("creating %s", archive_dir)
949 if not dry_run:
950 os.makedirs(archive_dir)
951
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400952 if logger is not None:
953 logger.info("creating '%s' and adding '%s' to it",
954 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000955
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400956 if not dry_run:
957 with zipfile.ZipFile(zip_filename, "w",
958 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300959 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300960 if path != os.curdir:
961 zf.write(path, path)
962 if logger is not None:
963 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400964 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300965 for name in sorted(dirnames):
966 path = os.path.normpath(os.path.join(dirpath, name))
967 zf.write(path, path)
968 if logger is not None:
969 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400970 for name in filenames:
971 path = os.path.normpath(os.path.join(dirpath, name))
972 if os.path.isfile(path):
973 zf.write(path, path)
974 if logger is not None:
975 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976
977 return zip_filename
978
979_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200981}
982
983if _ZLIB_SUPPORTED:
984 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
985 "gzip'ed tar-file")
986 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000987
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000988if _BZ2_SUPPORTED:
989 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
990 "bzip2'ed tar-file")
991
Serhiy Storchaka11213772014-08-06 18:50:19 +0300992if _LZMA_SUPPORTED:
993 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
994 "xz'ed tar-file")
995
Tarek Ziadé396fad72010-02-23 05:30:31 +0000996def get_archive_formats():
997 """Returns a list of supported formats for archiving and unarchiving.
998
999 Each element of the returned sequence is a tuple (name, description)
1000 """
1001 formats = [(name, registry[2]) for name, registry in
1002 _ARCHIVE_FORMATS.items()]
1003 formats.sort()
1004 return formats
1005
1006def register_archive_format(name, function, extra_args=None, description=''):
1007 """Registers an archive format.
1008
1009 name is the name of the format. function is the callable that will be
1010 used to create archives. If provided, extra_args is a sequence of
1011 (name, value) tuples that will be passed as arguments to the callable.
1012 description can be provided to describe the format, and will be returned
1013 by the get_archive_formats() function.
1014 """
1015 if extra_args is None:
1016 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001017 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018 raise TypeError('The %s object is not callable' % function)
1019 if not isinstance(extra_args, (tuple, list)):
1020 raise TypeError('extra_args needs to be a sequence')
1021 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001022 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023 raise TypeError('extra_args elements are : (arg_name, value)')
1024
1025 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
1026
1027def unregister_archive_format(name):
1028 del _ARCHIVE_FORMATS[name]
1029
1030def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
1031 dry_run=0, owner=None, group=None, logger=None):
1032 """Create an archive file (eg. zip or tar).
1033
1034 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001035 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
1036 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +00001037
1038 'root_dir' is a directory that will be the root directory of the
1039 archive; ie. we typically chdir into 'root_dir' before creating the
1040 archive. 'base_dir' is the directory where we start archiving from;
1041 ie. 'base_dir' will be the common prefix of all files and
1042 directories in the archive. 'root_dir' and 'base_dir' both default
1043 to the current directory. Returns the name of the archive file.
1044
1045 'owner' and 'group' are used when creating a tar archive. By default,
1046 uses the current owner and group.
1047 """
Steve Dower60419a72019-06-24 08:42:54 -07001048 sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001049 save_cwd = os.getcwd()
1050 if root_dir is not None:
1051 if logger is not None:
1052 logger.debug("changing into '%s'", root_dir)
1053 base_name = os.path.abspath(base_name)
1054 if not dry_run:
1055 os.chdir(root_dir)
1056
1057 if base_dir is None:
1058 base_dir = os.curdir
1059
1060 kwargs = {'dry_run': dry_run, 'logger': logger}
1061
1062 try:
1063 format_info = _ARCHIVE_FORMATS[format]
1064 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001065 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +00001066
1067 func = format_info[0]
1068 for arg, val in format_info[1]:
1069 kwargs[arg] = val
1070
1071 if format != 'zip':
1072 kwargs['owner'] = owner
1073 kwargs['group'] = group
1074
1075 try:
1076 filename = func(base_name, base_dir, **kwargs)
1077 finally:
1078 if root_dir is not None:
1079 if logger is not None:
1080 logger.debug("changing back to '%s'", save_cwd)
1081 os.chdir(save_cwd)
1082
1083 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001084
1085
1086def get_unpack_formats():
1087 """Returns a list of supported formats for unpacking.
1088
1089 Each element of the returned sequence is a tuple
1090 (name, extensions, description)
1091 """
1092 formats = [(name, info[0], info[3]) for name, info in
1093 _UNPACK_FORMATS.items()]
1094 formats.sort()
1095 return formats
1096
1097def _check_unpack_options(extensions, function, extra_args):
1098 """Checks what gets registered as an unpacker."""
1099 # first make sure no other unpacker is registered for this extension
1100 existing_extensions = {}
1101 for name, info in _UNPACK_FORMATS.items():
1102 for ext in info[0]:
1103 existing_extensions[ext] = name
1104
1105 for extension in extensions:
1106 if extension in existing_extensions:
1107 msg = '%s is already registered for "%s"'
1108 raise RegistryError(msg % (extension,
1109 existing_extensions[extension]))
1110
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001111 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001112 raise TypeError('The registered function must be a callable')
1113
1114
1115def register_unpack_format(name, extensions, function, extra_args=None,
1116 description=''):
1117 """Registers an unpack format.
1118
1119 `name` is the name of the format. `extensions` is a list of extensions
1120 corresponding to the format.
1121
1122 `function` is the callable that will be
1123 used to unpack archives. The callable will receive archives to unpack.
1124 If it's unable to handle an archive, it needs to raise a ReadError
1125 exception.
1126
1127 If provided, `extra_args` is a sequence of
1128 (name, value) tuples that will be passed as arguments to the callable.
1129 description can be provided to describe the format, and will be returned
1130 by the get_unpack_formats() function.
1131 """
1132 if extra_args is None:
1133 extra_args = []
1134 _check_unpack_options(extensions, function, extra_args)
1135 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1136
1137def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001138 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001139 del _UNPACK_FORMATS[name]
1140
1141def _ensure_directory(path):
1142 """Ensure that the parent directory of `path` exists"""
1143 dirname = os.path.dirname(path)
1144 if not os.path.isdir(dirname):
1145 os.makedirs(dirname)
1146
1147def _unpack_zipfile(filename, extract_dir):
1148 """Unpack zip `filename` to `extract_dir`
1149 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001150 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001151
1152 if not zipfile.is_zipfile(filename):
1153 raise ReadError("%s is not a zip file" % filename)
1154
1155 zip = zipfile.ZipFile(filename)
1156 try:
1157 for info in zip.infolist():
1158 name = info.filename
1159
1160 # don't extract absolute paths or ones with .. in them
1161 if name.startswith('/') or '..' in name:
1162 continue
1163
1164 target = os.path.join(extract_dir, *name.split('/'))
1165 if not target:
1166 continue
1167
1168 _ensure_directory(target)
1169 if not name.endswith('/'):
1170 # file
1171 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001172 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001173 try:
1174 f.write(data)
1175 finally:
1176 f.close()
1177 del data
1178 finally:
1179 zip.close()
1180
1181def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001182 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001183 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001184 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001185 try:
1186 tarobj = tarfile.open(filename)
1187 except tarfile.TarError:
1188 raise ReadError(
1189 "%s is not a compressed or uncompressed tar file" % filename)
1190 try:
1191 tarobj.extractall(extract_dir)
1192 finally:
1193 tarobj.close()
1194
1195_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001196 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001197 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1198}
1199
1200if _ZLIB_SUPPORTED:
1201 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1202 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001203
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001204if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001205 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001206 "bzip2'ed tar-file")
1207
Serhiy Storchaka11213772014-08-06 18:50:19 +03001208if _LZMA_SUPPORTED:
1209 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1210 "xz'ed tar-file")
1211
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001212def _find_unpack_format(filename):
1213 for name, info in _UNPACK_FORMATS.items():
1214 for extension in info[0]:
1215 if filename.endswith(extension):
1216 return name
1217 return None
1218
1219def unpack_archive(filename, extract_dir=None, format=None):
1220 """Unpack an archive.
1221
1222 `filename` is the name of the archive.
1223
1224 `extract_dir` is the name of the target directory, where the archive
1225 is unpacked. If not provided, the current working directory is used.
1226
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001227 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1228 or "xztar". Or any other registered format. If not provided,
1229 unpack_archive will use the filename extension and see if an unpacker
1230 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001231
1232 In case none is found, a ValueError is raised.
1233 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001234 sys.audit("shutil.unpack_archive", filename, extract_dir, format)
1235
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001236 if extract_dir is None:
1237 extract_dir = os.getcwd()
1238
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001239 extract_dir = os.fspath(extract_dir)
1240 filename = os.fspath(filename)
1241
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001242 if format is not None:
1243 try:
1244 format_info = _UNPACK_FORMATS[format]
1245 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001246 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001247
Nick Coghlanabf202d2011-03-16 13:52:20 -04001248 func = format_info[1]
1249 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001250 else:
1251 # we need to look at the registered unpackers supported extensions
1252 format = _find_unpack_format(filename)
1253 if format is None:
1254 raise ReadError("Unknown archive format '{0}'".format(filename))
1255
1256 func = _UNPACK_FORMATS[format][1]
1257 kwargs = dict(_UNPACK_FORMATS[format][2])
1258 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001259
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001260
1261if hasattr(os, 'statvfs'):
1262
1263 __all__.append('disk_usage')
1264 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001265 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1266 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1267 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001268
1269 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001270 """Return disk usage statistics about the given path.
1271
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001272 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001273 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001274 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001275 st = os.statvfs(path)
1276 free = st.f_bavail * st.f_frsize
1277 total = st.f_blocks * st.f_frsize
1278 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1279 return _ntuple_diskusage(total, used, free)
1280
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001281elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001282
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001283 __all__.append('disk_usage')
1284 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1285
1286 def disk_usage(path):
1287 """Return disk usage statistics about the given path.
1288
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001289 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001290 'free', which are the amount of total, used and free space, in bytes.
1291 """
1292 total, free = nt._getdiskusage(path)
1293 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001294 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001295
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001296
Sandro Tosid902a142011-08-22 23:28:27 +02001297def chown(path, user=None, group=None):
1298 """Change owner user and group of the given path.
1299
1300 user and group can be the uid/gid or the user/group names, and in that case,
1301 they are converted to their respective uid/gid.
1302 """
Saiyang Gou7514f4f2020-02-12 23:47:42 -08001303 sys.audit('shutil.chown', path, user, group)
Sandro Tosid902a142011-08-22 23:28:27 +02001304
1305 if user is None and group is None:
1306 raise ValueError("user and/or group must be set")
1307
1308 _user = user
1309 _group = group
1310
1311 # -1 means don't change it
1312 if user is None:
1313 _user = -1
1314 # user can either be an int (the uid) or a string (the system username)
1315 elif isinstance(user, str):
1316 _user = _get_uid(user)
1317 if _user is None:
1318 raise LookupError("no such user: {!r}".format(user))
1319
1320 if group is None:
1321 _group = -1
1322 elif not isinstance(group, int):
1323 _group = _get_gid(group)
1324 if _group is None:
1325 raise LookupError("no such group: {!r}".format(group))
1326
1327 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001328
1329def get_terminal_size(fallback=(80, 24)):
1330 """Get the size of the terminal window.
1331
1332 For each of the two dimensions, the environment variable, COLUMNS
1333 and LINES respectively, is checked. If the variable is defined and
1334 the value is a positive integer, it is used.
1335
1336 When COLUMNS or LINES is not defined, which is the common case,
1337 the terminal connected to sys.__stdout__ is queried
1338 by invoking os.get_terminal_size.
1339
1340 If the terminal size cannot be successfully queried, either because
1341 the system doesn't support querying, or because we are not
1342 connected to a terminal, the value given in fallback parameter
1343 is used. Fallback defaults to (80, 24) which is the default
1344 size used by many terminal emulators.
1345
1346 The value returned is a named tuple of type os.terminal_size.
1347 """
1348 # columns, lines are the working values
1349 try:
1350 columns = int(os.environ['COLUMNS'])
1351 except (KeyError, ValueError):
1352 columns = 0
1353
1354 try:
1355 lines = int(os.environ['LINES'])
1356 except (KeyError, ValueError):
1357 lines = 0
1358
1359 # only query if necessary
1360 if columns <= 0 or lines <= 0:
1361 try:
1362 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001363 except (AttributeError, ValueError, OSError):
1364 # stdout is None, closed, detached, or not a terminal, or
1365 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001366 size = os.terminal_size(fallback)
1367 if columns <= 0:
1368 columns = size.columns
1369 if lines <= 0:
1370 lines = size.lines
1371
1372 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001373
Cheryl Sabella5680f652019-02-13 06:25:10 -05001374
1375# Check that a given file can be accessed with the correct mode.
1376# Additionally check that `file` is not a directory, as on Windows
1377# directories pass the os.access check.
1378def _access_check(fn, mode):
1379 return (os.path.exists(fn) and os.access(fn, mode)
1380 and not os.path.isdir(fn))
1381
1382
Brian Curtinc57a3452012-06-22 16:00:30 -05001383def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001384 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001385 conforms to the given mode on the PATH, or None if there is no such
1386 file.
1387
1388 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1389 of os.environ.get("PATH"), or can be overridden with a custom search
1390 path.
1391
1392 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001393 # If we're given a path with a directory part, look it up directly rather
1394 # than referring to PATH directories. This includes checking relative to the
1395 # current directory, e.g. ./script
1396 if os.path.dirname(cmd):
1397 if _access_check(cmd, mode):
1398 return cmd
1399 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001400
Cheryl Sabella5680f652019-02-13 06:25:10 -05001401 use_bytes = isinstance(cmd, bytes)
1402
Barry Warsaw618738b2013-04-16 11:05:03 -04001403 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001404 path = os.environ.get("PATH", None)
1405 if path is None:
1406 try:
1407 path = os.confstr("CS_PATH")
1408 except (AttributeError, ValueError):
1409 # os.confstr() or CS_PATH is not available
1410 path = os.defpath
1411 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001412 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001413
1414 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001415 if not path:
1416 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001417
Cheryl Sabella5680f652019-02-13 06:25:10 -05001418 if use_bytes:
1419 path = os.fsencode(path)
1420 path = path.split(os.fsencode(os.pathsep))
1421 else:
1422 path = os.fsdecode(path)
1423 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001424
1425 if sys.platform == "win32":
1426 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001427 curdir = os.curdir
1428 if use_bytes:
1429 curdir = os.fsencode(curdir)
1430 if curdir not in path:
1431 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001432
1433 # PATHEXT is necessary to check on Windows.
Christopher Marchfelderda6f0982020-10-23 12:08:24 +02001434 pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
1435 pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
1436
Cheryl Sabella5680f652019-02-13 06:25:10 -05001437 if use_bytes:
1438 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001439 # See if the given file matches any of the expected path extensions.
1440 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001441 # If it does match, only test that one, otherwise we have to try
1442 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001443 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1444 files = [cmd]
1445 else:
1446 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001447 else:
1448 # On other platforms you don't have things like PATHEXT to tell you
1449 # what file suffixes are executable, so just pass on cmd as-is.
1450 files = [cmd]
1451
1452 seen = set()
1453 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001454 normdir = os.path.normcase(dir)
1455 if not normdir in seen:
1456 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001457 for thefile in files:
1458 name = os.path.join(dir, thefile)
1459 if _access_check(name, mode):
1460 return name
1461 return None