summaryrefslogtreecommitdiffstats
path: root/Lib/shutil.py
diff options
context:
space:
mode:
authorLarry Hastings <larry@hastings.org>2012-06-22 23:30:09 (GMT)
committerLarry Hastings <larry@hastings.org>2012-06-22 23:30:09 (GMT)
commit9cf065cfdc4245ea7e31edcb2e6ede0cea47d148 (patch)
tree22d8450865a023586034d555ae72e3753f95e84c /Lib/shutil.py
parentf0f4742b495554238d1204ce0002c1ef1ba23507 (diff)
downloadcpython-9cf065cfdc4245ea7e31edcb2e6ede0cea47d148.zip
cpython-9cf065cfdc4245ea7e31edcb2e6ede0cea47d148.tar.gz
cpython-9cf065cfdc4245ea7e31edcb2e6ede0cea47d148.tar.bz2
Issue #14626: Large refactoring of functions / parameters in the os module.
Many functions now support "dir_fd" and "follow_symlinks" parameters; some also support accepting an open file descriptor in place of of a path string. Added os.support_* collections as LBYL helpers. Removed many functions only previously seen in 3.3 alpha releases (often starting with "f" or "l", or ending with "at"). Originally suggested by Serhiy Storchaka; implemented by Larry Hastings.
Diffstat (limited to 'Lib/shutil.py')
-rw-r--r--Lib/shutil.py63
1 files changed, 36 insertions, 27 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 8da46d1..401e9ea 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -139,27 +139,45 @@ def copystat(src, dst, symlinks=False):
only if both `src` and `dst` are symlinks.
"""
- def _nop(*args, ns=None):
+ def _nop(*args, ns=None, follow_symlinks=None):
pass
- if symlinks and os.path.islink(src) and os.path.islink(dst):
- stat_func = os.lstat
- utime_func = os.lutimes if hasattr(os, 'lutimes') else _nop
- chmod_func = os.lchmod if hasattr(os, 'lchmod') else _nop
- chflags_func = os.lchflags if hasattr(os, 'lchflags') else _nop
+ # follow symlinks (aka don't not follow symlinks)
+ follow = not (symlinks and os.path.islink(src) and os.path.islink(dst))
+ if follow:
+ # use the real function if it exists
+ def lookup(name):
+ return getattr(os, name, _nop)
else:
- stat_func = os.stat
- utime_func = os.utime if hasattr(os, 'utime') else _nop
- chmod_func = os.chmod if hasattr(os, 'chmod') else _nop
- chflags_func = os.chflags if hasattr(os, 'chflags') else _nop
-
- st = stat_func(src)
+ # use the real function only if it exists
+ # *and* it supports follow_symlinks
+ def lookup(name):
+ fn = getattr(os, name, _nop)
+ if fn in os.supports_follow_symlinks:
+ return fn
+ return _nop
+
+ st = lookup("stat")(src, follow_symlinks=follow)
mode = stat.S_IMODE(st.st_mode)
- utime_func(dst, ns=(st.st_atime_ns, st.st_mtime_ns))
- chmod_func(dst, mode)
+ lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
+ follow_symlinks=follow)
+ try:
+ lookup("chmod")(dst, mode, follow_symlinks=follow)
+ except NotImplementedError:
+ # if we got a NotImplementedError, it's because
+ # * follow_symlinks=False,
+ # * lchown() is unavailable, and
+ # * either
+ # * fchownat() is unvailable or
+ # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
+ # (it returned ENOSUP.)
+ # therefore we're out of options--we simply cannot chown the
+ # symlink. give up, suppress the error.
+ # (which is what shutil always did in this circumstance.)
+ pass
if hasattr(st, 'st_flags'):
try:
- chflags_func(dst, st.st_flags)
+ lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
except OSError as why:
for err in 'EOPNOTSUPP', 'ENOTSUP':
if hasattr(errno, err) and why.errno == getattr(errno, err):
@@ -176,20 +194,11 @@ if hasattr(os, 'listxattr'):
If the optional flag `symlinks` is set, symlinks won't be followed.
"""
- if symlinks:
- listxattr = os.llistxattr
- removexattr = os.lremovexattr
- setxattr = os.lsetxattr
- getxattr = os.lgetxattr
- else:
- listxattr = os.listxattr
- removexattr = os.removexattr
- setxattr = os.setxattr
- getxattr = os.getxattr
- for attr in listxattr(src):
+ for name in os.listxattr(src, follow_symlinks=symlinks):
try:
- setxattr(dst, attr, getxattr(src, attr))
+ value = os.getxattr(src, name, follow_symlinks=symlinks)
+ os.setxattr(dst, name, value, follow_symlinks=symlinks)
except OSError as e:
if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
raise