blob: 39f793b5f3bde517edb8bbbce22129ff533942d4 [file] [log] [blame]
Tarek Ziadéc3399782010-02-23 05:39:18 +00001"""Utility functions for copying and archiving files and directory trees.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00002
Guido van Rossum959fa011999-08-18 20:03:17 +00003XXX The functions here don't copy the resource fork or other metadata on Mac.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00004
5"""
Guido van Rossumc6360141990-10-13 19:23:40 +00006
Guido van Rossumc96207a1992-03-31 18:55:40 +00007import os
Guido van Rossum83c03e21999-02-23 23:07:51 +00008import sys
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00009import stat
Georg Brandl2ee470f2008-07-16 12:55:28 +000010import fnmatch
Tarek Ziadé396fad72010-02-23 05:30:31 +000011import collections
Antoine Pitrou910bd512010-03-22 20:11:09 +000012import errno
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020013
14try:
15 import zlib
16 del zlib
17 _ZLIB_SUPPORTED = True
18except ImportError:
19 _ZLIB_SUPPORTED = False
Tarek Ziadé396fad72010-02-23 05:30:31 +000020
21try:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000022 import bz2
Florent Xicluna54540ec2011-11-04 08:29:17 +010023 del bz2
Tarek Ziadéffa155a2010-04-29 13:34:35 +000024 _BZ2_SUPPORTED = True
Brett Cannoncd171c82013-07-04 17:43:24 -040025except ImportError:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000026 _BZ2_SUPPORTED = False
27
28try:
Serhiy Storchaka11213772014-08-06 18:50:19 +030029 import lzma
30 del lzma
31 _LZMA_SUPPORTED = True
32except ImportError:
33 _LZMA_SUPPORTED = False
34
35try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000036 from pwd import getpwnam
Brett Cannoncd171c82013-07-04 17:43:24 -040037except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000038 getpwnam = None
39
40try:
41 from grp import getgrnam
Brett Cannoncd171c82013-07-04 17:43:24 -040042except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000043 getgrnam = None
Guido van Rossumc6360141990-10-13 19:23:40 +000044
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070045_WINDOWS = os.name == 'nt'
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020046posix = nt = None
47if os.name == 'posix':
48 import posix
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070049elif _WINDOWS:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020050 import nt
51
Inada Naoki4f190302019-03-02 13:31:01 +090052COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
Giampaolo Rodola413d9552019-05-30 14:05:41 +080053_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070054_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020055
Tarek Ziadéc3399782010-02-23 05:39:18 +000056__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
57 "copytree", "move", "rmtree", "Error", "SpecialFileError",
58 "ExecError", "make_archive", "get_archive_formats",
Tarek Ziadé6ac91722010-04-28 17:51:36 +000059 "register_archive_format", "unregister_archive_format",
60 "get_unpack_formats", "register_unpack_format",
Éric Araujoc5efe652011-08-21 14:30:00 +020061 "unregister_unpack_format", "unpack_archive",
Berker Peksag8083cd62014-11-01 11:04:06 +020062 "ignore_patterns", "chown", "which", "get_terminal_size",
63 "SameFileError"]
Éric Araujoe4d5b8e2011-08-08 16:51:11 +020064 # disk_usage is added later, if available on the platform
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000065
Andrew Svetlov3438fa42012-12-17 23:35:18 +020066class Error(OSError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000067 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000068
Hynek Schlawack48653762012-10-07 12:49:58 +020069class SameFileError(Error):
70 """Raised when source and destination are the same file."""
71
Andrew Svetlov3438fa42012-12-17 23:35:18 +020072class SpecialFileError(OSError):
Antoine Pitrou7fff0962009-05-01 21:09:44 +000073 """Raised when trying to do a kind of operation (e.g. copying) which is
74 not supported on a special file (e.g. a named pipe)"""
75
Andrew Svetlov3438fa42012-12-17 23:35:18 +020076class ExecError(OSError):
Tarek Ziadé396fad72010-02-23 05:30:31 +000077 """Raised when a command could not be executed"""
78
Andrew Svetlov3438fa42012-12-17 23:35:18 +020079class ReadError(OSError):
Tarek Ziadé6ac91722010-04-28 17:51:36 +000080 """Raised when an archive cannot be read"""
81
82class RegistryError(Exception):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030083 """Raised when a registry operation with the archiving
Raymond Hettinger15f44ab2016-08-30 10:47:49 -070084 and unpacking registries fails"""
Tarek Ziadé6ac91722010-04-28 17:51:36 +000085
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020086class _GiveupOnFastCopy(Exception):
87 """Raised as a signal to fallback on using raw read()/write()
88 file copy when fast-copy functions fail to do so.
89 """
Tarek Ziadé6ac91722010-04-28 17:51:36 +000090
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070091def _fastcopy_fcopyfile(fsrc, fdst, flags):
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020092 """Copy a regular file content or metadata by using high-performance
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070093 fcopyfile(3) syscall (macOS).
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020094 """
95 try:
96 infd = fsrc.fileno()
97 outfd = fdst.fileno()
98 except Exception as err:
99 raise _GiveupOnFastCopy(err) # not a regular file
100
101 try:
102 posix._fcopyfile(infd, outfd, flags)
103 except OSError as err:
104 err.filename = fsrc.name
105 err.filename2 = fdst.name
106 if err.errno in {errno.EINVAL, errno.ENOTSUP}:
107 raise _GiveupOnFastCopy(err)
108 else:
109 raise err from None
110
111def _fastcopy_sendfile(fsrc, fdst):
112 """Copy data from one regular mmap-like fd to another by using
113 high-performance sendfile(2) syscall.
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800114 This should work on Linux >= 2.6.33 only.
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200115 """
116 # Note: copyfileobj() is left alone in order to not introduce any
117 # unexpected breakage. Possible risks by using zero-copy calls
118 # in copyfileobj() are:
119 # - fdst cannot be open in "a"(ppend) mode
120 # - fsrc and fdst may be open in "t"(ext) mode
121 # - fsrc may be a BufferedReader (which hides unread data in a buffer),
122 # GzipFile (which decompresses data), HTTPResponse (which decodes
123 # chunks).
124 # - possibly others (e.g. encrypted fs/partition?)
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800125 global _USE_CP_SENDFILE
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200126 try:
127 infd = fsrc.fileno()
128 outfd = fdst.fileno()
129 except Exception as err:
130 raise _GiveupOnFastCopy(err) # not a regular file
131
132 # Hopefully the whole file will be copied in a single call.
133 # sendfile() is called in a loop 'till EOF is reached (0 return)
134 # so a bufsize smaller or bigger than the actual file size
135 # should not make any difference, also in case the file content
136 # changes while being copied.
137 try:
138 blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MB
139 except Exception:
140 blocksize = 2 ** 27 # 128MB
141
142 offset = 0
143 while True:
144 try:
145 sent = os.sendfile(outfd, infd, offset, blocksize)
146 except OSError as err:
147 # ...in oder to have a more informative exception.
148 err.filename = fsrc.name
149 err.filename2 = fdst.name
150
151 if err.errno == errno.ENOTSOCK:
152 # sendfile() on this platform (probably Linux < 2.6.33)
153 # does not support copies between regular files (only
154 # sockets).
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800155 _USE_CP_SENDFILE = False
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200156 raise _GiveupOnFastCopy(err)
157
158 if err.errno == errno.ENOSPC: # filesystem is full
159 raise err from None
160
161 # Give up on first call and if no data was copied.
162 if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0:
163 raise _GiveupOnFastCopy(err)
164
165 raise err
166 else:
167 if sent == 0:
168 break # EOF
169 offset += sent
170
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700171def _copyfileobj_readinto(fsrc, fdst, length=COPY_BUFSIZE):
172 """readinto()/memoryview() based variant of copyfileobj().
173 *fsrc* must support readinto() method and both files must be
174 open in binary mode.
175 """
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200176 # Localize variable access to minimize overhead.
177 fsrc_readinto = fsrc.readinto
178 fdst_write = fdst.write
179 with memoryview(bytearray(length)) as mv:
180 while True:
181 n = fsrc_readinto(mv)
182 if not n:
183 break
184 elif n < length:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700185 with mv[:n] as smv:
186 fdst.write(smv)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200187 else:
188 fdst_write(mv)
189
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800190def copyfileobj(fsrc, fdst, length=0):
Greg Stein42bb8b32000-07-12 09:55:30 +0000191 """copy data from file-like object fsrc to file-like object fdst"""
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700192 # Localize variable access to minimize overhead.
Giampaolo Rodola3b0abb02019-02-24 15:46:40 -0800193 if not length:
194 length = COPY_BUFSIZE
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700195 fsrc_read = fsrc.read
196 fdst_write = fdst.write
197 while True:
198 buf = fsrc_read(length)
199 if not buf:
200 break
201 fdst_write(buf)
Greg Stein42bb8b32000-07-12 09:55:30 +0000202
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000203def _samefile(src, dst):
204 # Macintosh, Unix.
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800205 if isinstance(src, os.DirEntry) and hasattr(os.path, 'samestat'):
206 try:
207 return os.path.samestat(src.stat(), os.stat(dst))
208 except OSError:
209 return False
210
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +0000211 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +0000212 try:
213 return os.path.samefile(src, dst)
214 except OSError:
215 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000216
217 # All other platforms: check for same pathname.
218 return (os.path.normcase(os.path.abspath(src)) ==
219 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +0000220
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800221def _stat(fn):
222 return fn.stat() if isinstance(fn, os.DirEntry) else os.stat(fn)
223
224def _islink(fn):
225 return fn.is_symlink() if isinstance(fn, os.DirEntry) else os.path.islink(fn)
226
Larry Hastingsb4038062012-07-15 10:57:38 -0700227def copyfile(src, dst, *, follow_symlinks=True):
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700228 """Copy data from src to dst in the most efficient way possible.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100229
Larry Hastingsb4038062012-07-15 10:57:38 -0700230 If follow_symlinks is not set and src is a symbolic link, a new
Antoine Pitrou78091e62011-12-29 18:54:15 +0100231 symlink will be created instead of copying the file it points to.
232
233 """
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000234 if _samefile(src, dst):
Hynek Schlawack48653762012-10-07 12:49:58 +0200235 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000236
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700237 file_size = 0
238 for i, fn in enumerate([src, dst]):
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000239 try:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800240 st = _stat(fn)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000241 except OSError:
242 # File most likely does not exist
243 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000244 else:
245 # XXX What about other special files? (sockets, devices...)
246 if stat.S_ISFIFO(st.st_mode):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800247 fn = fn.path if isinstance(fn, os.DirEntry) else fn
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000248 raise SpecialFileError("`%s` is a named pipe" % fn)
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700249 if _WINDOWS and i == 0:
250 file_size = st.st_size
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000251
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800252 if not follow_symlinks and _islink(src):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100253 os.symlink(os.readlink(src), dst)
254 else:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200255 with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700256 # macOS
257 if _HAS_FCOPYFILE:
258 try:
259 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
260 return dst
261 except _GiveupOnFastCopy:
262 pass
Giampaolo Rodola413d9552019-05-30 14:05:41 +0800263 # Linux
264 elif _USE_CP_SENDFILE:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200265 try:
266 _fastcopy_sendfile(fsrc, fdst)
267 return dst
268 except _GiveupOnFastCopy:
269 pass
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700270 # Windows, see:
271 # https://github.com/python/cpython/pull/7160#discussion_r195405230
272 elif _WINDOWS and file_size > 0:
273 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
274 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200275
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700276 copyfileobj(fsrc, fdst)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200277
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500278 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000279
Larry Hastingsb4038062012-07-15 10:57:38 -0700280def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100281 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000282
Larry Hastingsb4038062012-07-15 10:57:38 -0700283 If follow_symlinks is not set, symlinks aren't followed if and only
284 if both `src` and `dst` are symlinks. If `lchmod` isn't available
285 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100286
287 """
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800288 if not follow_symlinks and _islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100289 if hasattr(os, 'lchmod'):
290 stat_func, chmod_func = os.lstat, os.lchmod
291 else:
292 return
Antoine Pitrou78091e62011-12-29 18:54:15 +0100293 else:
Anthony Sottile8377cd42019-02-25 14:32:27 -0800294 stat_func, chmod_func = _stat, os.chmod
Antoine Pitrou78091e62011-12-29 18:54:15 +0100295
296 st = stat_func(src)
297 chmod_func(dst, stat.S_IMODE(st.st_mode))
298
Larry Hastingsad5ae042012-07-14 17:55:11 -0700299if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700300 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700301 """Copy extended filesystem attributes from `src` to `dst`.
302
303 Overwrite existing attributes.
304
Larry Hastingsb4038062012-07-15 10:57:38 -0700305 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700306
307 """
308
Hynek Schlawack0beab052013-02-05 08:22:44 +0100309 try:
310 names = os.listxattr(src, follow_symlinks=follow_symlinks)
311 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400312 if e.errno not in (errno.ENOTSUP, errno.ENODATA, errno.EINVAL):
Hynek Schlawack0beab052013-02-05 08:22:44 +0100313 raise
314 return
315 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700316 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700317 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
318 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700319 except OSError as e:
Ying Wanga16387a2019-05-29 23:25:31 -0400320 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
321 errno.EINVAL):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700322 raise
323else:
324 def _copyxattr(*args, **kwargs):
325 pass
326
Larry Hastingsb4038062012-07-15 10:57:38 -0700327def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200328 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100329
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200330 Copy the permission bits, last access time, last modification time, and
331 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
332 attributes" where possible. The file contents, owner, and group are
333 unaffected. `src` and `dst` are path names given as strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200335 If the optional flag `follow_symlinks` is not set, symlinks aren't
336 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100337 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700338 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100339 pass
340
Larry Hastings9cf065c2012-06-22 16:30:09 -0700341 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800342 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700343 if follow:
344 # use the real function if it exists
345 def lookup(name):
346 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100347 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700348 # use the real function only if it exists
349 # *and* it supports follow_symlinks
350 def lookup(name):
351 fn = getattr(os, name, _nop)
352 if fn in os.supports_follow_symlinks:
353 return fn
354 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100355
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800356 if isinstance(src, os.DirEntry):
357 st = src.stat(follow_symlinks=follow)
358 else:
359 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000360 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700361 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
362 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500363 # We must copy extended attributes before the file is (potentially)
364 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
365 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700366 try:
367 lookup("chmod")(dst, mode, follow_symlinks=follow)
368 except NotImplementedError:
369 # if we got a NotImplementedError, it's because
370 # * follow_symlinks=False,
371 # * lchown() is unavailable, and
372 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300373 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
375 # (it returned ENOSUP.)
376 # therefore we're out of options--we simply cannot chown the
377 # symlink. give up, suppress the error.
378 # (which is what shutil always did in this circumstance.)
379 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100380 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000381 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700382 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000383 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700384 for err in 'EOPNOTSUPP', 'ENOTSUP':
385 if hasattr(errno, err) and why.errno == getattr(errno, err):
386 break
387 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000388 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200389
Larry Hastingsb4038062012-07-15 10:57:38 -0700390def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500391 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000392
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000393 The destination may be a directory.
394
Larry Hastingsb4038062012-07-15 10:57:38 -0700395 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100396 resembles GNU's "cp -P src dst".
397
Hynek Schlawack48653762012-10-07 12:49:58 +0200398 If source and destination are the same file, a SameFileError will be
399 raised.
400
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000401 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000402 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000403 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700404 copyfile(src, dst, follow_symlinks=follow_symlinks)
405 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500406 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000407
Larry Hastingsb4038062012-07-15 10:57:38 -0700408def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200409 """Copy data and metadata. Return the file's destination.
410
411 Metadata is copied with copystat(). Please see the copystat function
412 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000413
414 The destination may be a directory.
415
Larry Hastingsb4038062012-07-15 10:57:38 -0700416 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100417 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000418 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000419 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000420 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700421 copyfile(src, dst, follow_symlinks=follow_symlinks)
422 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500423 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000424
Georg Brandl2ee470f2008-07-16 12:55:28 +0000425def ignore_patterns(*patterns):
426 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000427
Georg Brandl2ee470f2008-07-16 12:55:28 +0000428 Patterns is a sequence of glob-style patterns
429 that are used to exclude files"""
430 def _ignore_patterns(path, names):
431 ignored_names = []
432 for pattern in patterns:
433 ignored_names.extend(fnmatch.filter(names, pattern))
434 return set(ignored_names)
435 return _ignore_patterns
436
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800437def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500438 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800439 if ignore is not None:
440 ignored_names = ignore(src, set(os.listdir(src)))
441 else:
442 ignored_names = set()
443
jab9e00d9e2018-12-28 13:03:40 -0500444 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800445 errors = []
446 use_srcentry = copy_function is copy2 or copy_function is copy
447
448 for srcentry in entries:
449 if srcentry.name in ignored_names:
450 continue
451 srcname = os.path.join(src, srcentry.name)
452 dstname = os.path.join(dst, srcentry.name)
453 srcobj = srcentry if use_srcentry else srcname
454 try:
Steve Dower9eb3d542019-08-21 15:52:42 -0700455 is_symlink = srcentry.is_symlink()
456 if is_symlink and os.name == 'nt':
457 # Special check for directory junctions, which appear as
458 # symlinks but we want to recurse.
459 lstat = srcentry.stat(follow_symlinks=False)
460 if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
461 is_symlink = False
462 if is_symlink:
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800463 linkto = os.readlink(srcname)
464 if symlinks:
465 # We can't just leave it to `copy_function` because legacy
466 # code with a custom `copy_function` may rely on copytree
467 # doing the right thing.
468 os.symlink(linkto, dstname)
469 copystat(srcobj, dstname, follow_symlinks=not symlinks)
470 else:
471 # ignore dangling symlink if the flag is on
472 if not os.path.exists(linkto) and ignore_dangling_symlinks:
473 continue
jab9e00d9e2018-12-28 13:03:40 -0500474 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800475 if srcentry.is_dir():
476 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500477 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800478 else:
479 copy_function(srcobj, dstname)
480 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500481 copytree(srcobj, dstname, symlinks, ignore, copy_function,
482 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800483 else:
484 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100485 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800486 # catch the Error from the recursive copytree so that we can
487 # continue with other files
488 except Error as err:
489 errors.extend(err.args[0])
490 except OSError as why:
491 errors.append((srcname, dstname, str(why)))
492 try:
493 copystat(src, dst)
494 except OSError as why:
495 # Copying file access times may fail on Windows
496 if getattr(why, 'winerror', None) is None:
497 errors.append((src, dst, str(why)))
498 if errors:
499 raise Error(errors)
500 return dst
501
Tarek Ziadéfb437512010-04-20 08:57:33 +0000502def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500503 ignore_dangling_symlinks=False, dirs_exist_ok=False):
504 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000505
jab9e00d9e2018-12-28 13:03:40 -0500506 dirs_exist_ok dictates whether to raise an exception in case dst or any
507 missing parent directory already exists.
508
Neal Norwitza4c93b62003-02-23 21:36:32 +0000509 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000510
511 If the optional symlinks flag is true, symbolic links in the
512 source tree result in symbolic links in the destination tree; if
513 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000514 links are copied. If the file pointed by the symlink doesn't
515 exist, an exception will be added in the list of errors raised in
516 an Error exception at the end of the copy process.
517
518 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000519 want to silence this exception. Notice that this has no effect on
520 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000521
Georg Brandl2ee470f2008-07-16 12:55:28 +0000522 The optional ignore argument is a callable. If given, it
523 is called with the `src` parameter, which is the directory
524 being visited by copytree(), and `names` which is the list of
525 `src` contents, as returned by os.listdir():
526
527 callable(src, names) -> ignored_names
528
529 Since copytree() is called recursively, the callable will be
530 called once for each directory that is copied. It returns a
531 list of names relative to the `src` directory that should
532 not be copied.
533
Tarek Ziadé5340db32010-04-19 22:30:51 +0000534 The optional copy_function argument is a callable that will be used
535 to copy each file. It will be called with the source path and the
536 destination path as arguments. By default, copy2() is used, but any
537 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000538
539 """
Miss Islington (bot)8763d432019-06-24 09:09:47 -0700540 sys.audit("shutil.copytree", src, dst)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800541 with os.scandir(src) as entries:
542 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
543 ignore=ignore, copy_function=copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500544 ignore_dangling_symlinks=ignore_dangling_symlinks,
545 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000546
Steve Dower9eb3d542019-08-21 15:52:42 -0700547if hasattr(stat, 'FILE_ATTRIBUTE_REPARSE_POINT'):
548 # Special handling for directory junctions to make them behave like
549 # symlinks for shutil.rmtree, since in general they do not appear as
550 # regular links.
551 def _rmtree_isdir(entry):
552 try:
553 st = entry.stat(follow_symlinks=False)
554 return (stat.S_ISDIR(st.st_mode) and not
555 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
556 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
557 except OSError:
558 return False
559
560 def _rmtree_islink(path):
561 try:
562 st = os.lstat(path)
563 return (stat.S_ISLNK(st.st_mode) or
564 (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT
565 and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT))
566 except OSError:
567 return False
568else:
569 def _rmtree_isdir(entry):
570 try:
571 return entry.is_dir(follow_symlinks=False)
572 except OSError:
573 return False
574
575 def _rmtree_islink(path):
576 return os.path.islink(path)
577
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200578# version vulnerable to race conditions
579def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000580 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200581 with os.scandir(path) as scandir_it:
582 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000583 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200584 onerror(os.scandir, path, sys.exc_info())
585 entries = []
586 for entry in entries:
587 fullname = entry.path
Steve Dower9eb3d542019-08-21 15:52:42 -0700588 if _rmtree_isdir(entry):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200589 try:
590 if entry.is_symlink():
591 # This can only happen if someone replaces
592 # a directory with a symlink after the call to
593 # os.scandir or entry.is_dir above.
594 raise OSError("Cannot call rmtree on a symbolic link")
595 except OSError:
596 onerror(os.path.islink, fullname, sys.exc_info())
597 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200598 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000599 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000600 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200601 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200602 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200603 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000604 try:
605 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200606 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000607 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000608
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200609# Version using fd-based APIs to protect against races
610def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200611 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200612 with os.scandir(topfd) as scandir_it:
613 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100614 except OSError as err:
615 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200616 onerror(os.scandir, path, sys.exc_info())
617 return
618 for entry in entries:
619 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200620 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200621 is_dir = entry.is_dir(follow_symlinks=False)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100622 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200623 is_dir = False
Serhiy Storchakae9b51c02019-05-31 11:30:37 +0300624 else:
625 if is_dir:
626 try:
627 orig_st = entry.stat(follow_symlinks=False)
628 is_dir = stat.S_ISDIR(orig_st.st_mode)
629 except OSError:
630 onerror(os.lstat, fullname, sys.exc_info())
631 continue
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200632 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200633 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200634 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100635 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200636 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200637 else:
638 try:
639 if os.path.samestat(orig_st, os.fstat(dirfd)):
640 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200641 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200642 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100643 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200644 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100645 else:
646 try:
647 # This can only happen if someone replaces
648 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200649 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100650 raise OSError("Cannot call rmtree on a symbolic "
651 "link")
652 except OSError:
653 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200654 finally:
655 os.close(dirfd)
656 else:
657 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200658 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100659 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200660 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200661
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200662_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
663 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200664 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200665 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000666
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200667def rmtree(path, ignore_errors=False, onerror=None):
668 """Recursively delete a directory tree.
669
670 If ignore_errors is set, errors are ignored; otherwise, if onerror
671 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200672 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200673 path is the argument to that function that caused it to fail; and
674 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
675 is false and onerror is None, an exception is raised.
676
677 """
Miss Islington (bot)8763d432019-06-24 09:09:47 -0700678 sys.audit("shutil.rmtree", path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200679 if ignore_errors:
680 def onerror(*args):
681 pass
682 elif onerror is None:
683 def onerror(*args):
684 raise
685 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200686 # While the unsafe rmtree works fine on bytes, the fd based does not.
687 if isinstance(path, bytes):
688 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200689 # Note: To guard against symlink races, we use the standard
690 # lstat()/open()/fstat() trick.
691 try:
692 orig_st = os.lstat(path)
693 except Exception:
694 onerror(os.lstat, path, sys.exc_info())
695 return
696 try:
697 fd = os.open(path, os.O_RDONLY)
698 except Exception:
699 onerror(os.lstat, path, sys.exc_info())
700 return
701 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100702 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200703 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200704 try:
705 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200706 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200707 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200708 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100709 try:
710 # symlinks to directories are forbidden, see bug #1669
711 raise OSError("Cannot call rmtree on a symbolic link")
712 except OSError:
713 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200714 finally:
715 os.close(fd)
716 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200717 try:
Steve Dower9eb3d542019-08-21 15:52:42 -0700718 if _rmtree_islink(path):
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200719 # symlinks to directories are forbidden, see bug #1669
720 raise OSError("Cannot call rmtree on a symbolic link")
721 except OSError:
722 onerror(os.path.islink, path, sys.exc_info())
723 # can't continue even if onerror hook returns
724 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200725 return _rmtree_unsafe(path, onerror)
726
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000727# Allow introspection of whether or not the hardening against symlink
728# attacks is supported on the current platform
729rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000730
Christian Heimesada8c3b2008-03-18 18:26:33 +0000731def _basename(path):
732 # A basename() variant which first strips the trailing slash, if present.
733 # Thus we always get the last component of the path, even for directories.
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200734 sep = os.path.sep + (os.path.altsep or '')
735 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000736
R David Murray6ffface2014-06-11 14:40:13 -0400737def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000738 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500739 similar to the Unix "mv" command. Return the file or directory's
740 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000741
742 If the destination is a directory or a symlink to a directory, the source
743 is moved inside the directory. The destination path must not already
744 exist.
745
746 If the destination already exists but is not a directory, it may be
747 overwritten depending on os.rename() semantics.
748
749 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100750 Otherwise, src is copied to the destination and then removed. Symlinks are
751 recreated under the new name if os.rename() fails because of cross
752 filesystem renames.
753
R David Murray6ffface2014-06-11 14:40:13 -0400754 The optional `copy_function` argument is a callable that will be used
755 to copy the source or it will be delegated to `copytree`.
756 By default, copy2() is used, but any function that supports the same
757 signature (like copy()) can be used.
758
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000759 A lot more could be done here... A look at a mv.c shows a lot of
760 the issues this implementation glosses over.
761
762 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000763 real_dst = dst
764 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200765 if _samefile(src, dst):
766 # We might be on a case insensitive filesystem,
767 # perform the rename anyway.
768 os.rename(src, dst)
769 return
770
Christian Heimesada8c3b2008-03-18 18:26:33 +0000771 real_dst = os.path.join(dst, _basename(src))
772 if os.path.exists(real_dst):
773 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000774 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000775 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200776 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100777 if os.path.islink(src):
778 linkto = os.readlink(src)
779 os.symlink(linkto, real_dst)
780 os.unlink(src)
781 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000782 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400783 raise Error("Cannot move a directory '%s' into itself"
784 " '%s'." % (src, dst))
785 copytree(src, real_dst, copy_function=copy_function,
786 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000787 rmtree(src)
788 else:
R David Murray6ffface2014-06-11 14:40:13 -0400789 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000790 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500791 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000792
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000793def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300794 src = os.path.abspath(src)
795 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000796 if not src.endswith(os.path.sep):
797 src += os.path.sep
798 if not dst.endswith(os.path.sep):
799 dst += os.path.sep
800 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000801
802def _get_gid(name):
803 """Returns a gid, given a group name."""
804 if getgrnam is None or name is None:
805 return None
806 try:
807 result = getgrnam(name)
808 except KeyError:
809 result = None
810 if result is not None:
811 return result[2]
812 return None
813
814def _get_uid(name):
815 """Returns an uid, given a user name."""
816 if getpwnam is None or name is None:
817 return None
818 try:
819 result = getpwnam(name)
820 except KeyError:
821 result = None
822 if result is not None:
823 return result[2]
824 return None
825
826def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
827 owner=None, group=None, logger=None):
828 """Create a (possibly compressed) tar file from all the files under
829 'base_dir'.
830
Serhiy Storchaka11213772014-08-06 18:50:19 +0300831 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000832
833 'owner' and 'group' can be used to define an owner and a group for the
834 archive that is being built. If not provided, the current owner and group
835 will be used.
836
Éric Araujo4433a5f2010-12-15 20:26:30 +0000837 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300838 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000839
840 Returns the output filename.
841 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200842 if compress is None:
843 tar_compression = ''
844 elif _ZLIB_SUPPORTED and compress == 'gzip':
845 tar_compression = 'gz'
846 elif _BZ2_SUPPORTED and compress == 'bzip2':
847 tar_compression = 'bz2'
848 elif _LZMA_SUPPORTED and compress == 'xz':
849 tar_compression = 'xz'
850 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000851 raise ValueError("bad value for 'compress', or compression format not "
852 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000853
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200854 import tarfile # late import for breaking circular dependency
855
856 compress_ext = '.' + tar_compression if compress else ''
857 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000858 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000859
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200860 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000861 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200862 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000863 if not dry_run:
864 os.makedirs(archive_dir)
865
Tarek Ziadé396fad72010-02-23 05:30:31 +0000866 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000867 if logger is not None:
868 logger.info('Creating tar archive')
869
870 uid = _get_uid(owner)
871 gid = _get_gid(group)
872
873 def _set_uid_gid(tarinfo):
874 if gid is not None:
875 tarinfo.gid = gid
876 tarinfo.gname = group
877 if uid is not None:
878 tarinfo.uid = uid
879 tarinfo.uname = owner
880 return tarinfo
881
882 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200883 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000884 try:
885 tar.add(base_dir, filter=_set_uid_gid)
886 finally:
887 tar.close()
888
Tarek Ziadé396fad72010-02-23 05:30:31 +0000889 return archive_name
890
Tarek Ziadé396fad72010-02-23 05:30:31 +0000891def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
892 """Create a zip file from all the files under 'base_dir'.
893
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200894 The output zip file will be named 'base_name' + ".zip". Returns the
895 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000896 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200897 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400898
Tarek Ziadé396fad72010-02-23 05:30:31 +0000899 zip_filename = base_name + ".zip"
900 archive_dir = os.path.dirname(base_name)
901
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200902 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000903 if logger is not None:
904 logger.info("creating %s", archive_dir)
905 if not dry_run:
906 os.makedirs(archive_dir)
907
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400908 if logger is not None:
909 logger.info("creating '%s' and adding '%s' to it",
910 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000911
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400912 if not dry_run:
913 with zipfile.ZipFile(zip_filename, "w",
914 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300915 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300916 if path != os.curdir:
917 zf.write(path, path)
918 if logger is not None:
919 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400920 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300921 for name in sorted(dirnames):
922 path = os.path.normpath(os.path.join(dirpath, name))
923 zf.write(path, path)
924 if logger is not None:
925 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400926 for name in filenames:
927 path = os.path.normpath(os.path.join(dirpath, name))
928 if os.path.isfile(path):
929 zf.write(path, path)
930 if logger is not None:
931 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932
933 return zip_filename
934
935_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000936 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200937}
938
939if _ZLIB_SUPPORTED:
940 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
941 "gzip'ed tar-file")
942 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000943
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000944if _BZ2_SUPPORTED:
945 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
946 "bzip2'ed tar-file")
947
Serhiy Storchaka11213772014-08-06 18:50:19 +0300948if _LZMA_SUPPORTED:
949 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
950 "xz'ed tar-file")
951
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952def get_archive_formats():
953 """Returns a list of supported formats for archiving and unarchiving.
954
955 Each element of the returned sequence is a tuple (name, description)
956 """
957 formats = [(name, registry[2]) for name, registry in
958 _ARCHIVE_FORMATS.items()]
959 formats.sort()
960 return formats
961
962def register_archive_format(name, function, extra_args=None, description=''):
963 """Registers an archive format.
964
965 name is the name of the format. function is the callable that will be
966 used to create archives. If provided, extra_args is a sequence of
967 (name, value) tuples that will be passed as arguments to the callable.
968 description can be provided to describe the format, and will be returned
969 by the get_archive_formats() function.
970 """
971 if extra_args is None:
972 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200973 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000974 raise TypeError('The %s object is not callable' % function)
975 if not isinstance(extra_args, (tuple, list)):
976 raise TypeError('extra_args needs to be a sequence')
977 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200978 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000979 raise TypeError('extra_args elements are : (arg_name, value)')
980
981 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
982
983def unregister_archive_format(name):
984 del _ARCHIVE_FORMATS[name]
985
986def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
987 dry_run=0, owner=None, group=None, logger=None):
988 """Create an archive file (eg. zip or tar).
989
990 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200991 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
992 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993
994 'root_dir' is a directory that will be the root directory of the
995 archive; ie. we typically chdir into 'root_dir' before creating the
996 archive. 'base_dir' is the directory where we start archiving from;
997 ie. 'base_dir' will be the common prefix of all files and
998 directories in the archive. 'root_dir' and 'base_dir' both default
999 to the current directory. Returns the name of the archive file.
1000
1001 'owner' and 'group' are used when creating a tar archive. By default,
1002 uses the current owner and group.
1003 """
Miss Islington (bot)8763d432019-06-24 09:09:47 -07001004 sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005 save_cwd = os.getcwd()
1006 if root_dir is not None:
1007 if logger is not None:
1008 logger.debug("changing into '%s'", root_dir)
1009 base_name = os.path.abspath(base_name)
1010 if not dry_run:
1011 os.chdir(root_dir)
1012
1013 if base_dir is None:
1014 base_dir = os.curdir
1015
1016 kwargs = {'dry_run': dry_run, 'logger': logger}
1017
1018 try:
1019 format_info = _ARCHIVE_FORMATS[format]
1020 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001021 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +00001022
1023 func = format_info[0]
1024 for arg, val in format_info[1]:
1025 kwargs[arg] = val
1026
1027 if format != 'zip':
1028 kwargs['owner'] = owner
1029 kwargs['group'] = group
1030
1031 try:
1032 filename = func(base_name, base_dir, **kwargs)
1033 finally:
1034 if root_dir is not None:
1035 if logger is not None:
1036 logger.debug("changing back to '%s'", save_cwd)
1037 os.chdir(save_cwd)
1038
1039 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001040
1041
1042def get_unpack_formats():
1043 """Returns a list of supported formats for unpacking.
1044
1045 Each element of the returned sequence is a tuple
1046 (name, extensions, description)
1047 """
1048 formats = [(name, info[0], info[3]) for name, info in
1049 _UNPACK_FORMATS.items()]
1050 formats.sort()
1051 return formats
1052
1053def _check_unpack_options(extensions, function, extra_args):
1054 """Checks what gets registered as an unpacker."""
1055 # first make sure no other unpacker is registered for this extension
1056 existing_extensions = {}
1057 for name, info in _UNPACK_FORMATS.items():
1058 for ext in info[0]:
1059 existing_extensions[ext] = name
1060
1061 for extension in extensions:
1062 if extension in existing_extensions:
1063 msg = '%s is already registered for "%s"'
1064 raise RegistryError(msg % (extension,
1065 existing_extensions[extension]))
1066
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001067 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001068 raise TypeError('The registered function must be a callable')
1069
1070
1071def register_unpack_format(name, extensions, function, extra_args=None,
1072 description=''):
1073 """Registers an unpack format.
1074
1075 `name` is the name of the format. `extensions` is a list of extensions
1076 corresponding to the format.
1077
1078 `function` is the callable that will be
1079 used to unpack archives. The callable will receive archives to unpack.
1080 If it's unable to handle an archive, it needs to raise a ReadError
1081 exception.
1082
1083 If provided, `extra_args` is a sequence of
1084 (name, value) tuples that will be passed as arguments to the callable.
1085 description can be provided to describe the format, and will be returned
1086 by the get_unpack_formats() function.
1087 """
1088 if extra_args is None:
1089 extra_args = []
1090 _check_unpack_options(extensions, function, extra_args)
1091 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1092
1093def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001094 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001095 del _UNPACK_FORMATS[name]
1096
1097def _ensure_directory(path):
1098 """Ensure that the parent directory of `path` exists"""
1099 dirname = os.path.dirname(path)
1100 if not os.path.isdir(dirname):
1101 os.makedirs(dirname)
1102
1103def _unpack_zipfile(filename, extract_dir):
1104 """Unpack zip `filename` to `extract_dir`
1105 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001106 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001107
1108 if not zipfile.is_zipfile(filename):
1109 raise ReadError("%s is not a zip file" % filename)
1110
1111 zip = zipfile.ZipFile(filename)
1112 try:
1113 for info in zip.infolist():
1114 name = info.filename
1115
1116 # don't extract absolute paths or ones with .. in them
1117 if name.startswith('/') or '..' in name:
1118 continue
1119
1120 target = os.path.join(extract_dir, *name.split('/'))
1121 if not target:
1122 continue
1123
1124 _ensure_directory(target)
1125 if not name.endswith('/'):
1126 # file
1127 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001128 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001129 try:
1130 f.write(data)
1131 finally:
1132 f.close()
1133 del data
1134 finally:
1135 zip.close()
1136
1137def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001138 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001139 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001140 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001141 try:
1142 tarobj = tarfile.open(filename)
1143 except tarfile.TarError:
1144 raise ReadError(
1145 "%s is not a compressed or uncompressed tar file" % filename)
1146 try:
1147 tarobj.extractall(extract_dir)
1148 finally:
1149 tarobj.close()
1150
1151_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001152 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001153 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1154}
1155
1156if _ZLIB_SUPPORTED:
1157 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1158 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001159
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001160if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001161 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001162 "bzip2'ed tar-file")
1163
Serhiy Storchaka11213772014-08-06 18:50:19 +03001164if _LZMA_SUPPORTED:
1165 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1166 "xz'ed tar-file")
1167
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001168def _find_unpack_format(filename):
1169 for name, info in _UNPACK_FORMATS.items():
1170 for extension in info[0]:
1171 if filename.endswith(extension):
1172 return name
1173 return None
1174
1175def unpack_archive(filename, extract_dir=None, format=None):
1176 """Unpack an archive.
1177
1178 `filename` is the name of the archive.
1179
1180 `extract_dir` is the name of the target directory, where the archive
1181 is unpacked. If not provided, the current working directory is used.
1182
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001183 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1184 or "xztar". Or any other registered format. If not provided,
1185 unpack_archive will use the filename extension and see if an unpacker
1186 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001187
1188 In case none is found, a ValueError is raised.
1189 """
1190 if extract_dir is None:
1191 extract_dir = os.getcwd()
1192
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001193 extract_dir = os.fspath(extract_dir)
1194 filename = os.fspath(filename)
1195
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001196 if format is not None:
1197 try:
1198 format_info = _UNPACK_FORMATS[format]
1199 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001200 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001201
Nick Coghlanabf202d2011-03-16 13:52:20 -04001202 func = format_info[1]
1203 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001204 else:
1205 # we need to look at the registered unpackers supported extensions
1206 format = _find_unpack_format(filename)
1207 if format is None:
1208 raise ReadError("Unknown archive format '{0}'".format(filename))
1209
1210 func = _UNPACK_FORMATS[format][1]
1211 kwargs = dict(_UNPACK_FORMATS[format][2])
1212 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001213
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001214
1215if hasattr(os, 'statvfs'):
1216
1217 __all__.append('disk_usage')
1218 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001219 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1220 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1221 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001222
1223 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001224 """Return disk usage statistics about the given path.
1225
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001226 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001227 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001228 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001229 st = os.statvfs(path)
1230 free = st.f_bavail * st.f_frsize
1231 total = st.f_blocks * st.f_frsize
1232 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1233 return _ntuple_diskusage(total, used, free)
1234
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001235elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001236
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001237 __all__.append('disk_usage')
1238 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1239
1240 def disk_usage(path):
1241 """Return disk usage statistics about the given path.
1242
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001243 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001244 'free', which are the amount of total, used and free space, in bytes.
1245 """
1246 total, free = nt._getdiskusage(path)
1247 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001248 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001249
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001250
Sandro Tosid902a142011-08-22 23:28:27 +02001251def chown(path, user=None, group=None):
1252 """Change owner user and group of the given path.
1253
1254 user and group can be the uid/gid or the user/group names, and in that case,
1255 they are converted to their respective uid/gid.
1256 """
1257
1258 if user is None and group is None:
1259 raise ValueError("user and/or group must be set")
1260
1261 _user = user
1262 _group = group
1263
1264 # -1 means don't change it
1265 if user is None:
1266 _user = -1
1267 # user can either be an int (the uid) or a string (the system username)
1268 elif isinstance(user, str):
1269 _user = _get_uid(user)
1270 if _user is None:
1271 raise LookupError("no such user: {!r}".format(user))
1272
1273 if group is None:
1274 _group = -1
1275 elif not isinstance(group, int):
1276 _group = _get_gid(group)
1277 if _group is None:
1278 raise LookupError("no such group: {!r}".format(group))
1279
1280 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001281
1282def get_terminal_size(fallback=(80, 24)):
1283 """Get the size of the terminal window.
1284
1285 For each of the two dimensions, the environment variable, COLUMNS
1286 and LINES respectively, is checked. If the variable is defined and
1287 the value is a positive integer, it is used.
1288
1289 When COLUMNS or LINES is not defined, which is the common case,
1290 the terminal connected to sys.__stdout__ is queried
1291 by invoking os.get_terminal_size.
1292
1293 If the terminal size cannot be successfully queried, either because
1294 the system doesn't support querying, or because we are not
1295 connected to a terminal, the value given in fallback parameter
1296 is used. Fallback defaults to (80, 24) which is the default
1297 size used by many terminal emulators.
1298
1299 The value returned is a named tuple of type os.terminal_size.
1300 """
1301 # columns, lines are the working values
1302 try:
1303 columns = int(os.environ['COLUMNS'])
1304 except (KeyError, ValueError):
1305 columns = 0
1306
1307 try:
1308 lines = int(os.environ['LINES'])
1309 except (KeyError, ValueError):
1310 lines = 0
1311
1312 # only query if necessary
1313 if columns <= 0 or lines <= 0:
1314 try:
1315 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001316 except (AttributeError, ValueError, OSError):
1317 # stdout is None, closed, detached, or not a terminal, or
1318 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001319 size = os.terminal_size(fallback)
1320 if columns <= 0:
1321 columns = size.columns
1322 if lines <= 0:
1323 lines = size.lines
1324
1325 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001326
Cheryl Sabella5680f652019-02-13 06:25:10 -05001327
1328# Check that a given file can be accessed with the correct mode.
1329# Additionally check that `file` is not a directory, as on Windows
1330# directories pass the os.access check.
1331def _access_check(fn, mode):
1332 return (os.path.exists(fn) and os.access(fn, mode)
1333 and not os.path.isdir(fn))
1334
1335
Brian Curtinc57a3452012-06-22 16:00:30 -05001336def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001337 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001338 conforms to the given mode on the PATH, or None if there is no such
1339 file.
1340
1341 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1342 of os.environ.get("PATH"), or can be overridden with a custom search
1343 path.
1344
1345 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001346 # If we're given a path with a directory part, look it up directly rather
1347 # than referring to PATH directories. This includes checking relative to the
1348 # current directory, e.g. ./script
1349 if os.path.dirname(cmd):
1350 if _access_check(cmd, mode):
1351 return cmd
1352 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001353
Cheryl Sabella5680f652019-02-13 06:25:10 -05001354 use_bytes = isinstance(cmd, bytes)
1355
Barry Warsaw618738b2013-04-16 11:05:03 -04001356 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001357 path = os.environ.get("PATH", None)
1358 if path is None:
1359 try:
1360 path = os.confstr("CS_PATH")
1361 except (AttributeError, ValueError):
1362 # os.confstr() or CS_PATH is not available
1363 path = os.defpath
1364 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001365 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001366
1367 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001368 if not path:
1369 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001370
Cheryl Sabella5680f652019-02-13 06:25:10 -05001371 if use_bytes:
1372 path = os.fsencode(path)
1373 path = path.split(os.fsencode(os.pathsep))
1374 else:
1375 path = os.fsdecode(path)
1376 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001377
1378 if sys.platform == "win32":
1379 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001380 curdir = os.curdir
1381 if use_bytes:
1382 curdir = os.fsencode(curdir)
1383 if curdir not in path:
1384 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001385
1386 # PATHEXT is necessary to check on Windows.
1387 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
Cheryl Sabella5680f652019-02-13 06:25:10 -05001388 if use_bytes:
1389 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001390 # See if the given file matches any of the expected path extensions.
1391 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001392 # If it does match, only test that one, otherwise we have to try
1393 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001394 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1395 files = [cmd]
1396 else:
1397 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001398 else:
1399 # On other platforms you don't have things like PATHEXT to tell you
1400 # what file suffixes are executable, so just pass on cmd as-is.
1401 files = [cmd]
1402
1403 seen = set()
1404 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001405 normdir = os.path.normcase(dir)
1406 if not normdir in seen:
1407 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001408 for thefile in files:
1409 name = os.path.join(dir, thefile)
1410 if _access_check(name, mode):
1411 return name
1412 return None