readlink: fix handling of non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru
2025-08-14 10:52:24 +02:00
parent c0da27addc
commit 5c77fe1ab5
2 changed files with 34 additions and 7 deletions
+9 -7
View File
@@ -6,6 +6,7 @@
// spell-checker:ignore (ToDO) errno
use clap::{Arg, ArgAction, Command};
use std::ffi::OsString;
use std::fs;
use std::io::{Write, stdout};
use std::path::{Path, PathBuf};
@@ -54,9 +55,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
MissingHandling::Normal
};
let files: Vec<String> = matches
.get_many::<String>(ARG_FILES)
.map(|v| v.map(ToString::to_string).collect())
let files: Vec<PathBuf> = matches
.get_many::<OsString>(ARG_FILES)
.map(|v| v.map(PathBuf::from).collect())
.unwrap_or_default();
if files.is_empty() {
@@ -78,7 +79,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
};
for f in &files {
let p = PathBuf::from(f);
let p = f;
let path_result = if res_mode == ResolveMode::None {
fs::read_link(&p)
} else {
@@ -93,7 +94,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
return if verbose {
Err(USimpleError::new(
1,
err.map_err_context(move || f.maybe_quote().to_string())
err.map_err_context(move || f.to_string_lossy().to_string())
.to_string(),
))
} else {
@@ -171,13 +172,14 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(ARG_FILES)
.action(ArgAction::Append)
.value_parser(clap::value_parser!(OsString))
.value_hint(clap::ValueHint::AnyPath),
)
}
fn show(path: &Path, line_ending: Option<LineEnding>) -> std::io::Result<()> {
let path = path.to_str().unwrap();
print!("{path}");
use uucore::display::print_verbatim;
print_verbatim(path)?;
if let Some(line_ending) = line_ending {
print!("{line_ending}");
}
+25
View File
@@ -373,3 +373,28 @@ fn test_delimiters() {
.stderr_contains("ignoring --no-newline with multiple arguments")
.stdout_is("/a\n/a\n");
}
#[test]
#[cfg(target_os = "linux")]
fn test_readlink_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 target file and a symlink with non-UTF-8 bytes in the name
at.touch("target_file");
let non_utf8_bytes = b"symlink_\xFF\xFE";
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
// Create symlink using std::os::unix::fs::symlink
std::os::unix::fs::symlink(at.plus_as_string("target_file"), at.plus(non_utf8_name)).unwrap();
// Test that readlink handles non-UTF-8 symlink names without crashing
let result = scene.ucmd().arg(non_utf8_name).succeeds();
// The result should contain the target path
let output = result.stdout_str_lossy();
assert!(output.contains("target_file"));
}