1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

cksum: correctly output non-utf8 filename

This commit is contained in:
Ben Wiederhake 2024-07-16 03:57:37 +02:00
parent 244634b5c6
commit 6af9fd784e
2 changed files with 76 additions and 37 deletions

View file

@ -19,7 +19,7 @@ use uucore::checksum::{
use uucore::{ use uucore::{
encoding, encoding,
error::{FromIo, UResult, USimpleError}, 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}, sum::{div_ceil, Digest},
}; };
@ -117,52 +117,64 @@ where
}; };
// The BSD checksum output is 5 digit integer // The BSD checksum output is 5 digit integer
let bsd_width = 5; let bsd_width = 5;
match (options.algo_name, not_file) { let (before_filename, should_print_filename, after_filename) = match options.algo_name {
(ALGORITHM_OPTIONS_SYSV, true) => println!( ALGORITHM_OPTIONS_SYSV => (
"{} {}", format!(
sum.parse::<u16>().unwrap(), "{} {}{}",
div_ceil(sz, options.output_bits)
),
(ALGORITHM_OPTIONS_SYSV, false) => println!(
"{} {} {}",
sum.parse::<u16>().unwrap(), sum.parse::<u16>().unwrap(),
div_ceil(sz, options.output_bits), div_ceil(sz, options.output_bits),
filename.display() if not_file { "" } else { " " }
), ),
(ALGORITHM_OPTIONS_BSD, true) => println!( !not_file,
"{:0bsd_width$} {:bsd_width$}", String::new(),
sum.parse::<u16>().unwrap(),
div_ceil(sz, options.output_bits)
), ),
(ALGORITHM_OPTIONS_BSD, false) => println!( ALGORITHM_OPTIONS_BSD => (
"{:0bsd_width$} {:bsd_width$} {}", format!(
"{:0bsd_width$} {:bsd_width$}{}",
sum.parse::<u16>().unwrap(), sum.parse::<u16>().unwrap(),
div_ceil(sz, options.output_bits), div_ceil(sz, options.output_bits),
filename.display() if not_file { "" } else { " " }
), ),
(ALGORITHM_OPTIONS_CRC, true) => println!("{sum} {sz}"), !not_file,
(ALGORITHM_OPTIONS_CRC, false) => println!("{sum} {sz} {}", filename.display()), String::new(),
(ALGORITHM_OPTIONS_BLAKE2B, _) if options.tag => { ),
ALGORITHM_OPTIONS_CRC => (
format!("{sum} {sz}{}", if not_file { "" } else { " " }),
!not_file,
String::new(),
),
ALGORITHM_OPTIONS_BLAKE2B if options.tag => {
(
if let Some(length) = options.length { if let Some(length) = options.length {
// Multiply by 8 here, as we want to print the length in bits. // Multiply by 8 here, as we want to print the length in bits.
println!("BLAKE2b-{} ({}) = {sum}", length * 8, filename.display()); format!("BLAKE2b-{} (", length * 8)
} else { } else {
println!("BLAKE2b ({}) = {sum}", filename.display()); "BLAKE2b (".to_owned()
} },
true,
format!(") = {sum}"),
)
} }
_ => { _ => {
if options.tag { if options.tag {
println!( (
"{} ({}) = {sum}", format!("{} (", options.algo_name.to_ascii_uppercase()),
options.algo_name.to_ascii_uppercase(), true,
filename.display() format!(") = {sum}"),
); )
} else { } else {
let prefix = if options.asterisk { "*" } 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(()) Ok(())

View file

@ -2,7 +2,7 @@
// //
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // 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; use crate::common::util::TestScenario;
@ -1250,3 +1250,30 @@ fn test_several_files_error_mgmt() {
.stderr_contains("empty: no properly ") .stderr_contains("empty: no properly ")
.stderr_contains("incorrect: 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();
}