From b977d61f6727965b3b6fdbabc681922c65e0f2ca Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 14 Apr 2024 20:05:00 +0200 Subject: [PATCH] hashsum: implement the ignore-missing option Tested by gnu/tests/cksum/md5sum.pl --- src/uu/hashsum/src/hashsum.rs | 17 ++++++++++++++++- tests/by-util/test_hashsum.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 8f57522d6..4b049e8cf 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -21,7 +21,7 @@ use std::iter; use std::num::ParseIntError; use std::path::Path; use uucore::error::USimpleError; -use uucore::error::{FromIo, UError, UResult}; +use uucore::error::{set_exit_code, FromIo, UError, UResult}; use uucore::sum::{ Blake2b, Blake3, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Sha512, Shake128, Shake256, @@ -46,6 +46,7 @@ struct Options { warn: bool, output_bits: usize, zero: bool, + ignore_missing: bool, } /// Creates a Blake2b hasher instance based on the specified length argument. @@ -345,6 +346,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { let strict = matches.get_flag("strict"); let warn = matches.get_flag("warn") && !status; let zero = matches.get_flag("zero"); + let ignore_missing = matches.get_flag("ignore-missing"); let opts = Options { algoname: name, @@ -359,6 +361,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { strict, warn, zero, + ignore_missing, }; match matches.get_many::("FILE") { @@ -431,6 +434,12 @@ pub fn uu_app_common() -> Command { .help("exit non-zero for improperly formatted checksum lines") .action(ArgAction::SetTrue), ) + .arg( + Arg::new("ignore-missing") + .long("ignore-missing") + .help("don't fail or report status for missing files") + .action(ArgAction::SetTrue), + ) .arg( Arg::new("warn") .short('w') @@ -705,6 +714,11 @@ where let (ck_filename_unescaped, prefix) = unescape_filename(&ck_filename); let f = match File::open(ck_filename_unescaped) { Err(_) => { + if options.ignore_missing { + // No need to show an error + continue; + } + failed_open_file += 1; println!( "{}: {}: No such file or directory", @@ -712,6 +726,7 @@ where ck_filename ); println!("{ck_filename}: FAILED open or read"); + set_exit_code(1); continue; } Ok(file) => file, diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index 22a028a32..4e590902d 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -129,6 +129,33 @@ fn test_check_sha1() { .stderr_is(""); } +#[test] +fn test_check_md5_ignore_missing() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.write("testf", "foobar\n"); + at.write( + "testf.sha1", + "14758f1afd44c09b7992073ccf00b43d testf\n14758f1afd44c09b7992073ccf00b43d testf2\n", + ); + scene + .ccmd("md5sum") + .arg("-c") + .arg(at.subdir.join("testf.sha1")) + .fails() + .stdout_contains("testf2: FAILED open or read"); + + scene + .ccmd("md5sum") + .arg("-c") + .arg("--ignore-missing") + .arg(at.subdir.join("testf.sha1")) + .succeeds() + .stdout_is("testf: OK\n") + .stderr_is(""); +} + #[test] fn test_check_b2sum_length_option_0() { let scene = TestScenario::new(util_name!()); @@ -208,7 +235,7 @@ fn test_check_file_not_found_warning() { .ccmd("sha1sum") .arg("-c") .arg(at.subdir.join("testf.sha1")) - .succeeds() + .fails() .stdout_is("sha1sum: testf: No such file or directory\ntestf: FAILED open or read\n") .stderr_is("sha1sum: warning: 1 listed file could not be read\n"); }