From f664e7e87b979503f263334caa02cc0525b77c43 Mon Sep 17 00:00:00 2001 From: Luther Thompson Date: Sun, 22 Nov 2015 21:47:59 +0000 Subject: [PATCH] md5sum, sha*sum: add --ignore-missing for checking a subset of files * doc/coreutils.texi (md5sum invocation): Document the new option. * src/md5sum.c (digest_file): Return an empty digest to indicate a missing file. (digest_check): don't fail or output status given an empty checksum. (usage): Document the new option. (main): Process and validate the new option. * tests/misc/md5sum.pl: Add new test cases. * NEWS: Mention the new feature. --- NEWS | 4 ++++ doc/coreutils.texi | 8 ++++++++ src/md5sum.c | 39 +++++++++++++++++++++++++++++++++------ tests/misc/md5sum.pl | 23 +++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index fc5e927..9f6bff2 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,10 @@ GNU coreutils NEWS -*- outline -*- ** New features + md5sum now supports the --ignore-missing option to allow + verifying a subset of files given a larger list of checksums. + This also affects sha1sum, sha224sum, sha256sum, sha384sum and sha512sum. + printf now supports the '%q' format to print arguments in a form that is reusable by most shells, with non-printable characters escaped with the POSIX proposed $'...' syntax. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 0e28f49..7918aec 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -3830,6 +3830,14 @@ an MD5 checksum inconsistent with the associated file, or if no valid line is found, @command{md5sum} exits with nonzero status. Otherwise, it exits successfully. +@item --ignore-missing +@opindex --ignore-missing +@cindex verifying MD5 checksums +This option is useful only when verifying checksums. +When verifying checksums, don't fail or report any status +for missing files. This is useful when verifying a subset +of downloaded files given a larger list of checksums. + @item --quiet @opindex --quiet @cindex verifying MD5 checksums diff --git a/src/md5sum.c b/src/md5sum.c index 5d4b958..8990f1a 100644 --- a/src/md5sum.c +++ b/src/md5sum.c @@ -119,6 +119,9 @@ static bool status_only = false; improperly formatted checksum line. */ static bool warn = false; +/* With --check, ignore missing files. */ +static bool ignore_missing = false; + /* With --check, suppress the "OK" printed for each verified file. */ static bool quiet = false; @@ -133,7 +136,8 @@ static int bsd_reversed = -1; non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - STATUS_OPTION = CHAR_MAX + 1, + IGNORE_MISSING_OPTION = CHAR_MAX + 1, + STATUS_OPTION, QUIET_OPTION, STRICT_OPTION, TAG_OPTION @@ -143,6 +147,7 @@ static struct option const long_options[] = { { "binary", no_argument, NULL, 'b' }, { "check", no_argument, NULL, 'c' }, + { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION}, { "quiet", no_argument, NULL, QUIET_OPTION }, { "status", no_argument, NULL, STATUS_OPTION }, { "text", no_argument, NULL, 't' }, @@ -197,7 +202,8 @@ Print or check %s (%d-bit) checksums.\n\ "), stdout); fputs (_("\ \n\ -The following four options are useful only when verifying checksums:\n\ +The following five options are useful only when verifying checksums:\n\ + --ignore-missing don't fail or report status for missing files\n\ --quiet don't print OK for each successfully verified file\n\ --status don't output anything, status code shows success\n\ --strict exit non-zero for improperly formatted checksum lines\n\ @@ -482,6 +488,11 @@ digest_file (const char *filename, int *binary, unsigned char *bin_result) fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r")); if (fp == NULL) { + if (ignore_missing && errno == ENOENT) + { + *bin_result = '\0'; + return true; + } error (0, errno, "%s", quotef (filename)); return false; } @@ -597,6 +608,7 @@ digest_check (const char *checkfile_name) ++n_properly_formatted_lines; + *bin_buffer = '\1'; /* flag set to 0 for ignored missing files. */ ok = digest_file (filename, &binary, bin_buffer); if (!ok) @@ -613,10 +625,14 @@ digest_check (const char *checkfile_name) else { size_t digest_bin_bytes = digest_hex_bytes / 2; - size_t cnt; + size_t cnt = 0; + + if (ignore_missing && ! *bin_buffer) + cnt = digest_bin_bytes; + /* Compare generated binary number with text representation in check file. Ignore case of hex digits. */ - for (cnt = 0; cnt < digest_bin_bytes; ++cnt) + for (;cnt < digest_bin_bytes; ++cnt) { if (tolower (hex_digest[2 * cnt]) != bin2hex[bin_buffer[cnt] >> 4] @@ -629,7 +645,7 @@ digest_check (const char *checkfile_name) if (!status_only) { - if (cnt != digest_bin_bytes || ! quiet) + if (cnt != digest_bin_bytes || (! quiet && *bin_buffer)) { if (needs_escape) putchar ('\\'); @@ -638,7 +654,7 @@ digest_check (const char *checkfile_name) if (cnt != digest_bin_bytes) printf (": %s\n", _("FAILED")); - else if (!quiet) + else if (!quiet && *bin_buffer) printf (": %s\n", _("OK")); } } @@ -749,6 +765,9 @@ main (int argc, char **argv) warn = true; quiet = false; break; + case IGNORE_MISSING_OPTION: + ignore_missing = true; + break; case QUIET_OPTION: status_only = false; warn = false; @@ -795,6 +814,14 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + if (ignore_missing && !do_check) + { + error (0, 0, + _("the --ignore-missing option is meaningful only when " + "verifying checksums")); + usage (EXIT_FAILURE); + } + if (status_only && !do_check) { error (0, 0, diff --git a/tests/misc/md5sum.pl b/tests/misc/md5sum.pl index ad1896d..22a941f 100755 --- a/tests/misc/md5sum.pl +++ b/tests/misc/md5sum.pl @@ -25,6 +25,8 @@ my $prog = 'md5sum'; my $degenerate = "d41d8cd98f00b204e9800998ecf8427e"; +my $try_help = "Try 'md5sum --help' for more information.\n"; + my @Tests = ( ['1', {IN=> {f=> ''}}, {OUT=>"$degenerate f\n"}], @@ -120,6 +122,27 @@ my @Tests = ['check-openssl3', '--check', '--status', {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}}, {AUX=> {f=> 'bar'}}, {EXIT=> 1}], + ['check-ignore-missing-1', '--check', '--ignore-missing', + {AUX=> {f=> ''}}, + {IN=> {'f.md5' => "$degenerate f\n". + "$degenerate f.missing\n"}}, + {OUT=>"f: OK\n"}], + ['check-ignore-missing-2', '--check', '--ignore-missing', + {AUX=> {f=> ''}}, + {IN=> {'f.md5' => "$degenerate f\n". + "$degenerate f.missing\n"}}, + {OUT=>"f: OK\n"}], + ['check-ignore-missing-3', '--check', '--quiet', '--ignore-missing', + {AUX=> {f=> ''}}, + {IN=> {'f.md5' => "$degenerate f.missing\n". + "$degenerate f\n"}}, + {OUT=>""}], + ['check-ignore-missing-4', '--ignore-missing', + {IN=> {f=> ''}}, + {ERR=>"md5sum: the --ignore-missing option is ". + "meaningful only when verifying checksums\n". + $try_help}, + {EXIT=> 1}], ['bsd-segv', '--check', {IN=> {'z' => "MD5 ("}}, {EXIT=> 1}, {ERR=> "$prog: z: no properly formatted MD5 checksum lines found\n"}], -- 2.5.0