diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 50fafa90124..8d32c70bd24 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -406,8 +406,9 @@ pub fn link(src: &Path, dst: &Path, settings: &Settings) -> LnResult<()> { if dst.is_symlink() || dst.exists() { backup_path = backup_control::get_backup_path(settings.backup, dst, &settings.suffix); - if settings.backup == BackupMode::Existing && !settings.symbolic { - // when ln --backup f f, it should detect that it is the same file + if settings.backup != BackupMode::None && !settings.symbolic { + // `ln --backup f f`: the backup would move `f` away before the + // link is made, so detect the same file first, for any backup mode if paths_refer_to_same_file(src, dst, true) && is_same_entry(src, dst) { return Err(LnError::SameFile(src.to_owned(), dst.to_owned())); } diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index 68a8121066b..7b817177fd6 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -1016,6 +1016,42 @@ fn test_backup_same_file() { .stderr_contains("n: 'file1' and './file1' are the same file"); } +#[test] +fn test_backup_simple_numbered_same_file() { + for backup in ["--backup=simple", "--backup=numbered"] { + for args in [ + vec![backup, "a", "a"], + vec!["-f", backup, "a", "a"], + vec!["-f", backup, "./a", "a"], + ] { + let (at, mut ucmd) = at_and_ucmd!(); + at.write("a", "content"); + + ucmd.args(&args) + .fails_with_code(1) + .stderr_contains("are the same file"); + + assert_eq!(at.read("a"), "content"); + assert!(!at.file_exists("a~")); + assert!(!at.file_exists("a.~1~")); + } + } +} + +#[test] +fn test_backup_simple_same_file_into_directory() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("d"); + at.write("d/a", "content"); + + ucmd.args(&["-f", "--backup=simple", "d/a", "d"]) + .fails_with_code(1) + .stderr_contains("are the same file"); + + assert_eq!(at.read("d/a"), "content"); + assert!(!at.file_exists("d/a~")); +} + #[test] #[cfg(not(target_os = "android"))] fn test_backup_existing_hard_linked_under_different_name() {