diff --git a/src/uu/expand/src/expand.rs b/src/uu/expand/src/expand.rs index cd528316e..5b0b8f4e7 100644 --- a/src/uu/expand/src/expand.rs +++ b/src/uu/expand/src/expand.rs @@ -170,7 +170,7 @@ fn tabstops_parse(s: &str) -> Result<(RemainingMode, Vec), ParseError> { } struct Options { - files: Vec, + files: Vec, tabstops: Vec, tspaces: String, iflag: bool, @@ -204,9 +204,9 @@ impl Options { .unwrap(); // length of tabstops is guaranteed >= 1 let tspaces = " ".repeat(nspaces); - let files: Vec = match matches.get_many::(options::FILES) { - Some(s) => s.map(|v| v.to_string()).collect(), - None => vec!["-".to_owned()], + let files: Vec = match matches.get_many::(options::FILES) { + Some(s) => s.cloned().collect(), + None => vec![OsString::from("-")], }; Ok(Self { @@ -283,16 +283,18 @@ pub fn uu_app() -> Command { Arg::new(options::FILES) .action(ArgAction::Append) .hide(true) - .value_hint(clap::ValueHint::FilePath), + .value_hint(clap::ValueHint::FilePath) + .value_parser(clap::value_parser!(OsString)), ) } -fn open(path: &str) -> UResult>> { +fn open(path: &OsString) -> UResult>> { let file_buf; if path == "-" { Ok(BufReader::new(Box::new(stdin()) as Box)) } else { - file_buf = File::open(path).map_err_context(|| path.to_string())?; + let path_ref = Path::new(path); + file_buf = File::open(path_ref).map_err_context(|| path.to_string_lossy().to_string())?; Ok(BufReader::new(Box::new(file_buf) as Box)) } } @@ -446,7 +448,7 @@ fn expand(options: &Options) -> UResult<()> { if Path::new(file).is_dir() { show_error!( "{}", - translate!("expand-error-is-directory", "file" => file) + translate!("expand-error-is-directory", "file" => file.to_string_lossy()) ); set_exit_code(1); continue; diff --git a/tests/by-util/test_expand.rs b/tests/by-util/test_expand.rs index 799feb4a3..741aad366 100644 --- a/tests/by-util/test_expand.rs +++ b/tests/by-util/test_expand.rs @@ -426,3 +426,19 @@ fn test_nonexisting_file() { .stderr_contains("expand: nonexistent: No such file or directory") .stdout_contains_line("// !note: file contains significant whitespace"); } + +#[test] +#[cfg(target_os = "linux")] +fn test_expand_non_utf8_paths() { + use std::os::unix::ffi::OsStringExt; + use uutests::at_and_ucmd; + + let (at, mut ucmd) = at_and_ucmd!(); + + let filename = std::ffi::OsString::from_vec(vec![0xFF, 0xFE]); + std::fs::write(at.plus(&filename), b"hello\tworld\ntest\tline\n").unwrap(); + + ucmd.arg(&filename) + .succeeds() + .stdout_is("hello world\ntest line\n"); +}