mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
readlink: fix handling of non-UTF-8 filenames
This commit is contained in:
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user