From 682667fd1d9a6a5fc9dde43667d79623351b071c Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 4 Dec 2022 16:37:21 -0500 Subject: [PATCH] cp: force link between two files that exist Allow `cp` to link files that exist. For example, $ touch src dest $ cp -f --link src dest Before this commit, an error was raised. --- src/uu/cp/src/cp.rs | 6 ++++++ tests/by-util/test_cp.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 4050dd146..bb1ca8679 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1429,6 +1429,9 @@ fn copy_file( backup_dest(dest, &backup_path)?; fs::remove_file(dest)?; } + if options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) { + fs::remove_file(dest)?; + } } if options.dereference(source_in_command_line) && source.is_symlink() { let resolved = @@ -1451,6 +1454,9 @@ fn copy_file( )?; } CopyMode::SymLink => { + if dest.exists() && options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) { + fs::remove_file(dest)?; + } symlink_file(source, dest, context, symlinked_files)?; } CopyMode::Update => { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 2ab7b1598..8c27f10ac 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -13,6 +13,8 @@ use std::os::unix::fs::MetadataExt; use std::os::unix::fs::PermissionsExt; #[cfg(windows)] use std::os::windows::fs::symlink_file; +#[cfg(not(windows))] +use std::path::Path; #[cfg(any(target_os = "linux", target_os = "android"))] use filetime::FileTime; @@ -2389,3 +2391,31 @@ fn test_preserve_hardlink_attributes_in_directory() { at.metadata("dest/src/link").ino() ); } + +#[test] +#[cfg(not(windows))] +fn test_hard_link_file() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("src"); + at.touch("dest"); + ucmd.args(&["-f", "--link", "src", "dest"]) + .succeeds() + .no_output(); + #[cfg(all(unix, not(target_os = "freebsd")))] + assert_eq!(at.metadata("src").ino(), at.metadata("dest").ino()); +} + +#[test] +#[cfg(not(windows))] +fn test_symbolic_link_file() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("src"); + at.touch("dest"); + ucmd.args(&["-f", "--symbolic-link", "src", "dest"]) + .succeeds() + .no_output(); + assert_eq!( + std::fs::read_link(at.plus("dest")).unwrap(), + Path::new("src") + ); +}