blob: b2e8f5fd759bc6e6adef2160534a80302aa2a431 [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 Rodola4a172cc2018-06-12 23:04:50 +020053_HAS_SENDFILE = posix and hasattr(os, "sendfile")
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.
114 This should work on Linux >= 2.6.33 and Solaris only.
115 """
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?)
125 global _HAS_SENDFILE
126 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).
155 _HAS_SENDFILE = False
156 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
263 # Linux / Solaris
264 elif _HAS_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:
312 if e.errno not in (errno.ENOTSUP, errno.ENODATA):
313 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:
320 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
321 raise
322else:
323 def _copyxattr(*args, **kwargs):
324 pass
325
Larry Hastingsb4038062012-07-15 10:57:38 -0700326def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200327 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100328
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200329 Copy the permission bits, last access time, last modification time, and
330 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
331 attributes" where possible. The file contents, owner, and group are
332 unaffected. `src` and `dst` are path names given as strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200334 If the optional flag `follow_symlinks` is not set, symlinks aren't
335 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100336 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700337 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100338 pass
339
Larry Hastings9cf065c2012-06-22 16:30:09 -0700340 # follow symlinks (aka don't not follow symlinks)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800341 follow = follow_symlinks or not (_islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700342 if follow:
343 # use the real function if it exists
344 def lookup(name):
345 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700347 # use the real function only if it exists
348 # *and* it supports follow_symlinks
349 def lookup(name):
350 fn = getattr(os, name, _nop)
351 if fn in os.supports_follow_symlinks:
352 return fn
353 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100354
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800355 if isinstance(src, os.DirEntry):
356 st = src.stat(follow_symlinks=follow)
357 else:
358 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000359 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700360 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
361 follow_symlinks=follow)
Olexa Bilaniuk79efbb72019-05-09 22:22:06 -0500362 # We must copy extended attributes before the file is (potentially)
363 # chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
364 _copyxattr(src, dst, follow_symlinks=follow)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700365 try:
366 lookup("chmod")(dst, mode, follow_symlinks=follow)
367 except NotImplementedError:
368 # if we got a NotImplementedError, it's because
369 # * follow_symlinks=False,
370 # * lchown() is unavailable, and
371 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300372 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700373 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
374 # (it returned ENOSUP.)
375 # therefore we're out of options--we simply cannot chown the
376 # symlink. give up, suppress the error.
377 # (which is what shutil always did in this circumstance.)
378 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100379 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000380 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700381 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000382 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700383 for err in 'EOPNOTSUPP', 'ENOTSUP':
384 if hasattr(errno, err) and why.errno == getattr(errno, err):
385 break
386 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000387 raise
Antoine Pitrou424246f2012-05-12 19:02:01 +0200388
Larry Hastingsb4038062012-07-15 10:57:38 -0700389def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500390 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000391
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000392 The destination may be a directory.
393
Larry Hastingsb4038062012-07-15 10:57:38 -0700394 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100395 resembles GNU's "cp -P src dst".
396
Hynek Schlawack48653762012-10-07 12:49:58 +0200397 If source and destination are the same file, a SameFileError will be
398 raised.
399
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000400 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000401 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000402 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700403 copyfile(src, dst, follow_symlinks=follow_symlinks)
404 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500405 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000406
Larry Hastingsb4038062012-07-15 10:57:38 -0700407def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200408 """Copy data and metadata. Return the file's destination.
409
410 Metadata is copied with copystat(). Please see the copystat function
411 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000412
413 The destination may be a directory.
414
Larry Hastingsb4038062012-07-15 10:57:38 -0700415 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100416 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000417 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000418 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700420 copyfile(src, dst, follow_symlinks=follow_symlinks)
421 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500422 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000423
Georg Brandl2ee470f2008-07-16 12:55:28 +0000424def ignore_patterns(*patterns):
425 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000426
Georg Brandl2ee470f2008-07-16 12:55:28 +0000427 Patterns is a sequence of glob-style patterns
428 that are used to exclude files"""
429 def _ignore_patterns(path, names):
430 ignored_names = []
431 for pattern in patterns:
432 ignored_names.extend(fnmatch.filter(names, pattern))
433 return set(ignored_names)
434 return _ignore_patterns
435
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800436def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500437 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800438 if ignore is not None:
439 ignored_names = ignore(src, set(os.listdir(src)))
440 else:
441 ignored_names = set()
442
jab9e00d9e2018-12-28 13:03:40 -0500443 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800444 errors = []
445 use_srcentry = copy_function is copy2 or copy_function is copy
446
447 for srcentry in entries:
448 if srcentry.name in ignored_names:
449 continue
450 srcname = os.path.join(src, srcentry.name)
451 dstname = os.path.join(dst, srcentry.name)
452 srcobj = srcentry if use_srcentry else srcname
453 try:
454 if srcentry.is_symlink():
455 linkto = os.readlink(srcname)
456 if symlinks:
457 # We can't just leave it to `copy_function` because legacy
458 # code with a custom `copy_function` may rely on copytree
459 # doing the right thing.
460 os.symlink(linkto, dstname)
461 copystat(srcobj, dstname, follow_symlinks=not symlinks)
462 else:
463 # ignore dangling symlink if the flag is on
464 if not os.path.exists(linkto) and ignore_dangling_symlinks:
465 continue
jab9e00d9e2018-12-28 13:03:40 -0500466 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800467 if srcentry.is_dir():
468 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500469 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800470 else:
471 copy_function(srcobj, dstname)
472 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500473 copytree(srcobj, dstname, symlinks, ignore, copy_function,
474 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800475 else:
476 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100477 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800478 # catch the Error from the recursive copytree so that we can
479 # continue with other files
480 except Error as err:
481 errors.extend(err.args[0])
482 except OSError as why:
483 errors.append((srcname, dstname, str(why)))
484 try:
485 copystat(src, dst)
486 except OSError as why:
487 # Copying file access times may fail on Windows
488 if getattr(why, 'winerror', None) is None:
489 errors.append((src, dst, str(why)))
490 if errors:
491 raise Error(errors)
492 return dst
493
Tarek Ziadéfb437512010-04-20 08:57:33 +0000494def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500495 ignore_dangling_symlinks=False, dirs_exist_ok=False):
496 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000497
jab9e00d9e2018-12-28 13:03:40 -0500498 dirs_exist_ok dictates whether to raise an exception in case dst or any
499 missing parent directory already exists.
500
Neal Norwitza4c93b62003-02-23 21:36:32 +0000501 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000502
503 If the optional symlinks flag is true, symbolic links in the
504 source tree result in symbolic links in the destination tree; if
505 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000506 links are copied. If the file pointed by the symlink doesn't
507 exist, an exception will be added in the list of errors raised in
508 an Error exception at the end of the copy process.
509
510 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000511 want to silence this exception. Notice that this has no effect on
512 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000513
Georg Brandl2ee470f2008-07-16 12:55:28 +0000514 The optional ignore argument is a callable. If given, it
515 is called with the `src` parameter, which is the directory
516 being visited by copytree(), and `names` which is the list of
517 `src` contents, as returned by os.listdir():
518
519 callable(src, names) -> ignored_names
520
521 Since copytree() is called recursively, the callable will be
522 called once for each directory that is copied. It returns a
523 list of names relative to the `src` directory that should
524 not be copied.
525
Tarek Ziadé5340db32010-04-19 22:30:51 +0000526 The optional copy_function argument is a callable that will be used
527 to copy each file. It will be called with the source path and the
528 destination path as arguments. By default, copy2() is used, but any
529 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000530
531 """
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800532 with os.scandir(src) as entries:
533 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
534 ignore=ignore, copy_function=copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500535 ignore_dangling_symlinks=ignore_dangling_symlinks,
536 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000537
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200538# version vulnerable to race conditions
539def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000540 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200541 with os.scandir(path) as scandir_it:
542 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000543 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200544 onerror(os.scandir, path, sys.exc_info())
545 entries = []
546 for entry in entries:
547 fullname = entry.path
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000548 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200549 is_dir = entry.is_dir(follow_symlinks=False)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200550 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200551 is_dir = False
552 if is_dir:
553 try:
554 if entry.is_symlink():
555 # This can only happen if someone replaces
556 # a directory with a symlink after the call to
557 # os.scandir or entry.is_dir above.
558 raise OSError("Cannot call rmtree on a symbolic link")
559 except OSError:
560 onerror(os.path.islink, fullname, sys.exc_info())
561 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200562 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000563 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000564 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200565 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200566 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200567 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000568 try:
569 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200570 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000571 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000572
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200573# Version using fd-based APIs to protect against races
574def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200575 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200576 with os.scandir(topfd) as scandir_it:
577 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100578 except OSError as err:
579 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200580 onerror(os.scandir, path, sys.exc_info())
581 return
582 for entry in entries:
583 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200584 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200585 is_dir = entry.is_dir(follow_symlinks=False)
586 if is_dir:
587 orig_st = entry.stat(follow_symlinks=False)
588 is_dir = stat.S_ISDIR(orig_st.st_mode)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100589 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200590 is_dir = False
591 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200592 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200593 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100594 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200595 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200596 else:
597 try:
598 if os.path.samestat(orig_st, os.fstat(dirfd)):
599 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200600 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200601 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100602 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200603 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100604 else:
605 try:
606 # This can only happen if someone replaces
607 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200608 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100609 raise OSError("Cannot call rmtree on a symbolic "
610 "link")
611 except OSError:
612 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200613 finally:
614 os.close(dirfd)
615 else:
616 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200617 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100618 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200619 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200620
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200621_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
622 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200623 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200624 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000625
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200626def rmtree(path, ignore_errors=False, onerror=None):
627 """Recursively delete a directory tree.
628
629 If ignore_errors is set, errors are ignored; otherwise, if onerror
630 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200631 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200632 path is the argument to that function that caused it to fail; and
633 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
634 is false and onerror is None, an exception is raised.
635
636 """
637 if ignore_errors:
638 def onerror(*args):
639 pass
640 elif onerror is None:
641 def onerror(*args):
642 raise
643 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200644 # While the unsafe rmtree works fine on bytes, the fd based does not.
645 if isinstance(path, bytes):
646 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200647 # Note: To guard against symlink races, we use the standard
648 # lstat()/open()/fstat() trick.
649 try:
650 orig_st = os.lstat(path)
651 except Exception:
652 onerror(os.lstat, path, sys.exc_info())
653 return
654 try:
655 fd = os.open(path, os.O_RDONLY)
656 except Exception:
657 onerror(os.lstat, path, sys.exc_info())
658 return
659 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100660 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200661 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200662 try:
663 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200664 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200665 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200666 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100667 try:
668 # symlinks to directories are forbidden, see bug #1669
669 raise OSError("Cannot call rmtree on a symbolic link")
670 except OSError:
671 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200672 finally:
673 os.close(fd)
674 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200675 try:
676 if os.path.islink(path):
677 # symlinks to directories are forbidden, see bug #1669
678 raise OSError("Cannot call rmtree on a symbolic link")
679 except OSError:
680 onerror(os.path.islink, path, sys.exc_info())
681 # can't continue even if onerror hook returns
682 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200683 return _rmtree_unsafe(path, onerror)
684
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000685# Allow introspection of whether or not the hardening against symlink
686# attacks is supported on the current platform
687rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000688
Christian Heimesada8c3b2008-03-18 18:26:33 +0000689def _basename(path):
690 # A basename() variant which first strips the trailing slash, if present.
691 # Thus we always get the last component of the path, even for directories.
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200692 sep = os.path.sep + (os.path.altsep or '')
693 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000694
R David Murray6ffface2014-06-11 14:40:13 -0400695def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000696 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500697 similar to the Unix "mv" command. Return the file or directory's
698 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000699
700 If the destination is a directory or a symlink to a directory, the source
701 is moved inside the directory. The destination path must not already
702 exist.
703
704 If the destination already exists but is not a directory, it may be
705 overwritten depending on os.rename() semantics.
706
707 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100708 Otherwise, src is copied to the destination and then removed. Symlinks are
709 recreated under the new name if os.rename() fails because of cross
710 filesystem renames.
711
R David Murray6ffface2014-06-11 14:40:13 -0400712 The optional `copy_function` argument is a callable that will be used
713 to copy the source or it will be delegated to `copytree`.
714 By default, copy2() is used, but any function that supports the same
715 signature (like copy()) can be used.
716
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000717 A lot more could be done here... A look at a mv.c shows a lot of
718 the issues this implementation glosses over.
719
720 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000721 real_dst = dst
722 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200723 if _samefile(src, dst):
724 # We might be on a case insensitive filesystem,
725 # perform the rename anyway.
726 os.rename(src, dst)
727 return
728
Christian Heimesada8c3b2008-03-18 18:26:33 +0000729 real_dst = os.path.join(dst, _basename(src))
730 if os.path.exists(real_dst):
731 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000732 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000733 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200734 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100735 if os.path.islink(src):
736 linkto = os.readlink(src)
737 os.symlink(linkto, real_dst)
738 os.unlink(src)
739 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000740 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400741 raise Error("Cannot move a directory '%s' into itself"
742 " '%s'." % (src, dst))
743 copytree(src, real_dst, copy_function=copy_function,
744 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000745 rmtree(src)
746 else:
R David Murray6ffface2014-06-11 14:40:13 -0400747 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000748 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500749 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000750
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000751def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300752 src = os.path.abspath(src)
753 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000754 if not src.endswith(os.path.sep):
755 src += os.path.sep
756 if not dst.endswith(os.path.sep):
757 dst += os.path.sep
758 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000759
760def _get_gid(name):
761 """Returns a gid, given a group name."""
762 if getgrnam is None or name is None:
763 return None
764 try:
765 result = getgrnam(name)
766 except KeyError:
767 result = None
768 if result is not None:
769 return result[2]
770 return None
771
772def _get_uid(name):
773 """Returns an uid, given a user name."""
774 if getpwnam is None or name is None:
775 return None
776 try:
777 result = getpwnam(name)
778 except KeyError:
779 result = None
780 if result is not None:
781 return result[2]
782 return None
783
784def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
785 owner=None, group=None, logger=None):
786 """Create a (possibly compressed) tar file from all the files under
787 'base_dir'.
788
Serhiy Storchaka11213772014-08-06 18:50:19 +0300789 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000790
791 'owner' and 'group' can be used to define an owner and a group for the
792 archive that is being built. If not provided, the current owner and group
793 will be used.
794
Éric Araujo4433a5f2010-12-15 20:26:30 +0000795 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300796 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000797
798 Returns the output filename.
799 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200800 if compress is None:
801 tar_compression = ''
802 elif _ZLIB_SUPPORTED and compress == 'gzip':
803 tar_compression = 'gz'
804 elif _BZ2_SUPPORTED and compress == 'bzip2':
805 tar_compression = 'bz2'
806 elif _LZMA_SUPPORTED and compress == 'xz':
807 tar_compression = 'xz'
808 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000809 raise ValueError("bad value for 'compress', or compression format not "
810 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000811
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200812 import tarfile # late import for breaking circular dependency
813
814 compress_ext = '.' + tar_compression if compress else ''
815 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000816 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000817
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200818 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000819 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200820 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000821 if not dry_run:
822 os.makedirs(archive_dir)
823
Tarek Ziadé396fad72010-02-23 05:30:31 +0000824 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000825 if logger is not None:
826 logger.info('Creating tar archive')
827
828 uid = _get_uid(owner)
829 gid = _get_gid(group)
830
831 def _set_uid_gid(tarinfo):
832 if gid is not None:
833 tarinfo.gid = gid
834 tarinfo.gname = group
835 if uid is not None:
836 tarinfo.uid = uid
837 tarinfo.uname = owner
838 return tarinfo
839
840 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200841 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000842 try:
843 tar.add(base_dir, filter=_set_uid_gid)
844 finally:
845 tar.close()
846
Tarek Ziadé396fad72010-02-23 05:30:31 +0000847 return archive_name
848
Tarek Ziadé396fad72010-02-23 05:30:31 +0000849def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
850 """Create a zip file from all the files under 'base_dir'.
851
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200852 The output zip file will be named 'base_name' + ".zip". Returns the
853 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000854 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200855 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400856
Tarek Ziadé396fad72010-02-23 05:30:31 +0000857 zip_filename = base_name + ".zip"
858 archive_dir = os.path.dirname(base_name)
859
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200860 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000861 if logger is not None:
862 logger.info("creating %s", archive_dir)
863 if not dry_run:
864 os.makedirs(archive_dir)
865
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400866 if logger is not None:
867 logger.info("creating '%s' and adding '%s' to it",
868 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000869
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400870 if not dry_run:
871 with zipfile.ZipFile(zip_filename, "w",
872 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300873 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300874 if path != os.curdir:
875 zf.write(path, path)
876 if logger is not None:
877 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400878 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300879 for name in sorted(dirnames):
880 path = os.path.normpath(os.path.join(dirpath, name))
881 zf.write(path, path)
882 if logger is not None:
883 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400884 for name in filenames:
885 path = os.path.normpath(os.path.join(dirpath, name))
886 if os.path.isfile(path):
887 zf.write(path, path)
888 if logger is not None:
889 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000890
891 return zip_filename
892
893_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000894 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200895}
896
897if _ZLIB_SUPPORTED:
898 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
899 "gzip'ed tar-file")
900 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000901
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000902if _BZ2_SUPPORTED:
903 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
904 "bzip2'ed tar-file")
905
Serhiy Storchaka11213772014-08-06 18:50:19 +0300906if _LZMA_SUPPORTED:
907 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
908 "xz'ed tar-file")
909
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910def get_archive_formats():
911 """Returns a list of supported formats for archiving and unarchiving.
912
913 Each element of the returned sequence is a tuple (name, description)
914 """
915 formats = [(name, registry[2]) for name, registry in
916 _ARCHIVE_FORMATS.items()]
917 formats.sort()
918 return formats
919
920def register_archive_format(name, function, extra_args=None, description=''):
921 """Registers an archive format.
922
923 name is the name of the format. function is the callable that will be
924 used to create archives. If provided, extra_args is a sequence of
925 (name, value) tuples that will be passed as arguments to the callable.
926 description can be provided to describe the format, and will be returned
927 by the get_archive_formats() function.
928 """
929 if extra_args is None:
930 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200931 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932 raise TypeError('The %s object is not callable' % function)
933 if not isinstance(extra_args, (tuple, list)):
934 raise TypeError('extra_args needs to be a sequence')
935 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200936 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000937 raise TypeError('extra_args elements are : (arg_name, value)')
938
939 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
940
941def unregister_archive_format(name):
942 del _ARCHIVE_FORMATS[name]
943
944def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
945 dry_run=0, owner=None, group=None, logger=None):
946 """Create an archive file (eg. zip or tar).
947
948 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200949 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
950 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000951
952 'root_dir' is a directory that will be the root directory of the
953 archive; ie. we typically chdir into 'root_dir' before creating the
954 archive. 'base_dir' is the directory where we start archiving from;
955 ie. 'base_dir' will be the common prefix of all files and
956 directories in the archive. 'root_dir' and 'base_dir' both default
957 to the current directory. Returns the name of the archive file.
958
959 'owner' and 'group' are used when creating a tar archive. By default,
960 uses the current owner and group.
961 """
962 save_cwd = os.getcwd()
963 if root_dir is not None:
964 if logger is not None:
965 logger.debug("changing into '%s'", root_dir)
966 base_name = os.path.abspath(base_name)
967 if not dry_run:
968 os.chdir(root_dir)
969
970 if base_dir is None:
971 base_dir = os.curdir
972
973 kwargs = {'dry_run': dry_run, 'logger': logger}
974
975 try:
976 format_info = _ARCHIVE_FORMATS[format]
977 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +0300978 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +0000979
980 func = format_info[0]
981 for arg, val in format_info[1]:
982 kwargs[arg] = val
983
984 if format != 'zip':
985 kwargs['owner'] = owner
986 kwargs['group'] = group
987
988 try:
989 filename = func(base_name, base_dir, **kwargs)
990 finally:
991 if root_dir is not None:
992 if logger is not None:
993 logger.debug("changing back to '%s'", save_cwd)
994 os.chdir(save_cwd)
995
996 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000997
998
999def get_unpack_formats():
1000 """Returns a list of supported formats for unpacking.
1001
1002 Each element of the returned sequence is a tuple
1003 (name, extensions, description)
1004 """
1005 formats = [(name, info[0], info[3]) for name, info in
1006 _UNPACK_FORMATS.items()]
1007 formats.sort()
1008 return formats
1009
1010def _check_unpack_options(extensions, function, extra_args):
1011 """Checks what gets registered as an unpacker."""
1012 # first make sure no other unpacker is registered for this extension
1013 existing_extensions = {}
1014 for name, info in _UNPACK_FORMATS.items():
1015 for ext in info[0]:
1016 existing_extensions[ext] = name
1017
1018 for extension in extensions:
1019 if extension in existing_extensions:
1020 msg = '%s is already registered for "%s"'
1021 raise RegistryError(msg % (extension,
1022 existing_extensions[extension]))
1023
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001024 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001025 raise TypeError('The registered function must be a callable')
1026
1027
1028def register_unpack_format(name, extensions, function, extra_args=None,
1029 description=''):
1030 """Registers an unpack format.
1031
1032 `name` is the name of the format. `extensions` is a list of extensions
1033 corresponding to the format.
1034
1035 `function` is the callable that will be
1036 used to unpack archives. The callable will receive archives to unpack.
1037 If it's unable to handle an archive, it needs to raise a ReadError
1038 exception.
1039
1040 If provided, `extra_args` is a sequence of
1041 (name, value) tuples that will be passed as arguments to the callable.
1042 description can be provided to describe the format, and will be returned
1043 by the get_unpack_formats() function.
1044 """
1045 if extra_args is None:
1046 extra_args = []
1047 _check_unpack_options(extensions, function, extra_args)
1048 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1049
1050def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001051 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001052 del _UNPACK_FORMATS[name]
1053
1054def _ensure_directory(path):
1055 """Ensure that the parent directory of `path` exists"""
1056 dirname = os.path.dirname(path)
1057 if not os.path.isdir(dirname):
1058 os.makedirs(dirname)
1059
1060def _unpack_zipfile(filename, extract_dir):
1061 """Unpack zip `filename` to `extract_dir`
1062 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001063 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001064
1065 if not zipfile.is_zipfile(filename):
1066 raise ReadError("%s is not a zip file" % filename)
1067
1068 zip = zipfile.ZipFile(filename)
1069 try:
1070 for info in zip.infolist():
1071 name = info.filename
1072
1073 # don't extract absolute paths or ones with .. in them
1074 if name.startswith('/') or '..' in name:
1075 continue
1076
1077 target = os.path.join(extract_dir, *name.split('/'))
1078 if not target:
1079 continue
1080
1081 _ensure_directory(target)
1082 if not name.endswith('/'):
1083 # file
1084 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001085 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001086 try:
1087 f.write(data)
1088 finally:
1089 f.close()
1090 del data
1091 finally:
1092 zip.close()
1093
1094def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001095 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001096 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001097 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001098 try:
1099 tarobj = tarfile.open(filename)
1100 except tarfile.TarError:
1101 raise ReadError(
1102 "%s is not a compressed or uncompressed tar file" % filename)
1103 try:
1104 tarobj.extractall(extract_dir)
1105 finally:
1106 tarobj.close()
1107
1108_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001109 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001110 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1111}
1112
1113if _ZLIB_SUPPORTED:
1114 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1115 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001116
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001117if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001118 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001119 "bzip2'ed tar-file")
1120
Serhiy Storchaka11213772014-08-06 18:50:19 +03001121if _LZMA_SUPPORTED:
1122 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1123 "xz'ed tar-file")
1124
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001125def _find_unpack_format(filename):
1126 for name, info in _UNPACK_FORMATS.items():
1127 for extension in info[0]:
1128 if filename.endswith(extension):
1129 return name
1130 return None
1131
1132def unpack_archive(filename, extract_dir=None, format=None):
1133 """Unpack an archive.
1134
1135 `filename` is the name of the archive.
1136
1137 `extract_dir` is the name of the target directory, where the archive
1138 is unpacked. If not provided, the current working directory is used.
1139
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001140 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1141 or "xztar". Or any other registered format. If not provided,
1142 unpack_archive will use the filename extension and see if an unpacker
1143 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001144
1145 In case none is found, a ValueError is raised.
1146 """
1147 if extract_dir is None:
1148 extract_dir = os.getcwd()
1149
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001150 extract_dir = os.fspath(extract_dir)
1151 filename = os.fspath(filename)
1152
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001153 if format is not None:
1154 try:
1155 format_info = _UNPACK_FORMATS[format]
1156 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001157 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001158
Nick Coghlanabf202d2011-03-16 13:52:20 -04001159 func = format_info[1]
1160 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001161 else:
1162 # we need to look at the registered unpackers supported extensions
1163 format = _find_unpack_format(filename)
1164 if format is None:
1165 raise ReadError("Unknown archive format '{0}'".format(filename))
1166
1167 func = _UNPACK_FORMATS[format][1]
1168 kwargs = dict(_UNPACK_FORMATS[format][2])
1169 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001170
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001171
1172if hasattr(os, 'statvfs'):
1173
1174 __all__.append('disk_usage')
1175 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001176 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1177 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1178 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001179
1180 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001181 """Return disk usage statistics about the given path.
1182
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001183 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001184 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001185 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001186 st = os.statvfs(path)
1187 free = st.f_bavail * st.f_frsize
1188 total = st.f_blocks * st.f_frsize
1189 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1190 return _ntuple_diskusage(total, used, free)
1191
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001192elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001193
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001194 __all__.append('disk_usage')
1195 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1196
1197 def disk_usage(path):
1198 """Return disk usage statistics about the given path.
1199
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001200 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001201 'free', which are the amount of total, used and free space, in bytes.
1202 """
1203 total, free = nt._getdiskusage(path)
1204 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001205 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001206
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001207
Sandro Tosid902a142011-08-22 23:28:27 +02001208def chown(path, user=None, group=None):
1209 """Change owner user and group of the given path.
1210
1211 user and group can be the uid/gid or the user/group names, and in that case,
1212 they are converted to their respective uid/gid.
1213 """
1214
1215 if user is None and group is None:
1216 raise ValueError("user and/or group must be set")
1217
1218 _user = user
1219 _group = group
1220
1221 # -1 means don't change it
1222 if user is None:
1223 _user = -1
1224 # user can either be an int (the uid) or a string (the system username)
1225 elif isinstance(user, str):
1226 _user = _get_uid(user)
1227 if _user is None:
1228 raise LookupError("no such user: {!r}".format(user))
1229
1230 if group is None:
1231 _group = -1
1232 elif not isinstance(group, int):
1233 _group = _get_gid(group)
1234 if _group is None:
1235 raise LookupError("no such group: {!r}".format(group))
1236
1237 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001238
1239def get_terminal_size(fallback=(80, 24)):
1240 """Get the size of the terminal window.
1241
1242 For each of the two dimensions, the environment variable, COLUMNS
1243 and LINES respectively, is checked. If the variable is defined and
1244 the value is a positive integer, it is used.
1245
1246 When COLUMNS or LINES is not defined, which is the common case,
1247 the terminal connected to sys.__stdout__ is queried
1248 by invoking os.get_terminal_size.
1249
1250 If the terminal size cannot be successfully queried, either because
1251 the system doesn't support querying, or because we are not
1252 connected to a terminal, the value given in fallback parameter
1253 is used. Fallback defaults to (80, 24) which is the default
1254 size used by many terminal emulators.
1255
1256 The value returned is a named tuple of type os.terminal_size.
1257 """
1258 # columns, lines are the working values
1259 try:
1260 columns = int(os.environ['COLUMNS'])
1261 except (KeyError, ValueError):
1262 columns = 0
1263
1264 try:
1265 lines = int(os.environ['LINES'])
1266 except (KeyError, ValueError):
1267 lines = 0
1268
1269 # only query if necessary
1270 if columns <= 0 or lines <= 0:
1271 try:
1272 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001273 except (AttributeError, ValueError, OSError):
1274 # stdout is None, closed, detached, or not a terminal, or
1275 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001276 size = os.terminal_size(fallback)
1277 if columns <= 0:
1278 columns = size.columns
1279 if lines <= 0:
1280 lines = size.lines
1281
1282 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001283
Cheryl Sabella5680f652019-02-13 06:25:10 -05001284
1285# Check that a given file can be accessed with the correct mode.
1286# Additionally check that `file` is not a directory, as on Windows
1287# directories pass the os.access check.
1288def _access_check(fn, mode):
1289 return (os.path.exists(fn) and os.access(fn, mode)
1290 and not os.path.isdir(fn))
1291
1292
Brian Curtinc57a3452012-06-22 16:00:30 -05001293def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001294 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001295 conforms to the given mode on the PATH, or None if there is no such
1296 file.
1297
1298 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1299 of os.environ.get("PATH"), or can be overridden with a custom search
1300 path.
1301
1302 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001303 # If we're given a path with a directory part, look it up directly rather
1304 # than referring to PATH directories. This includes checking relative to the
1305 # current directory, e.g. ./script
1306 if os.path.dirname(cmd):
1307 if _access_check(cmd, mode):
1308 return cmd
1309 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001310
Cheryl Sabella5680f652019-02-13 06:25:10 -05001311 use_bytes = isinstance(cmd, bytes)
1312
Barry Warsaw618738b2013-04-16 11:05:03 -04001313 if path is None:
Victor Stinner228a3c92019-04-17 16:26:36 +02001314 path = os.environ.get("PATH", None)
1315 if path is None:
1316 try:
1317 path = os.confstr("CS_PATH")
1318 except (AttributeError, ValueError):
1319 # os.confstr() or CS_PATH is not available
1320 path = os.defpath
1321 # bpo-35755: Don't use os.defpath if the PATH environment variable is
Victor Stinner197f0442019-04-17 17:44:06 +02001322 # set to an empty string
Victor Stinner228a3c92019-04-17 16:26:36 +02001323
1324 # PATH='' doesn't match, whereas PATH=':' looks in the current directory
Barry Warsaw618738b2013-04-16 11:05:03 -04001325 if not path:
1326 return None
Victor Stinner228a3c92019-04-17 16:26:36 +02001327
Cheryl Sabella5680f652019-02-13 06:25:10 -05001328 if use_bytes:
1329 path = os.fsencode(path)
1330 path = path.split(os.fsencode(os.pathsep))
1331 else:
1332 path = os.fsdecode(path)
1333 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001334
1335 if sys.platform == "win32":
1336 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001337 curdir = os.curdir
1338 if use_bytes:
1339 curdir = os.fsencode(curdir)
1340 if curdir not in path:
1341 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001342
1343 # PATHEXT is necessary to check on Windows.
1344 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
Cheryl Sabella5680f652019-02-13 06:25:10 -05001345 if use_bytes:
1346 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001347 # See if the given file matches any of the expected path extensions.
1348 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001349 # If it does match, only test that one, otherwise we have to try
1350 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001351 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1352 files = [cmd]
1353 else:
1354 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001355 else:
1356 # On other platforms you don't have things like PATHEXT to tell you
1357 # what file suffixes are executable, so just pass on cmd as-is.
1358 files = [cmd]
1359
1360 seen = set()
1361 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001362 normdir = os.path.normcase(dir)
1363 if not normdir in seen:
1364 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001365 for thefile in files:
1366 name = os.path.join(dir, thefile)
1367 if _access_check(name, mode):
1368 return name
1369 return None