diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 851117bde..cf723e4ee 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1218,28 +1218,38 @@ fn copy_file(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> { /// Copy the file from `source` to `dest` either using the normal `fs::copy` or a /// copy-on-write scheme if --reflink is specified and the filesystem supports it. fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> { - if options.reflink_mode != ReflinkMode::Never { - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - return Err("--reflink is only supported on linux and macOS" - .to_string() - .into()); - - #[cfg(target_os = "macos")] - copy_on_write_macos(source, dest, options.reflink_mode)?; - #[cfg(target_os = "linux")] - copy_on_write_linux(source, dest, options.reflink_mode)?; - } else if !options.dereference && fs::symlink_metadata(&source)?.file_type().is_symlink() { - copy_link(source, dest)?; - } else if source.to_string_lossy() == "/dev/null" { + if options.parents { + let parent = dest.parent().unwrap_or(dest); + fs::create_dir_all(parent)?; + } + let is_symlink = fs::symlink_metadata(&source)?.file_type().is_symlink(); + if source.to_string_lossy() == "/dev/null" { /* workaround a limitation of fs::copy * https://github.com/rust-lang/rust/issues/79390 */ File::create(dest)?; - } else { - if options.parents { - let parent = dest.parent().unwrap_or(dest); - fs::create_dir_all(parent)?; + } else if !options.dereference && is_symlink { + copy_link(source, dest)?; + } else if options.reflink_mode != ReflinkMode::Never { + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + return Err("--reflink is only supported on linux and macOS" + .to_string() + .into()); + if is_symlink { + assert!(options.dereference); + let real_path = std::fs::read_link(source)?; + + #[cfg(target_os = "macos")] + copy_on_write_macos(&real_path, dest, options.reflink_mode)?; + #[cfg(target_os = "linux")] + copy_on_write_linux(&real_path, dest, options.reflink_mode)?; + } else { + #[cfg(target_os = "macos")] + copy_on_write_macos(source, dest, options.reflink_mode)?; + #[cfg(target_os = "linux")] + copy_on_write_linux(source, dest, options.reflink_mode)?; } + } else { fs::copy(source, dest).context(&*context_for(source, dest))?; }