Copy metadata from the given PathInfo to the given local path.
(info, target, follow_symlinks=True)
| 253 | |
| 254 | |
| 255 | def copy_info(info, target, follow_symlinks=True): |
| 256 | """Copy metadata from the given PathInfo to the given local path.""" |
| 257 | copy_times_ns = ( |
| 258 | hasattr(info, '_access_time_ns') and |
| 259 | hasattr(info, '_mod_time_ns') and |
| 260 | (follow_symlinks or os.utime in os.supports_follow_symlinks)) |
| 261 | if copy_times_ns: |
| 262 | t0 = info._access_time_ns(follow_symlinks=follow_symlinks) |
| 263 | t1 = info._mod_time_ns(follow_symlinks=follow_symlinks) |
| 264 | os.utime(target, ns=(t0, t1), follow_symlinks=follow_symlinks) |
| 265 | |
| 266 | # We must copy extended attributes before the file is (potentially) |
| 267 | # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. |
| 268 | copy_xattrs = ( |
| 269 | hasattr(info, '_xattrs') and |
| 270 | hasattr(os, 'setxattr') and |
| 271 | (follow_symlinks or os.setxattr in os.supports_follow_symlinks)) |
| 272 | if copy_xattrs: |
| 273 | xattrs = info._xattrs(follow_symlinks=follow_symlinks) |
| 274 | for attr, value in xattrs: |
| 275 | try: |
| 276 | os.setxattr(target, attr, value, follow_symlinks=follow_symlinks) |
| 277 | except OSError as e: |
| 278 | if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): |
| 279 | raise |
| 280 | |
| 281 | copy_posix_permissions = ( |
| 282 | hasattr(info, '_posix_permissions') and |
| 283 | (follow_symlinks or os.chmod in os.supports_follow_symlinks)) |
| 284 | if copy_posix_permissions: |
| 285 | posix_permissions = info._posix_permissions(follow_symlinks=follow_symlinks) |
| 286 | try: |
| 287 | os.chmod(target, posix_permissions, follow_symlinks=follow_symlinks) |
| 288 | except NotImplementedError: |
| 289 | # if we got a NotImplementedError, it's because |
| 290 | # * follow_symlinks=False, |
| 291 | # * lchown() is unavailable, and |
| 292 | # * either |
| 293 | # * fchownat() is unavailable or |
| 294 | # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. |
| 295 | # (it returned ENOSUP.) |
| 296 | # therefore we're out of options--we simply cannot chown the |
| 297 | # symlink. give up, suppress the error. |
| 298 | # (which is what shutil always did in this circumstance.) |
| 299 | pass |
| 300 | |
| 301 | copy_bsd_flags = ( |
| 302 | hasattr(info, '_bsd_flags') and |
| 303 | hasattr(os, 'chflags') and |
| 304 | (follow_symlinks or os.chflags in os.supports_follow_symlinks)) |
| 305 | if copy_bsd_flags: |
| 306 | bsd_flags = info._bsd_flags(follow_symlinks=follow_symlinks) |
| 307 | try: |
| 308 | os.chflags(target, bsd_flags, follow_symlinks=follow_symlinks) |
| 309 | except OSError as why: |
| 310 | if why.errno not in (EOPNOTSUPP, ENOTSUP): |
| 311 | raise |
| 312 |
no test coverage detected