diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index f1b7ff2bfec..0e094cb5385 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -335,22 +335,15 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) } } target_dir.to_path_buf() - } else if let Some(name) = srcpath.as_os_str().to_str() { - match Path::new(name).file_name() { + } else { + match srcpath.file_name() { Some(basename) => target_dir.join(basename), // This can be None only for "." or "..". Trying // to create a link with such name will fail with // EEXIST, which agrees with the behavior of GNU // coreutils. - None => target_dir.join(name), + None => target_dir.join(srcpath), } - } else { - show_error!( - "{}", - translate!("ln-error-cannot-stat", "path" => srcpath.quote()) - ); - all_successful = false; - continue; }; if linked_destinations.contains(&targetpath) { diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index 560a7364f2f..bc06956e8c6 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -378,6 +378,51 @@ fn test_symlink_target_dir() { assert_eq!(at.resolve_link(file_b_link), file_b); } +#[test] +#[cfg(target_os = "linux")] +fn test_symlink_target_dir_non_utf8_source_name() { + use std::ffi::OsStr; + use std::fs; + use std::os::unix::ffi::OsStrExt; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let target_dir = "test_symlink_target_dir_non_utf8"; + let source_bytes = b"source_\xFF\xFE"; + let source_name = OsStr::from_bytes(source_bytes); + + at.mkdir(target_dir); + at.touch(source_name); + + scene + .ucmd() + .args(&["-s", "-t", target_dir]) + .arg(source_name) + .succeeds() + .no_stderr(); + + let target_dir_path = at.plus(target_dir); + let mut dir_entries = fs::read_dir(&target_dir_path) + .expect("reading target directory entries after creating symlink"); + let created_entry = dir_entries + .next() + .expect("finding created entry in target directory") + .expect("reading created target-directory entry"); + assert!( + dir_entries.next().is_none(), + "expected only one created entry in target directory" + ); + assert_eq!( + created_entry.file_name().as_os_str().as_bytes(), + source_bytes + ); + + let created_link_path = target_dir_path.join(source_name); + let created_link_target = fs::read_link(&created_link_path) + .expect("reading created symlink target in target directory"); + assert_eq!(created_link_target.as_os_str().as_bytes(), source_bytes); +} + #[test] fn test_symlink_target_dir_from_dir() { let (at, mut ucmd) = at_and_ucmd!();