md5sum.c 5.1 KB

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