diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index 9bddd3d7ab3..559c957a73c 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -103,6 +103,7 @@ struct Options { algo_name: &'static str, digest: Box, output_bits: usize, + reverse: bool, } /// Calculate checksum @@ -131,36 +132,49 @@ where File::open(filename).map_err_context(|| filename.to_str().unwrap().to_string())?; Box::new(file_buf) as Box }); - let (sum, sz) = digest_read(&mut options.digest, &mut file, options.output_bits) + let (mut sum, sz) = digest_read(&mut options.digest, &mut file, options.output_bits) .map_err_context(|| "failed to read input".to_string())?; + if options.reverse { + sum = reverse_cksum(&sum); + } // 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::().unwrap(), + u16::from_ne_bytes(sum.try_into().unwrap()), div_ceil(sz, options.output_bits) ), (ALGORITHM_OPTIONS_SYSV, false) => println!( "{} {} {}", - sum.parse::().unwrap(), + u16::from_ne_bytes(sum.try_into().unwrap()), div_ceil(sz, options.output_bits), filename.display() ), (ALGORITHM_OPTIONS_BSD, true) => println!( "{:0bsd_width$} {:bsd_width$}", - sum.parse::().unwrap(), + u16::from_ne_bytes(sum.try_into().unwrap()), div_ceil(sz, options.output_bits) ), (ALGORITHM_OPTIONS_BSD, false) => println!( "{:0bsd_width$} {:bsd_width$} {}", - sum.parse::().unwrap(), + u16::from_ne_bytes(sum.try_into().unwrap()), div_ceil(sz, options.output_bits), filename.display() ), - (_, true) => println!("{sum} {sz}"), - (_, false) => println!("{sum} {sz} {}", filename.display()), + (ALGORITHM_OPTIONS_CRC, true) => { + println!("{} {sz}", u32::from_ne_bytes(sum.try_into().unwrap())); + } + (ALGORITHM_OPTIONS_CRC, false) => { + println!( + "{} {sz} {}", + u32::from_ne_bytes(sum.try_into().unwrap()), + filename.display() + ); + } + (_, true) => println!("{} {sz}", encode(sum)), + (_, false) => println!("{} {sz} {}", encode(sum), filename.display()), } } @@ -171,7 +185,7 @@ fn digest_read( digest: &mut Box, reader: &mut BufReader, output_bits: usize, -) -> io::Result<(String, usize)> { +) -> io::Result<(Vec, usize)> { digest.reset(); // Read bytes from `reader` and write those bytes to `digest`. @@ -189,21 +203,30 @@ fn digest_read( let mut digest_writer = DigestWriter::new(digest, true); let output_size = std::io::copy(reader, &mut digest_writer)? as usize; digest_writer.finalize(); - if digest.output_bits() > 0 { - Ok((digest.result_str(), output_size)) + Ok((digest.result_bytes(), output_size)) } else { // Assume it's SHAKE. result_str() doesn't work with shake (as of 8/30/2016) let mut bytes = Vec::new(); bytes.resize((output_bits + 7) / 8, 0); digest.hash_finalize(&mut bytes); - Ok((encode(bytes), output_size)) + Ok((bytes, output_size)) + } +} + +fn reverse_cksum(checksum: &[u8]) -> Vec { + let sz = checksum.len(); + let mut ret: Vec = std::iter::repeat(0).take(sz).collect::>(); + for i in 0..sz { + ret[i] = checksum[sz - i - 1].reverse_bits(); } + ret } mod options { pub static FILE: &str = "file"; pub static ALGORITHM: &str = "algorithm"; + pub static UNTAGGED: &str = "untagged"; } #[uucore::main] @@ -217,11 +240,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None => ALGORITHM_OPTIONS_CRC, }; + let untagged: bool = matches.get_flag(options::UNTAGGED); + let (name, algo, bits) = detect_algo(algo_name); let opts = Options { algo_name: name, digest: algo, output_bits: bits, + reverse: untagged, }; match matches.get_many::(options::FILE) { @@ -264,5 +290,11 @@ pub fn uu_app() -> Command { ALGORITHM_OPTIONS_SM3, ]), ) + .arg( + Arg::new(options::UNTAGGED) + .long(options::UNTAGGED) + .help("create a reversed style checksum, without digest type") + .action(clap::ArgAction::SetTrue), + ) .after_help(AFTER_HELP) } diff --git a/src/uucore/src/lib/features/sum.rs b/src/uucore/src/lib/features/sum.rs index c1cfaf5f84d..d26c102122c 100644 --- a/src/uucore/src/lib/features/sum.rs +++ b/src/uucore/src/lib/features/sum.rs @@ -36,6 +36,11 @@ pub trait Digest { self.hash_finalize(&mut buf); encode(buf) } + fn result_bytes(&mut self) -> Vec { + let mut buf: Vec = vec![0; self.output_bytes()]; + self.hash_finalize(&mut buf); + buf + } } /// first element of the tuple is the blake2b state @@ -200,12 +205,18 @@ impl Digest for CRC { format!("{}", self.state) } + fn result_bytes(&mut self) -> Vec { + let mut out: Vec = vec![0; 4]; + self.hash_finalize(&mut out); + out.to_vec() + } + fn reset(&mut self) { *self = Self::new(); } fn output_bits(&self) -> usize { - 256 + 32 } } @@ -241,6 +252,12 @@ impl Digest for BSD { format!("{}", self.state) } + fn result_bytes(&mut self) -> Vec { + let mut out: Vec = vec![0; 2]; + self.hash_finalize(&mut out); + out.to_vec() + } + fn reset(&mut self) { *self = Self::new(); } @@ -276,6 +293,12 @@ impl Digest for SYSV { format!("{}", self.state) } + fn result_bytes(&mut self) -> Vec { + let mut out: Vec = vec![0; 2]; + self.hash_finalize(&mut out); + out.to_vec() + } + fn reset(&mut self) { *self = Self::new(); } diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 814d4c03a68..d7554a4f346 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -15,6 +15,15 @@ fn test_single_file() { .stdout_is_fixture("single_file.expected"); } +#[test] +fn test_single_file_untagged() { + new_ucmd!() + .arg("--untagged") + .arg("lorem_ipsum.txt") + .succeeds() + .stdout_is_fixture("single_file_untagged.expected"); +} + #[test] fn test_multiple_files() { new_ucmd!() diff --git a/tests/fixtures/cksum/single_file_untagged.expected b/tests/fixtures/cksum/single_file_untagged.expected new file mode 100644 index 00000000000..e965284ac71 --- /dev/null +++ b/tests/fixtures/cksum/single_file_untagged.expected @@ -0,0 +1 @@ +369766760 772 lorem_ipsum.txt