summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2023-02-03 16:34:18 +0000
committerPádraig Brady <P@draigBrady.com>2023-02-06 13:09:40 +0000
commitead07bb3d461389bb52336109be7858458e49c38 (patch)
tree8d905a8a307dec94d422783162fc241dc659cc48
parent2984e47c789ebc39f55a3b1cb20b943de88eeedc (diff)
downloadcoreutils-ead07bb3d461389bb52336109be7858458e49c38.tar.gz
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.
-rw-r--r--NEWS3
-rw-r--r--doc/coreutils.texi11
-rw-r--r--src/cksum.c10
-rw-r--r--src/cksum.h2
-rw-r--r--src/digest.c38
-rw-r--r--src/sum.c25
-rw-r--r--src/sum.h4
-rw-r--r--tests/local.mk1
-rwxr-xr-xtests/misc/cksum-raw.sh60
9 files changed, 144 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index b3cde4a01..27334a595 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 4d7d9439d..412c513a0 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 30fbba724..5e38fef3a 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 28d72ee24..58e9310b9 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 c0616fcb2..6ee8a4854 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 46657a0ca..5046bb3f0 100644
--- a/src/sum.c
+++ b/src/sum.c
@@ -26,6 +26,13 @@
#include "human.h"
#include "sum.h"
+#include <byteswap.h>
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) (n)
+#else
+# define SWAP(n) bswap_16 (n)
+#endif
+
/* Calculate the checksum and the size in bytes of stream STREAM.
Return -1 on error, 0 on success. */
@@ -184,9 +191,16 @@ cleanup_buffer:
void
output_bsd (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)
{
+ if (raw)
+ {
+ /* Output in network byte order (big endian). */
+ uint16_t out_int = SWAP (*(uint16_t *)digest);
+ fwrite (&out_int, 1, 16/8, stdout);
+ return;
+ }
char hbuf[LONGEST_HUMAN_READABLE + 1];
printf ("%05d %5s", *(int *)digest,
@@ -201,9 +215,16 @@ output_bsd (char const *file, int binary_file, void const *digest,
void
output_sysv (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)
{
+ if (raw)
+ {
+ /* Output in network byte order (big endian). */
+ uint16_t out_int = SWAP (*(uint16_t *)digest);
+ fwrite (&out_int, 1, 16/8, stdout);
+ return;
+ }
char hbuf[LONGEST_HUMAN_READABLE + 1];
printf ("%d %s", *(int *)digest,
diff --git a/src/sum.h b/src/sum.h
index e1cf8a706..bd251a034 100644
--- a/src/sum.h
+++ b/src/sum.h
@@ -9,10 +9,10 @@ typedef int (*sumfn)(FILE *, void *, uintmax_t *);
extern void
output_bsd (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);
extern void
output_sysv (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);
diff --git a/tests/local.mk b/tests/local.mk
index 70a8f6e73..4c40fd115 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -294,6 +294,7 @@ all_tests = \
tests/misc/cksum-a.sh \
tests/misc/cksum-c.sh \
tests/misc/cksum-base64.pl \
+ tests/misc/cksum-raw.sh \
tests/misc/comm.pl \
tests/misc/csplit.sh \
tests/misc/csplit-1000.sh \
diff --git a/tests/misc/cksum-raw.sh b/tests/misc/cksum-raw.sh
new file mode 100755
index 000000000..a5f14be88
--- /dev/null
+++ b/tests/misc/cksum-raw.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Validate cksum --raw operation
+
+# Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum date od
+
+cat > digest_types <<\EOF || framework_failure_
+bsd u2
+sysv u2
+crc u4
+md5 x1
+sha1 x1
+sha224 x1
+sha256 x1
+sha384 x1
+sha512 x1
+blake2b x1
+sm3 x1
+EOF
+
+date > file.in || framework_failure_
+
+while read algo type; do
+ # Binary converted back to text
+ cksum --raw --algorithm $algo file.in > digest.bin || fail=1
+ d='digest.bin.txt'
+ od --endian=big -An -w1024 -t$type < digest.bin | tr -d ' ' \
+ > "$d" || framework_failure_
+ # Pad the bsd checksum with leading 0's, if needed.
+ case $algo in bsd) n=$(cat "$d"); printf '%05d\n' "$n" > "$d" ;; esac
+
+ # Standard text output
+ cksum --untagged --algorithm $algo < file.in | cut -d ' ' -f1 \
+ > digest.txt || fail=1
+
+ compare digest.txt "$d" || fail=1
+done < digest_types
+
+# Ensure --base64 and --raw not used together
+returns_ 1 cksum --base64 --raw </dev/null || fail=1
+
+# Ensure --raw not supported with multiple files
+returns_ 1 cksum --raw /dev/null /dev/null || fail=1
+
+Exit $fail