summaryrefslogtreecommitdiff
path: root/md5sum
diff options
context:
space:
mode:
authorIan Jackson <ian@chiark.chu.cam.ac.uk>1996-04-04 01:58:40 +0100
committerIan Jackson <ian@chiark.chu.cam.ac.uk>1996-04-04 01:58:40 +0100
commit1b80fb16c22db72457d7a456ffbf1f70a8dfc0a5 (patch)
treec0ee53eba4e71f4c246ee9e45fbd90e931bbd1f9 /md5sum
downloaddpkg-1b80fb16c22db72457d7a456ffbf1f70a8dfc0a5.tar.gz
dpkg (1.1.4); priority=MEDIUM
* Allow overwriting of conflicting packages being removed. (Bug#2614.) * a.out control file says Pre-Depends: libc4 | libc. (Bug#2640.) * ELF control file and libc dependencies changed to use finalised scheme. * ELF control file and libc dependencies for i386 only. (Bug#2617.) * Guidelines say use only released libraries and compilers. * Install wishlist as /usr/doc/dpkg/WISHLIST. * Remove spurious entries for Guidelines in info dir file. * dpkg-deb --build checks permissions on control (DEBIAN) directory. * Spaces in control file fields not copied by dpkg-split. (Bug#2633.) * Spaces in split file part control data ignore. (Bug#2633.) * Portability fixes, including patch from Richard Kettlewell. * Fixed minor configure.in bug causing mangled GCC -W options. -- Ian Jackson <ian@chiark.chu.cam.ac.uk> Thu, 4 Apr 1996 01:58:40 +0100
Diffstat (limited to 'md5sum')
-rw-r--r--md5sum/Makefile.in44
-rw-r--r--md5sum/md5.c241
-rw-r--r--md5sum/md5.h39
-rw-r--r--md5sum/md5sum.170
-rw-r--r--md5sum/md5sum.c246
5 files changed, 640 insertions, 0 deletions
diff --git a/md5sum/Makefile.in b/md5sum/Makefile.in
new file mode 100644
index 000000000..0cd7f852c
--- /dev/null
+++ b/md5sum/Makefile.in
@@ -0,0 +1,44 @@
+# (-*- Fundamental -*-)
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+mandir = $(prefix)/man/man1
+
+SRC = md5.c md5sum.c
+OBJ = md5.o md5sum.o
+HDR = md5.h
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib $(XLIBS)
+ALL_CFLAGS = -I../lib -I.. @DEFS@ $(CFLAGS)
+
+.SUFFIXES: .c .o
+
+.c.o:
+ $(CC) $(ALL_CFLAGS) -c $<
+
+all: md5sum
+
+md5sum: md5.o md5sum.o
+ $(CC) $(LDFLAGS) -o md5sum md5.o md5sum.o
+
+clean:
+ rm -f *.o core md5sum
+
+distclean: clean
+ rm -f Makefile *.orig *~ *.~* ./#*#
+
+install: all
+ $(INSTALL_PROGRAM) -s md5sum $(bindir)/md5sum
+ $(INSTALL_DATA) md5sum.1 $(mandir)/md5sum.1
diff --git a/md5sum/md5.c b/md5sum/md5.c
new file mode 100644
index 000000000..0ac9d192d
--- /dev/null
+++ b/md5sum/md5.c
@@ -0,0 +1,241 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for stupid systems */
+#include <netinet/in.h> /* for ntohl() */
+
+#include "config.h"
+#include "md5.h"
+
+#ifdef WORDS_BIGENDIAN
+void
+byteSwap(UWORD32 *buf, unsigned words)
+{
+ md5byte *p = (md5byte *)buf;
+
+ do {
+ *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
+ ((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+#else
+#define byteSwap(buf,words)
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
+{
+ UWORD32 t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy((md5byte *)ctx->in + 64 - t, buf, t);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(md5byte digest[16], struct MD5Context *ctx)
+{
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ md5byte *p = (md5byte *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ p = (md5byte *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ MD5Transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
+{
+ register UWORD32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
diff --git a/md5sum/md5.h b/md5sum/md5.h
new file mode 100644
index 000000000..021766c17
--- /dev/null
+++ b/md5sum/md5.h
@@ -0,0 +1,39 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define md5byte unsigned char
+
+struct MD5Context {
+ UWORD32 buf[4];
+ UWORD32 bytes[2];
+ UWORD32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
+
+#endif /* !MD5_H */
diff --git a/md5sum/md5sum.1 b/md5sum/md5sum.1
new file mode 100644
index 000000000..c5d5943cd
--- /dev/null
+++ b/md5sum/md5sum.1
@@ -0,0 +1,70 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.TH MD5SUM 1 "29th November 1995" "Lankester et al" "Debian GNU/Linux"
+.SH NAME
+md5sum \- generates or checks MD5 message digests
+
+.SH SYNOPSIS
+.B md5sum
+[-bv] [-c [file]] | [file...]
+
+.SH DESCRIPTION
+.B md5sum
+generates or checks MD5 checksums. The algorithm to generate the
+checksum is reasonably fast and strong enough for most cases. Exact
+specification of the algorithm is in
+.I RFC 1321.
+
+Normally
+.B md5sum
+generates checksums of all files given to it as a parameter and prints
+the checksums followed by the filenames. If, however,
+.B -c
+is specified, only one filename parameter is allowed. This file should
+contain checksums and filenames to which these checksums refer to, and
+the files listed in that file are checked against the checksums listed
+there. See option
+.B -c
+for more information.
+
+.SS OPTIONS
+.TP
+.B -b
+Use binary mode. In unix environment, only difference between this and
+the normal mode is an asterix preceding the filename in the output.
+.TP
+.B -c
+Check md5sum of all files listed in
+.I file
+against the checksum listed in the same file. The actual format of that
+file is the same as output of
+.B md5sum.
+That is, each line in the file describes a file. A line looks like:
+
+.B <MD5 checksum> <filename>
+
+So, for example, a file containing checksum for this manpage would look
+like(don't worry, if the checkusum doesn't match, there is a minor
+problem in keeping it up to date):
+
+.B c6514f34ffe6e1ce146e1f17db2c0f90 md5sum.1
+.TP
+.B -v
+Be more verbose. Print filenames when checking (with -c).
+
+.SH BUGS
+The related MD4 message digest algorithm was broken in October 1995.
+MD5 isn't looking as secure as it used to.
+
+This manpage is not quite accurate and has formatting inconsistent
+with other manpages.
+
+.B md5sum
+does not accept standard options like
+.BR -\-\help .
+
+.SH AUTHOR
+
+.B md5sum
+was originally written by Branko Lankester, and modified afterwards by
+Colin Plumb and Ian Jackson (ijackson@gnu.ai.mit.edu). Manual page was
+added by Juho Vuori (javuori@cc.helsinki.fi)
diff --git a/md5sum/md5sum.c b/md5sum/md5sum.c
new file mode 100644
index 000000000..cec2be761
--- /dev/null
+++ b/md5sum/md5sum.c
@@ -0,0 +1,246 @@
+/*
+ * md5sum.c - Generate/check MD5 Message Digests
+ *
+ * Compile and link with md5.c. If you don't have getopt() in your library
+ * also include getopt.c. For MSDOS you can also link with the wildcard
+ * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC)
+ * so that you can use wildcards on the commandline.
+ *
+ * Written March 1993 by Branko Lankester
+ * Modified June 1993 by Colin Plumb for altered md5.c.
+ * Modified Feburary 1995 by Ian Jackson for use with Colin Plumb's md5.c.
+ * This file is in the public domain.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "md5.h"
+
+#ifdef UNIX
+#define FOPRTXT "r"
+#define FOPRBIN "r"
+#else
+#ifdef VMS
+#define FOPRTXT "r","ctx=stm"
+#define FOPRBIN "rb","ctx=stm"
+#else
+#define FOPRTXT "r"
+#define FOPRBIN "rb"
+#endif
+#endif
+
+extern char *optarg;
+extern int optind;
+
+void usage();
+void print_digest();
+int mdfile(FILE *fp, unsigned char *digest);
+int do_check(FILE *chkf);
+
+char *progname;
+int verbose = 0;
+int bin_mode = 0;
+
+void
+main(int argc, char **argv)
+{
+ int opt, rc = 0;
+ int check = 0;
+ FILE *fp;
+ unsigned char digest[16];
+
+ progname = *argv;
+ while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
+ switch (opt) {
+ case 'c': check = 1; break;
+ case 'v': verbose = 1; break;
+ case 'b': bin_mode = 1; break;
+ default: usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (check) {
+ switch (argc) {
+ case 0: fp = stdin; break;
+ case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
+ perror(*argv);
+ exit(2);
+ }
+ break;
+ default: usage();
+ }
+ exit(do_check(fp));
+ }
+ if (argc == 0) {
+ if (mdfile(stdin, digest)) {
+ fprintf(stderr, "%s: read error on stdin\n", progname);
+ exit(2);
+ }
+ print_digest(digest);
+ printf("\n");
+ exit(0);
+ }
+ for ( ; argc > 0; --argc, ++argv) {
+ if (bin_mode)
+ fp = fopen(*argv, FOPRBIN);
+ else
+ fp = fopen(*argv, FOPRTXT);
+ if (fp == NULL) {
+ perror(*argv);
+ rc = 2;
+ continue;
+ }
+ if (mdfile(fp, digest)) {
+ fprintf(stderr, "%s: error reading %s\n", progname, *argv);
+ rc = 2;
+ } else {
+ print_digest(digest);
+ printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
+ }
+ fclose(fp);
+ }
+ exit(rc);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n");
+ fprintf(stderr, "Generates or checks MD5 Message Digests\n");
+ fprintf(stderr, " -c check message digests (default is generate)\n");
+ fprintf(stderr, " -v verbose, print file names when checking\n");
+ fprintf(stderr, " -b read files in binary mode\n");
+ fprintf(stderr, "The input for -c should be the list of message digests and file names\n");
+ fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n");
+ exit(2);
+}
+
+int
+mdfile(FILE *fp, unsigned char *digest)
+{
+ unsigned char buf[1024];
+ struct MD5Context ctx;
+ int n;
+
+ MD5Init(&ctx);
+ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
+ MD5Update(&ctx, buf, n);
+ MD5Final(digest, &ctx);
+ if (ferror(fp))
+ return -1;
+ return 0;
+}
+
+void
+print_digest(unsigned char *p)
+{
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ printf("%02x", *p++);
+}
+
+int
+hex_digit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+int
+get_md5_line(FILE *fp, unsigned char *digest, char *file)
+{
+ char buf[1024];
+ int i, d1, d2, rc;
+ char *p = buf;
+
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ return -1;
+
+ for (i = 0; i < 16; ++i) {
+ if ((d1 = hex_digit(*p++)) == -1)
+ return 0;
+ if ((d2 = hex_digit(*p++)) == -1)
+ return 0;
+ *digest++ = d1*16 + d2;
+ }
+ if (*p++ != ' ')
+ return 0;
+ /*
+ * next char is an attribute char, space means text file
+ * if it's a '*' the file should be checked in binary mode.
+ */
+ if (*p == ' ')
+ rc = 1;
+ else if (*p == '*')
+ rc = 2;
+ else {
+ fprintf(stderr, "%s: unrecognized line: %s", progname, buf);
+ return 0;
+ }
+ ++p;
+ i = strlen(p);
+ if (i < 2 || i > 255)
+ return 0;
+ p[i-1] = '\0';
+ strcpy(file, p);
+ return rc;
+}
+
+int
+do_check(FILE *chkf)
+{
+ int rc, ex = 0, failed = 0, checked = 0;
+ unsigned char chk_digest[16], file_digest[16];
+ char filename[256];
+ FILE *fp;
+ int flen = 14;
+
+ while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
+ if (rc == 0) /* not an md5 line */
+ continue;
+ if (verbose) {
+ if (strlen(filename) > flen)
+ flen = strlen(filename);
+ fprintf(stderr, "%-*s ", flen, filename);
+ }
+ if (bin_mode || rc == 2)
+ fp = fopen(filename, FOPRBIN);
+ else
+ fp = fopen(filename, FOPRTXT);
+ if (fp == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, filename);
+ ex = 2;
+ continue;
+ }
+ if (mdfile(fp, file_digest)) {
+ fprintf(stderr, "%s: error reading %s\n", progname, filename);
+ ex = 2;
+ fclose(fp);
+ continue;
+ }
+ fclose(fp);
+ if (memcmp(chk_digest, file_digest, 16) != 0) {
+ if (verbose)
+ fprintf(stderr, "FAILED\n");
+ else
+ fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename);
+ ++failed;
+ } else if (verbose)
+ fprintf(stderr, "OK\n");
+ ++checked;
+ }
+ if (verbose && failed)
+ fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked);
+ if (!checked) {
+ fprintf(stderr, "%s: no files checked\n", progname);
+ return 3;
+ }
+ if (!ex && failed)
+ ex = 1;
+ return ex;
+}