From 017dd864b2d0ff2eaefa37ff20d8e14131377622 Mon Sep 17 00:00:00 2001 From: barneygale Date: Sun, 28 Jul 2024 03:09:13 +0100 Subject: [PATCH] Fix copying metadata to non-symlinks --- Lib/pathlib/_abc.py | 24 +++++++++++++++++------- Lib/pathlib/_local.py | 6 +++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py index 86423da9c0945e..745c2328c96411 100644 --- a/Lib/pathlib/_abc.py +++ b/Lib/pathlib/_abc.py @@ -805,6 +805,16 @@ def _write_metadata(self, metadata, *, follow_symlinks=True): """ raise UnsupportedOperation(self._unsupported_msg('_write_metadata()')) + def _copy_metadata(self, target, *, follow_symlinks=True): + """ + Copies metadata (permissions, timestamps, etc) from this path to target. + """ + # Metadata types supported by both source and target. + keys = self._readable_metadata & target._writable_metadata + if keys: + metadata = self._read_metadata(keys, follow_symlinks=follow_symlinks) + target._write_metadata(metadata, follow_symlinks=follow_symlinks) + def _copy_data(self, target): """ Copy the contents of this file to the given target. @@ -839,20 +849,20 @@ def on_error(err): try: if not follow_symlinks and source.is_symlink(): target.symlink_to(source.readlink()) - elif source.is_dir(): + if preserve_metadata: + source._copy_metadata(target, follow_symlinks=False) + elif source.is_dir(follow_symlinks=follow_symlinks): children = source.iterdir() target.mkdir(exist_ok=dirs_exist_ok) for child in children: if not (ignore and ignore(child)): stack.append((child, target.joinpath(child.name))) + if preserve_metadata: + source._copy_metadata(target) else: source._copy_data(target) - if preserve_metadata: - # Metadata types supported by both source and target. - keys = source._readable_metadata & target._writable_metadata - if keys: - metadata = source._read_metadata(keys, follow_symlinks=follow_symlinks) - target._write_metadata(metadata, follow_symlinks=follow_symlinks) + if preserve_metadata: + source._copy_metadata(target) except OSError as err: on_error(err) diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py index a7e80824e7abf1..1e3b0fd5204d00 100644 --- a/Lib/pathlib/_local.py +++ b/Lib/pathlib/_local.py @@ -794,9 +794,9 @@ def _copy_data(self, target): try: target = os.fspath(target) except TypeError: - if isinstance(target, PathBase): - return PathBase._copy_data(self, target) - raise + if not isinstance(target, PathBase): + raise + PathBase._copy_data(self, target) else: copyfile(os.fspath(self), target)