Fix sum to handle non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru 2025-08-08 15:10:35 +02:00
parent 6e55a2a3bb
commit fddaa1187a
2 changed files with 42 additions and 24 deletions

View file

@ -6,6 +6,7 @@
// spell-checker:ignore (ToDO) sysv
use clap::{Arg, ArgAction, Command};
use std::ffi::OsString;
use std::fs::File;
use std::io::{ErrorKind, Read, Write, stdin, stdout};
use std::path::Path;
@ -67,27 +68,26 @@ fn sysv_sum(mut reader: impl Read) -> std::io::Result<(usize, u16)> {
Ok((blocks_read, ret as u16))
}
fn open(name: &str) -> UResult<Box<dyn Read>> {
match name {
"-" => Ok(Box::new(stdin()) as Box<dyn Read>),
_ => {
let path = &Path::new(name);
if path.is_dir() {
return Err(USimpleError::new(
2,
translate!("sum-error-is-directory", "name" => name.maybe_quote()),
));
}
// Silent the warning as we want to the error message
if path.metadata().is_err() {
return Err(USimpleError::new(
2,
translate!("sum-error-no-such-file-or-directory", "name" => name.maybe_quote()),
));
}
let f = File::open(path).map_err_context(String::new)?;
Ok(Box::new(f) as Box<dyn Read>)
fn open(name: &OsString) -> UResult<Box<dyn Read>> {
if name == "-" {
Ok(Box::new(stdin()) as Box<dyn Read>)
} else {
let path = Path::new(name);
if path.is_dir() {
return Err(USimpleError::new(
2,
translate!("sum-error-is-directory", "name" => name.to_string_lossy().maybe_quote()),
));
}
// Silent the warning as we want to the error message
if path.metadata().is_err() {
return Err(USimpleError::new(
2,
translate!("sum-error-no-such-file-or-directory", "name" => name.to_string_lossy().maybe_quote()),
));
}
let f = File::open(path).map_err_context(String::new)?;
Ok(Box::new(f) as Box<dyn Read>)
}
}
@ -101,9 +101,9 @@ mod options {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().get_matches_from_localized(args);
let files: Vec<String> = match matches.get_many::<String>(options::FILE) {
let files: Vec<OsString> = match matches.get_many::<OsString>(options::FILE) {
Some(v) => v.cloned().collect(),
None => vec!["-".to_owned()],
None => vec![OsString::from("-")],
};
let sysv = matches.get_flag(options::SYSTEM_V_COMPATIBLE);
@ -127,7 +127,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let mut stdout = stdout().lock();
if print_names {
writeln!(stdout, "{sum:0width$} {blocks:width$} {file}")?;
writeln!(
stdout,
"{sum:0width$} {blocks:width$} {}",
file.to_string_lossy()
)?;
} else {
writeln!(stdout, "{sum:0width$} {blocks:width$}")?;
}
@ -146,7 +150,8 @@ pub fn uu_app() -> Command {
Arg::new(options::FILE)
.action(ArgAction::Append)
.hide(true)
.value_hint(clap::ValueHint::FilePath),
.value_hint(clap::ValueHint::FilePath)
.value_parser(clap::value_parser!(OsString)),
)
.arg(
Arg::new(options::BSD_COMPATIBLE)

View file

@ -2,6 +2,8 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
#[cfg(target_os = "linux")]
use std::os::unix::ffi::OsStringExt;
use uutests::at_and_ucmd;
use uutests::new_ucmd;
@ -80,3 +82,14 @@ fn test_invalid_metadata() {
.fails()
.stderr_is("sum: b: No such file or directory\n");
}
#[test]
#[cfg(target_os = "linux")]
fn test_sum_non_utf8_paths() {
let (at, mut ucmd) = at_and_ucmd!();
let filename = std::ffi::OsString::from_vec(vec![0xFF, 0xFE]);
std::fs::write(at.plus(&filename), b"test content").unwrap();
ucmd.arg(&filename).succeeds();
}