mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Merge pull request #9135 from RenjiSann/cksum-reworks
cksum/hashsum: merge digest computation & various improvements
This commit is contained in:
+27
-310
@@ -3,270 +3,25 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (ToDO) fname, algo
|
||||
// spell-checker:ignore (ToDO) fname, algo, bitlen
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read, Write, stdin, stdout};
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
use uucore::checksum::compute::{
|
||||
ChecksumComputeOptions, figure_out_output_format, perform_checksum_computation,
|
||||
};
|
||||
use uucore::checksum::validate::{
|
||||
ChecksumValidateOptions, ChecksumVerbose, perform_checksum_validation,
|
||||
};
|
||||
use uucore::checksum::{
|
||||
ALGORITHM_OPTIONS_BLAKE2B, ALGORITHM_OPTIONS_BSD, ALGORITHM_OPTIONS_CRC,
|
||||
ALGORITHM_OPTIONS_CRC32B, ALGORITHM_OPTIONS_SHA2, ALGORITHM_OPTIONS_SHA3,
|
||||
ALGORITHM_OPTIONS_SYSV, ChecksumError, ChecksumOptions, ChecksumVerbose, HashAlgorithm,
|
||||
LEGACY_ALGORITHMS, SUPPORTED_ALGORITHMS, calculate_blake2b_length_str, detect_algo,
|
||||
digest_reader, perform_checksum_validation, sanitize_sha2_sha3_length_str,
|
||||
AlgoKind, ChecksumError, SUPPORTED_ALGORITHMS, SizedAlgoKind, calculate_blake2b_length_str,
|
||||
sanitize_sha2_sha3_length_str,
|
||||
};
|
||||
use uucore::translate;
|
||||
|
||||
use uucore::{
|
||||
encoding,
|
||||
error::{FromIo, UResult, USimpleError},
|
||||
format_usage,
|
||||
line_ending::LineEnding,
|
||||
os_str_as_bytes, show,
|
||||
sum::Digest,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
algo_name: &'static str,
|
||||
digest: Box<dyn Digest + 'static>,
|
||||
output_bits: usize,
|
||||
length: Option<usize>,
|
||||
output_format: OutputFormat,
|
||||
line_ending: LineEnding,
|
||||
}
|
||||
|
||||
/// Reading mode used to compute digest.
|
||||
///
|
||||
/// On most linux systems, this is irrelevant, as there is no distinction
|
||||
/// between text and binary files. Refer to GNU's cksum documentation for more
|
||||
/// information.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum ReadingMode {
|
||||
Binary,
|
||||
Text,
|
||||
}
|
||||
|
||||
impl ReadingMode {
|
||||
#[inline]
|
||||
fn as_char(&self) -> char {
|
||||
match self {
|
||||
Self::Binary => '*',
|
||||
Self::Text => ' ',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to write the digest as hexadecimal or encoded in base64.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum DigestFormat {
|
||||
Hexadecimal,
|
||||
Base64,
|
||||
}
|
||||
|
||||
impl DigestFormat {
|
||||
#[inline]
|
||||
fn is_base64(&self) -> bool {
|
||||
*self == Self::Base64
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the representation that shall be used for printing a checksum line
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum OutputFormat {
|
||||
/// Raw digest
|
||||
Raw,
|
||||
|
||||
/// Selected for older algorithms which had their custom formatting
|
||||
///
|
||||
/// Default for crc, sysv, bsd
|
||||
Legacy,
|
||||
|
||||
/// `$ALGO_NAME ($FILENAME) = $DIGEST`
|
||||
Tagged(DigestFormat),
|
||||
|
||||
/// '$DIGEST $FLAG$FILENAME'
|
||||
/// where 'flag' depends on the reading mode
|
||||
///
|
||||
/// Default for standalone checksum utilities
|
||||
Untagged(DigestFormat, ReadingMode),
|
||||
}
|
||||
|
||||
impl OutputFormat {
|
||||
#[inline]
|
||||
fn is_raw(&self) -> bool {
|
||||
*self == Self::Raw
|
||||
}
|
||||
}
|
||||
|
||||
fn print_legacy_checksum(
|
||||
options: &Options,
|
||||
filename: &OsStr,
|
||||
sum: &str,
|
||||
size: usize,
|
||||
) -> UResult<()> {
|
||||
debug_assert!(LEGACY_ALGORITHMS.contains(&options.algo_name));
|
||||
|
||||
// Print the sum
|
||||
match options.algo_name {
|
||||
ALGORITHM_OPTIONS_SYSV => print!(
|
||||
"{} {}",
|
||||
sum.parse::<u16>().unwrap(),
|
||||
size.div_ceil(options.output_bits),
|
||||
),
|
||||
ALGORITHM_OPTIONS_BSD => {
|
||||
// The BSD checksum output is 5 digit integer
|
||||
let bsd_width = 5;
|
||||
print!(
|
||||
"{:0bsd_width$} {:bsd_width$}",
|
||||
sum.parse::<u16>().unwrap(),
|
||||
size.div_ceil(options.output_bits),
|
||||
);
|
||||
}
|
||||
ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_CRC32B => {
|
||||
print!("{sum} {size}");
|
||||
}
|
||||
_ => unreachable!("Not a legacy algorithm"),
|
||||
}
|
||||
|
||||
// Print the filename after a space if not stdin
|
||||
if filename != "-" {
|
||||
print!(" ");
|
||||
let _dropped_result = stdout().write_all(os_str_as_bytes(filename)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_tagged_checksum(options: &Options, filename: &OsStr, sum: &String) -> UResult<()> {
|
||||
// Print algo name and opening parenthesis.
|
||||
print!(
|
||||
"{} (",
|
||||
match (options.algo_name, options.length) {
|
||||
// Multiply the length by 8, as we want to print the length in bits.
|
||||
(ALGORITHM_OPTIONS_BLAKE2B, Some(l)) => format!("BLAKE2b-{}", l * 8),
|
||||
(ALGORITHM_OPTIONS_BLAKE2B, None) => "BLAKE2b".into(),
|
||||
(name, _) => name.to_ascii_uppercase(),
|
||||
}
|
||||
);
|
||||
|
||||
// Print filename
|
||||
let _dropped_result = stdout().write_all(os_str_as_bytes(filename)?);
|
||||
|
||||
// Print closing parenthesis and sum
|
||||
print!(") = {sum}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_untagged_checksum(
|
||||
filename: &OsStr,
|
||||
sum: &String,
|
||||
reading_mode: ReadingMode,
|
||||
) -> UResult<()> {
|
||||
// Print checksum and reading mode flag
|
||||
print!("{sum} {}", reading_mode.as_char());
|
||||
|
||||
// Print filename
|
||||
let _dropped_result = stdout().write_all(os_str_as_bytes(filename)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Calculate checksum
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `options` - CLI options for the assigning checksum algorithm
|
||||
/// * `files` - A iterator of [`OsStr`] which is a bunch of files that are using for calculating checksum
|
||||
fn cksum<'a, I>(mut options: Options, files: I) -> UResult<()>
|
||||
where
|
||||
I: Iterator<Item = &'a OsStr>,
|
||||
{
|
||||
let mut files = files.peekable();
|
||||
|
||||
while let Some(filename) = files.next() {
|
||||
// Check that in raw mode, we are not provided with several files.
|
||||
if options.output_format.is_raw() && files.peek().is_some() {
|
||||
return Err(Box::new(ChecksumError::RawMultipleFiles));
|
||||
}
|
||||
|
||||
let filepath = Path::new(filename);
|
||||
let stdin_buf;
|
||||
let file_buf;
|
||||
if filepath.is_dir() {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
translate!("cksum-error-is-directory", "file" => filepath.display())
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle the file input
|
||||
let mut file = BufReader::new(if filename == "-" {
|
||||
stdin_buf = stdin();
|
||||
Box::new(stdin_buf) as Box<dyn Read>
|
||||
} else {
|
||||
file_buf = match File::open(filepath) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
show!(err.map_err_context(|| filepath.to_string_lossy().to_string()));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
Box::new(file_buf) as Box<dyn Read>
|
||||
});
|
||||
|
||||
let (sum_hex, sz) =
|
||||
digest_reader(&mut options.digest, &mut file, false, options.output_bits)
|
||||
.map_err_context(|| translate!("cksum-error-failed-to-read-input"))?;
|
||||
|
||||
// Encodes the sum if df is Base64, leaves as-is otherwise.
|
||||
let encode_sum = |sum: String, df: DigestFormat| {
|
||||
if df.is_base64() {
|
||||
encoding::for_cksum::BASE64.encode(&hex::decode(sum).unwrap())
|
||||
} else {
|
||||
sum
|
||||
}
|
||||
};
|
||||
|
||||
match options.output_format {
|
||||
OutputFormat::Raw => {
|
||||
let bytes = match options.algo_name {
|
||||
ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_CRC32B => {
|
||||
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()
|
||||
}
|
||||
_ => hex::decode(sum_hex).unwrap(),
|
||||
};
|
||||
// Cannot handle multiple files anyway, output immediately.
|
||||
stdout().write_all(&bytes)?;
|
||||
return Ok(());
|
||||
}
|
||||
OutputFormat::Legacy => {
|
||||
print_legacy_checksum(&options, filename, &sum_hex, sz)?;
|
||||
}
|
||||
OutputFormat::Tagged(digest_format) => {
|
||||
print_tagged_checksum(&options, filename, &encode_sum(sum_hex, digest_format))?;
|
||||
}
|
||||
OutputFormat::Untagged(digest_format, reading_mode) => {
|
||||
print_untagged_checksum(
|
||||
filename,
|
||||
&encode_sum(sum_hex, digest_format),
|
||||
reading_mode,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
print!("{}", options.line_ending);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
use uucore::error::UResult;
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::{format_usage, translate};
|
||||
|
||||
mod options {
|
||||
pub const ALGORITHM: &str = "algorithm";
|
||||
@@ -329,46 +84,9 @@ fn handle_tag_text_binary_flags<S: AsRef<OsStr>>(
|
||||
Ok((tag, binary))
|
||||
}
|
||||
|
||||
/// Use already-processed arguments to decide the output format.
|
||||
fn figure_out_output_format(
|
||||
algo: &HashAlgorithm,
|
||||
tag: bool,
|
||||
binary: bool,
|
||||
raw: bool,
|
||||
base64: bool,
|
||||
) -> OutputFormat {
|
||||
// Raw output format takes precedence over anything else.
|
||||
if raw {
|
||||
return OutputFormat::Raw;
|
||||
}
|
||||
|
||||
// Then, if the algo is legacy, takes precedence over the rest
|
||||
if LEGACY_ALGORITHMS.contains(&algo.name) {
|
||||
return OutputFormat::Legacy;
|
||||
}
|
||||
|
||||
let digest_format = if base64 {
|
||||
DigestFormat::Base64
|
||||
} else {
|
||||
DigestFormat::Hexadecimal
|
||||
};
|
||||
|
||||
// After that, decide between tagged and untagged output
|
||||
if tag {
|
||||
OutputFormat::Tagged(digest_format)
|
||||
} else {
|
||||
let reading_mode = if binary {
|
||||
ReadingMode::Binary
|
||||
} else {
|
||||
ReadingMode::Text
|
||||
};
|
||||
OutputFormat::Untagged(digest_format, reading_mode)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sanitize the `--length` argument depending on `--algorithm` and `--length`.
|
||||
fn maybe_sanitize_length(
|
||||
algo_cli: Option<&str>,
|
||||
algo_cli: Option<AlgoKind>,
|
||||
input_length: Option<&str>,
|
||||
) -> UResult<Option<usize>> {
|
||||
match (algo_cli, input_length) {
|
||||
@@ -376,12 +94,12 @@ fn maybe_sanitize_length(
|
||||
(_, None) => Ok(None),
|
||||
|
||||
// For SHA2 and SHA3, if a length is provided, ensure it is correct.
|
||||
(Some(algo @ (ALGORITHM_OPTIONS_SHA2 | ALGORITHM_OPTIONS_SHA3)), Some(s_len)) => {
|
||||
(Some(algo @ (AlgoKind::Sha2 | AlgoKind::Sha3)), Some(s_len)) => {
|
||||
sanitize_sha2_sha3_length_str(algo, s_len).map(Some)
|
||||
}
|
||||
|
||||
// For BLAKE2b, if a length is provided, validate it.
|
||||
(Some(ALGORITHM_OPTIONS_BLAKE2B), Some(len)) => calculate_blake2b_length_str(len),
|
||||
(Some(AlgoKind::Blake2b), Some(len)) => calculate_blake2b_length_str(len),
|
||||
|
||||
// For any other provided algorithm, check if length is 0.
|
||||
// Otherwise, this is an error.
|
||||
@@ -398,7 +116,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
let algo_cli = matches
|
||||
.get_one::<String>(options::ALGORITHM)
|
||||
.map(String::as_str);
|
||||
.map(AlgoKind::from_cksum)
|
||||
.transpose()?;
|
||||
|
||||
let input_length = matches
|
||||
.get_one::<String>(options::LENGTH)
|
||||
@@ -415,7 +134,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
if check {
|
||||
// cksum does not support '--check'ing legacy algorithms
|
||||
if algo_cli.is_some_and(|algo_name| LEGACY_ALGORITHMS.contains(&algo_name)) {
|
||||
if algo_cli.is_some_and(AlgoKind::is_legacy) {
|
||||
return Err(ChecksumError::AlgorithmNotSupportedWithCheck.into());
|
||||
}
|
||||
|
||||
@@ -435,8 +154,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
// Execute the checksum validation based on the presence of files or the use of stdin
|
||||
|
||||
let verbose = ChecksumVerbose::new(status, quiet, warn);
|
||||
let opts = ChecksumOptions {
|
||||
binary: binary_flag,
|
||||
let opts = ChecksumValidateOptions {
|
||||
ignore_missing,
|
||||
strict,
|
||||
verbose,
|
||||
@@ -448,31 +166,30 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
// Not --check
|
||||
|
||||
// Set the default algorithm to CRC when not '--check'ing.
|
||||
let algo_name = algo_cli.unwrap_or(ALGORITHM_OPTIONS_CRC);
|
||||
let algo_kind = algo_cli.unwrap_or(AlgoKind::Crc);
|
||||
|
||||
let (tag, binary) = handle_tag_text_binary_flags(std::env::args_os())?;
|
||||
|
||||
let algo = detect_algo(algo_name, length)?;
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, length)?;
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO));
|
||||
|
||||
let output_format = figure_out_output_format(
|
||||
&algo,
|
||||
algo,
|
||||
tag,
|
||||
binary,
|
||||
matches.get_flag(options::RAW),
|
||||
matches.get_flag(options::BASE64),
|
||||
);
|
||||
|
||||
let opts = Options {
|
||||
algo_name: algo.name,
|
||||
digest: (algo.create_fn)(),
|
||||
output_bits: algo.bits,
|
||||
length,
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format,
|
||||
line_ending,
|
||||
binary: false,
|
||||
no_names: false,
|
||||
};
|
||||
|
||||
cksum(opts, files)?;
|
||||
perform_checksum_computation(opts, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ path = "src/hashsum.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["checksum", "sum"] }
|
||||
uucore = { workspace = true, features = ["checksum", "encoding", "sum"] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
|
||||
+65
-200
@@ -3,53 +3,28 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (ToDO) algo, algoname, regexes, nread, nonames
|
||||
// spell-checker:ignore (ToDO) algo, algoname, bitlen, regexes, nread, nonames
|
||||
|
||||
use clap::ArgAction;
|
||||
use clap::builder::ValueParser;
|
||||
use clap::value_parser;
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read, stdin};
|
||||
use std::iter;
|
||||
use std::num::ParseIntError;
|
||||
use std::path::Path;
|
||||
use uucore::checksum::ChecksumError;
|
||||
use uucore::checksum::ChecksumOptions;
|
||||
use uucore::checksum::ChecksumVerbose;
|
||||
use uucore::checksum::HashAlgorithm;
|
||||
use uucore::checksum::calculate_blake2b_length;
|
||||
use uucore::checksum::create_sha3;
|
||||
use uucore::checksum::detect_algo;
|
||||
use uucore::checksum::digest_reader;
|
||||
use uucore::checksum::escape_filename;
|
||||
use uucore::checksum::perform_checksum_validation;
|
||||
use uucore::error::{UResult, strip_errno};
|
||||
use uucore::format_usage;
|
||||
use uucore::sum::{Digest, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Shake128, Shake256};
|
||||
use uucore::translate;
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command, value_parser};
|
||||
|
||||
use uucore::checksum::compute::{
|
||||
ChecksumComputeOptions, figure_out_output_format, perform_checksum_computation,
|
||||
};
|
||||
use uucore::checksum::validate::{
|
||||
ChecksumValidateOptions, ChecksumVerbose, perform_checksum_validation,
|
||||
};
|
||||
use uucore::checksum::{AlgoKind, ChecksumError, SizedAlgoKind, calculate_blake2b_length};
|
||||
use uucore::error::UResult;
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::{format_usage, translate};
|
||||
|
||||
const NAME: &str = "hashsum";
|
||||
// Using the same read buffer size as GNU
|
||||
const READ_BUFFER_SIZE: usize = 32 * 1024;
|
||||
|
||||
struct Options<'a> {
|
||||
algoname: &'static str,
|
||||
digest: Box<dyn Digest + 'static>,
|
||||
binary: bool,
|
||||
binary_name: &'a str,
|
||||
//check: bool,
|
||||
tag: bool,
|
||||
nonames: bool,
|
||||
//status: bool,
|
||||
//quiet: bool,
|
||||
//strict: bool,
|
||||
//warn: bool,
|
||||
output_bits: usize,
|
||||
zero: bool,
|
||||
//ignore_missing: bool,
|
||||
}
|
||||
|
||||
/// Creates a hasher instance based on the command-line flags.
|
||||
///
|
||||
@@ -63,10 +38,10 @@ struct Options<'a> {
|
||||
/// the output length in bits or an Err if multiple hash algorithms are specified or if a
|
||||
/// required flag is missing.
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<HashAlgorithm> {
|
||||
let mut alg: Option<HashAlgorithm> = None;
|
||||
fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<(AlgoKind, Option<usize>)> {
|
||||
let mut alg: Option<(AlgoKind, Option<usize>)> = None;
|
||||
|
||||
let mut set_or_err = |new_alg: HashAlgorithm| -> UResult<()> {
|
||||
let mut set_or_err = |new_alg: (AlgoKind, Option<usize>)| -> UResult<()> {
|
||||
if alg.is_some() {
|
||||
return Err(ChecksumError::CombineMultipleAlgorithms.into());
|
||||
}
|
||||
@@ -75,80 +50,57 @@ fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<HashAlgorithm> {
|
||||
};
|
||||
|
||||
if matches.get_flag("md5") {
|
||||
set_or_err(detect_algo("md5sum", None)?)?;
|
||||
set_or_err((AlgoKind::Md5, None))?;
|
||||
}
|
||||
if matches.get_flag("sha1") {
|
||||
set_or_err(detect_algo("sha1sum", None)?)?;
|
||||
set_or_err((AlgoKind::Sha1, None))?;
|
||||
}
|
||||
if matches.get_flag("sha224") {
|
||||
set_or_err(detect_algo("sha224sum", None)?)?;
|
||||
set_or_err((AlgoKind::Sha224, None))?;
|
||||
}
|
||||
if matches.get_flag("sha256") {
|
||||
set_or_err(detect_algo("sha256sum", None)?)?;
|
||||
set_or_err((AlgoKind::Sha256, None))?;
|
||||
}
|
||||
if matches.get_flag("sha384") {
|
||||
set_or_err(detect_algo("sha384sum", None)?)?;
|
||||
set_or_err((AlgoKind::Sha384, None))?;
|
||||
}
|
||||
if matches.get_flag("sha512") {
|
||||
set_or_err(detect_algo("sha512sum", None)?)?;
|
||||
set_or_err((AlgoKind::Sha512, None))?;
|
||||
}
|
||||
if matches.get_flag("b2sum") {
|
||||
set_or_err(detect_algo("b2sum", None)?)?;
|
||||
set_or_err((AlgoKind::Blake2b, None))?;
|
||||
}
|
||||
if matches.get_flag("b3sum") {
|
||||
set_or_err(detect_algo("b3sum", None)?)?;
|
||||
set_or_err((AlgoKind::Blake3, None))?;
|
||||
}
|
||||
if matches.get_flag("sha3") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits) => set_or_err(create_sha3(*bits)?)?,
|
||||
Some(bits @ (224 | 256 | 384 | 512)) => set_or_err((AlgoKind::Sha3, Some(*bits)))?,
|
||||
Some(bits) => return Err(ChecksumError::InvalidLengthForSha(bits.to_string()).into()),
|
||||
None => return Err(ChecksumError::LengthRequired("SHA3".into()).into()),
|
||||
}
|
||||
}
|
||||
if matches.get_flag("sha3-224") {
|
||||
set_or_err(HashAlgorithm {
|
||||
name: "SHA3-224",
|
||||
create_fn: Box::new(|| Box::new(Sha3_224::new())),
|
||||
bits: 224,
|
||||
})?;
|
||||
set_or_err((AlgoKind::Sha3, Some(224)))?;
|
||||
}
|
||||
if matches.get_flag("sha3-256") {
|
||||
set_or_err(HashAlgorithm {
|
||||
name: "SHA3-256",
|
||||
create_fn: Box::new(|| Box::new(Sha3_256::new())),
|
||||
bits: 256,
|
||||
})?;
|
||||
set_or_err((AlgoKind::Sha3, Some(256)))?;
|
||||
}
|
||||
if matches.get_flag("sha3-384") {
|
||||
set_or_err(HashAlgorithm {
|
||||
name: "SHA3-384",
|
||||
create_fn: Box::new(|| Box::new(Sha3_384::new())),
|
||||
bits: 384,
|
||||
})?;
|
||||
set_or_err((AlgoKind::Sha3, Some(384)))?;
|
||||
}
|
||||
if matches.get_flag("sha3-512") {
|
||||
set_or_err(HashAlgorithm {
|
||||
name: "SHA3-512",
|
||||
create_fn: Box::new(|| Box::new(Sha3_512::new())),
|
||||
bits: 512,
|
||||
})?;
|
||||
set_or_err((AlgoKind::Sha3, Some(512)))?;
|
||||
}
|
||||
if matches.get_flag("shake128") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits) => set_or_err(HashAlgorithm {
|
||||
name: "SHAKE128",
|
||||
create_fn: Box::new(|| Box::new(Shake128::new())),
|
||||
bits: *bits,
|
||||
})?,
|
||||
Some(bits) => set_or_err((AlgoKind::Shake128, Some(*bits)))?,
|
||||
None => return Err(ChecksumError::LengthRequired("SHAKE128".into()).into()),
|
||||
}
|
||||
}
|
||||
if matches.get_flag("shake256") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits) => set_or_err(HashAlgorithm {
|
||||
name: "SHAKE256",
|
||||
create_fn: Box::new(|| Box::new(Shake256::new())),
|
||||
bits: *bits,
|
||||
})?,
|
||||
Some(bits) => set_or_err((AlgoKind::Shake256, Some(*bits)))?,
|
||||
None => return Err(ChecksumError::LengthRequired("SHAKE256".into()).into()),
|
||||
}
|
||||
}
|
||||
@@ -198,10 +150,10 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||
None => None,
|
||||
};
|
||||
|
||||
let algo = if is_hashsum_bin {
|
||||
let (algo_kind, length) = if is_hashsum_bin {
|
||||
create_algorithm_from_flags(&matches)?
|
||||
} else {
|
||||
detect_algo(&binary_name, length)?
|
||||
(AlgoKind::from_bin_name(&binary_name)?, length)
|
||||
};
|
||||
|
||||
let binary = if matches.get_flag("binary") {
|
||||
@@ -213,9 +165,9 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||
};
|
||||
let check = matches.get_flag("check");
|
||||
let status = matches.get_flag("status");
|
||||
let quiet = matches.get_flag("quiet") || status;
|
||||
let quiet = matches.get_flag("quiet");
|
||||
let strict = matches.get_flag("strict");
|
||||
let warn = matches.get_flag("warn") && !status;
|
||||
let warn = matches.get_flag("warn");
|
||||
let ignore_missing = matches.get_flag("ignore-missing");
|
||||
|
||||
if ignore_missing && !check {
|
||||
@@ -227,16 +179,14 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||
// on Windows, allow --binary/--text to be used with --check
|
||||
// and keep the behavior of defaulting to binary
|
||||
#[cfg(not(windows))]
|
||||
let binary = {
|
||||
{
|
||||
let text_flag = matches.get_flag("text");
|
||||
let binary_flag = matches.get_flag("binary");
|
||||
|
||||
if binary_flag || text_flag {
|
||||
return Err(ChecksumError::BinaryTextConflict.into());
|
||||
}
|
||||
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
// Execute the checksum validation based on the presence of files or the use of stdin
|
||||
// Determine the source of input: a list of files or stdin.
|
||||
@@ -247,52 +197,51 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
let verbose = ChecksumVerbose::new(status, quiet, warn);
|
||||
|
||||
let opts = ChecksumOptions {
|
||||
binary,
|
||||
let opts = ChecksumValidateOptions {
|
||||
ignore_missing,
|
||||
strict,
|
||||
verbose,
|
||||
};
|
||||
|
||||
// Execute the checksum validation
|
||||
return perform_checksum_validation(
|
||||
input.iter().copied(),
|
||||
Some(algo.name),
|
||||
Some(algo.bits),
|
||||
opts,
|
||||
);
|
||||
return perform_checksum_validation(input.iter().copied(), Some(algo_kind), length, opts);
|
||||
} else if quiet {
|
||||
return Err(ChecksumError::QuietNotCheck.into());
|
||||
} else if strict {
|
||||
return Err(ChecksumError::StrictNotCheck.into());
|
||||
}
|
||||
|
||||
let nonames = *matches
|
||||
let no_names = *matches
|
||||
.try_get_one("no-names")
|
||||
.unwrap_or(None)
|
||||
.unwrap_or(&false);
|
||||
let zero = matches.get_flag("zero");
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag("zero"));
|
||||
|
||||
let opts = Options {
|
||||
algoname: algo.name,
|
||||
digest: (algo.create_fn)(),
|
||||
output_bits: algo.bits,
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, length)?;
|
||||
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format: figure_out_output_format(
|
||||
algo,
|
||||
matches.get_flag(options::TAG),
|
||||
binary,
|
||||
/* raw */ false,
|
||||
/* base64: */ false,
|
||||
),
|
||||
line_ending,
|
||||
binary,
|
||||
binary_name: &binary_name,
|
||||
tag: matches.get_flag("tag"),
|
||||
nonames,
|
||||
//status,
|
||||
//quiet,
|
||||
//warn,
|
||||
zero,
|
||||
//ignore_missing,
|
||||
no_names,
|
||||
};
|
||||
|
||||
let files = matches.get_many::<OsString>(options::FILE).map_or_else(
|
||||
// No files given, read from stdin.
|
||||
|| Box::new(iter::once(OsStr::new("-"))) as Box<dyn Iterator<Item = &OsStr>>,
|
||||
// At least one file given, read from them.
|
||||
|files| Box::new(files.map(OsStr::new)) as Box<dyn Iterator<Item = &OsStr>>,
|
||||
);
|
||||
|
||||
// Show the hashsum of the input
|
||||
match matches.get_many::<OsString>(options::FILE) {
|
||||
Some(files) => hashsum(opts, files.map(|f| f.as_os_str())),
|
||||
None => hashsum(opts, iter::once(OsStr::new("-"))),
|
||||
}
|
||||
perform_checksum_computation(opts, files)
|
||||
}
|
||||
|
||||
mod options {
|
||||
@@ -523,87 +472,3 @@ fn uu_app(binary_name: &str) -> (Command, bool) {
|
||||
|
||||
(command, is_hashsum_bin)
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn hashsum<'a, I>(mut options: Options, files: I) -> UResult<()>
|
||||
where
|
||||
I: Iterator<Item = &'a OsStr>,
|
||||
{
|
||||
let binary_marker = if options.binary { "*" } else { " " };
|
||||
let mut err_found = None;
|
||||
for filename in files {
|
||||
let filename = Path::new(filename);
|
||||
|
||||
let mut file = BufReader::with_capacity(
|
||||
READ_BUFFER_SIZE,
|
||||
if filename == OsStr::new("-") {
|
||||
Box::new(stdin()) as Box<dyn Read>
|
||||
} else {
|
||||
let file_buf = match File::open(filename) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"{}: {}: {}",
|
||||
options.binary_name,
|
||||
filename.to_string_lossy(),
|
||||
strip_errno(&e)
|
||||
);
|
||||
err_found = Some(ChecksumError::Io(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
Box::new(file_buf) as Box<dyn Read>
|
||||
},
|
||||
);
|
||||
|
||||
let sum = match digest_reader(
|
||||
&mut options.digest,
|
||||
&mut file,
|
||||
options.binary,
|
||||
options.output_bits,
|
||||
) {
|
||||
Ok((sum, _)) => sum,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"{}: {}: {}",
|
||||
options.binary_name,
|
||||
filename.to_string_lossy(),
|
||||
strip_errno(&e)
|
||||
);
|
||||
err_found = Some(ChecksumError::Io(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let (escaped_filename, prefix) = escape_filename(filename);
|
||||
if options.tag {
|
||||
if options.algoname == "blake2b" {
|
||||
if options.digest.output_bits() == 512 {
|
||||
println!("BLAKE2b ({escaped_filename}) = {sum}");
|
||||
} else {
|
||||
// special case for BLAKE2b with non-default output length
|
||||
println!(
|
||||
"BLAKE2b-{} ({escaped_filename}) = {sum}",
|
||||
options.digest.output_bits()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"{prefix}{} ({escaped_filename}) = {sum}",
|
||||
options.algoname.to_ascii_uppercase()
|
||||
);
|
||||
}
|
||||
} else if options.nonames {
|
||||
println!("{sum}");
|
||||
} else if options.zero {
|
||||
// with zero, we don't escape the filename
|
||||
print!("{sum} {binary_marker}{}\0", filename.display());
|
||||
} else {
|
||||
println!("{prefix}{sum} {binary_marker}{escaped_filename}");
|
||||
}
|
||||
}
|
||||
match err_found {
|
||||
None => Ok(()),
|
||||
Some(e) => Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore bitlen
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader, Read, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::checksum::{ChecksumError, SizedAlgoKind, digest_reader, escape_filename};
|
||||
use crate::error::{FromIo, UResult, USimpleError};
|
||||
use crate::line_ending::LineEnding;
|
||||
use crate::{encoding, show, translate};
|
||||
|
||||
/// Use the same buffer size as GNU when reading a file to create a checksum
|
||||
/// from it: 32 KiB.
|
||||
const READ_BUFFER_SIZE: usize = 32 * 1024;
|
||||
|
||||
pub struct ChecksumComputeOptions {
|
||||
/// Which algorithm to use to compute the digest.
|
||||
pub algo_kind: SizedAlgoKind,
|
||||
|
||||
/// Printing format to use for each checksum.
|
||||
pub output_format: OutputFormat,
|
||||
|
||||
/// Whether to finish lines with '\n' or '\0'.
|
||||
pub line_ending: LineEnding,
|
||||
|
||||
/// On windows, open files as binary instead of text
|
||||
pub binary: bool,
|
||||
|
||||
/// (non-GNU option) Do not print file names
|
||||
pub no_names: bool,
|
||||
}
|
||||
|
||||
/// Reading mode used to compute digest.
|
||||
///
|
||||
/// On most linux systems, this is irrelevant, as there is no distinction
|
||||
/// between text and binary files. Refer to GNU's cksum documentation for more
|
||||
/// information.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ReadingMode {
|
||||
Binary,
|
||||
Text,
|
||||
}
|
||||
|
||||
impl ReadingMode {
|
||||
#[inline]
|
||||
fn as_char(&self) -> char {
|
||||
match self {
|
||||
Self::Binary => '*',
|
||||
Self::Text => ' ',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to write the digest as hexadecimal or encoded in base64.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DigestFormat {
|
||||
Hexadecimal,
|
||||
Base64,
|
||||
}
|
||||
|
||||
impl DigestFormat {
|
||||
#[inline]
|
||||
fn is_base64(&self) -> bool {
|
||||
*self == Self::Base64
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the representation that shall be used for printing a checksum line
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum OutputFormat {
|
||||
/// Raw digest
|
||||
Raw,
|
||||
|
||||
/// Selected for older algorithms which had their custom formatting
|
||||
///
|
||||
/// Default for crc, sysv, bsd
|
||||
Legacy,
|
||||
|
||||
/// `$ALGO_NAME ($FILENAME) = $DIGEST`
|
||||
Tagged(DigestFormat),
|
||||
|
||||
/// '$DIGEST $FLAG$FILENAME'
|
||||
/// where 'flag' depends on the reading mode
|
||||
///
|
||||
/// Default for standalone checksum utilities
|
||||
Untagged(DigestFormat, ReadingMode),
|
||||
}
|
||||
|
||||
impl OutputFormat {
|
||||
#[inline]
|
||||
fn is_raw(&self) -> bool {
|
||||
*self == Self::Raw
|
||||
}
|
||||
}
|
||||
|
||||
/// Use already-processed arguments to decide the output format.
|
||||
pub fn figure_out_output_format(
|
||||
algo: SizedAlgoKind,
|
||||
tag: bool,
|
||||
binary: bool,
|
||||
raw: bool,
|
||||
base64: bool,
|
||||
) -> OutputFormat {
|
||||
// Raw output format takes precedence over anything else.
|
||||
if raw {
|
||||
return OutputFormat::Raw;
|
||||
}
|
||||
|
||||
// Then, if the algo is legacy, takes precedence over the rest
|
||||
if algo.is_legacy() {
|
||||
return OutputFormat::Legacy;
|
||||
}
|
||||
|
||||
let digest_format = if base64 {
|
||||
DigestFormat::Base64
|
||||
} else {
|
||||
DigestFormat::Hexadecimal
|
||||
};
|
||||
|
||||
// After that, decide between tagged and untagged output
|
||||
if tag {
|
||||
OutputFormat::Tagged(digest_format)
|
||||
} else {
|
||||
let reading_mode = if binary {
|
||||
ReadingMode::Binary
|
||||
} else {
|
||||
ReadingMode::Text
|
||||
};
|
||||
OutputFormat::Untagged(digest_format, reading_mode)
|
||||
}
|
||||
}
|
||||
|
||||
fn print_legacy_checksum(
|
||||
options: &ChecksumComputeOptions,
|
||||
filename: &OsStr,
|
||||
sum: &str,
|
||||
size: usize,
|
||||
) -> UResult<()> {
|
||||
debug_assert!(options.algo_kind.is_legacy());
|
||||
|
||||
let (escaped_filename, prefix) = if options.line_ending == LineEnding::Nul {
|
||||
(filename.to_string_lossy().to_string(), "")
|
||||
} else {
|
||||
escape_filename(filename)
|
||||
};
|
||||
|
||||
print!("{prefix}");
|
||||
|
||||
// Print the sum
|
||||
match options.algo_kind {
|
||||
SizedAlgoKind::Sysv => print!(
|
||||
"{} {}",
|
||||
sum.parse::<u16>().unwrap(),
|
||||
size.div_ceil(options.algo_kind.bitlen()),
|
||||
),
|
||||
SizedAlgoKind::Bsd => {
|
||||
// The BSD checksum output is 5 digit integer
|
||||
let bsd_width = 5;
|
||||
print!(
|
||||
"{:0bsd_width$} {:bsd_width$}",
|
||||
sum.parse::<u16>().unwrap(),
|
||||
size.div_ceil(options.algo_kind.bitlen()),
|
||||
);
|
||||
}
|
||||
SizedAlgoKind::Crc | SizedAlgoKind::Crc32b => {
|
||||
print!("{sum} {size}");
|
||||
}
|
||||
_ => unreachable!("Not a legacy algorithm"),
|
||||
}
|
||||
|
||||
// Print the filename after a space if not stdin
|
||||
if escaped_filename != "-" {
|
||||
print!(" ");
|
||||
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_tagged_checksum(
|
||||
options: &ChecksumComputeOptions,
|
||||
filename: &OsStr,
|
||||
sum: &String,
|
||||
) -> UResult<()> {
|
||||
let (escaped_filename, prefix) = if options.line_ending == LineEnding::Nul {
|
||||
(filename.to_string_lossy().to_string(), "")
|
||||
} else {
|
||||
escape_filename(filename)
|
||||
};
|
||||
|
||||
// Print algo name and opening parenthesis.
|
||||
print!("{prefix}{} (", options.algo_kind.to_tag());
|
||||
|
||||
// Print filename
|
||||
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
|
||||
|
||||
// Print closing parenthesis and sum
|
||||
print!(") = {sum}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_untagged_checksum(
|
||||
options: &ChecksumComputeOptions,
|
||||
filename: &OsStr,
|
||||
sum: &String,
|
||||
reading_mode: ReadingMode,
|
||||
) -> UResult<()> {
|
||||
// early check for the "no-names" option
|
||||
if options.no_names {
|
||||
print!("{sum}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (escaped_filename, prefix) = if options.line_ending == LineEnding::Nul {
|
||||
(filename.to_string_lossy().to_string(), "")
|
||||
} else {
|
||||
escape_filename(filename)
|
||||
};
|
||||
|
||||
// Print checksum and reading mode flag
|
||||
print!("{prefix}{sum} {}", reading_mode.as_char());
|
||||
|
||||
// Print filename
|
||||
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Calculate checksum
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `options` - CLI options for the assigning checksum algorithm
|
||||
/// * `files` - A iterator of [`OsStr`] which is a bunch of files that are using for calculating checksum
|
||||
pub fn perform_checksum_computation<'a, I>(options: ChecksumComputeOptions, files: I) -> UResult<()>
|
||||
where
|
||||
I: Iterator<Item = &'a OsStr>,
|
||||
{
|
||||
let mut files = files.peekable();
|
||||
|
||||
while let Some(filename) = files.next() {
|
||||
// Check that in raw mode, we are not provided with several files.
|
||||
if options.output_format.is_raw() && files.peek().is_some() {
|
||||
return Err(Box::new(ChecksumError::RawMultipleFiles));
|
||||
}
|
||||
|
||||
let filepath = Path::new(filename);
|
||||
let stdin_buf;
|
||||
let file_buf;
|
||||
if filepath.is_dir() {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
// TODO: Rework translation, which is broken since this code moved to uucore
|
||||
// translate!("cksum-error-is-directory", "file" => filepath.display())
|
||||
format!("{}: Is a directory", filepath.display())
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle the file input
|
||||
let mut file = BufReader::with_capacity(
|
||||
READ_BUFFER_SIZE,
|
||||
if filename == "-" {
|
||||
stdin_buf = io::stdin();
|
||||
Box::new(stdin_buf) as Box<dyn Read>
|
||||
} else {
|
||||
file_buf = match File::open(filepath) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
show!(err.map_err_context(|| filepath.to_string_lossy().into()));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
Box::new(file_buf) as Box<dyn Read>
|
||||
},
|
||||
);
|
||||
|
||||
let mut digest = options.algo_kind.create_digest();
|
||||
|
||||
let (sum_hex, sz) = digest_reader(
|
||||
&mut digest,
|
||||
&mut file,
|
||||
options.binary,
|
||||
options.algo_kind.bitlen(),
|
||||
)
|
||||
.map_err_context(|| translate!("cksum-error-failed-to-read-input"))?;
|
||||
|
||||
// Encodes the sum if df is Base64, leaves as-is otherwise.
|
||||
let encode_sum = |sum: String, df: DigestFormat| {
|
||||
if df.is_base64() {
|
||||
encoding::for_cksum::BASE64.encode(&hex::decode(sum).unwrap())
|
||||
} else {
|
||||
sum
|
||||
}
|
||||
};
|
||||
|
||||
match options.output_format {
|
||||
OutputFormat::Raw => {
|
||||
let bytes = match options.algo_kind {
|
||||
SizedAlgoKind::Crc | SizedAlgoKind::Crc32b => {
|
||||
sum_hex.parse::<u32>().unwrap().to_be_bytes().to_vec()
|
||||
}
|
||||
SizedAlgoKind::Sysv | SizedAlgoKind::Bsd => {
|
||||
sum_hex.parse::<u16>().unwrap().to_be_bytes().to_vec()
|
||||
}
|
||||
_ => hex::decode(sum_hex).unwrap(),
|
||||
};
|
||||
// Cannot handle multiple files anyway, output immediately.
|
||||
io::stdout().write_all(&bytes)?;
|
||||
return Ok(());
|
||||
}
|
||||
OutputFormat::Legacy => {
|
||||
print_legacy_checksum(&options, filename, &sum_hex, sz)?;
|
||||
}
|
||||
OutputFormat::Tagged(digest_format) => {
|
||||
print_tagged_checksum(&options, filename, &encode_sum(sum_hex, digest_format))?;
|
||||
}
|
||||
OutputFormat::Untagged(digest_format, reading_mode) => {
|
||||
print_untagged_checksum(
|
||||
&options,
|
||||
filename,
|
||||
&encode_sum(sum_hex, digest_format),
|
||||
reading_mode,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
print!("{}", options.line_ending);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+114
-660
File diff suppressed because it is too large
Load Diff
@@ -774,14 +774,31 @@ fn test_blake2b_length() {
|
||||
|
||||
#[test]
|
||||
fn test_blake2b_length_greater_than_512() {
|
||||
new_ucmd!()
|
||||
.arg("--length=1024")
|
||||
.arg("--algorithm=blake2b")
|
||||
.arg("lorem_ipsum.txt")
|
||||
.arg("alice_in_wonderland.txt")
|
||||
.fails_with_code(1)
|
||||
.no_stdout()
|
||||
.stderr_is_fixture("length_larger_than_512.expected");
|
||||
for l in ["513", "1024", "73786976294838206464"] {
|
||||
new_ucmd!()
|
||||
.arg("--algorithm=blake2b")
|
||||
.arg("--length")
|
||||
.arg(l)
|
||||
.arg("lorem_ipsum.txt")
|
||||
.fails_with_code(1)
|
||||
.no_stdout()
|
||||
.stderr_contains(format!("invalid length: '{l}'"))
|
||||
.stderr_contains("maximum digest length for 'BLAKE2b' is 512 bits");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2b_length_nan() {
|
||||
for l in ["foo", "512x", "x512", "0xff"] {
|
||||
new_ucmd!()
|
||||
.arg("--algorithm=blake2b")
|
||||
.arg("--length")
|
||||
.arg(l)
|
||||
.arg("lorem_ipsum.txt")
|
||||
.fails_with_code(1)
|
||||
.no_stdout()
|
||||
.stderr_contains(format!("invalid length: '{l}'"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -107,17 +107,12 @@ macro_rules! test_digest {
|
||||
at.write("a", "file1\n");
|
||||
at.write("c", "file3\n");
|
||||
|
||||
#[cfg(unix)]
|
||||
let file_not_found_str = "No such file or directory";
|
||||
#[cfg(not(unix))]
|
||||
let file_not_found_str = "The system cannot find the file specified";
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, BITS_ARG, "a", "b", "c"])
|
||||
.fails()
|
||||
.stdout_contains("a\n")
|
||||
.stdout_contains("c\n")
|
||||
.stderr_contains(format!("b: {file_not_found_str}"));
|
||||
.stderr_contains("b: No such file or directory");
|
||||
}
|
||||
}
|
||||
)*)
|
||||
@@ -1097,11 +1092,11 @@ fn test_sha256_stdin_binary() {
|
||||
);
|
||||
}
|
||||
|
||||
// This test is currently disabled on windows
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore = "Discussion is in #9168")]
|
||||
fn test_check_sha256_binary() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
ts.ucmd()
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"--sha256",
|
||||
"--bits=256",
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
cksum: invalid length: '1024'
|
||||
cksum: maximum digest length for 'BLAKE2b' is 512 bits
|
||||
Reference in New Issue
Block a user