summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/CICD.yml4
-rw-r--r--.github/workflows/android.yml4
-rw-r--r--.vscode/cspell.dictionaries/workspace.wordlist.txt1
-rw-r--r--Cargo.lock26
-rw-r--r--Cargo.toml11
-rw-r--r--deny.toml1
-rw-r--r--docs/src/extensions.md6
-rw-r--r--fuzz/Cargo.toml2
-rw-r--r--src/uu/cksum/Cargo.toml3
-rw-r--r--src/uu/cksum/src/cksum.rs376
-rw-r--r--src/uu/cp/src/copydir.rs56
-rw-r--r--src/uu/cp/src/cp.rs14
-rw-r--r--src/uu/env/src/env.rs112
-rw-r--r--src/uu/hashsum/Cargo.toml2
-rw-r--r--src/uu/hashsum/src/hashsum.rs59
-rw-r--r--src/uu/ls/src/ls.rs18
-rw-r--r--src/uu/pinky/src/platform/unix.rs2
-rw-r--r--src/uu/sort/src/sort.rs1
-rw-r--r--src/uu/tr/src/operation.rs119
-rw-r--r--src/uu/tr/src/tr.rs1
-rw-r--r--src/uucore/Cargo.toml1
-rw-r--r--src/uucore/src/lib/features.rs2
-rw-r--r--src/uucore/src/lib/features/checksum.rs27
-rw-r--r--src/uucore/src/lib/features/utmpx.rs3
-rw-r--r--src/uucore/src/lib/lib.rs2
-rw-r--r--src/uucore/src/lib/parser/parse_size.rs3
-rw-r--r--tests/by-util/test_chmod.rs74
-rw-r--r--tests/by-util/test_cksum.rs513
-rw-r--r--tests/by-util/test_cp.rs213
-rw-r--r--tests/by-util/test_du.rs1
-rw-r--r--tests/by-util/test_env.rs140
-rw-r--r--tests/by-util/test_expr.rs4
-rw-r--r--tests/by-util/test_hashsum.rs30
-rw-r--r--tests/by-util/test_head.rs2
-rw-r--r--tests/by-util/test_ls.rs90
-rw-r--r--tests/by-util/test_mkdir.rs72
-rw-r--r--tests/by-util/test_od.rs1
-rw-r--r--tests/by-util/test_shuf.rs16
-rw-r--r--tests/by-util/test_sort.rs1
-rw-r--r--tests/by-util/test_split.rs1
-rw-r--r--tests/by-util/test_stdbuf.rs1
-rw-r--r--tests/by-util/test_tail.rs47
-rw-r--r--tests/by-util/test_tr.rs5
-rw-r--r--tests/by-util/test_truncate.rs1
-rw-r--r--tests/by-util/test_unexpand.rs2
-rw-r--r--tests/by-util/test_wc.rs2
-rw-r--r--tests/common/util.rs63
-rw-r--r--tests/fixtures/cksum/supported_length.expected2
-rw-r--r--tests/fixtures/cksum/unsupported_length.expected2
-rw-r--r--tests/test_util_name.rs23
50 files changed, 1757 insertions, 405 deletions
diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml
index 75b867b71..a32bf74ee 100644
--- a/.github/workflows/CICD.yml
+++ b/.github/workflows/CICD.yml
@@ -477,8 +477,8 @@ jobs:
- { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-redox , features: feat_os_unix_redox , use-cross: redoxer , skip-tests: true }
- - { os: macos-14 , target: aarch64-apple-darwin , features: feat_os_macos } # M1 CPU
- - { os: macos-latest , target: x86_64-apple-darwin , features: feat_os_macos }
+ - { os: macos-latest , target: aarch64-apple-darwin , features: feat_os_macos } # M1 CPU
+ - { os: macos-13 , target: x86_64-apple-darwin , features: feat_os_macos }
- { os: windows-latest , target: i686-pc-windows-msvc , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index 528c2ad49..d4aff652a 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -112,7 +112,7 @@ jobs:
~/.android/avd/*/*.lock
- name: Create and cache emulator image
if: steps.avd-cache.outputs.cache-hit != 'true'
- uses: reactivecircus/android-emulator-runner@v2.30.1
+ uses: reactivecircus/android-emulator-runner@v2.31.0
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
@@ -157,7 +157,7 @@ jobs:
free -mh
df -Th
- name: Build and Test
- uses: reactivecircus/android-emulator-runner@v2.30.1
+ uses: reactivecircus/android-emulator-runner@v2.31.0
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt
index c3c854a4c..ce4822f1e 100644
--- a/.vscode/cspell.dictionaries/workspace.wordlist.txt
+++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt
@@ -166,6 +166,7 @@ RTLD_NEXT
RTLD
SIGINT
SIGKILL
+SIGSTOP
SIGTERM
SYS_fdatasync
SYS_syncfs
diff --git a/Cargo.lock b/Cargo.lock
index 0d229aed4..1dfc796d6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1303,9 +1303,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.154"
+version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libloading"
@@ -1619,11 +1619,12 @@ dependencies = [
[[package]]
name = "parse_datetime"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bbf4e25b13841080e018a1e666358adfe5e39b6d353f986ca5091c210b586a1"
+checksum = "a8720474e3dd4af20cea8716703498b9f3b690f318fa9d9d9e2e38eaf44b96d0"
dependencies = [
"chrono",
+ "nom",
"regex",
]
@@ -1733,9 +1734,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.82"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
dependencies = [
"unicode-ident",
]
@@ -2277,18 +2278,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.60"
+version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.60"
+version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
@@ -2494,6 +2495,7 @@ version = "0.0.26"
dependencies = [
"clap",
"hex",
+ "regex",
"uucore",
]
@@ -3847,9 +3849,9 @@ dependencies = [
[[package]]
name = "zip"
-version = "1.2.3"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700ea425e148de30c29c580c1f9508b93ca57ad31c9f4e96b83c194c37a7a8f"
+checksum = "f1f4a27345eb6f7aa7bd015ba7eb4175fa4e1b462a29874b779e0bbcf96c6ac7"
dependencies = [
"arbitrary",
"crc32fast",
diff --git a/Cargo.toml b/Cargo.toml
index 229d6b9f5..af58f45a2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -289,7 +289,7 @@ half = "2.4.1"
hostname = "0.4"
indicatif = "0.17.8"
itertools = "0.12.1"
-libc = "0.2.154"
+libc = "0.2.153"
lscolors = { version = "0.16.0", default-features = false, features = [
"gnu_legacy",
] }
@@ -304,7 +304,7 @@ num-traits = "0.2.19"
number_prefix = "0.4"
once_cell = "1.19.0"
onig = { version = "~6.4", default-features = false }
-parse_datetime = "0.5.0"
+parse_datetime = "0.6.0"
phf = "0.11.2"
phf_codegen = "0.11.2"
platform-info = "2.0.3"
@@ -490,7 +490,12 @@ sha1 = { version = "0.10.6", features = ["std"] }
tempfile = { workspace = true }
time = { workspace = true, features = ["local-offset"] }
unindent = "0.2.3"
-uucore = { workspace = true, features = ["entries", "process", "signals"] }
+uucore = { workspace = true, features = [
+ "entries",
+ "mode",
+ "process",
+ "signals",
+] }
walkdir = { workspace = true }
hex-literal = "0.4.1"
rstest = { workspace = true }
diff --git a/deny.toml b/deny.toml
index 22e1b689e..252f8b813 100644
--- a/deny.toml
+++ b/deny.toml
@@ -24,6 +24,7 @@ allow = [
"BSD-2-Clause",
"BSD-2-Clause-FreeBSD",
"BSD-3-Clause",
+ "BSL-1.0",
"CC0-1.0",
"Unicode-DFS-2016",
]
diff --git a/docs/src/extensions.md b/docs/src/extensions.md
index 61c25ba48..fb91f7d54 100644
--- a/docs/src/extensions.md
+++ b/docs/src/extensions.md
@@ -85,7 +85,11 @@ also provides a `-v`/`--verbose` flag.
## `id`
-`id` has three additional flags:
+`id` has three additional flags:
* `-P` displays the id as a password file entry
* `-p` makes the output human-readable
* `-A` displays the process audit user ID
+
+## `uptime`
+
+Similar to the proc-ps implementation and unlike GNU/Coreutils, `uptime` provides `-s`/`--since` to show since when the system is up.
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index f2848c071..45f3f22ec 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -9,7 +9,7 @@ cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4.7"
-libc = "0.2.154"
+libc = "0.2.153"
tempfile = "3.10.1"
rand = { version = "0.8.5", features = ["small_rng"] }
similar = "2.5.0"
diff --git a/src/uu/cksum/Cargo.toml b/src/uu/cksum/Cargo.toml
index f6a5a138a..208c01901 100644
--- a/src/uu/cksum/Cargo.toml
+++ b/src/uu/cksum/Cargo.toml
@@ -16,8 +16,9 @@ path = "src/cksum.rs"
[dependencies]
clap = { workspace = true }
-uucore = { workspace = true, features = ["encoding", "sum"] }
+uucore = { workspace = true, features = ["checksum", "encoding", "sum"] }
hex = { workspace = true }
+regex = { workspace = true }
[[bin]]
name = "cksum"
diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs
index a50abada5..9268a40bb 100644
--- a/src/uu/cksum/src/cksum.rs
+++ b/src/uu/cksum/src/cksum.rs
@@ -5,15 +5,18 @@
// spell-checker:ignore (ToDO) fname, algo
use clap::{crate_version, value_parser, Arg, ArgAction, Command};
-use hex::decode;
-use hex::encode;
+use regex::Regex;
use std::error::Error;
use std::ffi::OsStr;
use std::fmt::Display;
use std::fs::File;
+use std::io::BufRead;
use std::io::{self, stdin, stdout, BufReader, Read, Write};
use std::iter;
use std::path::Path;
+use uucore::checksum::cksum_output;
+use uucore::display::Quotable;
+use uucore::error::set_exit_code;
use uucore::{
encoding,
error::{FromIo, UError, UResult, USimpleError},
@@ -40,6 +43,20 @@ const ALGORITHM_OPTIONS_SHA512: &str = "sha512";
const ALGORITHM_OPTIONS_BLAKE2B: &str = "blake2b";
const ALGORITHM_OPTIONS_SM3: &str = "sm3";
+const SUPPORTED_ALGO: [&str; 11] = [
+ ALGORITHM_OPTIONS_SYSV,
+ ALGORITHM_OPTIONS_BSD,
+ ALGORITHM_OPTIONS_CRC,
+ ALGORITHM_OPTIONS_MD5,
+ ALGORITHM_OPTIONS_SHA1,
+ ALGORITHM_OPTIONS_SHA224,
+ ALGORITHM_OPTIONS_SHA256,
+ ALGORITHM_OPTIONS_SHA384,
+ ALGORITHM_OPTIONS_SHA512,
+ ALGORITHM_OPTIONS_BLAKE2B,
+ ALGORITHM_OPTIONS_SM3,
+];
+
#[derive(Debug)]
enum CkSumError {
RawMultipleFiles,
@@ -73,10 +90,10 @@ impl Display for CkSumError {
}
fn detect_algo(
- program: &str,
+ algo: &str,
length: Option<usize>,
) -> (&'static str, Box<dyn Digest + 'static>, usize) {
- match program {
+ match algo {
ALGORITHM_OPTIONS_SYSV => (
ALGORITHM_OPTIONS_SYSV,
Box::new(SYSV::new()) as Box<dyn Digest>,
@@ -205,7 +222,7 @@ where
ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => {
sum_hex.parse::<u16>().unwrap().to_be_bytes().to_vec()
}
- _ => decode(sum_hex).unwrap(),
+ _ => hex::decode(sum_hex).unwrap(),
};
// Cannot handle multiple files anyway, output immediately.
stdout().write_all(&bytes)?;
@@ -214,7 +231,8 @@ where
OutputFormat::Hexadecimal => sum_hex,
OutputFormat::Base64 => match options.algo_name {
ALGORITHM_OPTIONS_CRC | ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => sum_hex,
- _ => encoding::encode(encoding::Format::Base64, &decode(sum_hex).unwrap()).unwrap(),
+ _ => encoding::encode(encoding::Format::Base64, &hex::decode(sum_hex).unwrap())
+ .unwrap(),
},
};
// The BSD checksum output is 5 digit integer
@@ -299,7 +317,7 @@ fn digest_read<T: Read>(
// Assume it's SHAKE. result_str() doesn't work with shake (as of 8/30/2016)
let mut bytes = vec![0; (output_bits + 7) / 8];
digest.hash_finalize(&mut bytes);
- Ok((encode(bytes), output_size))
+ Ok((hex::encode(bytes), output_size))
}
}
@@ -312,6 +330,7 @@ mod options {
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";
}
@@ -353,17 +372,45 @@ fn had_reset(args: &[String]) -> bool {
}
}
+/// Calculates the length of the digest for the given algorithm.
+fn calculate_blake2b_length(length: usize) -> UResult<Option<usize>> {
+ match length {
+ 0 => Ok(None),
+ n if n % 8 != 0 => {
+ uucore::show_error!("invalid length: \u{2018}{length}\u{2019}");
+ Err(io::Error::new(io::ErrorKind::InvalidInput, "length is not a multiple of 8").into())
+ }
+ n if n > 512 => {
+ uucore::show_error!("invalid length: \u{2018}{length}\u{2019}");
+ Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "maximum digest length for \u{2018}BLAKE2b\u{2019} is 512 bits",
+ )
+ .into())
+ }
+ n => {
+ // Divide by 8, as our blake2b implementation expects bytes instead of bits.
+ if n == 512 {
+ // When length is 512, it is blake2b's default.
+ // So, don't show it
+ Ok(None)
+ } else {
+ Ok(Some(n / 8))
+ }
+ }
+ }
+}
+
/***
* cksum has a bunch of legacy behavior.
* We handle this in this function to make sure they are self contained
* and "easier" to understand
*/
-fn handle_tag_text_binary_flags(matches: &clap::ArgMatches, check: bool) -> UResult<(bool, bool)> {
+fn handle_tag_text_binary_flags(matches: &clap::ArgMatches) -> UResult<(bool, bool)> {
let untagged: bool = matches.get_flag(options::UNTAGGED);
let tag: bool = matches.get_flag(options::TAG);
let tag: bool = tag || !untagged;
- let text_flag: bool = matches.get_flag(options::TEXT);
let binary_flag: bool = matches.get_flag(options::BINARY);
let args: Vec<String> = std::env::args().collect();
@@ -371,78 +418,262 @@ fn handle_tag_text_binary_flags(matches: &clap::ArgMatches, check: bool) -> URes
let asterisk: bool = prompt_asterisk(tag, binary_flag, had_reset);
- if (binary_flag || text_flag) && check {
- return Err(io::Error::new(
- io::ErrorKind::InvalidInput,
- "the --binary and --text options are meaningless when verifying checksums",
- )
- .into());
- }
Ok((tag, asterisk))
}
+/***
+ * Do the checksum validation (can be strict or not)
+*/
+fn perform_checksum_validation<'a, I>(
+ files: I,
+ strict: bool,
+ algo_name_input: Option<&str>,
+) -> UResult<()>
+where
+ I: Iterator<Item = &'a OsStr>,
+{
+ // Regexp to handle the two input formats:
+ // 1. <algo>[-<bits>] (<filename>) = <checksum>
+ // algo must be uppercase or b (for blake2b)
+ // 2. <checksum> [* ]<filename>
+ let regex_pattern = r"^\s*\\?(?P<algo>(?:[A-Z0-9]+|BLAKE2b))(?:-(?P<bits>\d+))?\s?\((?P<filename1>.*)\) = (?P<checksum1>[a-fA-F0-9]+)$|^(?P<checksum2>[a-fA-F0-9]+)\s[* ](?P<filename2>.*)";
+ let re = Regex::new(regex_pattern).unwrap();
+
+ // if cksum has several input files, it will print the result for each file
+ for filename_input in files {
+ let mut bad_format = 0;
+ let mut failed_cksum = 0;
+ let mut failed_open_file = 0;
+ let mut properly_formatted = false;
+ let input_is_stdin = filename_input == OsStr::new("-");
+
+ let file: Box<dyn Read> = if input_is_stdin {
+ Box::new(stdin()) // Use stdin if "-" is specified
+ } else {
+ match File::open(filename_input) {
+ Ok(f) => Box::new(f),
+ Err(_) => {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ format!(
+ "{}: No such file or directory",
+ filename_input.to_string_lossy()
+ ),
+ )
+ .into());
+ }
+ }
+ };
+ let reader = BufReader::new(file);
+
+ // for each line in the input, check if it is a valid checksum line
+ for line in reader.lines() {
+ let line = line.unwrap_or_else(|_| String::new());
+ if let Some(caps) = re.captures(&line) {
+ properly_formatted = true;
+
+ // Determine what kind of file input we had
+ // we need it for case "--check -a sm3 <file>" when <file> is
+ // <algo>[-<bits>] (<filename>) = <checksum>
+ let algo_based_format =
+ caps.name("filename1").is_some() && caps.name("checksum1").is_some();
+
+ let filename_to_check = caps
+ .name("filename1")
+ .or(caps.name("filename2"))
+ .unwrap()
+ .as_str();
+ let expected_checksum = caps
+ .name("checksum1")
+ .or(caps.name("checksum2"))
+ .unwrap()
+ .as_str();
+
+ // If the algo_name is provided, we use it, otherwise we try to detect it
+ let (algo_name, length) = if algo_based_format {
+ // When the algo-based format is matched, extract details from regex captures
+ let algorithm = caps.name("algo").map_or("", |m| m.as_str()).to_lowercase();
+ if !SUPPORTED_ALGO.contains(&algorithm.as_str()) {
+ // Not supported algo, leave early
+ properly_formatted = false;
+ continue;
+ }
+
+ let bits = caps.name("bits").map_or(Some(None), |m| {
+ let bits_value = m.as_str().parse::<usize>().unwrap();
+ if bits_value % 8 == 0 {
+ Some(Some(bits_value / 8))
+ } else {
+ properly_formatted = false;
+ None // Return None to signal a parsing or divisibility issue
+ }
+ });
+
+ if bits.is_none() {
+ // If bits is None, we have a parsing or divisibility issue
+ // Exit the loop outside of the closure
+ continue;
+ }
+
+ (algorithm, bits.unwrap())
+ } else if let Some(a) = algo_name_input {
+ // When a specific algorithm name is input, use it and default bits to None
+ (a.to_lowercase(), None)
+ } else {
+ // Default case if no algorithm is specified and non-algo based format is matched
+ (String::new(), None)
+ };
+
+ if algo_based_format && algo_name_input.map_or(false, |input| algo_name != input) {
+ bad_format += 1;
+ continue;
+ }
+
+ if algo_name.is_empty() {
+ // we haven't been able to detect the algo name. No point to continue
+ properly_formatted = false;
+ continue;
+ }
+ let (_, mut algo, bits) = detect_algo(&algo_name, length);
+
+ // manage the input file
+ let file_to_check: Box<dyn Read> = if filename_to_check == "-" {
+ Box::new(stdin()) // Use stdin if "-" is specified in the checksum file
+ } else {
+ match File::open(filename_to_check) {
+ Ok(f) => Box::new(f),
+ Err(err) => {
+ // yes, we have both stderr and stdout here
+ show!(err.map_err_context(|| filename_to_check.to_string()));
+ println!("{}: FAILED open or read", filename_to_check);
+ failed_open_file += 1;
+ // we could not open the file but we want to continue
+ continue;
+ }
+ }
+ };
+ let mut file_reader = BufReader::new(file_to_check);
+ // Read the file and calculate the checksum
+ let (calculated_checksum, _) =
+ digest_read(&mut algo, &mut file_reader, bits).unwrap();
+
+ // Do the checksum validation
+ if expected_checksum == calculated_checksum {
+ println!("{}: OK", filename_to_check);
+ } else {
+ println!("{}: FAILED", filename_to_check);
+ failed_cksum += 1;
+ }
+ } else {
+ if line.is_empty() {
+ continue;
+ }
+ bad_format += 1;
+ }
+ }
+
+ // not a single line correctly formatted found
+ // return an error
+ if !properly_formatted {
+ let filename = filename_input.to_string_lossy();
+ uucore::show_error!(
+ "{}: no properly formatted checksum lines found",
+ if input_is_stdin {
+ "standard input"
+ } else {
+ &filename
+ }
+ .maybe_quote()
+ );
+ set_exit_code(1);
+ }
+ // strict means that we should have an exit code.
+ if strict && bad_format > 0 {
+ set_exit_code(1);
+ }
+
+ // if we have any failed checksum verification, we set an exit code
+ if failed_cksum > 0 || failed_open_file > 0 {
+ set_exit_code(1);
+ }
+
+ // if any incorrectly formatted line, show it
+ cksum_output(bad_format, failed_cksum, failed_open_file);
+ }
+ Ok(())
+}
+
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
+ let check = matches.get_flag(options::CHECK);
+
let algo_name: &str = match matches.get_one::<String>(options::ALGORITHM) {
Some(v) => v,
- None => ALGORITHM_OPTIONS_CRC,
+ None => {
+ if check {
+ // if we are doing a --check, we should not default to crc
+ ""
+ } else {
+ ALGORITHM_OPTIONS_CRC
+ }
+ }
};
- let input_length = matches.get_one::<usize>(options::LENGTH);
- let check = matches.get_flag(options::CHECK);
+ if ["bsd", "crc", "sysv"].contains(&algo_name) && check {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "--check is not supported with --algorithm={bsd,sysv,crc}",
+ )
+ .into());
+ }
- let length = if let Some(length) = input_length {
- match length.to_owned() {
- 0 => None,
- n if n % 8 != 0 => {
- // GNU's implementation seem to use these quotation marks
- // in their error messages, so we do the same.
- uucore::show_error!("invalid length: \u{2018}{length}\u{2019}");
- return Err(io::Error::new(
- io::ErrorKind::InvalidInput,
- "length is not a multiple of 8",
- )
- .into());
- }
- n if n > 512 => {
- uucore::show_error!("invalid length: \u{2018}{length}\u{2019}");
+ let input_length = matches.get_one::<usize>(options::LENGTH);
+ let length = match input_length {
+ Some(length) => {
+ if algo_name == ALGORITHM_OPTIONS_BLAKE2B {
+ calculate_blake2b_length(*length)?
+ } else {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
- "maximum digest length for \u{2018}BLAKE2b\u{2019} is 512 bits",
+ "--lengt