cksum: implement and test --base64 output method

This commit is contained in:
Ben Wiederhake 2024-03-02 04:10:32 +01:00
parent 7b219aee63
commit 133cdde885
15 changed files with 100 additions and 15 deletions

View file

@ -15,6 +15,7 @@ use std::io::{self, stdin, stdout, BufReader, Read, Write};
use std::iter;
use std::path::Path;
use uucore::{
encoding,
error::{FromIo, UError, UResult, USimpleError},
format_usage, help_about, help_section, help_usage, show,
sum::{
@ -44,6 +45,13 @@ enum CkSumError {
RawMultipleFiles,
}
#[derive(Debug, PartialEq)]
enum OutputFormat {
Hexadecimal,
Raw,
Base64,
}
impl UError for CkSumError {
fn code(&self) -> i32 {
match self {
@ -138,7 +146,7 @@ struct Options {
output_bits: usize,
untagged: bool,
length: Option<usize>,
raw: bool,
output_format: OutputFormat,
}
/// Calculate checksum
@ -153,7 +161,7 @@ where
I: Iterator<Item = &'a OsStr>,
{
let files: Vec<_> = files.collect();
if options.raw && files.len() > 1 {
if options.output_format == OutputFormat::Raw && files.len() > 1 {
return Err(Box::new(CkSumError::RawMultipleFiles));
}
@ -177,7 +185,7 @@ where
};
Box::new(file_buf) as Box<dyn Read>
});
let (sum, sz) = digest_read(&mut options.digest, &mut file, options.output_bits)
let (sum_hex, sz) = digest_read(&mut options.digest, &mut file, options.output_bits)
.map_err_context(|| "failed to read input".to_string())?;
if filename.is_dir() {
show!(USimpleError::new(
@ -186,17 +194,25 @@ where
));
continue;
}
if options.raw {
let bytes = match options.algo_name {
ALGORITHM_OPTIONS_CRC => sum.parse::<u32>().unwrap().to_be_bytes().to_vec(),
ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => {
sum.parse::<u16>().unwrap().to_be_bytes().to_vec()
}
_ => decode(sum).unwrap(),
};
stdout().write_all(&bytes)?;
return Ok(());
}
let sum = match options.output_format {
OutputFormat::Raw => {
let bytes = match options.algo_name {
ALGORITHM_OPTIONS_CRC => sum_hex.parse::<u32>().unwrap().to_be_bytes().to_vec(),
ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => {
sum_hex.parse::<u16>().unwrap().to_be_bytes().to_vec()
}
_ => decode(sum_hex).unwrap(),
};
// Cannot handle multiple files anyway, output immediately.
stdout().write_all(&bytes)?;
return Ok(());
}
OutputFormat::Hexadecimal => sum_hex,
OutputFormat::Base64 => match options.algo_name {
ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => sum_hex,
_ => encoding::encode(encoding::Format::Base64, &decode(sum_hex).unwrap()).unwrap(),
},
};
// The BSD checksum output is 5 digit integer
let bsd_width = 5;
match (options.algo_name, not_file) {
@ -289,6 +305,7 @@ mod options {
pub const TAG: &str = "tag";
pub const LENGTH: &str = "length";
pub const RAW: &str = "raw";
pub const BASE64: &str = "base64";
}
#[uucore::main]
@ -343,13 +360,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let (name, algo, bits) = detect_algo(algo_name, length);
let output_format = if matches.get_flag(options::RAW) {
OutputFormat::Raw
} else if matches.get_flag(options::BASE64) {
OutputFormat::Base64
} else {
OutputFormat::Hexadecimal
};
let opts = Options {
algo_name: name,
digest: algo,
output_bits: bits,
length,
untagged: matches.get_flag(options::UNTAGGED),
raw: matches.get_flag(options::RAW),
output_format,
};
match matches.get_many::<String>(options::FILE) {
@ -420,5 +445,14 @@ pub fn uu_app() -> Command {
.help("emit a raw binary digest, not hexadecimal")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::BASE64)
.long(options::BASE64)
.help("emit a base64 digest, not hexadecimal")
.action(ArgAction::SetTrue)
// Even though this could easily just override an earlier '--raw',
// GNU cksum does not permit these flags to be combined:
.conflicts_with(options::RAW),
)
.after_help(AFTER_HELP)
}

View file

@ -23,6 +23,7 @@ pub enum DecodeError {
Io(#[from] io::Error),
}
#[derive(Debug)]
pub enum EncodeError {
Z85InputLenNotMultipleOf4,
InvalidInput,

View file

@ -363,6 +363,43 @@ fn test_raw_multiple_files() {
.code_is(1);
}
#[test]
fn test_base64_raw_conflicts() {
new_ucmd!()
.arg("--base64")
.arg("--raw")
.arg("lorem_ipsum.txt")
.fails()
.no_stdout()
.stderr_contains("--base64")
.stderr_contains("cannot be used with")
.stderr_contains("--raw");
}
#[test]
fn test_base64_single_file() {
for algo in ALGOS {
new_ucmd!()
.arg("--base64")
.arg("lorem_ipsum.txt")
.arg(format!("--algorithm={algo}"))
.succeeds()
.no_stderr()
.stdout_is_fixture_bytes(format!("base64/{algo}_single_file.expected"));
}
}
#[test]
fn test_base64_multiple_files() {
new_ucmd!()
.arg("--base64")
.arg("--algorithm=md5")
.arg("lorem_ipsum.txt")
.arg("alice_in_wonderland.txt")
.succeeds()
.no_stderr()
.stdout_is_fixture_bytes(format!("base64/md5_multiple_files.expected"));
}
#[test]
fn test_fail_on_folder() {
let (at, mut ucmd) = at_and_ucmd!();

View file

@ -0,0 +1 @@
BLAKE2b (lorem_ipsum.txt) = DpegkYnlYMN4nAv/HwIBZoYe+FfR+/5FdN4YQuPAbKu5V15K9jCaFmFYwrQI08A4wbSdgos1FYFCzcA5bRGVww==

View file

@ -0,0 +1 @@
08109 1 lorem_ipsum.txt

View file

@ -0,0 +1 @@
378294376 772 lorem_ipsum.txt

View file

@ -0,0 +1,2 @@
MD5 (lorem_ipsum.txt) = zXJGkPfcYXdd+sQApx8sqg==
MD5 (alice_in_wonderland.txt) = 9vpwM+FhZqlYmqHAOI/9WA==

View file

@ -0,0 +1 @@
MD5 (lorem_ipsum.txt) = zXJGkPfcYXdd+sQApx8sqg==

View file

@ -0,0 +1 @@
SHA1 (lorem_ipsum.txt) = qx3QuuHYiDo9GKZt5q+9KCUs++8=

View file

@ -0,0 +1 @@
SHA224 (lorem_ipsum.txt) = PeZvvK0QbhtAqzkb5WxR0gB+sfnGVdD04pv8AQ==

View file

@ -0,0 +1 @@
SHA256 (lorem_ipsum.txt) = 98QgUBxQ4AswklAQDWfqXpEJgVNrRYL+nENb2Ss/HwI=

View file

@ -0,0 +1 @@
SHA384 (lorem_ipsum.txt) = S+S5Cg0NMpZpkpIQGfJKvIJNz7ixxAgQLx9niPuAupqaTFp7V1ozU6kKjucZSB3L

View file

@ -0,0 +1 @@
SHA512 (lorem_ipsum.txt) = llRkqyVWqtWOvHPYmtIh5Vl5dSnsr8D0ZsEXlc/21uLGD5agfFQs/R9Cbl5P4KSKoVZnukQJayE9CBPNA436BQ==

View file

@ -0,0 +1 @@
SM3 (lorem_ipsum.txt) = bSlrgF0GC/7SKAjfMI27m0MXeU3U7WdAoQdwp4Jpm8I=

View file

@ -0,0 +1 @@
6985 2 lorem_ipsum.txt