From ed4edb4b8a0177056fbdd81a1d2a9cdb78d9f477 Mon Sep 17 00:00:00 2001 From: Dorian Peron Date: Sun, 19 Jan 2025 20:02:59 +0100 Subject: [PATCH] cksum: Add `crc32b` algorithm --- Cargo.lock | 1 + Cargo.toml | 1 + src/uu/cksum/cksum.md | 1 + src/uu/cksum/src/cksum.rs | 11 +++++---- src/uucore/Cargo.toml | 2 ++ src/uucore/src/lib/features/checksum.rs | 13 ++++++++--- src/uucore/src/lib/features/sum.rs | 31 +++++++++++++++++++++++++ tests/by-util/test_cksum.rs | 31 ++++++++++++++++++++----- 8 files changed, 78 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 957a797e4..2e83584b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3461,6 +3461,7 @@ dependencies = [ "blake2b_simd", "blake3", "clap", + "crc32fast", "data-encoding", "data-encoding-macro", "digest", diff --git a/Cargo.toml b/Cargo.toml index 963051fce..7178771ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -356,6 +356,7 @@ sha3 = "0.10.8" blake2b_simd = "1.0.2" blake3 = "1.5.1" sm3 = "0.4.2" +crc32fast = "1.4.2" digest = "0.10.7" uucore = { version = "0.0.29", package = "uucore", path = "src/uucore" } diff --git a/src/uu/cksum/cksum.md b/src/uu/cksum/cksum.md index 4b0d25f32..5ca83b401 100644 --- a/src/uu/cksum/cksum.md +++ b/src/uu/cksum/cksum.md @@ -13,6 +13,7 @@ DIGEST determines the digest algorithm and default output format: - `sysv`: (equivalent to sum -s) - `bsd`: (equivalent to sum -r) - `crc`: (equivalent to cksum) +- `crc32b`: (only available through cksum) - `md5`: (equivalent to md5sum) - `sha1`: (equivalent to sha1sum) - `sha224`: (equivalent to sha224sum) diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index b9f741338..84be146ec 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -14,7 +14,7 @@ use std::path::Path; use uucore::checksum::{ calculate_blake2b_length, detect_algo, digest_reader, perform_checksum_validation, ChecksumError, ChecksumOptions, ALGORITHM_OPTIONS_BLAKE2B, ALGORITHM_OPTIONS_BSD, - ALGORITHM_OPTIONS_CRC, ALGORITHM_OPTIONS_SYSV, SUPPORTED_ALGORITHMS, + ALGORITHM_OPTIONS_CRC, ALGORITHM_OPTIONS_CRC32B, ALGORITHM_OPTIONS_SYSV, SUPPORTED_ALGORITHMS, }; use uucore::{ encoding, @@ -113,7 +113,10 @@ where } OutputFormat::Hexadecimal => sum_hex, OutputFormat::Base64 => match options.algo_name { - ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => sum_hex, + ALGORITHM_OPTIONS_CRC + | ALGORITHM_OPTIONS_CRC32B + | ALGORITHM_OPTIONS_SYSV + | ALGORITHM_OPTIONS_BSD => sum_hex, _ => encoding::for_cksum::BASE64.encode(&hex::decode(sum_hex).unwrap()), }, }; @@ -140,7 +143,7 @@ where !not_file, String::new(), ), - ALGORITHM_OPTIONS_CRC => ( + ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_CRC32B => ( format!("{sum} {sz}{}", if not_file { "" } else { " " }), !not_file, String::new(), @@ -289,7 +292,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None => None, }; - if ["bsd", "crc", "sysv"].contains(&algo_name) && check { + if ["bsd", "crc", "sysv", "crc32b"].contains(&algo_name) && check { return Err(ChecksumError::AlgorithmNotSupportedWithCheck.into()); } diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 92eaf0853..ce097d410 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -52,6 +52,7 @@ sha3 = { workspace = true, optional = true } blake2b_simd = { workspace = true, optional = true } blake3 = { workspace = true, optional = true } sm3 = { workspace = true, optional = true } +crc32fast = { workspace = true, optional = true } regex = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] @@ -106,6 +107,7 @@ sum = [ "blake2b_simd", "blake3", "sm3", + "crc32fast", ] update-control = [] utf8 = [] diff --git a/src/uucore/src/lib/features/checksum.rs b/src/uucore/src/lib/features/checksum.rs index 0b3e4e249..8b136922f 100644 --- a/src/uucore/src/lib/features/checksum.rs +++ b/src/uucore/src/lib/features/checksum.rs @@ -23,7 +23,7 @@ use crate::{ os_str_as_bytes, os_str_from_bytes, read_os_string_lines, show, show_error, show_warning_caps, sum::{ Blake2b, Blake3, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha3_224, - Sha3_256, Sha3_384, Sha3_512, Sha512, Shake128, Shake256, Sm3, BSD, CRC, SYSV, + Sha3_256, Sha3_384, Sha3_512, Sha512, Shake128, Shake256, Sm3, BSD, CRC, CRC32B, SYSV, }, util_name, }; @@ -32,6 +32,7 @@ use thiserror::Error; pub const ALGORITHM_OPTIONS_SYSV: &str = "sysv"; pub const ALGORITHM_OPTIONS_BSD: &str = "bsd"; pub const ALGORITHM_OPTIONS_CRC: &str = "crc"; +pub const ALGORITHM_OPTIONS_CRC32B: &str = "crc32b"; pub const ALGORITHM_OPTIONS_MD5: &str = "md5"; pub const ALGORITHM_OPTIONS_SHA1: &str = "sha1"; pub const ALGORITHM_OPTIONS_SHA3: &str = "sha3"; @@ -46,10 +47,11 @@ pub const ALGORITHM_OPTIONS_SM3: &str = "sm3"; pub const ALGORITHM_OPTIONS_SHAKE128: &str = "shake128"; pub const ALGORITHM_OPTIONS_SHAKE256: &str = "shake256"; -pub const SUPPORTED_ALGORITHMS: [&str; 15] = [ +pub const SUPPORTED_ALGORITHMS: [&str; 16] = [ ALGORITHM_OPTIONS_SYSV, ALGORITHM_OPTIONS_BSD, ALGORITHM_OPTIONS_CRC, + ALGORITHM_OPTIONS_CRC32B, ALGORITHM_OPTIONS_MD5, ALGORITHM_OPTIONS_SHA1, ALGORITHM_OPTIONS_SHA3, @@ -183,7 +185,7 @@ pub enum ChecksumError { LengthOnlyForBlake2b, #[error("the --binary and --text options are meaningless when verifying checksums")] BinaryTextConflict, - #[error("--check is not supported with --algorithm={{bsd,sysv,crc}}")] + #[error("--check is not supported with --algorithm={{bsd,sysv,crc,crc32b}}")] AlgorithmNotSupportedWithCheck, #[error("You cannot combine multiple hash algorithms!")] CombineMultipleAlgorithms, @@ -334,6 +336,11 @@ pub fn detect_algo(algo: &str, length: Option) -> UResult create_fn: Box::new(|| Box::new(CRC::new())), bits: 256, }), + ALGORITHM_OPTIONS_CRC32B => Ok(HashAlgorithm { + name: ALGORITHM_OPTIONS_CRC32B, + create_fn: Box::new(|| Box::new(CRC32B::new())), + bits: 32, + }), ALGORITHM_OPTIONS_MD5 | "md5sum" => Ok(HashAlgorithm { name: ALGORITHM_OPTIONS_MD5, create_fn: Box::new(|| Box::new(Md5::new())), diff --git a/src/uucore/src/lib/features/sum.rs b/src/uucore/src/lib/features/sum.rs index df9e1673d..258cb2362 100644 --- a/src/uucore/src/lib/features/sum.rs +++ b/src/uucore/src/lib/features/sum.rs @@ -207,6 +207,37 @@ impl Digest for CRC { } } +pub struct CRC32B(crc32fast::Hasher); +impl Digest for CRC32B { + fn new() -> Self { + Self(crc32fast::Hasher::new()) + } + + fn hash_update(&mut self, input: &[u8]) { + self.0.update(input); + } + + fn hash_finalize(&mut self, out: &mut [u8]) { + let result = self.0.clone().finalize(); + let slice = result.to_be_bytes(); + out.copy_from_slice(&slice); + } + + fn reset(&mut self) { + self.0.reset(); + } + + fn output_bits(&self) -> usize { + 32 + } + + fn result_str(&mut self) -> String { + let mut out = [0; 4]; + self.hash_finalize(&mut out); + format!("{}", u32::from_be_bytes(out)) + } +} + pub struct BSD { state: u16, } diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index b7c11320e..b73ee1425 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -301,7 +301,7 @@ fn test_check_algo() { .arg("lorem_ipsum.txt") .fails() .no_stdout() - .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc}") + .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}") .code_is(1); new_ucmd!() .arg("-a=sysv") @@ -309,7 +309,7 @@ fn test_check_algo() { .arg("lorem_ipsum.txt") .fails() .no_stdout() - .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc}") + .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}") .code_is(1); new_ucmd!() .arg("-a=crc") @@ -317,7 +317,15 @@ fn test_check_algo() { .arg("lorem_ipsum.txt") .fails() .no_stdout() - .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc}") + .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}") + .code_is(1); + new_ucmd!() + .arg("-a=crc32b") + .arg("--check") + .arg("lorem_ipsum.txt") + .fails() + .no_stdout() + .stderr_contains("cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}") .code_is(1); } @@ -1661,10 +1669,11 @@ mod gnu_cksum_base64 { use super::*; use crate::common::util::log_info; - const PAIRS: [(&str, &str); 11] = [ + const PAIRS: [(&str, &str); 12] = [ ("sysv", "0 0 f"), ("bsd", "00000 0 f"), ("crc", "4294967295 0 f"), + ("crc32b", "0 0 f"), ("md5", "1B2M2Y8AsgTpgAmY7PhCfg=="), ("sha1", "2jmj7l5rSw0yVb/vlWAYkK/YBwk="), ("sha224", "0UoCjCo6K8lHYQK7KII0xBWisB+CjqYqxbPkLw=="), @@ -1693,7 +1702,7 @@ mod gnu_cksum_base64 { } fn output_format(algo: &str, digest: &str) -> String { - if ["sysv", "bsd", "crc"].contains(&algo) { + if ["sysv", "bsd", "crc", "crc32b"].contains(&algo) { digest.to_string() } else { format!("{} (f) = {}", algo.to_uppercase(), digest).replace("BLAKE2B", "BLAKE2b") @@ -1706,6 +1715,7 @@ mod gnu_cksum_base64 { let scene = make_scene(); for (algo, digest) in PAIRS { + log_info("ALGORITHM", algo); scene .ucmd() .arg("--base64") @@ -1724,8 +1734,17 @@ mod gnu_cksum_base64 { let scene = make_scene(); for (algo, digest) in PAIRS { - if ["sysv", "bsd", "crc"].contains(&algo) { + if ["sysv", "bsd", "crc", "crc32b"].contains(&algo) { // These algorithms do not accept `--check` + scene + .ucmd() + .arg("--check") + .arg("-a") + .arg(algo) + .fails() + .stderr_only( + "cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}\n", + ); continue; }