Skip to content

Commit ed05338

Browse files
committed
cksum: correctly output non-utf8 filename
1 parent 24c8b99 commit ed05338

File tree

2 files changed

+92
-33
lines changed

2 files changed

+92
-33
lines changed

src/uu/cksum/src/cksum.rs

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -117,52 +117,82 @@ where
117117
};
118118
// The BSD checksum output is 5 digit integer
119119
let bsd_width = 5;
120-
match (options.algo_name, not_file) {
121-
(ALGORITHM_OPTIONS_SYSV, true) => println!(
122-
"{} {}",
123-
sum.parse::<u16>().unwrap(),
124-
div_ceil(sz, options.output_bits)
120+
let (before_filename, print_filename, after_filename) = match (options.algo_name, not_file)
121+
{
122+
(ALGORITHM_OPTIONS_SYSV, true) => (
123+
format!(
124+
"{} {}",
125+
sum.parse::<u16>().unwrap(),
126+
div_ceil(sz, options.output_bits)
127+
),
128+
false,
129+
String::new(),
125130
),
126-
(ALGORITHM_OPTIONS_SYSV, false) => println!(
127-
"{} {} {}",
128-
sum.parse::<u16>().unwrap(),
129-
div_ceil(sz, options.output_bits),
130-
filename.display()
131+
(ALGORITHM_OPTIONS_SYSV, false) => (
132+
format!(
133+
"{} {} ",
134+
sum.parse::<u16>().unwrap(),
135+
div_ceil(sz, options.output_bits)
136+
),
137+
true,
138+
String::new(),
131139
),
132-
(ALGORITHM_OPTIONS_BSD, true) => println!(
133-
"{:0bsd_width$} {:bsd_width$}",
134-
sum.parse::<u16>().unwrap(),
135-
div_ceil(sz, options.output_bits)
140+
(ALGORITHM_OPTIONS_BSD, true) => (
141+
format!(
142+
"{:0bsd_width$} {:bsd_width$}",
143+
sum.parse::<u16>().unwrap(),
144+
div_ceil(sz, options.output_bits)
145+
),
146+
false,
147+
String::new(),
136148
),
137-
(ALGORITHM_OPTIONS_BSD, false) => println!(
138-
"{:0bsd_width$} {:bsd_width$} {}",
139-
sum.parse::<u16>().unwrap(),
140-
div_ceil(sz, options.output_bits),
141-
filename.display()
149+
(ALGORITHM_OPTIONS_BSD, false) => (
150+
format!(
151+
"{:0bsd_width$} {:bsd_width$} ",
152+
sum.parse::<u16>().unwrap(),
153+
div_ceil(sz, options.output_bits),
154+
),
155+
true,
156+
String::new(),
142157
),
143-
(ALGORITHM_OPTIONS_CRC, true) => println!("{sum} {sz}"),
144-
(ALGORITHM_OPTIONS_CRC, false) => println!("{sum} {sz} {}", filename.display()),
158+
(ALGORITHM_OPTIONS_CRC, true) => (format!("{sum} {sz}"), false, String::new()),
159+
(ALGORITHM_OPTIONS_CRC, false) => (format!("{sum} {sz} "), true, String::new()),
145160
(ALGORITHM_OPTIONS_BLAKE2B, _) if options.tag => {
146-
if let Some(length) = options.length {
147-
// Multiply by 8 here, as we want to print the length in bits.
148-
println!("BLAKE2b-{} ({}) = {sum}", length * 8, filename.display());
149-
} else {
150-
println!("BLAKE2b ({}) = {sum}", filename.display());
151-
}
161+
(
162+
if let Some(length) = options.length {
163+
// Multiply by 8 here, as we want to print the length in bits.
164+
format!("BLAKE2b-{} (", length * 8)
165+
} else {
166+
format!("BLAKE2b (")
167+
},
168+
true,
169+
format!(") = {sum}"),
170+
)
152171
}
153172
_ => {
154173
if options.tag {
155-
println!(
156-
"{} ({}) = {sum}",
157-
options.algo_name.to_ascii_uppercase(),
158-
filename.display()
159-
);
174+
(
175+
format!("{} (", options.algo_name.to_ascii_uppercase()),
176+
true,
177+
format!(") = {sum}")
178+
)
160179
} else {
161180
let prefix = if options.asterisk { "*" } else { " " };
162-
println!("{sum} {prefix}{}", filename.display());
181+
(
182+
format!("{sum} {prefix}"),
183+
true,
184+
String::new()
185+
)
163186
}
164187
}
188+
};
189+
print!("{}", before_filename);
190+
if print_filename {
191+
// The filename might not be valid UTF-8, and filename.display() would mangle the names.
192+
// Therefore, emit the bytes directly to stdout, without any attempt at encoding them.
193+
stdout().write(filename.as_os_str().as_encoded_bytes()).expect("FIXME");
165194
}
195+
println!("{}", after_filename);
166196
}
167197

168198
Ok(())

tests/by-util/test_cksum.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
use crate::common::util::TestScenario;
88

9+
#[cfg(unix)]
10+
use std::ffi::OsString;
11+
#[cfg(unix)]
12+
use std::os::unix::ffi::OsStringExt;
13+
914
const ALGOS: [&str; 11] = [
1015
"sysv", "bsd", "crc", "md5", "sha1", "sha224", "sha256", "sha384", "sha512", "blake2b", "sm3",
1116
];
@@ -1250,3 +1255,27 @@ fn test_several_files_error_mgmt() {
12501255
.stderr_contains("empty: no properly ")
12511256
.stderr_contains("incorrect: no properly ");
12521257
}
1258+
1259+
#[cfg(unix)]
1260+
#[test]
1261+
fn test_non_utf8_filename() {
1262+
let scene = TestScenario::new(util_name!());
1263+
let at = &scene.fixtures;
1264+
let filename: OsString = OsStringExt::from_vec(b"funky\xffname".to_vec());
1265+
1266+
at.touch(filename.clone());
1267+
1268+
scene
1269+
.ucmd()
1270+
.arg(filename.clone())
1271+
.succeeds()
1272+
.stdout_is_bytes(b"4294967295 0 funky\xffname\n")
1273+
.no_stderr();
1274+
scene
1275+
.ucmd()
1276+
.arg("-asha256")
1277+
.arg(filename)
1278+
.succeeds()
1279+
.stdout_is_bytes(b"SHA256 (funky\xffname) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n")
1280+
.no_stderr();
1281+
}

0 commit comments

Comments
 (0)