bug-coreutils
[Top][All Lists]
Advanced

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

md5sum, sha1sum integer cleanups


From: Paul Eggert
Subject: md5sum, sha1sum integer cleanups
Date: Thu, 29 Jul 2004 17:58:28 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

md5sum and sha1sum report incorrect results when given a checksum file
with more than 2**31 entries in it.  I installed this patch as part of
my overall integer cleanups.

2004-07-29  Paul Eggert  <address@hidden>

        md5sum, sha1sum integer cleanups.

        * src/checksum.h: Don't include config.h, sys/types.h, stdio.h:
        not needed.
        (ALG_UNSPECIFIED): Remove.
        (ALG_MDT): Don't make it equal to CHAR_MAX + 1; this isn't necessary.
        * src/md5.c: Don't include any files other than checksum.h.
        * src/sha1sum.c: Likewise.
        * src/md5sum.c (OPENOPTS, have_read_stdin, status_only, warn,
        bsd_split_3, split_3, hex_digits, digest_file, digest_check, main):
        Use bool when appropriate.
        (digest_check): Increase limit of number of input lines to
        UINTMAX_MAX from INT_MAX.  Diagnose any overflows of this counter.
        Use ngettext instead of hard-to-i18nize hardcoded stuff for plurals.
        
Index: NEWS
===================================================================
RCS file: /home/eggert/coreutils/cu/NEWS,v
retrieving revision 1.226
diff -p -u -r1.226 NEWS
--- NEWS        26 Jul 2004 06:07:04 -0000      1.226
+++ NEWS        30 Jul 2004 00:52:42 -0000
@@ -36,6 +36,10 @@ GNU coreutils NEWS                      
     recursively-encountered symbolic link cannot be updated because
     the file system does not support it.
 
+  md5sum and sha1sum now report an error when given so many input
+  lines that their line counter overflows, instead of silently
+  reporting incorrect results.
+
   rm no longer requires read access to the current directory.
 
   tail -f no longer mishandles pipes and fifos.  With no operands,
Index: src/checksum.h
===================================================================
RCS file: /home/eggert/coreutils/cu/src/checksum.h,v
retrieving revision 1.3
diff -p -u -r1.3 checksum.h
--- src/checksum.h      26 Nov 2000 23:10:55 -0000      1.3
+++ src/checksum.h      15 Jul 2004 05:47:45 -0000
@@ -1,14 +1,6 @@
-#include <config.h>
-
-#include <sys/types.h>
-#include <stdio.h>
-
-/* For long options that have no equivalent short option, use a
-   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
 {
-  ALG_UNSPECIFIED = 0,
-  ALG_MD5 = CHAR_MAX + 1,
+  ALG_MD5,
   ALG_SHA1
 };
 
Index: src/md5.c
===================================================================
RCS file: /home/eggert/coreutils/cu/src/md5.c,v
retrieving revision 1.2
diff -p -u -r1.2 md5.c
--- src/md5.c   26 Nov 2000 23:12:44 -0000      1.2
+++ src/md5.c   15 Jul 2004 05:48:02 -0000
@@ -1,7 +1,2 @@
-#include <config.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include "system.h"
 #include "checksum.h"
-
 int algorithm = ALG_MD5;
Index: src/sha1sum.c
===================================================================
RCS file: /home/eggert/coreutils/cu/src/sha1sum.c,v
retrieving revision 1.2
diff -p -u -r1.2 sha1sum.c
--- src/sha1sum.c       26 Nov 2000 23:13:11 -0000      1.2
+++ src/sha1sum.c       15 Jul 2004 05:48:36 -0000
@@ -1,7 +1,2 @@
-#include <config.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include "system.h"
 #include "checksum.h"
-
 int algorithm = ALG_SHA1;
Index: src/md5sum.c
===================================================================
RCS file: /home/eggert/coreutils/cu/src/md5sum.c,v
retrieving revision 1.124
diff -p -u -r1.124 md5sum.c
--- src/md5sum.c        21 Jun 2004 15:03:35 -0000      1.124
+++ src/md5sum.c        29 Jul 2004 06:31:52 -0000
@@ -41,12 +41,12 @@
    text representations.  */
 /* FIXME: This begs for an autoconf test.  */
 #if O_BINARY
-# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT)
+# define OPENOPTS(BINARY) ((BINARY) ? TEXT1TO1 : TEXTCNVT)
 # define TEXT1TO1 "rb"
 # define TEXTCNVT "r"
 #else
 # if defined VMS
-#  define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT)
+#  define OPENOPTS(BINARY) ((BINARY) ? TEXT1TO1 : TEXTCNVT)
 #  define TEXT1TO1 "rb", "ctx=stm"
 #  define TEXTCNVT "r", "ctx=stm"
 # else
@@ -78,8 +78,8 @@
    + 2 /* blank and binary indicator */ \
    + 1 /* minimum filename length */ )
 
-/* Nonzero if any of the files read were the standard input. */
-static int have_read_stdin;
+/* True if any of the files read were the standard input. */
+static bool have_read_stdin;
 
 /* The minimum length of a valid checksum line for the selected algorithm.  */
 static size_t min_digest_line_length;
@@ -89,11 +89,11 @@ static size_t digest_hex_bytes;
 
 /* With --check, don't generate any output.
    The exit code indicates success or failure.  */
-static int status_only = 0;
+static bool status_only = false;
 
 /* With --check, print a message to standard error warning about each
    improperly formatted checksum line.  */
-static int warn = 0;
+static bool warn = false;
 
 /* Declared and set via one of the wrapper .c files.  */
 /* int algorithm = ALG_UNSPECIFIED; */
@@ -164,9 +164,9 @@ text), and name for each FILE.\n"),
 
 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
    'sha1' command into two parts: a hexadecimal digest, and the file
-   name.  S is modified.  */
+   name.  S is modified.  Return true if successful.  */
 
-static int
+static bool
 bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest, char 
