blob: 7dd470dfaba41a3b317c900b66485929f7ea2669 [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)
362 try:
363 lookup("chmod")(dst, mode, follow_symlinks=follow)
364 except NotImplementedError:
365 # if we got a NotImplementedError, it's because
366 # * follow_symlinks=False,
367 # * lchown() is unavailable, and
368 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300369 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700370 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
371 # (it returned ENOSUP.)
372 # therefore we're out of options--we simply cannot chown the
373 # symlink. give up, suppress the error.
374 # (which is what shutil always did in this circumstance.)
375 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100376 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000377 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700378 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000379 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700380 for err in 'EOPNOTSUPP', 'ENOTSUP':
381 if hasattr(errno, err) and why.errno == getattr(errno, err):
382 break
383 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000384 raise
Larry Hastingsb4038062012-07-15 10:57:38 -0700385 _copyxattr(src, dst, follow_symlinks=follow)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200386
Larry Hastingsb4038062012-07-15 10:57:38 -0700387def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500388 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000389
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000390 The destination may be a directory.
391
Larry Hastingsb4038062012-07-15 10:57:38 -0700392 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100393 resembles GNU's "cp -P src dst".
394
Hynek Schlawack48653762012-10-07 12:49:58 +0200395 If source and destination are the same file, a SameFileError will be
396 raised.
397
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000398 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000399 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700401 copyfile(src, dst, follow_symlinks=follow_symlinks)
402 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500403 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000404
Larry Hastingsb4038062012-07-15 10:57:38 -0700405def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200406 """Copy data and metadata. Return the file's destination.
407
408 Metadata is copied with copystat(). Please see the copystat function
409 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000410
411 The destination may be a directory.
412
Larry Hastingsb4038062012-07-15 10:57:38 -0700413 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100414 resembles GNU's "cp -P src dst".
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000415 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000416 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000417 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700418 copyfile(src, dst, follow_symlinks=follow_symlinks)
419 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500420 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000421
Georg Brandl2ee470f2008-07-16 12:55:28 +0000422def ignore_patterns(*patterns):
423 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000424
Georg Brandl2ee470f2008-07-16 12:55:28 +0000425 Patterns is a sequence of glob-style patterns
426 that are used to exclude files"""
427 def _ignore_patterns(path, names):
428 ignored_names = []
429 for pattern in patterns:
430 ignored_names.extend(fnmatch.filter(names, pattern))
431 return set(ignored_names)
432 return _ignore_patterns
433
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800434def _copytree(entries, src, dst, symlinks, ignore, copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500435 ignore_dangling_symlinks, dirs_exist_ok=False):
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800436 if ignore is not None:
437 ignored_names = ignore(src, set(os.listdir(src)))
438 else:
439 ignored_names = set()
440
jab9e00d9e2018-12-28 13:03:40 -0500441 os.makedirs(dst, exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800442 errors = []
443 use_srcentry = copy_function is copy2 or copy_function is copy
444
445 for srcentry in entries:
446 if srcentry.name in ignored_names:
447 continue
448 srcname = os.path.join(src, srcentry.name)
449 dstname = os.path.join(dst, srcentry.name)
450 srcobj = srcentry if use_srcentry else srcname
451 try:
452 if srcentry.is_symlink():
453 linkto = os.readlink(srcname)
454 if symlinks:
455 # We can't just leave it to `copy_function` because legacy
456 # code with a custom `copy_function` may rely on copytree
457 # doing the right thing.
458 os.symlink(linkto, dstname)
459 copystat(srcobj, dstname, follow_symlinks=not symlinks)
460 else:
461 # ignore dangling symlink if the flag is on
462 if not os.path.exists(linkto) and ignore_dangling_symlinks:
463 continue
jab9e00d9e2018-12-28 13:03:40 -0500464 # otherwise let the copy occur. copy2 will raise an error
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800465 if srcentry.is_dir():
466 copytree(srcobj, dstname, symlinks, ignore,
jab9e00d9e2018-12-28 13:03:40 -0500467 copy_function, dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800468 else:
469 copy_function(srcobj, dstname)
470 elif srcentry.is_dir():
jab9e00d9e2018-12-28 13:03:40 -0500471 copytree(srcobj, dstname, symlinks, ignore, copy_function,
472 dirs_exist_ok=dirs_exist_ok)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800473 else:
474 # Will raise a SpecialFileError for unsupported file types
Giampaolo Rodolac606a9c2019-02-26 12:04:41 +0100475 copy_function(srcobj, dstname)
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800476 # catch the Error from the recursive copytree so that we can
477 # continue with other files
478 except Error as err:
479 errors.extend(err.args[0])
480 except OSError as why:
481 errors.append((srcname, dstname, str(why)))
482 try:
483 copystat(src, dst)
484 except OSError as why:
485 # Copying file access times may fail on Windows
486 if getattr(why, 'winerror', None) is None:
487 errors.append((src, dst, str(why)))
488 if errors:
489 raise Error(errors)
490 return dst
491
Tarek Ziadéfb437512010-04-20 08:57:33 +0000492def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
jab9e00d9e2018-12-28 13:03:40 -0500493 ignore_dangling_symlinks=False, dirs_exist_ok=False):
494 """Recursively copy a directory tree and return the destination directory.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000495
jab9e00d9e2018-12-28 13:03:40 -0500496 dirs_exist_ok dictates whether to raise an exception in case dst or any
497 missing parent directory already exists.
498
Neal Norwitza4c93b62003-02-23 21:36:32 +0000499 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000500
501 If the optional symlinks flag is true, symbolic links in the
502 source tree result in symbolic links in the destination tree; if
503 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000504 links are copied. If the file pointed by the symlink doesn't
505 exist, an exception will be added in the list of errors raised in
506 an Error exception at the end of the copy process.
507
508 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000509 want to silence this exception. Notice that this has no effect on
510 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000511
Georg Brandl2ee470f2008-07-16 12:55:28 +0000512 The optional ignore argument is a callable. If given, it
513 is called with the `src` parameter, which is the directory
514 being visited by copytree(), and `names` which is the list of
515 `src` contents, as returned by os.listdir():
516
517 callable(src, names) -> ignored_names
518
519 Since copytree() is called recursively, the callable will be
520 called once for each directory that is copied. It returns a
521 list of names relative to the `src` directory that should
522 not be copied.
523
Tarek Ziadé5340db32010-04-19 22:30:51 +0000524 The optional copy_function argument is a callable that will be used
525 to copy each file. It will be called with the source path and the
526 destination path as arguments. By default, copy2() is used, but any
527 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000528
529 """
Giampaolo Rodola19c46a42018-11-12 06:18:15 -0800530 with os.scandir(src) as entries:
531 return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
532 ignore=ignore, copy_function=copy_function,
jab9e00d9e2018-12-28 13:03:40 -0500533 ignore_dangling_symlinks=ignore_dangling_symlinks,
534 dirs_exist_ok=dirs_exist_ok)
Guido van Rossumd7673291998-02-06 21:38:09 +0000535
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200536# version vulnerable to race conditions
537def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000538 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200539 with os.scandir(path) as scandir_it:
540 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000541 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200542 onerror(os.scandir, path, sys.exc_info())
543 entries = []
544 for entry in entries:
545 fullname = entry.path
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000546 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200547 is_dir = entry.is_dir(follow_symlinks=False)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200548 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200549 is_dir = False
550 if is_dir:
551 try:
552 if entry.is_symlink():
553 # This can only happen if someone replaces
554 # a directory with a symlink after the call to
555 # os.scandir or entry.is_dir above.
556 raise OSError("Cannot call rmtree on a symbolic link")
557 except OSError:
558 onerror(os.path.islink, fullname, sys.exc_info())
559 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200560 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000561 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000562 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200563 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200564 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200565 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000566 try:
567 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200568 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000569 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000570
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200571# Version using fd-based APIs to protect against races
572def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200573 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200574 with os.scandir(topfd) as scandir_it:
575 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100576 except OSError as err:
577 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200578 onerror(os.scandir, path, sys.exc_info())
579 return
580 for entry in entries:
581 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200582 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200583 is_dir = entry.is_dir(follow_symlinks=False)
584 if is_dir:
585 orig_st = entry.stat(follow_symlinks=False)
586 is_dir = stat.S_ISDIR(orig_st.st_mode)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100587 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200588 is_dir = False
589 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200590 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200591 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100592 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200593 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200594 else:
595 try:
596 if os.path.samestat(orig_st, os.fstat(dirfd)):
597 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200598 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200599 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100600 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200601 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100602 else:
603 try:
604 # This can only happen if someone replaces
605 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200606 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100607 raise OSError("Cannot call rmtree on a symbolic "
608 "link")
609 except OSError:
610 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200611 finally:
612 os.close(dirfd)
613 else:
614 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200615 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100616 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200617 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200618
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200619_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
620 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200621 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200622 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000623
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200624def rmtree(path, ignore_errors=False, onerror=None):
625 """Recursively delete a directory tree.
626
627 If ignore_errors is set, errors are ignored; otherwise, if onerror
628 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200629 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200630 path is the argument to that function that caused it to fail; and
631 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
632 is false and onerror is None, an exception is raised.
633
634 """
635 if ignore_errors:
636 def onerror(*args):
637 pass
638 elif onerror is None:
639 def onerror(*args):
640 raise
641 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200642 # While the unsafe rmtree works fine on bytes, the fd based does not.
643 if isinstance(path, bytes):
644 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200645 # Note: To guard against symlink races, we use the standard
646 # lstat()/open()/fstat() trick.
647 try:
648 orig_st = os.lstat(path)
649 except Exception:
650 onerror(os.lstat, path, sys.exc_info())
651 return
652 try:
653 fd = os.open(path, os.O_RDONLY)
654 except Exception:
655 onerror(os.lstat, path, sys.exc_info())
656 return
657 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100658 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200659 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200660 try:
661 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200662 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200663 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200664 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100665 try:
666 # symlinks to directories are forbidden, see bug #1669
667 raise OSError("Cannot call rmtree on a symbolic link")
668 except OSError:
669 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200670 finally:
671 os.close(fd)
672 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200673 try:
674 if os.path.islink(path):
675 # symlinks to directories are forbidden, see bug #1669
676 raise OSError("Cannot call rmtree on a symbolic link")
677 except OSError:
678 onerror(os.path.islink, path, sys.exc_info())
679 # can't continue even if onerror hook returns
680 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200681 return _rmtree_unsafe(path, onerror)
682
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000683# Allow introspection of whether or not the hardening against symlink
684# attacks is supported on the current platform
685rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000686
Christian Heimesada8c3b2008-03-18 18:26:33 +0000687def _basename(path):
688 # A basename() variant which first strips the trailing slash, if present.
689 # Thus we always get the last component of the path, even for directories.
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200690 sep = os.path.sep + (os.path.altsep or '')
691 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000692
R David Murray6ffface2014-06-11 14:40:13 -0400693def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000694 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500695 similar to the Unix "mv" command. Return the file or directory's
696 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000697
698 If the destination is a directory or a symlink to a directory, the source
699 is moved inside the directory. The destination path must not already
700 exist.
701
702 If the destination already exists but is not a directory, it may be
703 overwritten depending on os.rename() semantics.
704
705 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100706 Otherwise, src is copied to the destination and then removed. Symlinks are
707 recreated under the new name if os.rename() fails because of cross
708 filesystem renames.
709
R David Murray6ffface2014-06-11 14:40:13 -0400710 The optional `copy_function` argument is a callable that will be used
711 to copy the source or it will be delegated to `copytree`.
712 By default, copy2() is used, but any function that supports the same
713 signature (like copy()) can be used.
714
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000715 A lot more could be done here... A look at a mv.c shows a lot of
716 the issues this implementation glosses over.
717
718 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000719 real_dst = dst
720 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200721 if _samefile(src, dst):
722 # We might be on a case insensitive filesystem,
723 # perform the rename anyway.
724 os.rename(src, dst)
725 return
726
Christian Heimesada8c3b2008-03-18 18:26:33 +0000727 real_dst = os.path.join(dst, _basename(src))
728 if os.path.exists(real_dst):
729 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000730 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000731 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200732 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100733 if os.path.islink(src):
734 linkto = os.readlink(src)
735 os.symlink(linkto, real_dst)
736 os.unlink(src)
737 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000738 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400739 raise Error("Cannot move a directory '%s' into itself"
740 " '%s'." % (src, dst))
741 copytree(src, real_dst, copy_function=copy_function,
742 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000743 rmtree(src)
744 else:
R David Murray6ffface2014-06-11 14:40:13 -0400745 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000746 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500747 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000748
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000749def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300750 src = os.path.abspath(src)
751 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000752 if not src.endswith(os.path.sep):
753 src += os.path.sep
754 if not dst.endswith(os.path.sep):
755 dst += os.path.sep
756 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000757
758def _get_gid(name):
759 """Returns a gid, given a group name."""
760 if getgrnam is None or name is None:
761 return None
762 try:
763 result = getgrnam(name)
764 except KeyError:
765 result = None
766 if result is not None:
767 return result[2]
768 return None
769
770def _get_uid(name):
771 """Returns an uid, given a user name."""
772 if getpwnam is None or name is None:
773 return None
774 try:
775 result = getpwnam(name)
776 except KeyError:
777 result = None
778 if result is not None:
779 return result[2]
780 return None
781
782def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
783 owner=None, group=None, logger=None):
784 """Create a (possibly compressed) tar file from all the files under
785 'base_dir'.
786
Serhiy Storchaka11213772014-08-06 18:50:19 +0300787 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000788
789 'owner' and 'group' can be used to define an owner and a group for the
790 archive that is being built. If not provided, the current owner and group
791 will be used.
792
Éric Araujo4433a5f2010-12-15 20:26:30 +0000793 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300794 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000795
796 Returns the output filename.
797 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200798 if compress is None:
799 tar_compression = ''
800 elif _ZLIB_SUPPORTED and compress == 'gzip':
801 tar_compression = 'gz'
802 elif _BZ2_SUPPORTED and compress == 'bzip2':
803 tar_compression = 'bz2'
804 elif _LZMA_SUPPORTED and compress == 'xz':
805 tar_compression = 'xz'
806 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000807 raise ValueError("bad value for 'compress', or compression format not "
808 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000809
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200810 import tarfile # late import for breaking circular dependency
811
812 compress_ext = '.' + tar_compression if compress else ''
813 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000814 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000815
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200816 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000817 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200818 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000819 if not dry_run:
820 os.makedirs(archive_dir)
821
Tarek Ziadé396fad72010-02-23 05:30:31 +0000822 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000823 if logger is not None:
824 logger.info('Creating tar archive')
825
826 uid = _get_uid(owner)
827 gid = _get_gid(group)
828
829 def _set_uid_gid(tarinfo):
830 if gid is not None:
831 tarinfo.gid = gid
832 tarinfo.gname = group
833 if uid is not None:
834 tarinfo.uid = uid
835 tarinfo.uname = owner
836 return tarinfo
837
838 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200839 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000840 try:
841 tar.add(base_dir, filter=_set_uid_gid)
842 finally:
843 tar.close()
844
Tarek Ziadé396fad72010-02-23 05:30:31 +0000845 return archive_name
846
Tarek Ziadé396fad72010-02-23 05:30:31 +0000847def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
848 """Create a zip file from all the files under 'base_dir'.
849
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200850 The output zip file will be named 'base_name' + ".zip". Returns the
851 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000852 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200853 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400854
Tarek Ziadé396fad72010-02-23 05:30:31 +0000855 zip_filename = base_name + ".zip"
856 archive_dir = os.path.dirname(base_name)
857
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200858 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000859 if logger is not None:
860 logger.info("creating %s", archive_dir)
861 if not dry_run:
862 os.makedirs(archive_dir)
863
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400864 if logger is not None:
865 logger.info("creating '%s' and adding '%s' to it",
866 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000867
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400868 if not dry_run:
869 with zipfile.ZipFile(zip_filename, "w",
870 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300871 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300872 if path != os.curdir:
873 zf.write(path, path)
874 if logger is not None:
875 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400876 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300877 for name in sorted(dirnames):
878 path = os.path.normpath(os.path.join(dirpath, name))
879 zf.write(path, path)
880 if logger is not None:
881 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400882 for name in filenames:
883 path = os.path.normpath(os.path.join(dirpath, name))
884 if os.path.isfile(path):
885 zf.write(path, path)
886 if logger is not None:
887 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000888
889 return zip_filename
890
891_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000892 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200893}
894
895if _ZLIB_SUPPORTED:
896 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
897 "gzip'ed tar-file")
898 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000899
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000900if _BZ2_SUPPORTED:
901 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
902 "bzip2'ed tar-file")
903
Serhiy Storchaka11213772014-08-06 18:50:19 +0300904if _LZMA_SUPPORTED:
905 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
906 "xz'ed tar-file")
907
Tarek Ziadé396fad72010-02-23 05:30:31 +0000908def get_archive_formats():
909 """Returns a list of supported formats for archiving and unarchiving.
910
911 Each element of the returned sequence is a tuple (name, description)
912 """
913 formats = [(name, registry[2]) for name, registry in
914 _ARCHIVE_FORMATS.items()]
915 formats.sort()
916 return formats
917
918def register_archive_format(name, function, extra_args=None, description=''):
919 """Registers an archive format.
920
921 name is the name of the format. function is the callable that will be
922 used to create archives. If provided, extra_args is a sequence of
923 (name, value) tuples that will be passed as arguments to the callable.
924 description can be provided to describe the format, and will be returned
925 by the get_archive_formats() function.
926 """
927 if extra_args is None:
928 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200929 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000930 raise TypeError('The %s object is not callable' % function)
931 if not isinstance(extra_args, (tuple, list)):
932 raise TypeError('extra_args needs to be a sequence')
933 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200934 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000935 raise TypeError('extra_args elements are : (arg_name, value)')
936
937 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
938
939def unregister_archive_format(name):
940 del _ARCHIVE_FORMATS[name]
941
942def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
943 dry_run=0, owner=None, group=None, logger=None):
944 """Create an archive file (eg. zip or tar).
945
946 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200947 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
948 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000949
950 'root_dir' is a directory that will be the root directory of the
951 archive; ie. we typically chdir into 'root_dir' before creating the
952 archive. 'base_dir' is the directory where we start archiving from;
953 ie. 'base_dir' will be the common prefix of all files and
954 directories in the archive. 'root_dir' and 'base_dir' both default
955 to the current directory. Returns the name of the archive file.
956
957 'owner' and 'group' are used when creating a tar archive. By default,
958 uses the current owner and group.
959 """
960 save_cwd = os.getcwd()
961 if root_dir is not None:
962 if logger is not None:
963 logger.debug("changing into '%s'", root_dir)
964 base_name = os.path.abspath(base_name)
965 if not dry_run:
966 os.chdir(root_dir)
967
968 if base_dir is None:
969 base_dir = os.curdir
970
971 kwargs = {'dry_run': dry_run, 'logger': logger}
972
973 try:
974 format_info = _ARCHIVE_FORMATS[format]
975 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +0300976 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +0000977
978 func = format_info[0]
979 for arg, val in format_info[1]:
980 kwargs[arg] = val
981
982 if format != 'zip':
983 kwargs['owner'] = owner
984 kwargs['group'] = group
985
986 try:
987 filename = func(base_name, base_dir, **kwargs)
988 finally:
989 if root_dir is not None:
990 if logger is not None:
991 logger.debug("changing back to '%s'", save_cwd)
992 os.chdir(save_cwd)
993
994 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000995
996
997def get_unpack_formats():
998 """Returns a list of supported formats for unpacking.
999
1000 Each element of the returned sequence is a tuple
1001 (name, extensions, description)
1002 """
1003 formats = [(name, info[0], info[3]) for name, info in
1004 _UNPACK_FORMATS.items()]
1005 formats.sort()
1006 return formats
1007
1008def _check_unpack_options(extensions, function, extra_args):
1009 """Checks what gets registered as an unpacker."""
1010 # first make sure no other unpacker is registered for this extension
1011 existing_extensions = {}
1012 for name, info in _UNPACK_FORMATS.items():
1013 for ext in info[0]:
1014 existing_extensions[ext] = name
1015
1016 for extension in extensions:
1017 if extension in existing_extensions:
1018 msg = '%s is already registered for "%s"'
1019 raise RegistryError(msg % (extension,
1020 existing_extensions[extension]))
1021
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001022 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001023 raise TypeError('The registered function must be a callable')
1024
1025
1026def register_unpack_format(name, extensions, function, extra_args=None,
1027 description=''):
1028 """Registers an unpack format.
1029
1030 `name` is the name of the format. `extensions` is a list of extensions
1031 corresponding to the format.
1032
1033 `function` is the callable that will be
1034 used to unpack archives. The callable will receive archives to unpack.
1035 If it's unable to handle an archive, it needs to raise a ReadError
1036 exception.
1037
1038 If provided, `extra_args` is a sequence of
1039 (name, value) tuples that will be passed as arguments to the callable.
1040 description can be provided to describe the format, and will be returned
1041 by the get_unpack_formats() function.
1042 """
1043 if extra_args is None:
1044 extra_args = []
1045 _check_unpack_options(extensions, function, extra_args)
1046 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1047
1048def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001049 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001050 del _UNPACK_FORMATS[name]
1051
1052def _ensure_directory(path):
1053 """Ensure that the parent directory of `path` exists"""
1054 dirname = os.path.dirname(path)
1055 if not os.path.isdir(dirname):
1056 os.makedirs(dirname)
1057
1058def _unpack_zipfile(filename, extract_dir):
1059 """Unpack zip `filename` to `extract_dir`
1060 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001061 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001062
1063 if not zipfile.is_zipfile(filename):
1064 raise ReadError("%s is not a zip file" % filename)
1065
1066 zip = zipfile.ZipFile(filename)
1067 try:
1068 for info in zip.infolist():
1069 name = info.filename
1070
1071 # don't extract absolute paths or ones with .. in them
1072 if name.startswith('/') or '..' in name:
1073 continue
1074
1075 target = os.path.join(extract_dir, *name.split('/'))
1076 if not target:
1077 continue
1078
1079 _ensure_directory(target)
1080 if not name.endswith('/'):
1081 # file
1082 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001083 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001084 try:
1085 f.write(data)
1086 finally:
1087 f.close()
1088 del data
1089 finally:
1090 zip.close()
1091
1092def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001093 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001094 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001095 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001096 try:
1097 tarobj = tarfile.open(filename)
1098 except tarfile.TarError:
1099 raise ReadError(
1100 "%s is not a compressed or uncompressed tar file" % filename)
1101 try:
1102 tarobj.extractall(extract_dir)
1103 finally:
1104 tarobj.close()
1105
1106_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001107 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001108 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1109}
1110
1111if _ZLIB_SUPPORTED:
1112 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1113 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001114
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001115if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001116 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001117 "bzip2'ed tar-file")
1118
Serhiy Storchaka11213772014-08-06 18:50:19 +03001119if _LZMA_SUPPORTED:
1120 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1121 "xz'ed tar-file")
1122
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001123def _find_unpack_format(filename):
1124 for name, info in _UNPACK_FORMATS.items():
1125 for extension in info[0]:
1126 if filename.endswith(extension):
1127 return name
1128 return None
1129
1130def unpack_archive(filename, extract_dir=None, format=None):
1131 """Unpack an archive.
1132
1133 `filename` is the name of the archive.
1134
1135 `extract_dir` is the name of the target directory, where the archive
1136 is unpacked. If not provided, the current working directory is used.
1137
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001138 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1139 or "xztar". Or any other registered format. If not provided,
1140 unpack_archive will use the filename extension and see if an unpacker
1141 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001142
1143 In case none is found, a ValueError is raised.
1144 """
1145 if extract_dir is None:
1146 extract_dir = os.getcwd()
1147
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001148 extract_dir = os.fspath(extract_dir)
1149 filename = os.fspath(filename)
1150
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001151 if format is not None:
1152 try:
1153 format_info = _UNPACK_FORMATS[format]
1154 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001155 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001156
Nick Coghlanabf202d2011-03-16 13:52:20 -04001157 func = format_info[1]
1158 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001159 else:
1160 # we need to look at the registered unpackers supported extensions
1161 format = _find_unpack_format(filename)
1162 if format is None:
1163 raise ReadError("Unknown archive format '{0}'".format(filename))
1164
1165 func = _UNPACK_FORMATS[format][1]
1166 kwargs = dict(_UNPACK_FORMATS[format][2])
1167 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001168
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001169
1170if hasattr(os, 'statvfs'):
1171
1172 __all__.append('disk_usage')
1173 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001174 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1175 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1176 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001177
1178 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001179 """Return disk usage statistics about the given path.
1180
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001181 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001182 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001183 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001184 st = os.statvfs(path)
1185 free = st.f_bavail * st.f_frsize
1186 total = st.f_blocks * st.f_frsize
1187 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1188 return _ntuple_diskusage(total, used, free)
1189
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001190elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001191
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001192 __all__.append('disk_usage')
1193 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1194
1195 def disk_usage(path):
1196 """Return disk usage statistics about the given path.
1197
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001198 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001199 'free', which are the amount of total, used and free space, in bytes.
1200 """
1201 total, free = nt._getdiskusage(path)
1202 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001203 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001204
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001205
Sandro Tosid902a142011-08-22 23:28:27 +02001206def chown(path, user=None, group=None):
1207 """Change owner user and group of the given path.
1208
1209 user and group can be the uid/gid or the user/group names, and in that case,
1210 they are converted to their respective uid/gid.
1211 """
1212
1213 if user is None and group is None:
1214 raise ValueError("user and/or group must be set")
1215
1216 _user = user
1217 _group = group
1218
1219 # -1 means don't change it
1220 if user is None:
1221 _user = -1
1222 # user can either be an int (the uid) or a string (the system username)
1223 elif isinstance(user, str):
1224 _user = _get_uid(user)
1225 if _user is None:
1226 raise LookupError("no such user: {!r}".format(user))
1227
1228 if group is None:
1229 _group = -1
1230 elif not isinstance(group, int):
1231 _group = _get_gid(group)
1232 if _group is None:
1233 raise LookupError("no such group: {!r}".format(group))
1234
1235 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001236
1237def get_terminal_size(fallback=(80, 24)):
1238 """Get the size of the terminal window.
1239
1240 For each of the two dimensions, the environment variable, COLUMNS
1241 and LINES respectively, is checked. If the variable is defined and
1242 the value is a positive integer, it is used.
1243
1244 When COLUMNS or LINES is not defined, which is the common case,
1245 the terminal connected to sys.__stdout__ is queried
1246 by invoking os.get_terminal_size.
1247
1248 If the terminal size cannot be successfully queried, either because
1249 the system doesn't support querying, or because we are not
1250 connected to a terminal, the value given in fallback parameter
1251 is used. Fallback defaults to (80, 24) which is the default
1252 size used by many terminal emulators.
1253
1254 The value returned is a named tuple of type os.terminal_size.
1255 """
1256 # columns, lines are the working values
1257 try:
1258 columns = int(os.environ['COLUMNS'])
1259 except (KeyError, ValueError):
1260 columns = 0
1261
1262 try:
1263 lines = int(os.environ['LINES'])
1264 except (KeyError, ValueError):
1265 lines = 0
1266
1267 # only query if necessary
1268 if columns <= 0 or lines <= 0:
1269 try:
1270 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001271 except (AttributeError, ValueError, OSError):
1272 # stdout is None, closed, detached, or not a terminal, or
1273 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001274 size = os.terminal_size(fallback)
1275 if columns <= 0:
1276 columns = size.columns
1277 if lines <= 0:
1278 lines = size.lines
1279
1280 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001281
Cheryl Sabella5680f652019-02-13 06:25:10 -05001282
1283# Check that a given file can be accessed with the correct mode.
1284# Additionally check that `file` is not a directory, as on Windows
1285# directories pass the os.access check.
1286def _access_check(fn, mode):
1287 return (os.path.exists(fn) and os.access(fn, mode)
1288 and not os.path.isdir(fn))
1289
1290
Brian Curtinc57a3452012-06-22 16:00:30 -05001291def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001292 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001293 conforms to the given mode on the PATH, or None if there is no such
1294 file.
1295
1296 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1297 of os.environ.get("PATH"), or can be overridden with a custom search
1298 path.
1299
1300 """
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001301 # If we're given a path with a directory part, look it up directly rather
1302 # than referring to PATH directories. This includes checking relative to the
1303 # current directory, e.g. ./script
1304 if os.path.dirname(cmd):
1305 if _access_check(cmd, mode):
1306 return cmd
1307 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001308
Cheryl Sabella5680f652019-02-13 06:25:10 -05001309 use_bytes = isinstance(cmd, bytes)
1310
Barry Warsaw618738b2013-04-16 11:05:03 -04001311 if path is None:
1312 path = os.environ.get("PATH", os.defpath)
1313 if not path:
1314 return None
Cheryl Sabella5680f652019-02-13 06:25:10 -05001315 if use_bytes:
1316 path = os.fsencode(path)
1317 path = path.split(os.fsencode(os.pathsep))
1318 else:
1319 path = os.fsdecode(path)
1320 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001321
1322 if sys.platform == "win32":
1323 # The current directory takes precedence on Windows.
Cheryl Sabella5680f652019-02-13 06:25:10 -05001324 curdir = os.curdir
1325 if use_bytes:
1326 curdir = os.fsencode(curdir)
1327 if curdir not in path:
1328 path.insert(0, curdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001329
1330 # PATHEXT is necessary to check on Windows.
1331 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
Cheryl Sabella5680f652019-02-13 06:25:10 -05001332 if use_bytes:
1333 pathext = [os.fsencode(ext) for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001334 # See if the given file matches any of the expected path extensions.
1335 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001336 # If it does match, only test that one, otherwise we have to try
1337 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001338 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1339 files = [cmd]
1340 else:
1341 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001342 else:
1343 # On other platforms you don't have things like PATHEXT to tell you
1344 # what file suffixes are executable, so just pass on cmd as-is.
1345 files = [cmd]
1346
1347 seen = set()
1348 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001349 normdir = os.path.normcase(dir)
1350 if not normdir in seen:
1351 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001352 for thefile in files:
1353 name = os.path.join(dir, thefile)
1354 if _access_check(name, mode):
1355 return name
1356 return None