blob: 40dd070ed11f793a8d356a6373f1e9305b7b6944 [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
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020013import io
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020014
15try:
16 import zlib
17 del zlib
18 _ZLIB_SUPPORTED = True
19except ImportError:
20 _ZLIB_SUPPORTED = False
Tarek Ziadé396fad72010-02-23 05:30:31 +000021
22try:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000023 import bz2
Florent Xicluna54540ec2011-11-04 08:29:17 +010024 del bz2
Tarek Ziadéffa155a2010-04-29 13:34:35 +000025 _BZ2_SUPPORTED = True
Brett Cannoncd171c82013-07-04 17:43:24 -040026except ImportError:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000027 _BZ2_SUPPORTED = False
28
29try:
Serhiy Storchaka11213772014-08-06 18:50:19 +030030 import lzma
31 del lzma
32 _LZMA_SUPPORTED = True
33except ImportError:
34 _LZMA_SUPPORTED = False
35
36try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000037 from pwd import getpwnam
Brett Cannoncd171c82013-07-04 17:43:24 -040038except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000039 getpwnam = None
40
41try:
42 from grp import getgrnam
Brett Cannoncd171c82013-07-04 17:43:24 -040043except ImportError:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 getgrnam = None
Guido van Rossumc6360141990-10-13 19:23:40 +000045
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070046_WINDOWS = os.name == 'nt'
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020047posix = nt = None
48if os.name == 'posix':
49 import posix
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070050elif _WINDOWS:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020051 import nt
52
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070053COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 16 * 1024
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020054_HAS_SENDFILE = posix and hasattr(os, "sendfile")
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070055_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020056
Tarek Ziadéc3399782010-02-23 05:39:18 +000057__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
58 "copytree", "move", "rmtree", "Error", "SpecialFileError",
59 "ExecError", "make_archive", "get_archive_formats",
Tarek Ziadé6ac91722010-04-28 17:51:36 +000060 "register_archive_format", "unregister_archive_format",
61 "get_unpack_formats", "register_unpack_format",
Éric Araujoc5efe652011-08-21 14:30:00 +020062 "unregister_unpack_format", "unpack_archive",
Berker Peksag8083cd62014-11-01 11:04:06 +020063 "ignore_patterns", "chown", "which", "get_terminal_size",
64 "SameFileError"]
Éric Araujoe4d5b8e2011-08-08 16:51:11 +020065 # disk_usage is added later, if available on the platform
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000066
Andrew Svetlov3438fa42012-12-17 23:35:18 +020067class Error(OSError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000068 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000069
Hynek Schlawack48653762012-10-07 12:49:58 +020070class SameFileError(Error):
71 """Raised when source and destination are the same file."""
72
Andrew Svetlov3438fa42012-12-17 23:35:18 +020073class SpecialFileError(OSError):
Antoine Pitrou7fff0962009-05-01 21:09:44 +000074 """Raised when trying to do a kind of operation (e.g. copying) which is
75 not supported on a special file (e.g. a named pipe)"""
76
Andrew Svetlov3438fa42012-12-17 23:35:18 +020077class ExecError(OSError):
Tarek Ziadé396fad72010-02-23 05:30:31 +000078 """Raised when a command could not be executed"""
79
Andrew Svetlov3438fa42012-12-17 23:35:18 +020080class ReadError(OSError):
Tarek Ziadé6ac91722010-04-28 17:51:36 +000081 """Raised when an archive cannot be read"""
82
83class RegistryError(Exception):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030084 """Raised when a registry operation with the archiving
Raymond Hettinger15f44ab2016-08-30 10:47:49 -070085 and unpacking registries fails"""
Tarek Ziadé6ac91722010-04-28 17:51:36 +000086
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020087class _GiveupOnFastCopy(Exception):
88 """Raised as a signal to fallback on using raw read()/write()
89 file copy when fast-copy functions fail to do so.
90 """
Tarek Ziadé6ac91722010-04-28 17:51:36 +000091
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070092def _fastcopy_fcopyfile(fsrc, fdst, flags):
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020093 """Copy a regular file content or metadata by using high-performance
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -070094 fcopyfile(3) syscall (macOS).
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +020095 """
96 try:
97 infd = fsrc.fileno()
98 outfd = fdst.fileno()
99 except Exception as err:
100 raise _GiveupOnFastCopy(err) # not a regular file
101
102 try:
103 posix._fcopyfile(infd, outfd, flags)
104 except OSError as err:
105 err.filename = fsrc.name
106 err.filename2 = fdst.name
107 if err.errno in {errno.EINVAL, errno.ENOTSUP}:
108 raise _GiveupOnFastCopy(err)
109 else:
110 raise err from None
111
112def _fastcopy_sendfile(fsrc, fdst):
113 """Copy data from one regular mmap-like fd to another by using
114 high-performance sendfile(2) syscall.
115 This should work on Linux >= 2.6.33 and Solaris only.
116 """
117 # Note: copyfileobj() is left alone in order to not introduce any
118 # unexpected breakage. Possible risks by using zero-copy calls
119 # in copyfileobj() are:
120 # - fdst cannot be open in "a"(ppend) mode
121 # - fsrc and fdst may be open in "t"(ext) mode
122 # - fsrc may be a BufferedReader (which hides unread data in a buffer),
123 # GzipFile (which decompresses data), HTTPResponse (which decodes
124 # chunks).
125 # - possibly others (e.g. encrypted fs/partition?)
126 global _HAS_SENDFILE
127 try:
128 infd = fsrc.fileno()
129 outfd = fdst.fileno()
130 except Exception as err:
131 raise _GiveupOnFastCopy(err) # not a regular file
132
133 # Hopefully the whole file will be copied in a single call.
134 # sendfile() is called in a loop 'till EOF is reached (0 return)
135 # so a bufsize smaller or bigger than the actual file size
136 # should not make any difference, also in case the file content
137 # changes while being copied.
138 try:
139 blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MB
140 except Exception:
141 blocksize = 2 ** 27 # 128MB
142
143 offset = 0
144 while True:
145 try:
146 sent = os.sendfile(outfd, infd, offset, blocksize)
147 except OSError as err:
148 # ...in oder to have a more informative exception.
149 err.filename = fsrc.name
150 err.filename2 = fdst.name
151
152 if err.errno == errno.ENOTSOCK:
153 # sendfile() on this platform (probably Linux < 2.6.33)
154 # does not support copies between regular files (only
155 # sockets).
156 _HAS_SENDFILE = False
157 raise _GiveupOnFastCopy(err)
158
159 if err.errno == errno.ENOSPC: # filesystem is full
160 raise err from None
161
162 # Give up on first call and if no data was copied.
163 if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0:
164 raise _GiveupOnFastCopy(err)
165
166 raise err
167 else:
168 if sent == 0:
169 break # EOF
170 offset += sent
171
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700172def _copyfileobj_readinto(fsrc, fdst, length=COPY_BUFSIZE):
173 """readinto()/memoryview() based variant of copyfileobj().
174 *fsrc* must support readinto() method and both files must be
175 open in binary mode.
176 """
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200177 # Localize variable access to minimize overhead.
178 fsrc_readinto = fsrc.readinto
179 fdst_write = fdst.write
180 with memoryview(bytearray(length)) as mv:
181 while True:
182 n = fsrc_readinto(mv)
183 if not n:
184 break
185 elif n < length:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700186 with mv[:n] as smv:
187 fdst.write(smv)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200188 else:
189 fdst_write(mv)
190
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200191def copyfileobj(fsrc, fdst, length=COPY_BUFSIZE):
Greg Stein42bb8b32000-07-12 09:55:30 +0000192 """copy data from file-like object fsrc to file-like object fdst"""
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700193 # Localize variable access to minimize overhead.
194 fsrc_read = fsrc.read
195 fdst_write = fdst.write
196 while True:
197 buf = fsrc_read(length)
198 if not buf:
199 break
200 fdst_write(buf)
Greg Stein42bb8b32000-07-12 09:55:30 +0000201
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000202def _samefile(src, dst):
203 # Macintosh, Unix.
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +0000204 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +0000205 try:
206 return os.path.samefile(src, dst)
207 except OSError:
208 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000209
210 # All other platforms: check for same pathname.
211 return (os.path.normcase(os.path.abspath(src)) ==
212 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +0000213
Larry Hastingsb4038062012-07-15 10:57:38 -0700214def copyfile(src, dst, *, follow_symlinks=True):
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700215 """Copy data from src to dst in the most efficient way possible.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100216
Larry Hastingsb4038062012-07-15 10:57:38 -0700217 If follow_symlinks is not set and src is a symbolic link, a new
Antoine Pitrou78091e62011-12-29 18:54:15 +0100218 symlink will be created instead of copying the file it points to.
219
220 """
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000221 if _samefile(src, dst):
Hynek Schlawack48653762012-10-07 12:49:58 +0200222 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +0000223
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700224 file_size = 0
225 for i, fn in enumerate([src, dst]):
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000226 try:
227 st = os.stat(fn)
228 except OSError:
229 # File most likely does not exist
230 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000231 else:
232 # XXX What about other special files? (sockets, devices...)
233 if stat.S_ISFIFO(st.st_mode):
234 raise SpecialFileError("`%s` is a named pipe" % fn)
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700235 if _WINDOWS and i == 0:
236 file_size = st.st_size
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000237
Larry Hastingsb4038062012-07-15 10:57:38 -0700238 if not follow_symlinks and os.path.islink(src):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100239 os.symlink(os.readlink(src), dst)
240 else:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200241 with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700242 # macOS
243 if _HAS_FCOPYFILE:
244 try:
245 _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
246 return dst
247 except _GiveupOnFastCopy:
248 pass
249 # Linux / Solaris
250 elif _HAS_SENDFILE:
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200251 try:
252 _fastcopy_sendfile(fsrc, fdst)
253 return dst
254 except _GiveupOnFastCopy:
255 pass
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700256 # Windows, see:
257 # https://github.com/python/cpython/pull/7160#discussion_r195405230
258 elif _WINDOWS and file_size > 0:
259 _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
260 return dst
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200261
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -0700262 copyfileobj(fsrc, fdst)
Giampaolo Rodola4a172cc2018-06-12 23:04:50 +0200263
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500264 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000265
Larry Hastingsb4038062012-07-15 10:57:38 -0700266def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100267 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000268
Larry Hastingsb4038062012-07-15 10:57:38 -0700269 If follow_symlinks is not set, symlinks aren't followed if and only
270 if both `src` and `dst` are symlinks. If `lchmod` isn't available
271 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272
273 """
Larry Hastingsb4038062012-07-15 10:57:38 -0700274 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100275 if hasattr(os, 'lchmod'):
276 stat_func, chmod_func = os.lstat, os.lchmod
277 else:
278 return
279 elif hasattr(os, 'chmod'):
280 stat_func, chmod_func = os.stat, os.chmod
281 else:
282 return
283
284 st = stat_func(src)
285 chmod_func(dst, stat.S_IMODE(st.st_mode))
286
Larry Hastingsad5ae042012-07-14 17:55:11 -0700287if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700288 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700289 """Copy extended filesystem attributes from `src` to `dst`.
290
291 Overwrite existing attributes.
292
Larry Hastingsb4038062012-07-15 10:57:38 -0700293 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700294
295 """
296
Hynek Schlawack0beab052013-02-05 08:22:44 +0100297 try:
298 names = os.listxattr(src, follow_symlinks=follow_symlinks)
299 except OSError as e:
300 if e.errno not in (errno.ENOTSUP, errno.ENODATA):
301 raise
302 return
303 for name in names:
Larry Hastingsad5ae042012-07-14 17:55:11 -0700304 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700305 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
306 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700307 except OSError as e:
308 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
309 raise
310else:
311 def _copyxattr(*args, **kwargs):
312 pass
313
Larry Hastingsb4038062012-07-15 10:57:38 -0700314def copystat(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200315 """Copy file metadata
Antoine Pitrou78091e62011-12-29 18:54:15 +0100316
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200317 Copy the permission bits, last access time, last modification time, and
318 flags from `src` to `dst`. On Linux, copystat() also copies the "extended
319 attributes" where possible. The file contents, owner, and group are
320 unaffected. `src` and `dst` are path names given as strings.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200322 If the optional flag `follow_symlinks` is not set, symlinks aren't
323 followed if and only if both `src` and `dst` are symlinks.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100324 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700325 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100326 pass
327
Larry Hastings9cf065c2012-06-22 16:30:09 -0700328 # follow symlinks (aka don't not follow symlinks)
Larry Hastingsb4038062012-07-15 10:57:38 -0700329 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700330 if follow:
331 # use the real function if it exists
332 def lookup(name):
333 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700335 # use the real function only if it exists
336 # *and* it supports follow_symlinks
337 def lookup(name):
338 fn = getattr(os, name, _nop)
339 if fn in os.supports_follow_symlinks:
340 return fn
341 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100342
Larry Hastings9cf065c2012-06-22 16:30:09 -0700343 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000344 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700345 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
346 follow_symlinks=follow)
347 try:
348 lookup("chmod")(dst, mode, follow_symlinks=follow)
349 except NotImplementedError:
350 # if we got a NotImplementedError, it's because
351 # * follow_symlinks=False,
352 # * lchown() is unavailable, and
353 # * either
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300354 # * fchownat() is unavailable or
Larry Hastings9cf065c2012-06-22 16:30:09 -0700355 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
356 # (it returned ENOSUP.)
357 # therefore we're out of options--we simply cannot chown the
358 # symlink. give up, suppress the error.
359 # (which is what shutil always did in this circumstance.)
360 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100361 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000362 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700363 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000364 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700365 for err in 'EOPNOTSUPP', 'ENOTSUP':
366 if hasattr(errno, err) and why.errno == getattr(errno, err):
367 break
368 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000369 raise
Larry Hastingsb4038062012-07-15 10:57:38 -0700370 _copyxattr(src, dst, follow_symlinks=follow)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200371
Larry Hastingsb4038062012-07-15 10:57:38 -0700372def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500373 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000374
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000375 The destination may be a directory.
376
Larry Hastingsb4038062012-07-15 10:57:38 -0700377 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100378 resembles GNU's "cp -P src dst".
379
Hynek Schlawack48653762012-10-07 12:49:58 +0200380 If source and destination are the same file, a SameFileError will be
381 raised.
382
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000383 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000384 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000385 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700386 copyfile(src, dst, follow_symlinks=follow_symlinks)
387 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500388 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000389
Larry Hastingsb4038062012-07-15 10:57:38 -0700390def copy2(src, dst, *, follow_symlinks=True):
Zsolt Cserna4f399be2018-10-23 12:09:50 +0200391 """Copy data and metadata. Return the file's destination.
392
393 Metadata is copied with copystat(). Please see the copystat function
394 for more information.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000395
396 The destination may be a directory.
397
Larry Hastingsb4038062012-07-15 10:57:38 -0700398 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100399 resembles GNU's "cp -P src dst".
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 copystat(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
Georg Brandl2ee470f2008-07-16 12:55:28 +0000407def ignore_patterns(*patterns):
408 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000409
Georg Brandl2ee470f2008-07-16 12:55:28 +0000410 Patterns is a sequence of glob-style patterns
411 that are used to exclude files"""
412 def _ignore_patterns(path, names):
413 ignored_names = []
414 for pattern in patterns:
415 ignored_names.extend(fnmatch.filter(names, pattern))
416 return set(ignored_names)
417 return _ignore_patterns
418
Tarek Ziadéfb437512010-04-20 08:57:33 +0000419def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
420 ignore_dangling_symlinks=False):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000421 """Recursively copy a directory tree.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000422
423 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000424 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000425
426 If the optional symlinks flag is true, symbolic links in the
427 source tree result in symbolic links in the destination tree; if
428 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000429 links are copied. If the file pointed by the symlink doesn't
430 exist, an exception will be added in the list of errors raised in
431 an Error exception at the end of the copy process.
432
433 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000434 want to silence this exception. Notice that this has no effect on
435 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000436
Georg Brandl2ee470f2008-07-16 12:55:28 +0000437 The optional ignore argument is a callable. If given, it
438 is called with the `src` parameter, which is the directory
439 being visited by copytree(), and `names` which is the list of
440 `src` contents, as returned by os.listdir():
441
442 callable(src, names) -> ignored_names
443
444 Since copytree() is called recursively, the callable will be
445 called once for each directory that is copied. It returns a
446 list of names relative to the `src` directory that should
447 not be copied.
448
Tarek Ziadé5340db32010-04-19 22:30:51 +0000449 The optional copy_function argument is a callable that will be used
450 to copy each file. It will be called with the source path and the
451 destination path as arguments. By default, copy2() is used, but any
452 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000453
454 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000455 names = os.listdir(src)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000456 if ignore is not None:
457 ignored_names = ignore(src, names)
458 else:
459 ignored_names = set()
460
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000461 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000462 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000463 for name in names:
Georg Brandl2ee470f2008-07-16 12:55:28 +0000464 if name in ignored_names:
465 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000466 srcname = os.path.join(src, name)
467 dstname = os.path.join(dst, name)
468 try:
Tarek Ziadéfb437512010-04-20 08:57:33 +0000469 if os.path.islink(srcname):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000470 linkto = os.readlink(srcname)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000471 if symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100472 # We can't just leave it to `copy_function` because legacy
473 # code with a custom `copy_function` may rely on copytree
474 # doing the right thing.
Tarek Ziadéfb437512010-04-20 08:57:33 +0000475 os.symlink(linkto, dstname)
Larry Hastingsb4038062012-07-15 10:57:38 -0700476 copystat(srcname, dstname, follow_symlinks=not symlinks)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000477 else:
478 # ignore dangling symlink if the flag is on
479 if not os.path.exists(linkto) and ignore_dangling_symlinks:
480 continue
481 # otherwise let the copy occurs. copy2 will raise an error
Berker Peksag5a294d82015-07-25 14:53:48 +0300482 if os.path.isdir(srcname):
483 copytree(srcname, dstname, symlinks, ignore,
484 copy_function)
485 else:
486 copy_function(srcname, dstname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000487 elif os.path.isdir(srcname):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000488 copytree(srcname, dstname, symlinks, ignore, copy_function)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000489 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000490 # Will raise a SpecialFileError for unsupported file types
Tarek Ziadé5340db32010-04-19 22:30:51 +0000491 copy_function(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000492 # catch the Error from the recursive copytree so that we can
493 # continue with other files
Guido van Rossumb940e112007-01-10 16:19:56 +0000494 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000495 errors.extend(err.args[0])
Andrew Svetlov3438fa42012-12-17 23:35:18 +0200496 except OSError as why:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000497 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000498 try:
499 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000500 except OSError as why:
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200501 # Copying file access times may fail on Windows
Berker Peksag884afd92014-12-10 02:50:32 +0200502 if getattr(why, 'winerror', None) is None:
Georg Brandlc8076df2012-08-25 10:11:57 +0200503 errors.append((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000504 if errors:
Collin Winterce36ad82007-08-30 01:19:48 +0000505 raise Error(errors)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500506 return dst
Guido van Rossumd7673291998-02-06 21:38:09 +0000507
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200508# version vulnerable to race conditions
509def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000510 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200511 with os.scandir(path) as scandir_it:
512 entries = list(scandir_it)
Christian Heimes9bd667a2008-01-20 15:14:11 +0000513 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200514 onerror(os.scandir, path, sys.exc_info())
515 entries = []
516 for entry in entries:
517 fullname = entry.path
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000518 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200519 is_dir = entry.is_dir(follow_symlinks=False)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200520 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200521 is_dir = False
522 if is_dir:
523 try:
524 if entry.is_symlink():
525 # This can only happen if someone replaces
526 # a directory with a symlink after the call to
527 # os.scandir or entry.is_dir above.
528 raise OSError("Cannot call rmtree on a symbolic link")
529 except OSError:
530 onerror(os.path.islink, fullname, sys.exc_info())
531 continue
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200532 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000533 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000534 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200535 os.unlink(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200536 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200537 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000538 try:
539 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200540 except OSError:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000541 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000542
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200543# Version using fd-based APIs to protect against races
544def _rmtree_safe_fd(topfd, path, onerror):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200545 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200546 with os.scandir(topfd) as scandir_it:
547 entries = list(scandir_it)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100548 except OSError as err:
549 err.filename = path
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200550 onerror(os.scandir, path, sys.exc_info())
551 return
552 for entry in entries:
553 fullname = os.path.join(path, entry.name)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200554 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200555 is_dir = entry.is_dir(follow_symlinks=False)
556 if is_dir:
557 orig_st = entry.stat(follow_symlinks=False)
558 is_dir = stat.S_ISDIR(orig_st.st_mode)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100559 except OSError:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200560 is_dir = False
561 if is_dir:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200562 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200563 dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100564 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200565 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200566 else:
567 try:
568 if os.path.samestat(orig_st, os.fstat(dirfd)):
569 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200570 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200571 os.rmdir(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100572 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200573 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawackb5501102012-12-10 09:11:25 +0100574 else:
575 try:
576 # This can only happen if someone replaces
577 # a directory with a symlink after the call to
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200578 # os.scandir or stat.S_ISDIR above.
Hynek Schlawackb5501102012-12-10 09:11:25 +0100579 raise OSError("Cannot call rmtree on a symbolic "
580 "link")
581 except OSError:
582 onerror(os.path.islink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200583 finally:
584 os.close(dirfd)
585 else:
586 try:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200587 os.unlink(entry.name, dir_fd=topfd)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100588 except OSError:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200589 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200590
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200591_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
592 os.supports_dir_fd and
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200593 os.scandir in os.supports_fd and
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200594 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000595
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200596def rmtree(path, ignore_errors=False, onerror=None):
597 """Recursively delete a directory tree.
598
599 If ignore_errors is set, errors are ignored; otherwise, if onerror
600 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200601 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200602 path is the argument to that function that caused it to fail; and
603 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
604 is false and onerror is None, an exception is raised.
605
606 """
607 if ignore_errors:
608 def onerror(*args):
609 pass
610 elif onerror is None:
611 def onerror(*args):
612 raise
613 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200614 # While the unsafe rmtree works fine on bytes, the fd based does not.
615 if isinstance(path, bytes):
616 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200617 # Note: To guard against symlink races, we use the standard
618 # lstat()/open()/fstat() trick.
619 try:
620 orig_st = os.lstat(path)
621 except Exception:
622 onerror(os.lstat, path, sys.exc_info())
623 return
624 try:
625 fd = os.open(path, os.O_RDONLY)
626 except Exception:
627 onerror(os.lstat, path, sys.exc_info())
628 return
629 try:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100630 if os.path.samestat(orig_st, os.fstat(fd)):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200631 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200632 try:
633 os.rmdir(path)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200634 except OSError:
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200635 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200636 else:
Hynek Schlawackb5501102012-12-10 09:11:25 +0100637 try:
638 # symlinks to directories are forbidden, see bug #1669
639 raise OSError("Cannot call rmtree on a symbolic link")
640 except OSError:
641 onerror(os.path.islink, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200642 finally:
643 os.close(fd)
644 else:
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200645 try:
646 if os.path.islink(path):
647 # symlinks to directories are forbidden, see bug #1669
648 raise OSError("Cannot call rmtree on a symbolic link")
649 except OSError:
650 onerror(os.path.islink, path, sys.exc_info())
651 # can't continue even if onerror hook returns
652 return
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200653 return _rmtree_unsafe(path, onerror)
654
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000655# Allow introspection of whether or not the hardening against symlink
656# attacks is supported on the current platform
657rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000658
Christian Heimesada8c3b2008-03-18 18:26:33 +0000659def _basename(path):
660 # A basename() variant which first strips the trailing slash, if present.
661 # Thus we always get the last component of the path, even for directories.
Serhiy Storchaka3a308b92014-02-11 10:30:59 +0200662 sep = os.path.sep + (os.path.altsep or '')
663 return os.path.basename(path.rstrip(sep))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000664
R David Murray6ffface2014-06-11 14:40:13 -0400665def move(src, dst, copy_function=copy2):
Christian Heimesada8c3b2008-03-18 18:26:33 +0000666 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500667 similar to the Unix "mv" command. Return the file or directory's
668 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000669
670 If the destination is a directory or a symlink to a directory, the source
671 is moved inside the directory. The destination path must not already
672 exist.
673
674 If the destination already exists but is not a directory, it may be
675 overwritten depending on os.rename() semantics.
676
677 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100678 Otherwise, src is copied to the destination and then removed. Symlinks are
679 recreated under the new name if os.rename() fails because of cross
680 filesystem renames.
681
R David Murray6ffface2014-06-11 14:40:13 -0400682 The optional `copy_function` argument is a callable that will be used
683 to copy the source or it will be delegated to `copytree`.
684 By default, copy2() is used, but any function that supports the same
685 signature (like copy()) can be used.
686
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000687 A lot more could be done here... A look at a mv.c shows a lot of
688 the issues this implementation glosses over.
689
690 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000691 real_dst = dst
692 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200693 if _samefile(src, dst):
694 # We might be on a case insensitive filesystem,
695 # perform the rename anyway.
696 os.rename(src, dst)
697 return
698
Christian Heimesada8c3b2008-03-18 18:26:33 +0000699 real_dst = os.path.join(dst, _basename(src))
700 if os.path.exists(real_dst):
701 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000702 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000703 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200704 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100705 if os.path.islink(src):
706 linkto = os.readlink(src)
707 os.symlink(linkto, real_dst)
708 os.unlink(src)
709 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000710 if _destinsrc(src, dst):
R David Murray6ffface2014-06-11 14:40:13 -0400711 raise Error("Cannot move a directory '%s' into itself"
712 " '%s'." % (src, dst))
713 copytree(src, real_dst, copy_function=copy_function,
714 symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000715 rmtree(src)
716 else:
R David Murray6ffface2014-06-11 14:40:13 -0400717 copy_function(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000718 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500719 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000720
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000721def _destinsrc(src, dst):
Berker Peksag3715da52014-09-18 05:11:15 +0300722 src = os.path.abspath(src)
723 dst = os.path.abspath(dst)
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000724 if not src.endswith(os.path.sep):
725 src += os.path.sep
726 if not dst.endswith(os.path.sep):
727 dst += os.path.sep
728 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000729
730def _get_gid(name):
731 """Returns a gid, given a group name."""
732 if getgrnam is None or name is None:
733 return None
734 try:
735 result = getgrnam(name)
736 except KeyError:
737 result = None
738 if result is not None:
739 return result[2]
740 return None
741
742def _get_uid(name):
743 """Returns an uid, given a user name."""
744 if getpwnam is None or name is None:
745 return None
746 try:
747 result = getpwnam(name)
748 except KeyError:
749 result = None
750 if result is not None:
751 return result[2]
752 return None
753
754def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
755 owner=None, group=None, logger=None):
756 """Create a (possibly compressed) tar file from all the files under
757 'base_dir'.
758
Serhiy Storchaka11213772014-08-06 18:50:19 +0300759 'compress' must be "gzip" (the default), "bzip2", "xz", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000760
761 'owner' and 'group' can be used to define an owner and a group for the
762 archive that is being built. If not provided, the current owner and group
763 will be used.
764
Éric Araujo4433a5f2010-12-15 20:26:30 +0000765 The output tar file will be named 'base_name' + ".tar", possibly plus
Serhiy Storchaka11213772014-08-06 18:50:19 +0300766 the appropriate compression extension (".gz", ".bz2", or ".xz").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000767
768 Returns the output filename.
769 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200770 if compress is None:
771 tar_compression = ''
772 elif _ZLIB_SUPPORTED and compress == 'gzip':
773 tar_compression = 'gz'
774 elif _BZ2_SUPPORTED and compress == 'bzip2':
775 tar_compression = 'bz2'
776 elif _LZMA_SUPPORTED and compress == 'xz':
777 tar_compression = 'xz'
778 else:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000779 raise ValueError("bad value for 'compress', or compression format not "
780 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000781
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200782 import tarfile # late import for breaking circular dependency
783
784 compress_ext = '.' + tar_compression if compress else ''
785 archive_name = base_name + '.tar' + compress_ext
Tarek Ziadé396fad72010-02-23 05:30:31 +0000786 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000787
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200788 if archive_dir and not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000789 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200790 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000791 if not dry_run:
792 os.makedirs(archive_dir)
793
Tarek Ziadé396fad72010-02-23 05:30:31 +0000794 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000795 if logger is not None:
796 logger.info('Creating tar archive')
797
798 uid = _get_uid(owner)
799 gid = _get_gid(group)
800
801 def _set_uid_gid(tarinfo):
802 if gid is not None:
803 tarinfo.gid = gid
804 tarinfo.gname = group
805 if uid is not None:
806 tarinfo.uid = uid
807 tarinfo.uname = owner
808 return tarinfo
809
810 if not dry_run:
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200811 tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000812 try:
813 tar.add(base_dir, filter=_set_uid_gid)
814 finally:
815 tar.close()
816
Tarek Ziadé396fad72010-02-23 05:30:31 +0000817 return archive_name
818
Tarek Ziadé396fad72010-02-23 05:30:31 +0000819def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
820 """Create a zip file from all the files under 'base_dir'.
821
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200822 The output zip file will be named 'base_name' + ".zip". Returns the
823 name of the output zip file.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000824 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200825 import zipfile # late import for breaking circular dependency
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400826
Tarek Ziadé396fad72010-02-23 05:30:31 +0000827 zip_filename = base_name + ".zip"
828 archive_dir = os.path.dirname(base_name)
829
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +0200830 if archive_dir and not os.path.exists(archive_dir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000831 if logger is not None:
832 logger.info("creating %s", archive_dir)
833 if not dry_run:
834 os.makedirs(archive_dir)
835
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400836 if logger is not None:
837 logger.info("creating '%s' and adding '%s' to it",
838 zip_filename, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000839
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400840 if not dry_run:
841 with zipfile.ZipFile(zip_filename, "w",
842 compression=zipfile.ZIP_DEFLATED) as zf:
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300843 path = os.path.normpath(base_dir)
Serhiy Storchaka666de772016-10-23 15:55:09 +0300844 if path != os.curdir:
845 zf.write(path, path)
846 if logger is not None:
847 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400848 for dirpath, dirnames, filenames in os.walk(base_dir):
Serhiy Storchakad941d7a2015-09-08 05:51:00 +0300849 for name in sorted(dirnames):
850 path = os.path.normpath(os.path.join(dirpath, name))
851 zf.write(path, path)
852 if logger is not None:
853 logger.info("adding '%s'", path)
Andrew Kuchlinga0934b22014-03-20 16:11:16 -0400854 for name in filenames:
855 path = os.path.normpath(os.path.join(dirpath, name))
856 if os.path.isfile(path):
857 zf.write(path, path)
858 if logger is not None:
859 logger.info("adding '%s'", path)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000860
861 return zip_filename
862
863_ARCHIVE_FORMATS = {
Tarek Ziadé396fad72010-02-23 05:30:31 +0000864 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200865}
866
867if _ZLIB_SUPPORTED:
868 _ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
869 "gzip'ed tar-file")
870 _ARCHIVE_FORMATS['zip'] = (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000871
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000872if _BZ2_SUPPORTED:
873 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
874 "bzip2'ed tar-file")
875
Serhiy Storchaka11213772014-08-06 18:50:19 +0300876if _LZMA_SUPPORTED:
877 _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
878 "xz'ed tar-file")
879
Tarek Ziadé396fad72010-02-23 05:30:31 +0000880def get_archive_formats():
881 """Returns a list of supported formats for archiving and unarchiving.
882
883 Each element of the returned sequence is a tuple (name, description)
884 """
885 formats = [(name, registry[2]) for name, registry in
886 _ARCHIVE_FORMATS.items()]
887 formats.sort()
888 return formats
889
890def register_archive_format(name, function, extra_args=None, description=''):
891 """Registers an archive format.
892
893 name is the name of the format. function is the callable that will be
894 used to create archives. If provided, extra_args is a sequence of
895 (name, value) tuples that will be passed as arguments to the callable.
896 description can be provided to describe the format, and will be returned
897 by the get_archive_formats() function.
898 """
899 if extra_args is None:
900 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200901 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000902 raise TypeError('The %s object is not callable' % function)
903 if not isinstance(extra_args, (tuple, list)):
904 raise TypeError('extra_args needs to be a sequence')
905 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200906 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000907 raise TypeError('extra_args elements are : (arg_name, value)')
908
909 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
910
911def unregister_archive_format(name):
912 del _ARCHIVE_FORMATS[name]
913
914def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
915 dry_run=0, owner=None, group=None, logger=None):
916 """Create an archive file (eg. zip or tar).
917
918 'base_name' is the name of the file to create, minus any format-specific
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200919 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
920 "bztar", or "xztar". Or any other registered format.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000921
922 'root_dir' is a directory that will be the root directory of the
923 archive; ie. we typically chdir into 'root_dir' before creating the
924 archive. 'base_dir' is the directory where we start archiving from;
925 ie. 'base_dir' will be the common prefix of all files and
926 directories in the archive. 'root_dir' and 'base_dir' both default
927 to the current directory. Returns the name of the archive file.
928
929 'owner' and 'group' are used when creating a tar archive. By default,
930 uses the current owner and group.
931 """
932 save_cwd = os.getcwd()
933 if root_dir is not None:
934 if logger is not None:
935 logger.debug("changing into '%s'", root_dir)
936 base_name = os.path.abspath(base_name)
937 if not dry_run:
938 os.chdir(root_dir)
939
940 if base_dir is None:
941 base_dir = os.curdir
942
943 kwargs = {'dry_run': dry_run, 'logger': logger}
944
945 try:
946 format_info = _ARCHIVE_FORMATS[format]
947 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +0300948 raise ValueError("unknown archive format '%s'" % format) from None
Tarek Ziadé396fad72010-02-23 05:30:31 +0000949
950 func = format_info[0]
951 for arg, val in format_info[1]:
952 kwargs[arg] = val
953
954 if format != 'zip':
955 kwargs['owner'] = owner
956 kwargs['group'] = group
957
958 try:
959 filename = func(base_name, base_dir, **kwargs)
960 finally:
961 if root_dir is not None:
962 if logger is not None:
963 logger.debug("changing back to '%s'", save_cwd)
964 os.chdir(save_cwd)
965
966 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000967
968
969def get_unpack_formats():
970 """Returns a list of supported formats for unpacking.
971
972 Each element of the returned sequence is a tuple
973 (name, extensions, description)
974 """
975 formats = [(name, info[0], info[3]) for name, info in
976 _UNPACK_FORMATS.items()]
977 formats.sort()
978 return formats
979
980def _check_unpack_options(extensions, function, extra_args):
981 """Checks what gets registered as an unpacker."""
982 # first make sure no other unpacker is registered for this extension
983 existing_extensions = {}
984 for name, info in _UNPACK_FORMATS.items():
985 for ext in info[0]:
986 existing_extensions[ext] = name
987
988 for extension in extensions:
989 if extension in existing_extensions:
990 msg = '%s is already registered for "%s"'
991 raise RegistryError(msg % (extension,
992 existing_extensions[extension]))
993
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200994 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000995 raise TypeError('The registered function must be a callable')
996
997
998def register_unpack_format(name, extensions, function, extra_args=None,
999 description=''):
1000 """Registers an unpack format.
1001
1002 `name` is the name of the format. `extensions` is a list of extensions
1003 corresponding to the format.
1004
1005 `function` is the callable that will be
1006 used to unpack archives. The callable will receive archives to unpack.
1007 If it's unable to handle an archive, it needs to raise a ReadError
1008 exception.
1009
1010 If provided, `extra_args` is a sequence of
1011 (name, value) tuples that will be passed as arguments to the callable.
1012 description can be provided to describe the format, and will be returned
1013 by the get_unpack_formats() function.
1014 """
1015 if extra_args is None:
1016 extra_args = []
1017 _check_unpack_options(extensions, function, extra_args)
1018 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
1019
1020def unregister_unpack_format(name):
Martin Pantereb995702016-07-28 01:11:04 +00001021 """Removes the pack format from the registry."""
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001022 del _UNPACK_FORMATS[name]
1023
1024def _ensure_directory(path):
1025 """Ensure that the parent directory of `path` exists"""
1026 dirname = os.path.dirname(path)
1027 if not os.path.isdir(dirname):
1028 os.makedirs(dirname)
1029
1030def _unpack_zipfile(filename, extract_dir):
1031 """Unpack zip `filename` to `extract_dir`
1032 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001033 import zipfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001034
1035 if not zipfile.is_zipfile(filename):
1036 raise ReadError("%s is not a zip file" % filename)
1037
1038 zip = zipfile.ZipFile(filename)
1039 try:
1040 for info in zip.infolist():
1041 name = info.filename
1042
1043 # don't extract absolute paths or ones with .. in them
1044 if name.startswith('/') or '..' in name:
1045 continue
1046
1047 target = os.path.join(extract_dir, *name.split('/'))
1048 if not target:
1049 continue
1050
1051 _ensure_directory(target)
1052 if not name.endswith('/'):
1053 # file
1054 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +02001055 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001056 try:
1057 f.write(data)
1058 finally:
1059 f.close()
1060 del data
1061 finally:
1062 zip.close()
1063
1064def _unpack_tarfile(filename, extract_dir):
Serhiy Storchaka11213772014-08-06 18:50:19 +03001065 """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001066 """
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001067 import tarfile # late import for breaking circular dependency
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001068 try:
1069 tarobj = tarfile.open(filename)
1070 except tarfile.TarError:
1071 raise ReadError(
1072 "%s is not a compressed or uncompressed tar file" % filename)
1073 try:
1074 tarobj.extractall(extract_dir)
1075 finally:
1076 tarobj.close()
1077
1078_UNPACK_FORMATS = {
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001079 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001080 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"),
1081}
1082
1083if _ZLIB_SUPPORTED:
1084 _UNPACK_FORMATS['gztar'] = (['.tar.gz', '.tgz'], _unpack_tarfile, [],
1085 "gzip'ed tar-file")
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001086
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001087if _BZ2_SUPPORTED:
Serhiy Storchaka11213772014-08-06 18:50:19 +03001088 _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [],
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001089 "bzip2'ed tar-file")
1090
Serhiy Storchaka11213772014-08-06 18:50:19 +03001091if _LZMA_SUPPORTED:
1092 _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
1093 "xz'ed tar-file")
1094
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001095def _find_unpack_format(filename):
1096 for name, info in _UNPACK_FORMATS.items():
1097 for extension in info[0]:
1098 if filename.endswith(extension):
1099 return name
1100 return None
1101
1102def unpack_archive(filename, extract_dir=None, format=None):
1103 """Unpack an archive.
1104
1105 `filename` is the name of the archive.
1106
1107 `extract_dir` is the name of the target directory, where the archive
1108 is unpacked. If not provided, the current working directory is used.
1109
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001110 `format` is the archive format: one of "zip", "tar", "gztar", "bztar",
1111 or "xztar". Or any other registered format. If not provided,
1112 unpack_archive will use the filename extension and see if an unpacker
1113 was registered for that extension.
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001114
1115 In case none is found, a ValueError is raised.
1116 """
1117 if extract_dir is None:
1118 extract_dir = os.getcwd()
1119
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001120 extract_dir = os.fspath(extract_dir)
1121 filename = os.fspath(filename)
1122
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001123 if format is not None:
1124 try:
1125 format_info = _UNPACK_FORMATS[format]
1126 except KeyError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +03001127 raise ValueError("Unknown unpack format '{0}'".format(format)) from None
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001128
Nick Coghlanabf202d2011-03-16 13:52:20 -04001129 func = format_info[1]
1130 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001131 else:
1132 # we need to look at the registered unpackers supported extensions
1133 format = _find_unpack_format(filename)
1134 if format is None:
1135 raise ReadError("Unknown archive format '{0}'".format(filename))
1136
1137 func = _UNPACK_FORMATS[format][1]
1138 kwargs = dict(_UNPACK_FORMATS[format][2])
1139 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001140
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001141
1142if hasattr(os, 'statvfs'):
1143
1144 __all__.append('disk_usage')
1145 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Raymond Hettinger5b798ab2015-08-17 22:04:45 -07001146 _ntuple_diskusage.total.__doc__ = 'Total space in bytes'
1147 _ntuple_diskusage.used.__doc__ = 'Used space in bytes'
1148 _ntuple_diskusage.free.__doc__ = 'Free space in bytes'
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001149
1150 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001151 """Return disk usage statistics about the given path.
1152
Sandro Tosif8ae4fa2012-04-23 20:07:15 +02001153 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001154 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001155 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001156 st = os.statvfs(path)
1157 free = st.f_bavail * st.f_frsize
1158 total = st.f_blocks * st.f_frsize
1159 used = (st.f_blocks - st.f_bfree) * st.f_frsize
1160 return _ntuple_diskusage(total, used, free)
1161
Giampaolo Rodolac7f02a92018-06-19 08:27:29 -07001162elif _WINDOWS:
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001163
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001164 __all__.append('disk_usage')
1165 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
1166
1167 def disk_usage(path):
1168 """Return disk usage statistics about the given path.
1169
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001170 Returned values is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +02001171 'free', which are the amount of total, used and free space, in bytes.
1172 """
1173 total, free = nt._getdiskusage(path)
1174 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001175 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +02001176
Éric Araujo0ac4a5d2011-09-01 08:31:51 +02001177
Sandro Tosid902a142011-08-22 23:28:27 +02001178def chown(path, user=None, group=None):
1179 """Change owner user and group of the given path.
1180
1181 user and group can be the uid/gid or the user/group names, and in that case,
1182 they are converted to their respective uid/gid.
1183 """
1184
1185 if user is None and group is None:
1186 raise ValueError("user and/or group must be set")
1187
1188 _user = user
1189 _group = group
1190
1191 # -1 means don't change it
1192 if user is None:
1193 _user = -1
1194 # user can either be an int (the uid) or a string (the system username)
1195 elif isinstance(user, str):
1196 _user = _get_uid(user)
1197 if _user is None:
1198 raise LookupError("no such user: {!r}".format(user))
1199
1200 if group is None:
1201 _group = -1
1202 elif not isinstance(group, int):
1203 _group = _get_gid(group)
1204 if _group is None:
1205 raise LookupError("no such group: {!r}".format(group))
1206
1207 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001208
1209def get_terminal_size(fallback=(80, 24)):
1210 """Get the size of the terminal window.
1211
1212 For each of the two dimensions, the environment variable, COLUMNS
1213 and LINES respectively, is checked. If the variable is defined and
1214 the value is a positive integer, it is used.
1215
1216 When COLUMNS or LINES is not defined, which is the common case,
1217 the terminal connected to sys.__stdout__ is queried
1218 by invoking os.get_terminal_size.
1219
1220 If the terminal size cannot be successfully queried, either because
1221 the system doesn't support querying, or because we are not
1222 connected to a terminal, the value given in fallback parameter
1223 is used. Fallback defaults to (80, 24) which is the default
1224 size used by many terminal emulators.
1225
1226 The value returned is a named tuple of type os.terminal_size.
1227 """
1228 # columns, lines are the working values
1229 try:
1230 columns = int(os.environ['COLUMNS'])
1231 except (KeyError, ValueError):
1232 columns = 0
1233
1234 try:
1235 lines = int(os.environ['LINES'])
1236 except (KeyError, ValueError):
1237 lines = 0
1238
1239 # only query if necessary
1240 if columns <= 0 or lines <= 0:
1241 try:
1242 size = os.get_terminal_size(sys.__stdout__.fileno())
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001243 except (AttributeError, ValueError, OSError):
1244 # stdout is None, closed, detached, or not a terminal, or
1245 # os.get_terminal_size() is unsupported
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001246 size = os.terminal_size(fallback)
1247 if columns <= 0:
1248 columns = size.columns
1249 if lines <= 0:
1250 lines = size.lines
1251
1252 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001253
1254def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001255 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001256 conforms to the given mode on the PATH, or None if there is no such
1257 file.
1258
1259 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1260 of os.environ.get("PATH"), or can be overridden with a custom search
1261 path.
1262
1263 """
Victor Stinner1d006a22013-12-16 23:39:40 +01001264 # Check that a given file can be accessed with the correct mode.
1265 # Additionally check that `file` is not a directory, as on Windows
1266 # directories pass the os.access check.
1267 def _access_check(fn, mode):
1268 return (os.path.exists(fn) and os.access(fn, mode)
1269 and not os.path.isdir(fn))
1270
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001271 # If we're given a path with a directory part, look it up directly rather
1272 # than referring to PATH directories. This includes checking relative to the
1273 # current directory, e.g. ./script
1274 if os.path.dirname(cmd):
1275 if _access_check(cmd, mode):
1276 return cmd
1277 return None
Brian Curtinc57a3452012-06-22 16:00:30 -05001278
Barry Warsaw618738b2013-04-16 11:05:03 -04001279 if path is None:
1280 path = os.environ.get("PATH", os.defpath)
1281 if not path:
1282 return None
Victor Stinner1d006a22013-12-16 23:39:40 +01001283 path = path.split(os.pathsep)
Brian Curtinc57a3452012-06-22 16:00:30 -05001284
1285 if sys.platform == "win32":
1286 # The current directory takes precedence on Windows.
1287 if not os.curdir in path:
1288 path.insert(0, os.curdir)
1289
1290 # PATHEXT is necessary to check on Windows.
1291 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
1292 # See if the given file matches any of the expected path extensions.
1293 # This will allow us to short circuit when given "python.exe".
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001294 # If it does match, only test that one, otherwise we have to try
1295 # others.
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001296 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
1297 files = [cmd]
1298 else:
1299 files = [cmd + ext for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001300 else:
1301 # On other platforms you don't have things like PATHEXT to tell you
1302 # what file suffixes are executable, so just pass on cmd as-is.
1303 files = [cmd]
1304
1305 seen = set()
1306 for dir in path:
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001307 normdir = os.path.normcase(dir)
1308 if not normdir in seen:
1309 seen.add(normdir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001310 for thefile in files:
1311 name = os.path.join(dir, thefile)
1312 if _access_check(name, mode):
1313 return name
1314 return None