**file_name)
 {
   size_t i;
@@ -180,7 +180,7 @@ bsd_split_3 (char *s, size_t s_len, unsi
     i--;
 
   if (s[i] != ')')
-    return 1;
+    return false;
 
   s[i++] = '\0';
 
@@ -188,7 +188,7 @@ bsd_split_3 (char *s, size_t s_len, unsi
     i++;
 
   if (s[i] != '=')
-    return 1;
+    return false;
 
   i++;
 
@@ -196,19 +196,19 @@ bsd_split_3 (char *s, size_t s_len, unsi
     i++;
 
   *hex_digest = (unsigned char *) &s[i];
-  return 0;
+  return true;
 }
 
 /* Split the string S (of length S_LEN) into three parts:
    a hexadecimal digest, binary flag, and the file name.
-   S is modified.  */
+   S is modified.  Return true if successful.  */
 
-static int
+static bool
 split_3 (char *s, size_t s_len,
-        unsigned char **hex_digest, int *binary, char **file_name)
+        unsigned char **hex_digest, bool *binary, char **file_name)
 {
   size_t i;
-  int escaped_filename = 0;
+  bool escaped_filename = false;
   size_t algo_name_len;
 
   i = 0;
@@ -221,7 +221,7 @@ split_3 (char *s, size_t s_len,
     {
       if (strncmp (s + i + algo_name_len, " (", 2) == 0)
        {
-         *binary = 0;
+         *binary = false;
          return bsd_split_3 (s +      i + algo_name_len + 2,
                              s_len - (i + algo_name_len + 2),
                              hex_digest, file_name);
@@ -233,12 +233,12 @@ split_3 (char *s, size_t s_len,
      the first is a backslash) more characters to contain correct message 
digest
      information.  */
   if (s_len - i < min_digest_line_length + (s[i] == '\\'))
-    return 1;
+    return false;
 
   if (s[i] == '\\')
     {
       ++i;
-      escaped_filename = 1;
+      escaped_filename = true;
     }
   *hex_digest = (unsigned char *) &s[i];
 
@@ -247,12 +247,12 @@ split_3 (char *s, size_t s_len,
      immediately by a white space it's an error.  */
   i += digest_hex_bytes;
   if (!ISWHITE (s[i]))
-    return 1;
+    return false;
 
   s[i++] = '\0';
 
   if (s[i] != ' ' && s[i] != '*')
-    return 1;
+    return false;
   *binary = (s[i++] == '*');
 
   /* All characters between the type indicator and end of line are
@@ -274,7 +274,7 @@ split_3 (char *s, size_t s_len,
              if (i == s_len - 1)
                {
                  /* A valid line does not end with a backslash.  */
-                 return 1;
+                 return false;
                }
              ++i;
              switch (s[i++])
@@ -287,13 +287,13 @@ split_3 (char *s, size_t s_len,
                  break;
                default:
                  /* Only `\' or `n' may follow a backslash.  */
-                 return 1;
+                 return false;
                }
              break;
 
            case '\0':
              /* The file name may not contain a NUL.  */
-             return 1;
+             return false;
              break;
 
            default:
@@ -303,36 +303,36 @@ split_3 (char *s, size_t s_len,
        }
       *dst = '\0';
     }
-  return 0;
+  return true;
 }
 
-static int
+static bool
 hex_digits (unsigned char const *s)
 {
   while (*s)
     {
       if (!ISXDIGIT (*s))
-        return 0;
+        return false;
       ++s;
     }
-  return 1;
+  return true;
 }
 
 /* An interface to the function, DIGEST_STREAM,
    (either md5_stream or sha_stream).
    Operate on FILENAME (it may be "-") and put the result in *BIN_RESULT.
-   Return non-zero upon failure, zero to indicate success.  */
+   Return true if successful.  */
 
-static int
-digest_file (const char *filename, int binary, unsigned char *bin_result,
-          int (*digest_stream)(FILE *, void *))
+static bool
+digest_file (const char *filename, bool binary, unsigned char *bin_result,
+            int (*digest_stream) (FILE *, void *))
 {
   FILE *fp;
   int err;
 
   if (STREQ (filename, "-"))
     {
-      have_read_stdin = 1;
+      have_read_stdin = true;
       fp = stdin;
 #if O_BINARY
       /* If we need binary reads from a pipe or redirected stdin, we need
@@ -351,7 +351,7 @@ digest_file (const char *filename, int b
       if (fp == NULL)
        {
          error (0, errno, "%s", filename);
-         return 1;
+         return false;
        }
     }
 
@@ -361,33 +361,33 @@ digest_file (const char *filename, int b
       error (0, errno, "%s", filename);
       if (fp != stdin)
        fclose (fp);
-      return 1;
+      return false;
     }
 
   if (fp != stdin && fclose (fp) == EOF)
     {
       error (0, errno, "%s", filename);
-      return 1;
+      return false;
     }
 
-  return 0;
+  return true;
 }
 
-static int
-digest_check (const char *checkfile_name, int (*digest_stream)(FILE *, void *))
+static bool
+digest_check (const char *checkfile_name, int (*digest_stream) (FILE *, void 
*))
 {
   FILE *checkfile_stream;
-  int n_properly_formated_lines = 0;
-  int n_mismatched_checksums = 0;
-  int n_open_or_read_failures = 0;
+  uintmax_t n_properly_formatted_lines = 0;
+  uintmax_t n_mismatched_checksums = 0;
+  uintmax_t n_open_or_read_failures = 0;
   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
-  size_t line_number;
+  uintmax_t line_number;
   char *line;
   size_t line_chars_allocated;
 
   if (STREQ (checkfile_name, "-"))
     {
-      have_read_stdin = 1;
+      have_read_stdin = true;
       checkfile_name = _("standard input");
       checkfile_stream = stdin;
     }
@@ -397,7 +397,7 @@ digest_check (const char *checkfile_name
       if (checkfile_stream == NULL)
        {
          error (0, errno, "%s", checkfile_name);
-         return 1;
+         return false;
        }
     }
 
@@ -408,12 +408,14 @@ digest_check (const char *checkfile_name
   do
     {
       char *filename;
-      int binary;
+      bool binary;
       unsigned char *hex_digest;
-      int err;
-      int line_length;
+      ssize_t line_length;
 
       ++line_number;
+      if (line_number == 0)
+       error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
+              checkfile_name);
 
       line_length = getline (&line, &line_chars_allocated, checkfile_stream);
       if (line_length <= 0)
@@ -427,14 +429,15 @@ digest_check (const char *checkfile_name
       if (line[line_length - 1] == '\n')
        line[--line_length] = '\0';
 
-      err = split_3 (line, line_length, &hex_digest, &binary, &filename);
-      if (err || !hex_digits (hex_digest))
+      if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
+            && hex_digits (hex_digest)))
        {
          if (warn)
            {
              error (0, 0,
-                    _("%s: %lu: improperly formatted %s checksum line"),
-                    checkfile_name, (unsigned long) line_number,
+                    _("%s: %" PRIuMAX
+                      ": improperly formatted %s checksum line"),
+                    checkfile_name, line_number,
                     DIGEST_TYPE_STRING (algorithm));
            }
        }
@@ -444,13 +447,13 @@ digest_check (const char *checkfile_name
                                          '4', '5', '6', '7',
                                          '8', '9', 'a', 'b',
                                          'c', 'd', 'e', 'f' };
-         int fail;
+         bool ok;
 
-         ++n_properly_formated_lines;
+         ++n_properly_formatted_lines;
 
-         fail = digest_file (filename, binary, bin_buffer, digest_stream);
+         ok = digest_file (filename, binary, bin_buffer, digest_stream);
 
-         if (fail)
+         if (!ok)
            {
              ++n_open_or_read_failures;
              if (!status_only)
@@ -493,16 +496,16 @@ digest_check (const char *checkfile_name
   if (ferror (checkfile_stream))
     {
       error (0, 0, _("%s: read error"), checkfile_name);
-      return 1;
+      return false;
     }
 
   if (checkfile_stream != stdin && fclose (checkfile_stream) == EOF)
     {
       error (0, errno, "%s", checkfile_name);
-      return 1;
+      return false;
     }
 
-  if (n_properly_formated_lines == 0)
+  if (n_properly_formatted_lines == 0)
     {
       /* Warn if no tests are found.  */
       error (0, 0, _("%s: no properly formatted %s checksum lines found"),
@@ -512,51 +515,53 @@ digest_check (const char *checkfile_name
     {
       if (!status_only)
        {
-         int n_computed_checkums = (n_properly_formated_lines
-                                    - n_open_or_read_failures);
+         if (n_open_or_read_failures != 0)
+           error (0, 0,
+                  ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
+                            " listed file could not be read",
+                            "WARNING: %" PRIuMAX " of %" PRIuMAX
+                            " listed files could not be read",
+                            n_properly_formatted_lines),
+                  n_open_or_read_failures, n_properly_formatted_lines);
 
-         if (n_open_or_read_failures > 0)
+         if (n_mismatched_checksums != 0)
            {
+             uintmax_t n_computed_checksums =
+               (n_properly_formatted_lines - n_open_or_read_failures);
              error (0, 0,
-                    _("WARNING: %d of %d listed %s could not be read"),
-                    n_open_or_read_failures, n_properly_formated_lines,
-                    (n_properly_formated_lines == 1
-                     ? _("file") : _("files")));
-           }
-
-         if (n_mismatched_checksums > 0)
-           {
-             error (0, 0,
-                  _("WARNING: %d of %d computed %s did NOT match"),
-                    n_mismatched_checksums, n_computed_checkums,
-                    (n_computed_checkums == 1
-                     ? _("checksum") : _("checksums")));
+                    ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
+                              " computed checksum did NOT match",
+                              "WARNING: %" PRIuMAX " of %" PRIuMAX
+                              " computed checksums did NOT match",
+                              n_computed_checksums),
+                    n_mismatched_checksums, n_computed_checksums);
            }
        }
     }
 
-  return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
-          && n_open_or_read_failures == 0) ? 0 : 1);
+  return (n_properly_formatted_lines != 0
+         && n_mismatched_checksums == 0
+         && n_open_or_read_failures == 0);
 }
 
 int
 main (int argc, char **argv)
 {
   unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES];
-  int do_check = 0;
+  bool do_check = false;
   int opt;
   char **string = NULL;
   size_t n_strings = 0;
-  int err = 0;
-  int file_type_specified = 0;
+  bool ok = true;
+  bool file_type_specified = false;
 
 #if O_BINARY
   /* Binary is default on MSDOS, so the actual file contents
      are used in computation.  */
-  int binary = 1;
+  bool binary = true;
 #else
   /* Text is default of the Plumb/Lankester format.  */
-  int binary = 0;
+  bool binary = false;
 #endif
 
   /* Setting values of global variables.  */
@@ -584,23 +589,23 @@ main (int argc, char **argv)
        }
        break;
       case 'b':
-       file_type_specified = 1;
-       binary = 1;
+       file_type_specified = true;
+       binary = true;
        break;
       case 'c':
-       do_check = 1;
+       do_check = true;
        break;
       case 2:
-       status_only = 1;
-       warn = 0;
+       status_only = true;
+       warn = false;
        break;
       case 't':
-       file_type_specified = 1;
-       binary = 0;
+       file_type_specified = true;
+       binary = false;
        break;
       case 'w':
-       status_only = 0;
-       warn = 1;
+       status_only = false;
+       warn = true;
        break;
       case_GETOPT_HELP_CHAR;
       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -611,7 +616,7 @@ main (int argc, char **argv)
   min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm);
   digest_hex_bytes = DIGEST_HEX_BYTES (algorithm);
 
