diff options
author | Pádraig Brady <P@draigBrady.com> | 2023-02-03 16:34:18 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2023-02-06 13:09:40 +0000 |
commit | ead07bb3d461389bb52336109be7858458e49c38 (patch) | |
tree | 8d905a8a307dec94d422783162fc241dc659cc48 | |
parent | 2984e47c789ebc39f55a3b1cb20b943de88eeedc (diff) | |
download | coreutils-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-- | NEWS | 3 | ||||
-rw-r--r-- | doc/coreutils.texi | 11 | ||||
-rw-r--r-- | src/cksum.c | 10 | ||||
-rw-r--r-- | src/cksum.h | 2 | ||||
-rw-r--r-- | src/digest.c | 38 | ||||
-rw-r--r-- | src/sum.c | 25 | ||||
-rw-r--r-- | src/sum.h | 4 | ||||
-rw-r--r-- | tests/local.mk | 1 | ||||
-rwxr-xr-x | tests/misc/cksum-raw.sh | 60 |
9 files changed, 144 insertions, 10 deletions
@@ -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); } } @@ -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, @@ -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 |