Skip to content

Commit 77fa3c2

Browse files
committed
checksum: fix GNU test cksum-base64-untagged.sh
1 parent 2a314c7 commit 77fa3c2

File tree

1 file changed

+38
-28
lines changed

1 file changed

+38
-28
lines changed

src/uucore/src/lib/features/checksum/validate.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -296,27 +296,7 @@ impl LineFormat {
296296
SubCase::OpenSSL => ByteSliceExt::rsplit_once(after_paren, b")= ")?,
297297
};
298298

299-
fn is_valid_checksum(checksum: &[u8]) -> bool {
300-
if checksum.is_empty() {
301-
return false;
302-
}
303-
304-
let mut parts = checksum.splitn(2, |&b| b == b'=');
305-
let main = parts.next().unwrap(); // Always exists since checksum isn't empty
306-
let padding = parts.next().unwrap_or_default(); // Empty if no '='
307-
308-
main.iter()
309-
.all(|&b| b.is_ascii_alphanumeric() || b == b'+' || b == b'/')
310-
&& !main.is_empty()
311-
&& padding.len() <= 2
312-
&& padding.iter().all(|&b| b == b'=')
313-
}
314-
if !is_valid_checksum(checksum) {
315-
return None;
316-
}
317-
// SAFETY: we just validated the contents of checksum, we can unsafely make a
318-
// String from it
319-
let checksum_utf8 = unsafe { String::from_utf8_unchecked(checksum.to_vec()) };
299+
let checksum_utf8 = Self::validate_checksum_format(checksum)?;
320300

321301
Some(LineInfo {
322302
algo_name: Some(algo_utf8),
@@ -336,12 +316,8 @@ impl LineFormat {
336316
fn parse_untagged(line: &[u8]) -> Option<LineInfo> {
337317
let space_idx = line.iter().position(|&b| b == b' ')?;
338318
let checksum = &line[..space_idx];
339-
if !checksum.iter().all(|&b| b.is_ascii_hexdigit()) || checksum.is_empty() {
340-
return None;
341-
}
342-
// SAFETY: we just validated the contents of checksum, we can unsafely make a
343-
// String from it
344-
let checksum_utf8 = unsafe { String::from_utf8_unchecked(checksum.to_vec()) };
319+
320+
let checksum_utf8 = Self::validate_checksum_format(checksum)?;
345321

346322
let rest = &line[space_idx..];
347323
let filename = rest
@@ -388,6 +364,34 @@ impl LineFormat {
388364
format: Self::SingleSpace,
389365
})
390366
}
367+
368+
/// Ensure that the given checksum is syntactically valid (that it is either
369+
/// hexadecimal or base64 encoded).
370+
fn validate_checksum_format(checksum: &[u8]) -> Option<String> {
371+
if checksum.is_empty() {
372+
return None;
373+
}
374+
375+
let mut parts = checksum.splitn(2, |&b| b == b'=');
376+
let main = parts.next().unwrap(); // Always exists since checksum isn't empty
377+
let padding = parts.next().unwrap_or_default(); // Empty if no '='
378+
379+
if main.is_empty()
380+
|| !main
381+
.iter()
382+
.all(|&b| b.is_ascii_alphanumeric() || b == b'+' || b == b'/')
383+
{
384+
return None;
385+
}
386+
387+
if padding.len() > 2 || padding.iter().any(|&b| b != b'=') {
388+
return None;
389+
}
390+
391+
// SAFETY: we just validated the contents of checksum, we can unsafely make a
392+
// String from it
393+
Some(unsafe { String::from_utf8_unchecked(checksum.to_vec()) })
394+
}
391395
}
392396

393397
// Helper trait for byte slice operations
@@ -1039,7 +1043,13 @@ mod tests {
10391043
b"b064a020db8018f18ff5ae367d01b212 ",
10401044
Some((b"b064a020db8018f18ff5ae367d01b212", b" ")),
10411045
),
1042-
(b"invalidchecksum test", None),
1046+
// base64 checksums are accepted
1047+
(
1048+
b"b21lbGV0dGUgZHUgZnJvbWFnZQ== ",
1049+
Some((b"b21lbGV0dGUgZHUgZnJvbWFnZQ==", b" ")),
1050+
),
1051+
// Invalid checksums fail
1052+
(b"inva|idchecksum test", None),
10431053
];
10441054

10451055
for (input, expected) in test_cases {

0 commit comments

Comments
 (0)