-  if (file_type_specified && do_check)
+  if (file_type_specified & do_check)
     {
       error (0, 0, _("the --binary and --text options are meaningless when \
 verifying checksums"));
@@ -625,14 +630,14 @@ verifying checksums"));
       usage (EXIT_FAILURE);
     }
 
-  if (status_only && !do_check)
+  if (status_only & !do_check)
     {
       error (0, 0,
        _("the --status option is meaningful only when verifying checksums"));
       usage (EXIT_FAILURE);
     }
 
-  if (warn && !do_check)
+  if (warn & !do_check)
     {
       error (0, 0,
        _("the --warn option is meaningful only when verifying checksums"));
@@ -674,8 +679,8 @@ verifying checksums"));
          usage (EXIT_FAILURE);
        }
 
-      err = digest_check ((optind == argc) ? "-" : argv[optind],
-                         DIGEST_STREAM (algorithm));
+      ok = digest_check (optind == argc ? "-" : argv[optind],
+                        DIGEST_STREAM (algorithm));
     }
   else
     {
@@ -684,13 +689,12 @@ verifying checksums"));
 
       for (; optind < argc; ++optind)
        {
-         int fail;
          char *file = argv[optind];
 
-         fail = digest_file (file, binary, bin_buffer,
-                             DIGEST_STREAM (algorithm));
-         err |= fail;
-         if (!fail)
+         if (! digest_file (file, binary, bin_buffer,
+                            DIGEST_STREAM (algorithm)))
+           ok = false;
+         else
            {
              size_t i;
 
@@ -735,5 +739,5 @@ verifying checksums"));
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));
 
-  exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
 }




reply via email to

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