summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Wiederhake <BenWiederhake.GitHub@gmx.de>2024-07-16 03:57:37 +0200
committerBen Wiederhake <BenWiederhake.GitHub@gmx.de>2024-07-27 01:29:01 +0200
commit6af9fd784ea41621cdcc44478302f49db1191d7b (patch)
treec4b8f7076ea59f2758ee9b0e9e78bcb8e7817ca0
parent244634b5c6ca77e0b970b97393b9fc81e2470d26 (diff)
cksum: correctly output non-utf8 filename
-rw-r--r--src/uu/cksum/src/cksum.rs84
-rw-r--r--tests/by-util/test_cksum.rs29
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();
+}