diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index f8ce6f241..fa9a1df65 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1309,6 +1309,15 @@ fn copy_file( match options.copy_mode { CopyMode::Link => { + if dest.exists() { + let backup_path = + backup_control::get_backup_path(options.backup, &dest, &options.backup_suffix); + if let Some(backup_path) = backup_path { + backup_dest(&dest, &backup_path)?; + fs::remove_file(&dest)?; + } + } + fs::hard_link(&source, &dest).context(context)?; } CopyMode::Copy => { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 92637dfbe..52081eb52 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1444,3 +1444,17 @@ fn test_cp_archive_on_nonexistent_file() { "cp: cannot stat 'nonexistent_file.txt': No such file or directory (os error 2)", ); } + +#[test] +fn test_cp_link_backup() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("file2"); + ucmd.arg("-l") + .arg("-b") + .arg(TEST_HELLO_WORLD_SOURCE) + .arg("file2") + .succeeds(); + + assert!(at.file_exists("file2~")); + assert_eq!(at.read("file2"), "Hello, World!\n"); +}