From 6c46d09397759118343a3e7fdd21310aa99debac Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Wed, 2 Jun 2021 21:27:08 +0200 Subject: [PATCH] ln: canonicalize the parent directory of dst, not dst dst may or may not exist. In case it exists it might already be a symlink. In neither case we should try to canonicalize dst, only its parent directory. https://www.gnu.org/software/coreutils/manual/html_node/ln-invocation.html > Relative symbolic links are generated based on their canonicalized > **containing directory**, and canonicalized targets. --- src/uu/ln/src/ln.rs | 3 ++- tests/by-util/test_ln.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 4087716bd..33ec5f449 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -372,7 +372,8 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) fn relative_path<'a>(src: &Path, dst: &Path) -> Result> { let src_abs = canonicalize(src, CanonicalizeMode::Normal)?; - let dst_abs = canonicalize(dst, CanonicalizeMode::Normal)?; + let mut dst_abs = canonicalize(dst.parent().unwrap(), CanonicalizeMode::Normal)?; + dst_abs.push(dst.components().last().unwrap()); let suffix_pos = src_abs .components() .zip(dst_abs.components()) diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index 00ea85ecd..fc97ff779 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -562,3 +562,21 @@ fn test_symlink_no_deref_file() { fn test_relative_requires_symbolic() { new_ucmd!().args(&["-r", "foo", "bar"]).fails(); } + +#[test] +fn test_relative_dst_already_symlink() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("file1"); + at.symlink_file("file1", "file2"); + ucmd.arg("-srf").arg("file1").arg("file2").succeeds(); + at.is_symlink("file2"); +} + +#[test] +fn test_relative_src_already_symlink() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("file1"); + at.symlink_file("file1", "file2"); + ucmd.arg("-sr").arg("file2").arg("file3").succeeds(); + assert!(at.resolve_link("file3").ends_with("file1")); +}