coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] cksum: add --raw option to output a binary digest


From: Pádraig Brady
Subject: [PATCH] cksum: add --raw option to output a binary digest
Date: Sat, 4 Feb 2023 13:51:33 +0000

--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      |  8 ++++++
 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 | 57 +++++++++++++++++++++++++++++++++++++++++
 9 files changed, 138 insertions(+), 10 deletions(-)
 create mode 100755 tests/misc/cksum-raw.sh

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..536301d63 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4059,6 +4059,14 @@ 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 an unencoded raw binary digest, not hexadecimal.
+No file name or other information is output in this mode.
+Bytes are output in network byte order (big endian).
+This option is ignored with @option{--check}.
+
 @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..de27732f0
--- /dev/null
+++ b/tests/misc/cksum-raw.sh
@@ -0,0 +1,57 @@
+#!/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
+  od --endian=big -An -w1024 -t$type < digest.bin | tr -d ' ' \
+    > digest.bin.txt || framework_failure_
+
+  # Standard text output
+  cksum --untagged --algorithm $algo < file.in | cut -d ' ' -f1 \
+    > digest.txt || fail=1
+
+  compare digest.txt digest.bin.txt || 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
-- 
2.26.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]