Skip to content

Commit 04a7f9c

Browse files
authored
Merge pull request #5731 from cakebaker/cp_backup_with_dest_a_symlink
cp: fix backup of destination symlink
2 parents bf26eda + 0701f53 commit 04a7f9c

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

src/uu/cp/src/cp.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,11 @@ fn context_for(src: &Path, dest: &Path) -> String {
14961496
/// Implements a simple backup copy for the destination file.
14971497
/// TODO: for the backup, should this function be replaced by `copy_file(...)`?
14981498
fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult<PathBuf> {
1499-
fs::copy(dest, backup_path)?;
1499+
if dest.is_symlink() {
1500+
fs::rename(dest, backup_path)?;
1501+
} else {
1502+
fs::copy(dest, backup_path)?;
1503+
}
15001504
Ok(backup_path.into())
15011505
}
15021506

tests/by-util/test_cp.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,27 @@ fn test_cp_arg_backup() {
678678
);
679679
}
680680

681+
#[test]
682+
fn test_cp_arg_backup_with_dest_a_symlink() {
683+
let (at, mut ucmd) = at_and_ucmd!();
684+
let source = "source";
685+
let source_content = "content";
686+
let symlink = "symlink";
687+
let original = "original";
688+
let backup = "symlink~";
689+
690+
at.write(source, source_content);
691+
at.write(original, "original");
692+
at.symlink_file(original, symlink);
693+
694+
ucmd.arg("-b").arg(source).arg(symlink).succeeds();
695+
696+
assert!(!at.symlink_exists(symlink));
697+
assert_eq!(source_content, at.read(symlink));
698+
assert!(at.symlink_exists(backup));
699+
assert_eq!(original, at.resolve_link(backup));
700+
}
701+
681702
#[test]
682703
fn test_cp_arg_backup_with_other_args() {
683704
let (at, mut ucmd) = at_and_ucmd!();

0 commit comments

Comments
 (0)