From: Pádraig Brady
Date: Sat, 11 Sep 2021 15:19:39 +0000 (+0100)
Subject: cksum: support digest detection for tagged format
X-Git-Tag: v9.0~35
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=772173a8328ffdbde7a6639f456b36a5522e60bc;p=thirdparty%2Fcoreutils.git
cksum: support digest detection for tagged format
Support `cksum --check FILE` without having to specify a digest
algorithm, allowing for more generic file check instructions.
This also supports mixed digest checksum files, supporting
more robust multi digest checks.
* src/digest.c (algorithm_from_tag): A new function to
identify the digest algorithm from a tagged format line.
(split3): Set the algorithm depending on tag, and update
the expected digest length accordingly.
* tests/misc/cksum-c.sh: Add a new test.
* tests/local.mk: Reference the new test.
* tests/misc/md5sum.pl: Adjust to more generic error.
* tests/misc/sha1sum.pl: Likewise.
* doc/coreutils.texi (md5sum invocation): Mention the new -c feature.
* NEWS: Mention the new feature.
---
diff --git a/NEWS b/NEWS
index 217cf987c0..b7d770bc3e 100644
--- a/NEWS
+++ b/NEWS
@@ -95,6 +95,9 @@ GNU coreutils NEWS -*- outline -*-
cksum -a now supports the 'sm3' argument, to use the SM3 digest algorithm.
+ cksum --check now supports auto detecting the digest type to use,
+ when verifying tagged format checksums.
+
expr and factor now support bignums on all platforms.
ls --classify now supports the "always", "auto", or "never" flags,
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 183dde12cc..a5537d7897 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4087,10 +4087,16 @@ Read file names and checksum information (not data) from each
whether the checksums match the contents of the named files.
The input to this mode of @command{md5sum} is usually the output of
a prior, checksum-generating run of @samp{md5sum}.
+
Three input formats are supported. Either the default output
format described above, the @option{--tag} output format,
or the BSD reversed mode format which is similar to the default mode,
but doesn't use a character to distinguish binary and text modes.
+
+For the @command{cksum} command, the @option{--check} option
+supports auto-detecting the digest algorithm to use,
+when presented with checksum information in the @option{--tag} output format.
+
Output with @option{--zero} enabled is not supported by @option{--check}.
@sp 1
For each such line, @command{md5sum} reads the named file and computes its
diff --git a/src/digest.c b/src/digest.c
index 57b37c782b..c785751c14 100644
--- a/src/digest.c
+++ b/src/digest.c
@@ -311,6 +311,7 @@ static int const algorithm_bits[] =
verify (ARRAY_CARDINALITY (algorithm_bits)
== ARRAY_CARDINALITY (algorithm_args));
+static bool algorithm_specified = false;
static enum Algorithm cksum_algorithm = crc;
static sumfn cksumfns[]=
{
@@ -630,6 +631,45 @@ bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest,
return hex_digits (*hex_digest);
}
+#if HASH_ALGO_CKSUM
+/* Return the corresponding Algorithm for the string S,
+ or -1 for no match. */
+
+static ptrdiff_t
+algorithm_from_tag (char *s)
+{
+ /* Limit check size to this length for perf reasons. */
+ static size_t max_tag_len;
+ if (! max_tag_len)
+ {
+ char const * const * tag = algorithm_tags;
+ while (*tag)
+ {
+ size_t tag_len = strlen (*tag++);
+ max_tag_len = MAX (tag_len, max_tag_len);
+ }
+ }
+
+ size_t i = 0;
+
+ /* Find end of tag */
+ while (i <= max_tag_len && s[i] && ! ISWHITE (s[i])
+ && s[i] != '-' && s[i] != '(')
+ ++i;
+
+ if (i > max_tag_len)
+ return -1;
+
+ /* Terminate tag, and lookup. */
+ char sep = s[i];
+ s[i] = '\0';
+ ptrdiff_t algo = argmatch (s, algorithm_tags, NULL, 0);
+ s[i] = sep;
+
+ return algo;
+}
+#endif
+
/* Split the string S (of length S_LEN) into three parts:
a hexadecimal digest, binary flag, and the file name.
S is modified. Return true if successful. */
@@ -653,6 +693,21 @@ split_3 (char *s, size_t s_len,
/* Check for BSD-style checksum line. */
+#if HASH_ALGO_CKSUM
+ if (! algorithm_specified)
+ {
+ ptrdiff_t algo_tag = algorithm_from_tag (s+i);
+ if (algo_tag >= 0)
+ {
+ if (algo_tag <= crc)
+ return false; /* We don't support checking these older formats. */
+ cksum_algorithm = algo_tag;
+ }
+ else
+ return false; /* We only support tagged format without -a. */
+ }
+#endif
+
algo_name_len = strlen (DIGEST_TYPE_STRING);
if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
{
@@ -687,7 +742,14 @@ split_3 (char *s, size_t s_len,
# if HASH_ALGO_CKSUM
}
# endif
+# if HASH_ALGO_CKSUM
+ if (cksum_algorithm == blake2b)
+ digest_hex_bytes = b2_length / 4;
+ else
+ digest_hex_bytes = algorithm_bits[cksum_algorithm] / 4;
+# else
digest_hex_bytes = b2_length / 4;
+# endif
#endif
if (s[i] == ' ')
++i;
@@ -1102,8 +1164,8 @@ digest_check (char const *checkfile_name)
if (! properly_formatted_lines)
{
/* Warn if no tests are found. */
- error (0, 0, _("%s: no properly formatted %s checksum lines found"),
- quotef (checkfile_name), DIGEST_TYPE_STRING);
+ error (0, 0, _("%s: no properly formatted checksum lines found"),
+ quotef (checkfile_name));
}
else
{
@@ -1190,6 +1252,7 @@ main (int argc, char **argv)
case 'a':
cksum_algorithm = XARGMATCH ("--algorithm", optarg,
algorithm_args, algorithm_types);
+ algorithm_specified = true;
break;
case DEBUG_PROGRAM_OPTION:
@@ -1303,7 +1366,7 @@ main (int argc, char **argv)
if (prefix_tag)
die (EXIT_FAILURE, 0,
_("--tag is not supported with --algorithm={bsd,sysv,crc}"));
- if (do_check)
+ if (do_check && algorithm_specified)
die (EXIT_FAILURE, 0,
_("--check is not supported with --algorithm={bsd,sysv,crc}"));
break;
diff --git a/tests/local.mk b/tests/local.mk
index 192c0d31c9..228d0e3688 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -290,6 +290,7 @@ all_tests = \
tests/misc/chroot-fail.sh \
tests/misc/cksum.sh \
tests/misc/cksum-a.sh \
+ tests/misc/cksum-c.sh \
tests/misc/comm.pl \
tests/misc/csplit.sh \
tests/misc/csplit-1000.sh \
diff --git a/tests/misc/cksum-c.sh b/tests/misc/cksum-c.sh
new file mode 100755
index 0000000000..d8d26d8139
--- /dev/null
+++ b/tests/misc/cksum-c.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Validate cksum --check dynamic operation
+
+# Copyright (C) 2021 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see