From ead07bb3d461389bb52336109be7858458e49c38 Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Fri, 3 Feb 2023 16:34:18 +0000
Subject: [PATCH] cksum: add --raw option to output a binary digest
--raw output is the most composable format, and also is a
robust way to discard the file name without parsing (escaped) output.
Examples:
$ cksum --raw -a crc "$afile" | basenc --base16
4ACFC4F0
$ cksum --raw -a crc "$afile" | basenc --base2msbf
01001010110011111100010011110000
$ cksum --raw -a sha256 "$bfile" | basenc --base32
AAAAAAAADHLGRHAILLQWLAY6SNH7OY5OI2RKNQLSWPY3MCUM4JXQ====
* doc/coreutils.texi (cksum invocation): Describe the new feature.
* src/digest.c (output_file): Inspect the new RAW_DIGEST global,
and output the bytes directly if set.
* src/cksum.c (output_crc): Likewise.
* src/sum.c (output_bsd, output_sysv): Likewise.
* tests/misc/cksum-raw.sh: A new test.
* tests/local.mk: Reference the new test.
* NEWS: Mention the new feature.
---
NEWS | 3 +++
doc/coreutils.texi | 11 ++++++++
src/cksum.c | 10 ++++++-
src/cksum.h | 2 +-
src/digest.c | 38 +++++++++++++++++++++++---
src/sum.c | 25 +++++++++++++++--
src/sum.h | 4 +--
tests/local.mk | 1 +
tests/misc/cksum-raw.sh | 60 +++++++++++++++++++++++++++++++++++++++++
9 files changed, 144 insertions(+), 10 deletions(-)
create mode 100755 tests/misc/cksum-raw.sh
diff --git a/NEWS b/NEWS
index b3cde4a013..27334a595c 100644
--- a/NEWS
+++ b/NEWS
@@ -97,6 +97,9 @@ GNU coreutils NEWS -*- outline -*-
cksum now accepts the --base64 (-b) option to print base64-encoded
checksums. It also accepts/checks such checksums.
+ cksum now accepts the --raw option to output a raw binary checksum.
+ No file name or other information is output in this mode.
+
factor now accepts the --exponents (-h) option to print factors
in the form p^e, rather than repeating the prime p, e times.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 4d7d9439d0..412c513a06 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4059,6 +4059,17 @@ input digest string as what is output. I.e., removing or adding any
@opindex --debug
Output extra information to stderr, like the checksum implementation being used.
+@item --raw
+@opindex --raw
+@cindex raw binary checksum
+Print only the unencoded raw binary digest for a single input.
+Do not output the file name or anything else.
+Use network byte order (big endian) where applicable:
+for @samp{bsd}, @samp{crc}, and @samp{sysv}.
+This option works only with a single input.
+Unlike other output formats, @command{cksum} provides no way to
+@option{--check} a @option{--raw} checksum.
+
@item --untagged
@opindex --untagged
Output using the original Coreutils format used by the other
diff --git a/src/cksum.c b/src/cksum.c
index 30fbba7249..5e38fef3a7 100644
--- a/src/cksum.c
+++ b/src/cksum.c
@@ -285,9 +285,17 @@ crc_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
If ARGS is true, also print the FILE name. */
void
-output_crc (char const *file, int binary_file, void const *digest,
+output_crc (char const *file, int binary_file, void const *digest, bool raw,
bool tagged, unsigned char delim, bool args, uintmax_t length)
{
+ if (raw)
+ {
+ /* Output in network byte order (big endian). */
+ uint32_t out_int = SWAP (*(uint32_t *)digest);
+ fwrite (&out_int, 1, 32/8, stdout);
+ return;
+ }
+
char length_buf[INT_BUFSIZE_BOUND (uintmax_t)];
printf ("%u %s", *(unsigned int *)digest, umaxtostr (length, length_buf));
if (args)
diff --git a/src/cksum.h b/src/cksum.h
index 28d72ee247..58e9310b9d 100644
--- a/src/cksum.h
+++ b/src/cksum.h
@@ -7,7 +7,7 @@ extern int
crc_sum_stream (FILE *stream, void *resstream, uintmax_t *length);
extern void
-output_crc (char const *file, int binary_file, void const *digest,
+output_crc (char const *file, int binary_file, void const *digest, bool raw,
bool tagged, unsigned char delim, bool args, uintmax_t length)
_GL_ATTRIBUTE_NONNULL ((3));
diff --git a/src/digest.c b/src/digest.c
index c0616fcb25..6ee8a48547 100644
--- a/src/digest.c
+++ b/src/digest.c
@@ -168,7 +168,7 @@
#if !HASH_ALGO_SUM
static void
output_file (char const *file, int binary_file, void const *digest,
- bool tagged, unsigned char delim, bool args,
+ bool raw, bool tagged, unsigned char delim, bool args,
uintmax_t length);
#endif
@@ -210,12 +210,15 @@ static unsigned char digest_delim = '\n';
static bool base64_digest = false;
#endif
+/* If true, print binary digests, not hex. */
+static bool raw_digest = false;
+
#if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
# define BLAKE2B_MAX_LEN BLAKE2B_OUTBYTES
static uintmax_t digest_length;
#endif /* HASH_ALGO_BLAKE2 */
-typedef void (*digest_output_fn)(char const *, int, void const *,
+typedef void (*digest_output_fn)(char const *, int, void const *, bool,
bool, unsigned char, bool, uintmax_t);
#if HASH_ALGO_SUM
enum Algorithm
@@ -365,6 +368,7 @@ enum
TAG_OPTION,
UNTAG_OPTION,
DEBUG_PROGRAM_OPTION,
+ RAW_OPTION,
};
static struct option const long_options[] =
@@ -387,6 +391,7 @@ static struct option const long_options[] =
{ "algorithm", required_argument, NULL, 'a'},
{ "base64", no_argument, NULL, 'b' },
{ "debug", no_argument, NULL, DEBUG_PROGRAM_OPTION},
+ { "raw", no_argument, NULL, RAW_OPTION},
{ "untagged", no_argument, NULL, UNTAG_OPTION },
# else
{ "binary", no_argument, NULL, 'b' },
@@ -468,6 +473,10 @@ Print or check %s (%d-bit) checksums.\n\
"), stdout);
# endif
# if HASH_ALGO_CKSUM
+ fputs (_("\
+ --raw emit a raw binary digest, not hexadecimal\
+\n\
+"), stdout);
fputs (_("\
--tag create a BSD-style checksum (the default)\n\
"), stdout);
@@ -1005,9 +1014,17 @@ digest_file (char const *filename, int *binary, unsigned char *bin_result,
#if !HASH_ALGO_SUM
static void
output_file (char const *file, int binary_file, void const *digest,
- bool tagged, unsigned char delim, MAYBE_UNUSED bool args,
+ bool raw, bool tagged, unsigned char delim, MAYBE_UNUSED bool args,
MAYBE_UNUSED uintmax_t length)
{
+# if HASH_ALGO_CKSUM
+ if (raw)
+ {
+ fwrite (digest, 1, digest_length / 8, stdout);
+ return;
+ }
+# endif
+
unsigned char const *bin_buffer = digest;
/* Output a leading backslash if the file name contains problematic chars.
@@ -1421,6 +1438,9 @@ main (int argc, char **argv)
case 'b':
base64_digest = true;
break;
+ case RAW_OPTION:
+ raw_digest = true;
+ break;
case UNTAG_OPTION:
prefix_tag = false;
break;
@@ -1490,6 +1510,11 @@ main (int argc, char **argv)
break;
}
+ if (base64_digest && raw_digest)
+ {
+ error (0, 0, _("--base64 and --raw are mutually exclusive"));
+ usage (EXIT_FAILURE);
+ }
#endif
if (prefix_tag && !binary)
@@ -1569,6 +1594,11 @@ main (int argc, char **argv)
char **operand_lim = argv + argc;
if (optind == argc)
*operand_lim++ = bad_cast ("-");
+ else if (1 < argc - optind && raw_digest)
+ {
+ die (EXIT_FAILURE, 0,
+ _("the --raw option is not supported with multiple files"));
+ }
for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
{
@@ -1585,7 +1615,7 @@ main (int argc, char **argv)
ok = false;
else
{
- DIGEST_OUT (file, binary_file, bin_buffer, prefix_tag,
+ DIGEST_OUT (file, binary_file, bin_buffer, raw_digest, prefix_tag,
digest_delim, optind != argc, length);
}
}
diff --git a/src/sum.c b/src/sum.c
index 46657a0cad..5046bb3f0d 100644
--- a/src/sum.c
+++ b/src/sum.c
@@ -26,6 +26,13 @@
#include "human.h"
#include "sum.h"
+#include