ln: fix handling of non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru
2025-08-14 10:52:24 +02:00
parent ce7c571754
commit b8702bd5df
2 changed files with 51 additions and 6 deletions
+8 -6
View File
@@ -34,7 +34,7 @@ pub struct Settings {
symbolic: bool,
relative: bool,
logical: bool,
target_dir: Option<String>,
target_dir: Option<PathBuf>,
no_target_dir: bool,
no_dereference: bool,
verbose: bool,
@@ -102,7 +102,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
/* the list of files */
let paths: Vec<PathBuf> = matches
.get_many::<String>(ARG_FILES)
.get_many::<OsString>(ARG_FILES)
.unwrap()
.map(PathBuf::from)
.collect();
@@ -131,8 +131,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
logical,
relative: matches.get_flag(options::RELATIVE),
target_dir: matches
.get_one::<String>(options::TARGET_DIRECTORY)
.map(String::from),
.get_one::<OsString>(options::TARGET_DIRECTORY)
.map(PathBuf::from),
no_target_dir: matches.get_flag(options::NO_TARGET_DIRECTORY),
no_dereference: matches.get_flag(options::NO_DEREFERENCE),
verbose: matches.get_flag(options::VERBOSE),
@@ -210,6 +210,7 @@ pub fn uu_app() -> Command {
.help(translate!("ln-help-target-directory"))
.value_name("DIRECTORY")
.value_hint(clap::ValueHint::DirPath)
.value_parser(clap::value_parser!(OsString))
.conflicts_with(options::NO_TARGET_DIRECTORY),
)
.arg(
@@ -238,6 +239,7 @@ pub fn uu_app() -> Command {
Arg::new(ARG_FILES)
.action(ArgAction::Append)
.value_hint(clap::ValueHint::AnyPath)
.value_parser(clap::value_parser!(OsString))
.required(true)
.num_args(1..),
)
@@ -245,9 +247,9 @@ pub fn uu_app() -> Command {
fn exec(files: &[PathBuf], settings: &Settings) -> UResult<()> {
// Handle cases where we create links in a directory first.
if let Some(ref name) = settings.target_dir {
if let Some(ref target_path) = settings.target_dir {
// 4th form: a directory is specified by -t.
return link_files_in_dir(files, &PathBuf::from(name), settings);
return link_files_in_dir(files, target_path, settings);
}
if !settings.no_target_dir {
if files.len() == 1 {
+43
View File
@@ -843,3 +843,46 @@ fn test_ln_seen_file() {
);
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_ln_non_utf8_paths() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
// Create a test file with non-UTF-8 bytes in the name
let non_utf8_bytes = b"test_\xFF\xFE.txt";
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
let non_utf8_link_bytes = b"link_\xFF\xFE.txt";
let non_utf8_link_name = OsStr::from_bytes(non_utf8_link_bytes);
// Create the actual file
at.touch(non_utf8_name);
// Test creating a hard link with non-UTF-8 file names
scene.ucmd()
.arg(non_utf8_name)
.arg(non_utf8_link_name)
.succeeds();
// Both files should exist
assert!(at.file_exists(non_utf8_name));
assert!(at.file_exists(non_utf8_link_name));
// Test creating a symbolic link with non-UTF-8 file names
let symlink_bytes = b"symlink_\xFF\xFE.txt";
let symlink_name = OsStr::from_bytes(symlink_bytes);
scene.ucmd()
.args(&["-s"])
.arg(non_utf8_name)
.arg(symlink_name)
.succeeds();
// Check if symlink was created successfully
let symlink_path = at.plus(symlink_name);
assert!(symlink_path.is_symlink());
}