home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / ftp.vapor.com / 3rdparty / md5sum.lzx / source / md5sum.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-11  |  7.2 KB  |  252 lines

  1. /*
  2.  * md5sum.c     - Generate/check MD5 Message Digests
  3.  *
  4.  * Compile and link with md5.c.  If you don't have getopt() in your library
  5.  * also include getopt.c.  For MSDOS you can also link with the wildcard
  6.  * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC)
  7.  * so that you can use wildcards on the commandline.
  8.  *
  9.  * Written March 1993 by Branko Lankester
  10.  * Modified June 1993 by Colin Plumb for altered md5.c.
  11.  * Modified Sept 1993 by Peter Simons to compile on the Amiga.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "md5.h"
  18. #include "getopt.h"
  19.  
  20. #ifdef UNIX
  21. #define FOPRTXT "r"
  22. #define FOPRBIN "r"
  23. #else
  24. #ifdef VMS
  25. #define FOPRTXT "r","ctx=stm"
  26. #define FOPRBIN "rb","ctx=stm"
  27. #else
  28. #define FOPRTXT "r"
  29. #define FOPRBIN "rb"
  30. #endif
  31. #endif
  32.  
  33. #define USAGE "usage: md5sum [-bv] [-c [file]] | [file...]\n"           \
  34.         "Generates or checks MD5 Message Digests\n"                     \
  35.         "    -c  check message digests (default is generate)\n"         \
  36.         "    -v  verbose, print file names when checking\n"             \
  37.         "    -b  read files in binary mode\n"                           \
  38.         "The input for -c should be the list of message digests and "   \
  39.         "file names\nthat is printed on stdout by this program "        \
  40.         "when it generates digests.\n"
  41.  
  42.  
  43. extern char *optarg;
  44. extern int optind;
  45.  
  46. void usage(void);
  47. void print_digest(unsigned char *);
  48. int mdfile(FILE *fp, unsigned char *digest);
  49. int do_check(FILE *chkf);
  50.  
  51. char *progname;
  52. int verbose = 0;
  53. int bin_mode = 0;
  54.  
  55. void
  56. main(int argc, char **argv)
  57. {
  58.         int opt, rc = 0;
  59.         int check = 0;
  60.         FILE *fp;
  61.         unsigned char digest[16];
  62.  
  63.         progname = *argv;
  64.         while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
  65.                 switch (opt) {
  66.                         case 'c': check = 1; break;
  67.                         case 'v': verbose = 1; break;
  68.                         case 'b': bin_mode = 1; break;
  69.                         default: usage();
  70.                 }
  71.         }
  72.         argc -= optind;
  73.         argv += optind;
  74.         if (check) {
  75.                 switch (argc) {
  76.                         case 0: fp = stdin; break;
  77.                         case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
  78.                                         perror(*argv);
  79.                                         exit(2);
  80.                                 }
  81.                                 break;
  82.                         default: usage();
  83.                 }
  84.                 exit(do_check(fp));
  85.         }
  86.         if (argc == 0) {
  87.                 if (mdfile(stdin, digest)) {
  88.                         fprintf(stderr, "%s: read error on stdin\n", progname);
  89.                         exit(2);
  90.                 }
  91.                 print_digest(digest);
  92.                 printf("\n");
  93.                 exit(0);
  94.         }
  95.         for ( ; argc > 0; --argc, ++argv) {
  96.                 if (bin_mode)
  97.                         fp = fopen(*argv, FOPRBIN);
  98.                 else
  99.                         fp = fopen(*argv, FOPRTXT);
  100.                 if (fp == NULL) {
  101.                         perror(*argv);
  102.                         rc = 2;
  103.                         continue;
  104.                 }
  105.                 if (mdfile(fp, digest)) {
  106.                         fprintf(stderr, "%s: error reading %s\n", progname, *argv);
  107.                         rc = 2;
  108.                 } else {
  109.                         print_digest(digest);
  110.                         printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
  111.                 }
  112.                 fclose(fp);
  113.         }
  114.         exit(rc);
  115. }
  116.  
  117. void
  118. usage()
  119. {
  120.         fprintf(stderr, USAGE);
  121.         exit(2);
  122. }
  123.  
  124. int
  125. mdfile(FILE *fp, unsigned char *digest)
  126. {
  127.         unsigned char buf[1024];
  128.         MD5_CTX ctx;
  129.         int n;
  130.  
  131.         MD5Init(&ctx);
  132.         while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
  133.                 MD5Update(&ctx, buf, n);
  134.         MD5Final(digest, &ctx);
  135.         if (ferror(fp))
  136.                 return -1;
  137.         return 0;
  138. }
  139.  
  140. void
  141. print_digest(unsigned char *p)
  142. {
  143.         int i;
  144.  
  145.         for (i = 0; i < 16; ++i)
  146.                 printf("%02x", *p++);
  147. }
  148.  
  149. int
  150. hex_digit(int c)
  151. {
  152.         if (c >= '0' && c <= '9')
  153.                 return c - '0';
  154.         if (c >= 'a' && c <= 'f')
  155.                 return c - 'a' + 10;
  156.         return -1;
  157. }
  158.  
  159. int
  160. get_md5_line(FILE *fp, unsigned char *digest, char *file)
  161. {
  162.         char buf[1024];
  163.         int i, d1, d2, rc;
  164.         char *p = buf;
  165.  
  166.         if (fgets(buf, sizeof(buf), fp) == NULL)
  167.                 return -1;
  168.  
  169.         for (i = 0; i < 16; ++i) {
  170.                 if ((d1 = hex_digit(*p++)) == -1)
  171.                         return 0;
  172.                 if ((d2 = hex_digit(*p++)) == -1)
  173.                         return 0;
  174.                 *digest++ = d1*16 + d2;
  175.         }
  176.         if (*p++ != ' ')
  177.                 return 0;
  178.         /*
  179.          * next char is an attribute char, space means text file
  180.          * if it's a '*' the file should be checked in binary mode.
  181.          */
  182.         if (*p == ' ')
  183.                 rc = 1;
  184.         else if (*p == '*')
  185.                 rc = 2;
  186.         else {
  187.                 fprintf(stderr, "%s: unrecognized line: %s", progname, buf);
  188.                 return 0;
  189.         }
  190.         ++p;
  191.         i = strlen(p);
  192.         if (i < 2 || i > 255)
  193.                 return 0;
  194.         p[i-1] = '\0';
  195.         strcpy(file, p);
  196.         return rc;
  197. }
  198.  
  199. int
  200. do_check(FILE *chkf)
  201. {
  202.         int rc, ex = 0, failed = 0, checked = 0;
  203.         unsigned char chk_digest[16], file_digest[16];
  204.         char filename[256];
  205.         FILE *fp;
  206.         int flen = 14;
  207.  
  208.         while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
  209.                 if (rc == 0)    /* not an md5 line */
  210.                         continue;
  211.                 if (verbose) {
  212.                         if (strlen(filename) > flen)
  213.                                 flen = strlen(filename);
  214.                         fprintf(stderr, "%-*s ", flen, filename);
  215.                 }
  216.                 if (bin_mode || rc == 2)
  217.                         fp = fopen(filename, FOPRBIN);
  218.                 else
  219.                         fp = fopen(filename, FOPRTXT);
  220.                 if (fp == NULL) {
  221.                         fprintf(stderr, "%s: can't open %s\n", progname, filename);
  222.                         ex = 2;
  223.                         continue;
  224.                 }
  225.                 if (mdfile(fp, file_digest)) {
  226.                         fprintf(stderr, "%s: error reading %s\n", progname, filename);
  227.                         ex = 2;
  228.                         fclose(fp);
  229.                         continue;
  230.                 }
  231.                 fclose(fp);
  232.                 if (memcmp(chk_digest, file_digest, 16) != 0) {
  233.                         if (verbose)
  234.                                 fprintf(stderr, "FAILED\n");
  235.                         else
  236.                                 fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename);
  237.                         ++failed;
  238.                 } else if (verbose)
  239.                         fprintf(stderr, "OK\n");
  240.                 ++checked;
  241.         }
  242.         if (verbose && failed)
  243.                 fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked);
  244.         if (!checked) {
  245.                 fprintf(stderr, "%s: no files checked\n", progname);
  246.                 return 3;
  247.         }
  248.         if (!ex && failed)
  249.                 ex = 1;
  250.         return ex;
  251. }
  252.