diff options
author | Ben Wiederhake <BenWiederhake.GitHub@gmx.de> | 2024-07-16 03:57:37 +0200 |
---|---|---|
committer | Ben Wiederhake <BenWiederhake.GitHub@gmx.de> | 2024-07-27 01:29:01 +0200 |
commit | 6af9fd784ea41621cdcc44478302f49db1191d7b (patch) | |
tree | c4b8f7076ea59f2758ee9b0e9e78bcb8e7817ca0 | |
parent | 244634b5c6ca77e0b970b97393b9fc81e2470d26 (diff) |
cksum: correctly output non-utf8 filename
-rw-r--r-- | src/uu/cksum/src/cksum.rs | 84 | ||||
-rw-r--r-- | tests/by-util/test_cksum.rs | 29 |
2 files changed, 76 insertions, 37 deletions
diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index ca0badae5c..1a3c51b3e7 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -19,7 +19,7 @@ use uucore::checksum::{ use uucore::{ encoding, error::{FromIo, UResult, USimpleError}, - format_usage, help_about, help_section, help_usage, show, + format_usage, help_about, help_section, help_usage, os_str_as_bytes, show, sum::{div_ceil, Digest}, }; @@ -117,52 +117,64 @@ where }; // The BSD checksum output is 5 digit integer let bsd_width = 5; - match (options.algo_name, not_file) { - (ALGORITHM_OPTIONS_SYSV, true) => println!( - "{} {}", - sum.parse::<u16>().unwrap(), - div_ceil(sz, options.output_bits) + let (before_filename, should_print_filename, after_filename) = match options.algo_name { + ALGORITHM_OPTIONS_SYSV => ( + format!( + "{} {}{}", + sum.parse::<u16>().unwrap(), + div_ceil(sz, options.output_bits), + if not_file { "" } else { " " } + ), + !not_file, + String::new(), ), - (ALGORITHM_OPTIONS_SYSV, false) => println!( - "{} {} {}", - sum.parse::<u16>().unwrap(), - div_ceil(sz, options.output_bits), - filename.display() + ALGORITHM_OPTIONS_BSD => ( + format!( + "{:0bsd_width$} {:bsd_width$}{}", + sum.parse::<u16>().unwrap(), + div_ceil(sz, options.output_bits), + if not_file { "" } else { " " } + ), + !not_file, + String::new(), ), - (ALGORITHM_OPTIONS_BSD, true) => println!( - "{:0bsd_width$} {:bsd_width$}", - sum.parse::<u16>().unwrap(), - div_ceil(sz, options.output_bits) + ALGORITHM_OPTIONS_CRC => ( + format!("{sum} {sz}{}", if not_file { "" } else { " " }), + !not_file, + String::new(), ), - (ALGORITHM_OPTIONS_BSD, false) => println!( - "{:0bsd_width$} {:bsd_width$} {}", - sum.parse::<u16>().unwrap(), - div_ceil(sz, options.output_bits), - filename.display() - ), - (ALGORITHM_OPTIONS_CRC, true) => println!("{sum} {sz}"), - (ALGORITHM_OPTIONS_CRC, false) => println!("{sum} {sz} {}", filename.display()), - (ALGORITHM_OPTIONS_BLAKE2B, _) if options.tag => { - if let Some(length) = options.length { - // Multiply by 8 here, as we want to print the length in bits. - println!("BLAKE2b-{} ({}) = {sum}", length * 8, filename.display()); - } else { - println!("BLAKE2b ({}) = {sum}", filename.display()); - } + ALGORITHM_OPTIONS_BLAKE2B if options.tag => { + ( + if let Some(length) = options.length { + // Multiply by 8 here, as we want to print the length in bits. + format!("BLAKE2b-{} (", length * 8) + } else { + "BLAKE2b (".to_owned() + }, + true, + format!(") = {sum}"), + ) } _ => { if options.tag { - println!( - "{} ({}) = {sum}", - options.algo_name.to_ascii_uppercase(), - filename.display() - ); + ( + format!("{} (", options.algo_name.to_ascii_uppercase()), + true, + format!(") = {sum}"), + ) } else { let prefix = if options.asterisk { "*" } else { " " }; - println!("{sum} {prefix}{}", filename.display()); + (format!("{sum} {prefix}"), true, String::new()) } } + }; + print!("{}", before_filename); + if should_print_filename { + // The filename might not be valid UTF-8, and filename.display() would mangle the names. + // Therefore, emit the bytes directly to stdout, without any attempt at encoding them. + let _dropped_result = stdout().write_all(os_str_as_bytes(filename.as_os_str())?); } + println!("{}", after_filename); } Ok(()) diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index b2aafc2cbd..117e54e1ef 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -2,7 +2,7 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (words) asdf algo algos mgmt +// spell-checker:ignore (words) asdf algo algos asha mgmt xffname use crate::common::util::TestScenario; @@ -1250,3 +1250,30 @@ fn test_several_files_error_mgmt() { .stderr_contains("empty: no properly ") .stderr_contains("incorrect: no properly "); } + +#[cfg(target_os = "linux")] +#[test] +fn test_non_utf8_filename() { + use std::ffi::OsString; + use std::os::unix::ffi::OsStringExt; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let filename: OsString = OsStringExt::from_vec(b"funky\xffname".to_vec()); + + at.touch(&filename); + + scene + .ucmd() + .arg(&filename) + .succeeds() + .stdout_is_bytes(b"4294967295 0 funky\xffname\n") + .no_stderr(); + scene + .ucmd() + .arg("-asha256") + .arg(filename) + .succeeds() + .stdout_is_bytes(b"SHA256 (funky\xffname) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n") + .no_stderr(); +} |