realpath: fix handling of non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru
2025-08-14 10:52:24 +02:00
parent becbc0e19d
commit ce7c571754
2 changed files with 33 additions and 7 deletions
+8 -7
View File
@@ -5,8 +5,9 @@
// spell-checker:ignore (ToDO) retcode
use clap::{Arg, ArgAction, ArgMatches, Command, builder::NonEmptyStringValueParser};
use clap::{Arg, ArgAction, ArgMatches, Command};
use std::{
ffi::OsString,
io::{Write, stdout},
path::{Path, PathBuf},
};
@@ -40,7 +41,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();
@@ -145,21 +146,21 @@ pub fn uu_app() -> Command {
Arg::new(OPT_RELATIVE_TO)
.long(OPT_RELATIVE_TO)
.value_name("DIR")
.value_parser(NonEmptyStringValueParser::new())
.value_parser(clap::value_parser!(OsString))
.help(translate!("realpath-help-relative-to")),
)
.arg(
Arg::new(OPT_RELATIVE_BASE)
.long(OPT_RELATIVE_BASE)
.value_name("DIR")
.value_parser(NonEmptyStringValueParser::new())
.value_parser(clap::value_parser!(OsString))
.help(translate!("realpath-help-relative-base")),
)
.arg(
Arg::new(ARG_FILES)
.action(ArgAction::Append)
.required(true)
.value_parser(NonEmptyStringValueParser::new())
.value_parser(clap::value_parser!(OsString))
.value_hint(clap::ValueHint::AnyPath),
)
}
@@ -174,10 +175,10 @@ fn prepare_relative_options(
resolve_mode: ResolveMode,
) -> UResult<(Option<PathBuf>, Option<PathBuf>)> {
let relative_to = matches
.get_one::<String>(OPT_RELATIVE_TO)
.get_one::<OsString>(OPT_RELATIVE_TO)
.map(PathBuf::from);
let relative_base = matches
.get_one::<String>(OPT_RELATIVE_BASE)
.get_one::<OsString>(OPT_RELATIVE_BASE)
.map(PathBuf::from);
let relative_to = canonicalize_relative_option(relative_to, can_mode, resolve_mode)?;
let relative_base = canonicalize_relative_option(relative_base, can_mode, resolve_mode)?;
+25
View File
@@ -464,3 +464,28 @@ fn test_realpath_trailing_slash() {
fn test_realpath_empty() {
new_ucmd!().fails_with_code(1);
}
#[test]
#[cfg(target_os = "linux")]
fn test_realpath_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);
// Create the actual file
at.touch(non_utf8_name);
// Test that realpath handles non-UTF-8 paths without crashing
let result = scene.ucmd().arg(non_utf8_name).succeeds();
// The result should contain the non-UTF-8 bytes
let output = result.stdout_str_lossy();
assert!(output.contains("test_"));
assert!(output.contains(".txt"));
}