mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
Merge 0d46fcbcf2 into 836e5d19c4
This commit is contained in:
commit
f82d5780c4
31 changed files with 1097 additions and 467 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -565,6 +565,7 @@ dependencies = [
|
|||
"time",
|
||||
"unindent",
|
||||
"uu_arch",
|
||||
"uu_b2sum",
|
||||
"uu_base32",
|
||||
"uu_base64",
|
||||
"uu_basename",
|
||||
|
|
@ -3012,6 +3013,17 @@ dependencies = [
|
|||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_b2sum"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codspeed-divan-compat",
|
||||
"fluent",
|
||||
"tempfile",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uu_base32"
|
||||
version = "0.5.0"
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ feat_common_core = [
|
|||
"basenc",
|
||||
"cat",
|
||||
"cksum",
|
||||
"b2sum",
|
||||
"comm",
|
||||
"cp",
|
||||
"csplit",
|
||||
|
|
@ -431,6 +432,7 @@ chmod = { optional = true, version = "0.5.0", package = "uu_chmod", path = "src/
|
|||
chown = { optional = true, version = "0.5.0", package = "uu_chown", path = "src/uu/chown" }
|
||||
chroot = { optional = true, version = "0.5.0", package = "uu_chroot", path = "src/uu/chroot" }
|
||||
cksum = { optional = true, version = "0.5.0", package = "uu_cksum", path = "src/uu/cksum" }
|
||||
b2sum = { optional = true, version = "0.5.0", package = "uu_b2sum", path = "src/uu/b2sum" }
|
||||
comm = { optional = true, version = "0.5.0", package = "uu_comm", path = "src/uu/comm" }
|
||||
cp = { optional = true, version = "0.5.0", package = "uu_cp", path = "src/uu/cp" }
|
||||
csplit = { optional = true, version = "0.5.0", package = "uu_csplit", path = "src/uu/csplit" }
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ PROGS := \
|
|||
basename \
|
||||
cat \
|
||||
cksum \
|
||||
b2sum \
|
||||
comm \
|
||||
cp \
|
||||
csplit \
|
||||
|
|
@ -185,7 +186,6 @@ SELINUX_PROGS := \
|
|||
runcon
|
||||
|
||||
HASHSUM_PROGS := \
|
||||
b2sum \
|
||||
md5sum \
|
||||
sha1sum \
|
||||
sha224sum \
|
||||
|
|
@ -223,6 +223,7 @@ TEST_PROGS := \
|
|||
chmod \
|
||||
chown \
|
||||
cksum \
|
||||
b2sum \
|
||||
comm \
|
||||
cp \
|
||||
csplit \
|
||||
|
|
|
|||
1
build.rs
1
build.rs
|
|
@ -85,7 +85,6 @@ pub fn main() {
|
|||
phf_map.entry("sha256sum", map_value.clone());
|
||||
phf_map.entry("sha384sum", map_value.clone());
|
||||
phf_map.entry("sha512sum", map_value.clone());
|
||||
phf_map.entry("b2sum", map_value.clone());
|
||||
}
|
||||
_ => {
|
||||
phf_map.entry(krate, map_value.clone());
|
||||
|
|
|
|||
41
src/uu/b2sum/Cargo.toml
Normal file
41
src/uu/b2sum/Cargo.toml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
[package]
|
||||
name = "uu_b2sum"
|
||||
description = "b2sum ~ (uutils) Print or check the BLAKE2b checksums"
|
||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/b2sum"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
edition.workspace = true
|
||||
readme.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/b2sum.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"checksum",
|
||||
"encoding",
|
||||
"sum",
|
||||
"hardware",
|
||||
] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
divan = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
uucore = { workspace = true, features = ["benchmark"] }
|
||||
|
||||
[[bin]]
|
||||
name = "b2sum"
|
||||
path = "src/main.rs"
|
||||
|
||||
# [[bench]]
|
||||
# name = "b2sum_bench"
|
||||
# harness = false
|
||||
1
src/uu/b2sum/LICENSE
Symbolic link
1
src/uu/b2sum/LICENSE
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../../LICENSE
|
||||
3
src/uu/b2sum/locales/en-US.ftl
Normal file
3
src/uu/b2sum/locales/en-US.ftl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
b2sum-about = Print or check the BLAKE2b checksums
|
||||
b2sum-usage = b2sum [OPTIONS] [FILE]...
|
||||
b2sum-after-help = With no FILE or when FILE is -, read standard input
|
||||
2
src/uu/b2sum/locales/fr-FR.ftl
Normal file
2
src/uu/b2sum/locales/fr-FR.ftl
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
b2sum-about = Afficher le BLAKE2b et la taille de chaque fichier
|
||||
b2sum-usage = b2sum [OPTION]... [FICHIER]...
|
||||
36
src/uu/b2sum/src/b2sum.rs
Normal file
36
src/uu/b2sum/src/b2sum.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// 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 (ToDO) algo
|
||||
|
||||
use clap::Command;
|
||||
use uucore::checksum::cli::{checksum_main, options, standalone_checksum_app_with_length};
|
||||
use uucore::checksum::compute::OutputFormat;
|
||||
use uucore::checksum::{AlgoKind, calculate_blake2b_length_str};
|
||||
use uucore::error::UResult;
|
||||
use uucore::translate;
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
|
||||
let algo = Some(AlgoKind::Blake2b);
|
||||
|
||||
let length = matches
|
||||
.get_one::<String>(options::LENGTH)
|
||||
.map(String::as_str)
|
||||
.map(calculate_blake2b_length_str)
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
let format = OutputFormat::from_standalone(std::env::args_os().into_iter());
|
||||
|
||||
checksum_main(algo, length, matches, format?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uu_app() -> Command {
|
||||
standalone_checksum_app_with_length(translate!("b2sum-about"), translate!("b2sum-usage"))
|
||||
.after_help(translate!("b2sum-after-help"))
|
||||
}
|
||||
1
src/uu/b2sum/src/main.rs
Normal file
1
src/uu/b2sum/src/main.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
uucore::bin!(uu_b2sum);
|
||||
|
|
@ -12,19 +12,3 @@ cksum-after-help = DIGEST determines the digest algorithm and default output for
|
|||
- sha3: (only available through cksum)
|
||||
- blake2b: (equivalent to b2sum)
|
||||
- sm3: (only available through cksum)
|
||||
|
||||
# Help messages
|
||||
cksum-help-algorithm = select the digest type to use. See DIGEST below
|
||||
cksum-help-untagged = create a reversed style checksum, without digest type
|
||||
cksum-help-tag = create a BSD style checksum, undo --untagged (default)
|
||||
cksum-help-length = digest length in bits; must not exceed the max for the blake2 algorithm and must be a multiple of 8
|
||||
cksum-help-raw = emit a raw binary digest, not hexadecimal
|
||||
cksum-help-strict = exit non-zero for improperly formatted checksum lines
|
||||
cksum-help-check = read hashsums from the FILEs and check them
|
||||
cksum-help-base64 = emit a base64 digest, not hexadecimal
|
||||
cksum-help-warn = warn about improperly formatted checksum lines
|
||||
cksum-help-status = don't output anything, status code shows success
|
||||
cksum-help-quiet = don't print OK for each successfully verified file
|
||||
cksum-help-ignore-missing = don't fail or report status for missing files
|
||||
cksum-help-zero = end each output line with NUL, not newline, and disable file name escaping
|
||||
cksum-help-debug = print CPU hardware capability detection info used by cksum
|
||||
|
|
|
|||
|
|
@ -12,19 +12,3 @@ cksum-after-help = DIGEST détermine l'algorithme de condensé et le format de s
|
|||
- sha3 : (disponible uniquement via cksum)
|
||||
- blake2b : (équivalent à b2sum)
|
||||
- sm3 : (disponible uniquement via cksum)
|
||||
|
||||
# Messages d'aide
|
||||
cksum-help-algorithm = sélectionner le type de condensé à utiliser. Voir DIGEST ci-dessous
|
||||
cksum-help-untagged = créer une somme de contrôle de style inversé, sans type de condensé
|
||||
cksum-help-tag = créer une somme de contrôle de style BSD, annuler --untagged (par défaut)
|
||||
cksum-help-length = longueur du condensé en bits ; ne doit pas dépasser le maximum pour l'algorithme blake2 et doit être un multiple de 8
|
||||
cksum-help-raw = émettre un condensé binaire brut, pas hexadécimal
|
||||
cksum-help-strict = sortir avec un code non-zéro pour les lignes de somme de contrôle mal formatées
|
||||
cksum-help-check = lire les sommes de hachage des FICHIERs et les vérifier
|
||||
cksum-help-base64 = émettre un condensé base64, pas hexadécimal
|
||||
cksum-help-warn = avertir des lignes de somme de contrôle mal formatées
|
||||
cksum-help-status = ne rien afficher, le code de statut indique le succès
|
||||
cksum-help-quiet = ne pas afficher OK pour chaque fichier vérifié avec succès
|
||||
cksum-help-ignore-missing = ne pas échouer ou signaler le statut pour les fichiers manquants
|
||||
cksum-help-zero = terminer chaque ligne de sortie avec NUL, pas un saut de ligne, et désactiver l'échappement des noms de fichiers
|
||||
cksum-help-debug = afficher les informations de débogage sur la détection de la prise en charge matérielle du processeur
|
||||
|
|
|
|||
|
|
@ -5,24 +5,18 @@
|
|||
|
||||
// spell-checker:ignore (ToDO) fname, algo, bitlen
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::iter;
|
||||
use uucore::checksum::compute::{
|
||||
ChecksumComputeOptions, figure_out_output_format, perform_checksum_computation,
|
||||
};
|
||||
use uucore::checksum::validate::{
|
||||
ChecksumValidateOptions, ChecksumVerbose, perform_checksum_validation,
|
||||
};
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use clap::Command;
|
||||
use uucore::checksum::cli::{ChecksumCommand, checksum_main, default_checksum_app};
|
||||
use uucore::checksum::compute::OutputFormat;
|
||||
use uucore::checksum::{
|
||||
AlgoKind, ChecksumError, SUPPORTED_ALGORITHMS, SizedAlgoKind, calculate_blake2b_length_str,
|
||||
AlgoKind, ChecksumError, calculate_blake2b_length_str, cli::options,
|
||||
sanitize_sha2_sha3_length_str,
|
||||
};
|
||||
use uucore::error::UResult;
|
||||
use uucore::hardware::{HasHardwareFeatures as _, SimdPolicy};
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::{format_usage, show_error, translate};
|
||||
use uucore::{show_error, translate};
|
||||
|
||||
/// Print CPU hardware capability detection information to stderr
|
||||
/// This matches GNU cksum's --debug behavior
|
||||
|
|
@ -48,24 +42,28 @@ fn print_cpu_debug_info() {
|
|||
}
|
||||
}
|
||||
|
||||
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";
|
||||
pub const CHECK: &str = "check";
|
||||
pub const STRICT: &str = "strict";
|
||||
pub const TEXT: &str = "text";
|
||||
pub const BINARY: &str = "binary";
|
||||
pub const STATUS: &str = "status";
|
||||
pub const WARN: &str = "warn";
|
||||
pub const IGNORE_MISSING: &str = "ignore-missing";
|
||||
pub const QUIET: &str = "quiet";
|
||||
pub const ZERO: &str = "zero";
|
||||
pub const DEBUG: &str = "debug";
|
||||
/// Sanitize the `--length` argument depending on `--algorithm` and `--length`.
|
||||
fn maybe_sanitize_length(
|
||||
algo_cli: Option<AlgoKind>,
|
||||
input_length: Option<&str>,
|
||||
) -> UResult<Option<usize>> {
|
||||
match (algo_cli, input_length) {
|
||||
// No provided length is not a problem so far.
|
||||
(_, None) => Ok(None),
|
||||
|
||||
// For SHA2 and SHA3, if a length is provided, ensure it is correct.
|
||||
(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(AlgoKind::Blake2b), Some(len)) => calculate_blake2b_length_str(len),
|
||||
|
||||
// For any other provided algorithm, check if length is 0.
|
||||
// Otherwise, this is an error.
|
||||
(_, Some(len)) if len.parse::<u32>() == Ok(0_u32) => Ok(None),
|
||||
(_, Some(_)) => Err(ChecksumError::LengthOnlyForBlake2bSha2Sha3.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// cksum has a bunch of legacy behavior. We handle this in this function to
|
||||
|
|
@ -110,50 +108,10 @@ fn handle_tag_text_binary_flags<S: AsRef<OsStr>>(
|
|||
Ok((tag, binary))
|
||||
}
|
||||
|
||||
/// Sanitize the `--length` argument depending on `--algorithm` and `--length`.
|
||||
fn maybe_sanitize_length(
|
||||
algo_cli: Option<AlgoKind>,
|
||||
input_length: Option<&str>,
|
||||
) -> UResult<Option<usize>> {
|
||||
match (algo_cli, input_length) {
|
||||
// No provided length is not a problem so far.
|
||||
(_, None) => Ok(None),
|
||||
|
||||
// For SHA2 and SHA3, if a length is provided, ensure it is correct.
|
||||
(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(AlgoKind::Blake2b), Some(len)) => calculate_blake2b_length_str(len),
|
||||
|
||||
// For any other provided algorithm, check if length is 0.
|
||||
// Otherwise, this is an error.
|
||||
(_, Some(len)) if len.parse::<u32>() == Ok(0_u32) => Ok(None),
|
||||
(_, Some(_)) => Err(ChecksumError::LengthOnlyForBlake2bSha2Sha3.into()),
|
||||
}
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
|
||||
|
||||
let check = matches.get_flag(options::CHECK);
|
||||
|
||||
let check_flag = |flag| match (check, matches.get_flag(flag)) {
|
||||
(_, false) => Ok(false),
|
||||
(true, true) => Ok(true),
|
||||
(false, true) => Err(ChecksumError::CheckOnlyFlag(flag.into())),
|
||||
};
|
||||
|
||||
// Each of the following flags are only expected in --check mode.
|
||||
// If we encounter them otherwise, end with an error.
|
||||
let ignore_missing = check_flag(options::IGNORE_MISSING)?;
|
||||
let warn = check_flag(options::WARN)?;
|
||||
let quiet = check_flag(options::QUIET)?;
|
||||
let strict = check_flag(options::STRICT)?;
|
||||
let status = check_flag(options::STATUS)?;
|
||||
|
||||
let algo_cli = matches
|
||||
.get_one::<String>(options::ALGORITHM)
|
||||
.map(AlgoKind::from_cksum)
|
||||
|
|
@ -165,199 +123,38 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
let length = maybe_sanitize_length(algo_cli, input_length)?;
|
||||
|
||||
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>>,
|
||||
let (tag, binary) = handle_tag_text_binary_flags(std::env::args_os())?;
|
||||
|
||||
let output_format = OutputFormat::from_cksum(
|
||||
algo_cli.unwrap_or(AlgoKind::Crc),
|
||||
tag,
|
||||
binary,
|
||||
/* raw: */
|
||||
matches.get_flag(options::RAW),
|
||||
/* base64: */
|
||||
matches.get_flag(options::BASE64),
|
||||
);
|
||||
|
||||
if check {
|
||||
// cksum does not support '--check'ing legacy algorithms
|
||||
if algo_cli.is_some_and(AlgoKind::is_legacy) {
|
||||
return Err(ChecksumError::AlgorithmNotSupportedWithCheck.into());
|
||||
}
|
||||
|
||||
let text_flag = matches.get_flag(options::TEXT);
|
||||
let binary_flag = matches.get_flag(options::BINARY);
|
||||
let tag = matches.get_flag(options::TAG);
|
||||
|
||||
if tag || binary_flag || text_flag {
|
||||
return Err(ChecksumError::BinaryTextConflict.into());
|
||||
}
|
||||
|
||||
// Execute the checksum validation based on the presence of files or the use of stdin
|
||||
|
||||
let verbose = ChecksumVerbose::new(status, quiet, warn);
|
||||
let opts = ChecksumValidateOptions {
|
||||
ignore_missing,
|
||||
strict,
|
||||
verbose,
|
||||
};
|
||||
|
||||
return perform_checksum_validation(files, algo_cli, length, opts);
|
||||
}
|
||||
|
||||
// Not --check
|
||||
|
||||
// Print hardware debug info if requested
|
||||
if matches.get_flag(options::DEBUG) {
|
||||
print_cpu_debug_info();
|
||||
}
|
||||
|
||||
// Set the default algorithm to CRC when not '--check'ing.
|
||||
let algo_kind = algo_cli.unwrap_or(AlgoKind::Crc);
|
||||
|
||||
let (tag, binary) = handle_tag_text_binary_flags(std::env::args_os())?;
|
||||
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, length)?;
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO));
|
||||
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format: figure_out_output_format(
|
||||
algo,
|
||||
tag,
|
||||
binary,
|
||||
matches.get_flag(options::RAW),
|
||||
matches.get_flag(options::BASE64),
|
||||
),
|
||||
line_ending,
|
||||
};
|
||||
|
||||
perform_checksum_computation(opts, files)?;
|
||||
|
||||
Ok(())
|
||||
checksum_main(algo_cli, length, matches, output_format)
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(uucore::crate_version!())
|
||||
.help_template(uucore::localized_help_template(uucore::util_name()))
|
||||
.about(translate!("cksum-about"))
|
||||
.override_usage(format_usage(&translate!("cksum-usage")))
|
||||
.infer_long_args(true)
|
||||
.args_override_self(true)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_hint(clap::ValueHint::FilePath),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ALGORITHM)
|
||||
.long(options::ALGORITHM)
|
||||
.short('a')
|
||||
.help(translate!("cksum-help-algorithm"))
|
||||
.value_name("ALGORITHM")
|
||||
.value_parser(SUPPORTED_ALGORITHMS),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::UNTAGGED)
|
||||
.long(options::UNTAGGED)
|
||||
.help(translate!("cksum-help-untagged"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::TAG),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::TAG)
|
||||
.long(options::TAG)
|
||||
.help(translate!("cksum-help-tag"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::UNTAGGED),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LENGTH)
|
||||
.long(options::LENGTH)
|
||||
.short('l')
|
||||
.help(translate!("cksum-help-length"))
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RAW)
|
||||
.long(options::RAW)
|
||||
.help(translate!("cksum-help-raw"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STRICT)
|
||||
.long(options::STRICT)
|
||||
.help(translate!("cksum-help-strict"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CHECK)
|
||||
.short('c')
|
||||
.long(options::CHECK)
|
||||
.help(translate!("cksum-help-check"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::BASE64)
|
||||
.long(options::BASE64)
|
||||
.help(translate!("cksum-help-base64"))
|
||||
.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),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::TEXT)
|
||||
.long(options::TEXT)
|
||||
.short('t')
|
||||
.hide(true)
|
||||
.overrides_with(options::BINARY)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::BINARY)
|
||||
.long(options::BINARY)
|
||||
.short('b')
|
||||
.hide(true)
|
||||
.overrides_with(options::TEXT)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::WARN)
|
||||
.short('w')
|
||||
.long("warn")
|
||||
.help(translate!("cksum-help-warn"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::STATUS, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STATUS)
|
||||
.long("status")
|
||||
.help(translate!("cksum-help-status"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::WARN, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
.long(options::QUIET)
|
||||
.help(translate!("cksum-help-quiet"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::WARN, options::STATUS]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_MISSING)
|
||||
.long(options::IGNORE_MISSING)
|
||||
.help(translate!("cksum-help-ignore-missing"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ZERO)
|
||||
.long(options::ZERO)
|
||||
.short('z')
|
||||
.help(translate!("cksum-help-zero"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.long(options::DEBUG)
|
||||
.help(translate!("cksum-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
default_checksum_app(translate!("cksum-about"), translate!("cksum-usage"))
|
||||
.with_algo()
|
||||
.with_length()
|
||||
.with_check()
|
||||
.with_untagged()
|
||||
.with_tag(true)
|
||||
.with_raw()
|
||||
.with_base64()
|
||||
.with_text(false)
|
||||
.with_binary()
|
||||
.with_zero()
|
||||
.with_debug()
|
||||
.after_help(translate!("cksum-after-help"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,19 +7,21 @@
|
|||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::iter;
|
||||
use std::num::ParseIntError;
|
||||
use std::path::Path;
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
|
||||
use uucore::checksum::compute::{
|
||||
ChecksumComputeOptions, figure_out_output_format, perform_checksum_computation,
|
||||
ChecksumComputeOptions, OutputFormat, perform_checksum_computation,
|
||||
};
|
||||
use uucore::checksum::validate::{
|
||||
ChecksumValidateOptions, ChecksumVerbose, perform_checksum_validation,
|
||||
};
|
||||
use uucore::checksum::{AlgoKind, ChecksumError, SizedAlgoKind, calculate_blake2b_length_str};
|
||||
use uucore::checksum::{
|
||||
AlgoKind, ChecksumError, SizedAlgoKind, calculate_blake2b_length_str,
|
||||
sanitize_sha2_sha3_length_str,
|
||||
};
|
||||
use uucore::error::UResult;
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::{format_usage, translate};
|
||||
|
|
@ -74,9 +76,11 @@ fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<(AlgoKind, Optio
|
|||
set_or_err((AlgoKind::Blake3, None))?;
|
||||
}
|
||||
if matches.get_flag("sha3") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits @ (224 | 256 | 384 | 512)) => set_or_err((AlgoKind::Sha3, Some(*bits)))?,
|
||||
Some(bits) => return Err(ChecksumError::InvalidLengthForSha(bits.to_string()).into()),
|
||||
match matches.get_one::<String>(options::LENGTH) {
|
||||
Some(len) => set_or_err((
|
||||
AlgoKind::Sha3,
|
||||
Some(sanitize_sha2_sha3_length_str(AlgoKind::Sha3, len)?),
|
||||
))?,
|
||||
None => return Err(ChecksumError::LengthRequired("SHA3".into()).into()),
|
||||
}
|
||||
}
|
||||
|
|
@ -93,16 +97,10 @@ fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<(AlgoKind, Optio
|
|||
set_or_err((AlgoKind::Sha3, Some(512)))?;
|
||||
}
|
||||
if matches.get_flag("shake128") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits) => set_or_err((AlgoKind::Shake128, Some(*bits)))?,
|
||||
None => return Err(ChecksumError::LengthRequired("SHAKE128".into()).into()),
|
||||
}
|
||||
set_or_err((AlgoKind::Shake128, Some(128)))?;
|
||||
}
|
||||
if matches.get_flag("shake256") {
|
||||
match matches.get_one::<usize>("bits") {
|
||||
Some(bits) => set_or_err((AlgoKind::Shake256, Some(*bits)))?,
|
||||
None => return Err(ChecksumError::LengthRequired("SHAKE256".into()).into()),
|
||||
}
|
||||
set_or_err((AlgoKind::Shake256, Some(256)))?;
|
||||
}
|
||||
|
||||
if alg.is_none() {
|
||||
|
|
@ -112,11 +110,6 @@ fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<(AlgoKind, Optio
|
|||
Ok(alg.unwrap())
|
||||
}
|
||||
|
||||
// TODO: return custom error type
|
||||
fn parse_bit_num(arg: &str) -> Result<usize, ParseIntError> {
|
||||
arg.parse()
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||
// if there is no program name for some reason, default to "hashsum"
|
||||
|
|
@ -128,9 +121,6 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
let args = iter::once(program.clone()).chain(args);
|
||||
|
||||
// Default binary in Windows, text mode otherwise
|
||||
let binary_flag_default = cfg!(windows);
|
||||
|
||||
let (command, is_hashsum_bin) = uu_app(&binary_name);
|
||||
|
||||
// FIXME: this should use try_get_matches_from() and crash!(), but at the moment that just
|
||||
|
|
@ -139,30 +129,22 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
|||
// least somewhat better from a user's perspective.
|
||||
let matches = uucore::clap_localization::handle_clap_result(command, args)?;
|
||||
|
||||
let input_length: Option<&String> = if binary_name == "b2sum" {
|
||||
matches.get_one::<String>(options::LENGTH)
|
||||
let length: Option<usize> = if binary_name == "b2sum" {
|
||||
if let Some(len) = matches.get_one::<String>(options::LENGTH) {
|
||||
calculate_blake2b_length_str(len)?
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let length = match input_length {
|
||||
Some(length) => calculate_blake2b_length_str(length)?,
|
||||
None => None,
|
||||
};
|
||||
|
||||
let (algo_kind, length) = if is_hashsum_bin {
|
||||
create_algorithm_from_flags(&matches)?
|
||||
} else {
|
||||
(AlgoKind::from_bin_name(&binary_name)?, length)
|
||||
};
|
||||
|
||||
let binary = if matches.get_flag("binary") {
|
||||
true
|
||||
} else if matches.get_flag("text") {
|
||||
false
|
||||
} else {
|
||||
binary_flag_default
|
||||
};
|
||||
let check = matches.get_flag("check");
|
||||
|
||||
let check_flag = |flag| match (check, matches.get_flag(flag)) {
|
||||
|
|
@ -216,13 +198,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format: figure_out_output_format(
|
||||
algo,
|
||||
matches.get_flag(options::TAG),
|
||||
binary,
|
||||
/* raw */ false,
|
||||
/* base64: */ false,
|
||||
),
|
||||
output_format: OutputFormat::from_standalone(std::env::args_os().into_iter())?,
|
||||
line_ending,
|
||||
};
|
||||
|
||||
|
|
@ -371,24 +347,8 @@ fn uu_app_opt_length(command: Command) -> Command {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn uu_app_bits() -> Command {
|
||||
uu_app_opt_bits(uu_app_common())
|
||||
}
|
||||
|
||||
fn uu_app_opt_bits(command: Command) -> Command {
|
||||
// Needed for variable-length output sums (e.g. SHAKE)
|
||||
command.arg(
|
||||
Arg::new("bits")
|
||||
.long("bits")
|
||||
.help(translate!("hashsum-help-bits"))
|
||||
.value_name("BITS")
|
||||
// XXX: should we actually use validators? they're not particularly efficient
|
||||
.value_parser(parse_bit_num),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn uu_app_custom() -> Command {
|
||||
let mut command = uu_app_opt_bits(uu_app_common());
|
||||
let mut command = uu_app_opt_length(uu_app_common());
|
||||
let algorithms = &[
|
||||
("md5", translate!("hashsum-help-md5")),
|
||||
("sha1", translate!("hashsum-help-sha1")),
|
||||
|
|
|
|||
|
|
@ -73,3 +73,23 @@ checksum-failed-open-file = { $count ->
|
|||
*[other] { $count } listed files could not be read
|
||||
}
|
||||
checksum-error-algo-bad-format = { $file }: { $line }: improperly formatted { $algo } checksum line
|
||||
|
||||
# checksum argument help messages
|
||||
checksum-help-algorithm = select the digest type to use. See DIGEST below
|
||||
checksum-help-untagged = create a reversed style checksum, without digest type
|
||||
checksum-help-tag-default = create a BSD style checksum (default)
|
||||
checksum-help-tag = create a BSD style checksum
|
||||
checksum-help-text = read in text mode (default)
|
||||
checksum-help-length = digest length in bits; must not exceed the max size and must be a multiple of 8 for blake2b; must be 224, 256, 384, or 512 for sha2 or sha3
|
||||
checksum-help-check = read checksums from the FILEs and check them
|
||||
checksum-help-base64 = emit base64-encoded digests, not hexadecimal
|
||||
checksum-help-raw = emit a raw binary digest, not hexadecimal
|
||||
checksum-help-zero = end each output line with NUL, not newline, and disable file name escaping
|
||||
|
||||
checksum-help-strict = exit non-zero for improperly formatted checksum lines
|
||||
checksum-help-warn = warn about improperly formatted checksum lines
|
||||
checksum-help-status = don't output anything, status code shows success
|
||||
checksum-help-quiet = don't print OK for each successfully verified file
|
||||
checksum-help-ignore-missing = don't fail or report status for missing files
|
||||
|
||||
checksum-help-debug = print CPU hardware capability detection info used by cksum
|
||||
|
|
|
|||
|
|
@ -73,3 +73,21 @@ checksum-failed-open-file = { $count ->
|
|||
*[other] { $count } fichiers passés n'ont pas pu être lu
|
||||
}
|
||||
checksum-error-algo-bad-format = { $file }: { $line }: ligne invalide pour { $algo }
|
||||
|
||||
# Messages d'aide d'arguments checksum
|
||||
checksum-help-algorithm = sélectionner le type de condensé à utiliser. Voir DIGEST ci-dessous
|
||||
checksum-help-untagged = créer une somme de contrôle de style inversé, sans type de condensé
|
||||
checksum-help-tag-default = créer une somme de contrôle de style BSD (par défaut)
|
||||
checksum-help-tag = créer une somme de contrôle de style BSD
|
||||
checksum-help-text = lire en mode texte (par défaut)
|
||||
checksum-help-length = longueur du condensé en bits ; ne doit pas dépasser le maximum pour l'algorithme blake2 et doit être un multiple de 8
|
||||
checksum-help-raw = émettre un condensé binaire brut, pas hexadécimal
|
||||
checksum-help-strict = sortir avec un code non-zéro pour les lignes de somme de contrôle mal formatées
|
||||
checksum-help-check = lire les sommes de hachage des FICHIERs et les vérifier
|
||||
checksum-help-base64 = émettre un condensé base64, pas hexadécimal
|
||||
checksum-help-warn = avertir des lignes de somme de contrôle mal formatées
|
||||
checksum-help-status = ne rien afficher, le code de statut indique le succès
|
||||
checksum-help-quiet = ne pas afficher OK pour chaque fichier vérifié avec succès
|
||||
checksum-help-ignore-missing = ne pas échouer ou signaler le statut pour les fichiers manquants
|
||||
checksum-help-zero = terminer chaque ligne de sortie avec NUL, pas un saut de ligne, et désactiver l'échappement des noms de fichiers
|
||||
checksum-help-debug = afficher les informations de débogage sur la détection de la prise en charge matérielle du processeur
|
||||
|
|
|
|||
326
src/uucore/src/lib/features/checksum/cli.rs
Normal file
326
src/uucore/src/lib/features/checksum/cli.rs
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};
|
||||
|
||||
use crate::checksum::compute::{
|
||||
ChecksumComputeOptions, OutputFormat, perform_checksum_computation,
|
||||
};
|
||||
use crate::checksum::validate::{ChecksumValidateOptions, ChecksumVerbose};
|
||||
use crate::checksum::{AlgoKind, ChecksumError, SUPPORTED_ALGORITHMS, SizedAlgoKind};
|
||||
use crate::error::UResult;
|
||||
use crate::line_ending::LineEnding;
|
||||
use crate::{crate_version, format_usage, localized_help_template, translate, util_name};
|
||||
|
||||
pub mod options {
|
||||
// cksum-specific
|
||||
pub const ALGORITHM: &str = "algorithm";
|
||||
pub const DEBUG: &str = "debug";
|
||||
|
||||
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";
|
||||
pub const CHECK: &str = "check";
|
||||
pub const TEXT: &str = "text";
|
||||
pub const BINARY: &str = "binary";
|
||||
pub const ZERO: &str = "zero";
|
||||
|
||||
// check-specific
|
||||
pub const STRICT: &str = "strict";
|
||||
pub const STATUS: &str = "status";
|
||||
pub const WARN: &str = "warn";
|
||||
pub const IGNORE_MISSING: &str = "ignore-missing";
|
||||
pub const QUIET: &str = "quiet";
|
||||
}
|
||||
|
||||
pub trait ChecksumCommand {
|
||||
fn with_algo(self) -> Self;
|
||||
|
||||
fn with_length(self) -> Self;
|
||||
|
||||
fn with_check(self) -> Self;
|
||||
|
||||
fn with_binary(self) -> Self;
|
||||
|
||||
fn with_text(self, default: bool) -> Self;
|
||||
|
||||
fn with_tag(self, default: bool) -> Self;
|
||||
|
||||
fn with_untagged(self) -> Self;
|
||||
|
||||
fn with_raw(self) -> Self;
|
||||
|
||||
fn with_base64(self) -> Self;
|
||||
|
||||
fn with_zero(self) -> Self;
|
||||
|
||||
fn with_debug(self) -> Self;
|
||||
}
|
||||
|
||||
impl ChecksumCommand for Command {
|
||||
fn with_algo(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::ALGORITHM)
|
||||
.long(options::ALGORITHM)
|
||||
.short('a')
|
||||
.help(translate!("checksum-help-algorithm"))
|
||||
.value_name("ALGORITHM")
|
||||
.value_parser(SUPPORTED_ALGORITHMS),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_length(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::LENGTH)
|
||||
.long(options::LENGTH)
|
||||
.short('l')
|
||||
.help(translate!("checksum-help-length"))
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_check(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::CHECK)
|
||||
.short('c')
|
||||
.long(options::CHECK)
|
||||
.help(translate!("checksum-help-check"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::WARN)
|
||||
.short('w')
|
||||
.long("warn")
|
||||
.help(translate!("checksum-help-warn"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::STATUS, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STATUS)
|
||||
.long("status")
|
||||
.help(translate!("checksum-help-status"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::WARN, options::QUIET]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
.long(options::QUIET)
|
||||
.help(translate!("checksum-help-quiet"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with_all([options::WARN, options::STATUS]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_MISSING)
|
||||
.long(options::IGNORE_MISSING)
|
||||
.help(translate!("checksum-help-ignore-missing"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STRICT)
|
||||
.long(options::STRICT)
|
||||
.help(translate!("checksum-help-strict"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_binary(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::BINARY)
|
||||
.long(options::BINARY)
|
||||
.short('b')
|
||||
.hide(true)
|
||||
.overrides_with(options::TEXT)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_text(self, default: bool) -> Self {
|
||||
let mut arg = Arg::new(options::TEXT)
|
||||
.long(options::TEXT)
|
||||
.short('t')
|
||||
.action(ArgAction::SetTrue);
|
||||
if default {
|
||||
arg = arg.help(translate!("checksum-help-text"));
|
||||
} else {
|
||||
arg = arg.hide(true);
|
||||
}
|
||||
self.arg(arg)
|
||||
}
|
||||
|
||||
fn with_tag(self, default: bool) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::TAG)
|
||||
.long(options::TAG)
|
||||
.help(if default {
|
||||
translate!("checksum-help-tag-default")
|
||||
} else {
|
||||
translate!("checksum-help-tag")
|
||||
})
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_untagged(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::UNTAGGED)
|
||||
.long(options::UNTAGGED)
|
||||
.help(translate!("checksum-help-untagged"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::TAG),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_raw(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::RAW)
|
||||
.long(options::RAW)
|
||||
.help(translate!("checksum-help-raw"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_base64(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::BASE64)
|
||||
.long(options::BASE64)
|
||||
.help(translate!("checksum-help-base64"))
|
||||
.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),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_zero(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::ZERO)
|
||||
.long(options::ZERO)
|
||||
.short('z')
|
||||
.help(translate!("checksum-help-zero"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn with_debug(self) -> Self {
|
||||
self.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.long(options::DEBUG)
|
||||
.help(translate!("checksum-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_checksum_app(about: String, usage: String) -> Command {
|
||||
Command::new(util_name())
|
||||
.version(crate_version!())
|
||||
.help_template(localized_help_template(util_name()))
|
||||
.about(about)
|
||||
.override_usage(format_usage(&usage))
|
||||
.infer_long_args(true)
|
||||
.args_override_self(true)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_hint(ValueHint::FilePath),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn standalone_checksum_app(about: String, usage: String) -> Command {
|
||||
default_checksum_app(about, usage)
|
||||
.with_binary()
|
||||
.with_check()
|
||||
.with_tag(false)
|
||||
.with_text(true)
|
||||
.with_zero()
|
||||
}
|
||||
|
||||
pub fn standalone_checksum_app_with_length(about: String, usage: String) -> Command {
|
||||
default_checksum_app(about, usage)
|
||||
.with_binary()
|
||||
.with_check()
|
||||
.with_length()
|
||||
.with_tag(false)
|
||||
.with_text(true)
|
||||
.with_zero()
|
||||
}
|
||||
|
||||
pub fn checksum_main(
|
||||
algo: Option<AlgoKind>,
|
||||
length: Option<usize>,
|
||||
matches: ArgMatches,
|
||||
output_format: OutputFormat,
|
||||
) -> UResult<()> {
|
||||
let check = matches.get_flag(options::CHECK);
|
||||
|
||||
let check_flag = |flag| match (check, matches.get_flag(flag)) {
|
||||
(_, false) => Ok(false),
|
||||
(true, true) => Ok(true),
|
||||
(false, true) => Err(ChecksumError::CheckOnlyFlag(flag.into())),
|
||||
};
|
||||
|
||||
// Each of the following flags are only expected in --check mode.
|
||||
// If we encounter them otherwise, end with an error.
|
||||
let ignore_missing = check_flag(options::IGNORE_MISSING)?;
|
||||
let warn = check_flag(options::WARN)?;
|
||||
let quiet = check_flag(options::QUIET)?;
|
||||
let strict = check_flag(options::STRICT)?;
|
||||
let status = check_flag(options::STATUS)?;
|
||||
|
||||
let files = matches.get_many::<OsString>(options::FILE).map_or_else(
|
||||
// No files given, read from stdin.
|
||||
|| Box::new(std::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>>,
|
||||
);
|
||||
|
||||
if check {
|
||||
// cksum does not support '--check'ing legacy algorithms
|
||||
if algo.is_some_and(AlgoKind::is_legacy) {
|
||||
return Err(ChecksumError::AlgorithmNotSupportedWithCheck.into());
|
||||
}
|
||||
|
||||
let text_flag = matches.get_flag(options::TEXT);
|
||||
let binary_flag = matches.get_flag(options::BINARY);
|
||||
let tag = matches.get_flag(options::TAG);
|
||||
|
||||
if tag || binary_flag || text_flag {
|
||||
return Err(ChecksumError::BinaryTextConflict.into());
|
||||
}
|
||||
|
||||
// Execute the checksum validation based on the presence of files or the use of stdin
|
||||
|
||||
let verbose = ChecksumVerbose::new(status, quiet, warn);
|
||||
let opts = ChecksumValidateOptions {
|
||||
ignore_missing,
|
||||
strict,
|
||||
verbose,
|
||||
};
|
||||
|
||||
return super::validate::perform_checksum_validation(files, algo, length, opts);
|
||||
}
|
||||
|
||||
// Not --check
|
||||
|
||||
// Set the default algorithm to CRC when not '--check'ing.
|
||||
let algo_kind = algo.unwrap_or(AlgoKind::Crc);
|
||||
|
||||
let algo = SizedAlgoKind::from_unsized(algo_kind, length)?;
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO));
|
||||
|
||||
let opts = ChecksumComputeOptions {
|
||||
algo_kind: algo,
|
||||
output_format,
|
||||
line_ending,
|
||||
};
|
||||
|
||||
perform_checksum_computation(opts, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
// spell-checker:ignore bitlen
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
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::checksum::{AlgoKind, ChecksumError, SizedAlgoKind, digest_reader, escape_filename};
|
||||
use crate::error::{FromIo, UResult, USimpleError};
|
||||
use crate::line_ending::LineEnding;
|
||||
use crate::sum::DigestOutput;
|
||||
|
|
@ -103,42 +103,76 @@ impl OutputFormat {
|
|||
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;
|
||||
}
|
||||
/// Find the correct output format for cksum.
|
||||
pub fn from_cksum(algo: AlgoKind, tag: bool, binary: bool, raw: bool, base64: bool) -> Self {
|
||||
// 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;
|
||||
}
|
||||
// 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
|
||||
let digest_format = if base64 {
|
||||
DigestFormat::Base64
|
||||
} else {
|
||||
ReadingMode::Text
|
||||
DigestFormat::Hexadecimal
|
||||
};
|
||||
OutputFormat::Untagged(digest_format, reading_mode)
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the correct output format for a standalone checksum util (b2sum,
|
||||
/// md5sum, etc)
|
||||
///
|
||||
/// Since standalone utils can't use the Raw or Legacy output format, it is
|
||||
/// decided only using the --tag, --binary and --text arguments.
|
||||
pub fn from_standalone<'a, I: Iterator<Item = OsString>>(args: I) -> UResult<Self> {
|
||||
let mut text = true;
|
||||
let mut tag = false;
|
||||
|
||||
for arg in args {
|
||||
if arg == "--" {
|
||||
break;
|
||||
} else if arg == "--tag" {
|
||||
tag = true;
|
||||
text = false;
|
||||
} else if arg == "--binary" || arg == "-b" {
|
||||
text = false;
|
||||
} else if arg == "--text" || arg == "-t" {
|
||||
// Finding a `--text` after `--tag` is an error.
|
||||
if tag {
|
||||
return Err(ChecksumError::TextAfterTag.into());
|
||||
}
|
||||
text = true;
|
||||
}
|
||||
}
|
||||
|
||||
if tag {
|
||||
Ok(OutputFormat::Tagged(DigestFormat::Hexadecimal))
|
||||
} else {
|
||||
Ok(OutputFormat::Untagged(
|
||||
DigestFormat::Hexadecimal,
|
||||
if text {
|
||||
ReadingMode::Text
|
||||
} else {
|
||||
ReadingMode::Binary
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use crate::sum::{
|
|||
Sha3_256, Sha3_384, Sha3_512, Sha224, Sha256, Sha384, Sha512, Shake128, Shake256, Sm3, SysV,
|
||||
};
|
||||
|
||||
pub mod cli;
|
||||
pub mod compute;
|
||||
pub mod validate;
|
||||
|
||||
|
|
@ -397,6 +398,8 @@ pub enum ChecksumError {
|
|||
BinaryTextConflict,
|
||||
#[error("--text mode is only supported with --untagged")]
|
||||
TextWithoutUntagged,
|
||||
#[error("--tag does not support --text mode")]
|
||||
TextAfterTag,
|
||||
#[error("--check is not supported with --algorithm={{bsd,sysv,crc,crc32b}}")]
|
||||
AlgorithmNotSupportedWithCheck,
|
||||
#[error("You cannot combine multiple hash algorithms!")]
|
||||
|
|
|
|||
|
|
@ -170,9 +170,7 @@ pub fn get_canonical_util_name(util_name: &str) -> &str {
|
|||
"[" => "test",
|
||||
|
||||
// hashsum aliases - all these hash commands are aliases for hashsum
|
||||
"md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" | "b2sum" => {
|
||||
"hashsum"
|
||||
}
|
||||
"md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" => "hashsum",
|
||||
|
||||
"dir" => "ls", // dir is an alias for ls
|
||||
|
||||
|
|
|
|||
289
tests/by-util/test_b2sum.rs
Normal file
289
tests/by-util/test_b2sum.rs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
// 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.
|
||||
|
||||
use rstest::rstest;
|
||||
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::{new_ucmd, util_name};
|
||||
// spell-checker:ignore checkfile, nonames, testf, ntestf
|
||||
macro_rules! get_hash(
|
||||
($str:expr) => (
|
||||
$str.split(' ').collect::<Vec<&str>>()[0]
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! test_digest_with_len {
|
||||
($id:ident, $t:ident, $size:expr) => {
|
||||
mod $id {
|
||||
use uutests::util::*;
|
||||
use uutests::util_name;
|
||||
static LENGTH_ARG: &'static str = concat!("--length=", stringify!($size));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
|
||||
static CHECK_FILE: &'static str = concat!(stringify!($id), ".checkfile");
|
||||
static INPUT_FILE: &'static str = "input.txt";
|
||||
|
||||
#[test]
|
||||
fn test_single_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(LENGTH_ARG)
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdin() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(LENGTH_ARG)
|
||||
.pipe_in_fixture(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
println!("File content='{}'", ts.fixtures.read(INPUT_FILE));
|
||||
println!("Check file='{}'", ts.fixtures.read(CHECK_FILE));
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[LENGTH_ARG, "--check", CHECK_FILE])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("input.txt: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(LENGTH_ARG)
|
||||
.arg("--zero")
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("a", "file1\n");
|
||||
at.write("c", "file3\n");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[LENGTH_ARG, "a", "b", "c"])
|
||||
.fails()
|
||||
.stdout_contains("a\n")
|
||||
.stdout_contains("c\n")
|
||||
.stderr_contains("b: No such file or directory");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_digest_with_len! {b2sum, b2sum, 512}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_length_option_0() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("testf", "foobar\n");
|
||||
at.write("testf.b2sum", "9e2bf63e933e610efee4a8d6cd4a9387e80860edee97e27db3b37a828d226ab1eb92a9cdd8ca9ca67a753edaf8bd89a0558496f67a30af6f766943839acf0110 testf\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=0")
|
||||
.arg("-c")
|
||||
.arg(at.subdir.join("testf.b2sum"))
|
||||
.succeeds()
|
||||
.stdout_only("testf: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_length_duplicate() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("testf", "foobar\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=123")
|
||||
.arg("--length=128")
|
||||
.arg("testf")
|
||||
.succeeds()
|
||||
.stdout_contains("d6d45901dec53e65d2b55fb6e2ab67b0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_length_option_8() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("testf", "foobar\n");
|
||||
at.write("testf.b2sum", "6a testf\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=8")
|
||||
.arg("-c")
|
||||
.arg(at.subdir.join("testf.b2sum"))
|
||||
.succeeds()
|
||||
.stdout_only("testf: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_b2sum_length_option_not_multiple_of_8() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("testf", "foobar\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=9")
|
||||
.arg(at.subdir.join("testf"))
|
||||
.fails_with_code(1)
|
||||
.stderr_contains("b2sum: invalid length: '9'")
|
||||
.stderr_contains("b2sum: length is not a multiple of 8");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("513")]
|
||||
#[case("1024")]
|
||||
#[case("18446744073709552000")]
|
||||
fn test_invalid_b2sum_length_option_too_large(#[case] len: &str) {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("testf", "foobar\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length")
|
||||
.arg(len)
|
||||
.arg(at.subdir.join("testf"))
|
||||
.fails_with_code(1)
|
||||
.no_stdout()
|
||||
.stderr_contains(format!("b2sum: invalid length: '{len}'"))
|
||||
.stderr_contains("b2sum: maximum digest length for 'BLAKE2b' is 512 bits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_tag_output() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.touch("f");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=0")
|
||||
.arg("--tag")
|
||||
.arg("f")
|
||||
.succeeds()
|
||||
.stdout_only("BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--length=128")
|
||||
.arg("--tag")
|
||||
.arg("f")
|
||||
.succeeds()
|
||||
.stdout_only("BLAKE2b-128 (f) = cae66941d9efbd404e4d88758ea67670\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_verify() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("a", "a\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--tag")
|
||||
.arg("a")
|
||||
.succeeds()
|
||||
.stdout_only("BLAKE2b (a) = bedfbb90d858c2d67b7ee8f7523be3d3b54004ef9e4f02f2ad79a1d05bfdfe49b81e3c92ebf99b504102b6bf003fa342587f5b3124c205f55204e8c4b4ce7d7c\n");
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--tag")
|
||||
.arg("-l")
|
||||
.arg("128")
|
||||
.arg("a")
|
||||
.succeeds()
|
||||
.stdout_only("BLAKE2b-128 (a) = b93e0fc7bb21633c08bba07c5e71dc00\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_b2sum_strict_check() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("f");
|
||||
|
||||
let checksums = [
|
||||
"2e f\n",
|
||||
"e4a6a0577479b2b4 f\n",
|
||||
"cae66941d9efbd404e4d88758ea67670 f\n",
|
||||
"246c0442cd564aced8145b8b60f1370aa7 f\n",
|
||||
"0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8 f\n",
|
||||
"4ded8c5fc8b12f3273f877ca585a44ad6503249a2b345d6d9c0e67d85bcb700db4178c0303e93b8f4ad758b8e2c9fd8b3d0c28e585f1928334bb77d36782e8 f\n",
|
||||
"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce f\n",
|
||||
];
|
||||
|
||||
at.write("ck", &checksums.join(""));
|
||||
|
||||
let output = "f: OK\n".to_string().repeat(checksums.len());
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("-c")
|
||||
.arg(at.subdir.join("ck"))
|
||||
.succeeds()
|
||||
.stdout_only(&output);
|
||||
|
||||
scene
|
||||
.ccmd("b2sum")
|
||||
.arg("--strict")
|
||||
.arg("-c")
|
||||
.arg(at.subdir.join("ck"))
|
||||
.succeeds()
|
||||
.stdout_only(&output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help_shows_correct_utility_name() {
|
||||
// Test b2sum
|
||||
new_ucmd!()
|
||||
.arg("--help")
|
||||
.succeeds()
|
||||
.stdout_contains("Usage: b2sum")
|
||||
.stdout_does_not_contain("Usage: hashsum");
|
||||
}
|
||||
|
|
@ -16,87 +16,206 @@ macro_rules! get_hash(
|
|||
);
|
||||
|
||||
macro_rules! test_digest {
|
||||
($($id:ident $t:ident $size:expr)*) => ($(
|
||||
($id:ident, $t:ident) => {
|
||||
mod $id {
|
||||
use uutests::util::*;
|
||||
use uutests::util_name;
|
||||
static DIGEST_ARG: &'static str = concat!("--", stringify!($t));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
|
||||
static CHECK_FILE: &'static str = concat!(stringify!($id), ".checkfile");
|
||||
static INPUT_FILE: &'static str = "input.txt";
|
||||
|
||||
mod $id {
|
||||
use uutests::util::*;
|
||||
use uutests::util_name;
|
||||
static DIGEST_ARG: &'static str = concat!("--", stringify!($t));
|
||||
static BITS_ARG: &'static str = concat!("--bits=", stringify!($size));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
|
||||
static CHECK_FILE: &'static str = concat!(stringify!($id), ".checkfile");
|
||||
static INPUT_FILE: &'static str = "input.txt";
|
||||
#[test]
|
||||
fn test_single_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg(INPUT_FILE).succeeds().no_stderr().stdout_str()));
|
||||
#[test]
|
||||
fn test_stdin() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.pipe_in_fixture(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
println!("File content='{}'", ts.fixtures.read(INPUT_FILE));
|
||||
println!("Check file='{}'", ts.fixtures.read(CHECK_FILE));
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, "--check", CHECK_FILE])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("input.txt: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.arg("--zero")
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("a", "file1\n");
|
||||
at.write("c", "file3\n");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, "a", "b", "c"])
|
||||
.fails()
|
||||
.stdout_contains("a\n")
|
||||
.stdout_contains("c\n")
|
||||
.stderr_contains("b: No such file or directory");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdin() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).pipe_in_fixture(INPUT_FILE).succeeds().no_stderr().stdout_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
println!("File content='{}'", ts.fixtures.read(INPUT_FILE));
|
||||
println!("Check file='{}'", ts.fixtures.read(CHECK_FILE));
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, BITS_ARG, "--check", CHECK_FILE])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("input.txt: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("--zero").arg(INPUT_FILE).succeeds().no_stderr().stdout_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("a", "file1\n");
|
||||
at.write("c", "file3\n");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, BITS_ARG, "a", "b", "c"])
|
||||
.fails()
|
||||
.stdout_contains("a\n")
|
||||
.stdout_contains("c\n")
|
||||
.stderr_contains("b: No such file or directory");
|
||||
}
|
||||
}
|
||||
)*)
|
||||
};
|
||||
}
|
||||
|
||||
test_digest! {
|
||||
md5 md5 128
|
||||
sha1 sha1 160
|
||||
sha224 sha224 224
|
||||
sha256 sha256 256
|
||||
sha384 sha384 384
|
||||
sha512 sha512 512
|
||||
sha3_224 sha3 224
|
||||
sha3_256 sha3 256
|
||||
sha3_384 sha3 384
|
||||
sha3_512 sha3 512
|
||||
shake128_256 shake128 256
|
||||
shake256_512 shake256 512
|
||||
b2sum b2sum 512
|
||||
b3sum b3sum 256
|
||||
macro_rules! test_digest_with_len {
|
||||
($id:ident, $t:ident, $size:expr) => {
|
||||
mod $id {
|
||||
use uutests::util::*;
|
||||
use uutests::util_name;
|
||||
static DIGEST_ARG: &'static str = concat!("--", stringify!($t));
|
||||
static LENGTH_ARG: &'static str = concat!("--length=", stringify!($size));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
|
||||
static CHECK_FILE: &'static str = concat!(stringify!($id), ".checkfile");
|
||||
static INPUT_FILE: &'static str = "input.txt";
|
||||
|
||||
#[test]
|
||||
fn test_single_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.arg(LENGTH_ARG)
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdin() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.arg(LENGTH_ARG)
|
||||
.pipe_in_fixture(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
println!("File content='{}'", ts.fixtures.read(INPUT_FILE));
|
||||
println!("Check file='{}'", ts.fixtures.read(CHECK_FILE));
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, LENGTH_ARG, "--check", CHECK_FILE])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("input.txt: OK\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
assert_eq!(
|
||||
ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg(DIGEST_ARG)
|
||||
.arg(LENGTH_ARG)
|
||||
.arg("--zero")
|
||||
.arg(INPUT_FILE)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("a", "file1\n");
|
||||
at.write("c", "file3\n");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&[DIGEST_ARG, LENGTH_ARG, "a", "b", "c"])
|
||||
.fails()
|
||||
.stdout_contains("a\n")
|
||||
.stdout_contains("c\n")
|
||||
.stderr_contains("b: No such file or directory");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_digest! {md5, md5}
|
||||
test_digest! {sha1, sha1}
|
||||
test_digest! {b3sum, b3sum}
|
||||
test_digest! {shake128, shake128}
|
||||
test_digest! {shake256, shake256}
|
||||
|
||||
test_digest_with_len! {sha224, sha224, 224}
|
||||
test_digest_with_len! {sha256, sha256, 256}
|
||||
test_digest_with_len! {sha384, sha384, 384}
|
||||
test_digest_with_len! {sha512, sha512, 512}
|
||||
test_digest_with_len! {sha3_224, sha3, 224}
|
||||
test_digest_with_len! {sha3_256, sha3, 256}
|
||||
test_digest_with_len! {sha3_384, sha3, 384}
|
||||
test_digest_with_len! {sha3_512, sha3, 512}
|
||||
|
||||
#[test]
|
||||
fn test_check_sha1() {
|
||||
// To make sure that #3815 doesn't happen again
|
||||
|
|
@ -1037,7 +1156,6 @@ fn test_sha256_binary() {
|
|||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg("--sha256")
|
||||
.arg("--bits=256")
|
||||
.arg("binary.png")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
|
|
@ -1054,7 +1172,6 @@ fn test_sha256_stdin_binary() {
|
|||
get_hash!(
|
||||
ts.ucmd()
|
||||
.arg("--sha256")
|
||||
.arg("--bits=256")
|
||||
.pipe_in_fixture("binary.png")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
|
|
@ -1068,12 +1185,7 @@ fn test_sha256_stdin_binary() {
|
|||
#[cfg_attr(windows, ignore = "Discussion is in #9168")]
|
||||
fn test_check_sha256_binary() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"--sha256",
|
||||
"--bits=256",
|
||||
"--check",
|
||||
"binary.sha256.checkfile",
|
||||
])
|
||||
.args(&["--sha256", "--check", "binary.sha256.checkfile"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("binary.png: OK\n");
|
||||
|
|
|
|||
1
tests/fixtures/b2sum/b2sum.checkfile
vendored
Normal file
1
tests/fixtures/b2sum/b2sum.checkfile
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
7355dd5276c21cfe0c593b5063b96af3f96a454b33216f58314f44c3ade92e9cd6cec4210a0836246780e9baf927cc50b9a3d7073e8f9bd12780fddbcb930c6d input.txt
|
||||
1
tests/fixtures/b2sum/b2sum.expected
vendored
Normal file
1
tests/fixtures/b2sum/b2sum.expected
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
7355dd5276c21cfe0c593b5063b96af3f96a454b33216f58314f44c3ade92e9cd6cec4210a0836246780e9baf927cc50b9a3d7073e8f9bd12780fddbcb930c6d
|
||||
BIN
tests/fixtures/b2sum/binary.png
vendored
Normal file
BIN
tests/fixtures/b2sum/binary.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
1
tests/fixtures/b2sum/input.txt
vendored
Normal file
1
tests/fixtures/b2sum/input.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
hello, world
|
||||
|
|
@ -64,6 +64,10 @@ mod test_chroot;
|
|||
#[path = "by-util/test_cksum.rs"]
|
||||
mod test_cksum;
|
||||
|
||||
#[cfg(feature = "b2sum")]
|
||||
#[path = "by-util/test_b2sum.rs"]
|
||||
mod test_b2sum;
|
||||
|
||||
#[cfg(feature = "comm")]
|
||||
#[path = "by-util/test_comm.rs"]
|
||||
mod test_comm;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue