Skip to content

Commit

Permalink
Merge pull request #6041 from BenWiederhake/dev-cksum-repeat-and-flags
Browse files Browse the repository at this point in the history
cksum: permit repeated flags, handle overrides correctly, implement base64 output
  • Loading branch information
sylvestre authored Mar 18, 2024
2 parents 32b5591 + 133cdde commit 6f95d05
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 15 deletions.
73 changes: 58 additions & 15 deletions src/uu/cksum/src/cksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -138,7 +146,7 @@ struct Options {
output_bits: usize,
untagged: bool,
length: Option<usize>,
raw: bool,
output_format: OutputFormat,
}

/// Calculate checksum
Expand All @@ -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));
}

Expand All @@ -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(
Expand All @@ -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) {
Expand Down Expand Up @@ -286,8 +302,10 @@ mod options {
pub const ALGORITHM: &str = "algorithm";
pub const FILE: &str = "file";
pub const UNTAGGED: &str = "untagged";
pub const TAG: &str = "tag";
pub const LENGTH: &str = "length";
pub const RAW: &str = "raw";
pub const BASE64: &str = "base64";
}

#[uucore::main]
Expand Down Expand Up @@ -342,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) {
Expand All @@ -365,6 +391,7 @@ pub fn uu_app() -> Command {
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.args_override_self(true)
.arg(
Arg::new(options::FILE)
.hide(true)
Expand Down Expand Up @@ -395,6 +422,13 @@ pub fn uu_app() -> Command {
Arg::new(options::UNTAGGED)
.long(options::UNTAGGED)
.help("create a reversed style checksum, without digest type")
.action(ArgAction::SetTrue)
.overrides_with(options::TAG),
)
.arg(
Arg::new(options::TAG)
.long(options::TAG)
.help("create a BSD style checksum, undo --untagged (default)")
.action(ArgAction::SetTrue),
)
.arg(
Expand All @@ -411,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)
}
1 change: 1 addition & 0 deletions src/uucore/src/lib/features/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum DecodeError {
Io(#[from] io::Error),
}

#[derive(Debug)]
pub enum EncodeError {
Z85InputLenNotMultipleOf4,
InvalidInput,
Expand Down
85 changes: 85 additions & 0 deletions tests/by-util/test_cksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,29 @@ fn test_stdin_larger_than_128_bytes() {
assert_eq!(bytes_cnt, 2058);
}

#[test]
fn test_repeated_flags() {
new_ucmd!()
.arg("-a")
.arg("sha1")
.arg("--algo=sha256")
.arg("-a=md5")
.arg("lorem_ipsum.txt")
.succeeds()
.stdout_is_fixture("md5_single_file.expected");
}

#[test]
fn test_tag_after_untagged() {
new_ucmd!()
.arg("--untagged")
.arg("--tag")
.arg("-a=md5")
.arg("lorem_ipsum.txt")
.succeeds()
.stdout_is_fixture("md5_single_file.expected");
}

#[test]
fn test_algorithm_single_file() {
for algo in ALGOS {
Expand Down Expand Up @@ -208,6 +231,17 @@ fn test_untagged_algorithm_single_file() {
}
}

#[test]
fn test_untagged_algorithm_after_tag() {
new_ucmd!()
.arg("--tag")
.arg("--untagged")
.arg("--algorithm=md5")
.arg("lorem_ipsum.txt")
.succeeds()
.stdout_is_fixture("untagged/md5_single_file.expected");
}

#[test]
fn test_untagged_algorithm_multiple_files() {
for algo in ALGOS {
Expand Down Expand Up @@ -291,6 +325,20 @@ fn test_length_is_zero() {
.stdout_is_fixture("length_is_zero.expected");
}

#[test]
fn test_length_repeated() {
new_ucmd!()
.arg("--length=10")
.arg("--length=123456")
.arg("--length=0")
.arg("--algorithm=blake2b")
.arg("lorem_ipsum.txt")
.arg("alice_in_wonderland.txt")
.succeeds()
.no_stderr()
.stdout_is_fixture("length_is_zero.expected");
}

#[test]
fn test_raw_single_file() {
for algo in ALGOS {
Expand All @@ -315,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!();
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/blake2b_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BLAKE2b (lorem_ipsum.txt) = DpegkYnlYMN4nAv/HwIBZoYe+FfR+/5FdN4YQuPAbKu5V15K9jCaFmFYwrQI08A4wbSdgos1FYFCzcA5bRGVww==
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/bsd_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
08109 1 lorem_ipsum.txt
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/crc_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
378294376 772 lorem_ipsum.txt
2 changes: 2 additions & 0 deletions tests/fixtures/cksum/base64/md5_multiple_files.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MD5 (lorem_ipsum.txt) = zXJGkPfcYXdd+sQApx8sqg==
MD5 (alice_in_wonderland.txt) = 9vpwM+FhZqlYmqHAOI/9WA==
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/md5_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MD5 (lorem_ipsum.txt) = zXJGkPfcYXdd+sQApx8sqg==
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sha1_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SHA1 (lorem_ipsum.txt) = qx3QuuHYiDo9GKZt5q+9KCUs++8=
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sha224_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SHA224 (lorem_ipsum.txt) = PeZvvK0QbhtAqzkb5WxR0gB+sfnGVdD04pv8AQ==
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sha256_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SHA256 (lorem_ipsum.txt) = 98QgUBxQ4AswklAQDWfqXpEJgVNrRYL+nENb2Ss/HwI=
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sha384_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SHA384 (lorem_ipsum.txt) = S+S5Cg0NMpZpkpIQGfJKvIJNz7ixxAgQLx9niPuAupqaTFp7V1ozU6kKjucZSB3L
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sha512_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SHA512 (lorem_ipsum.txt) = llRkqyVWqtWOvHPYmtIh5Vl5dSnsr8D0ZsEXlc/21uLGD5agfFQs/R9Cbl5P4KSKoVZnukQJayE9CBPNA436BQ==
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sm3_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SM3 (lorem_ipsum.txt) = bSlrgF0GC/7SKAjfMI27m0MXeU3U7WdAoQdwp4Jpm8I=
1 change: 1 addition & 0 deletions tests/fixtures/cksum/base64/sysv_single_file.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6985 2 lorem_ipsum.txt

0 comments on commit 6f95d05

Please sign in to comment.