4 * Tool to calculate and print MD5 checksums in jigdo's awkward
7 * Copyright (c) 2004-2019 Steve McIntyre <steve@einval.com>
15 #include <sys/types.h>
20 #include "jig-base64.h"
23 #define BUF_SIZE 65536
26 #define CKSUM_BITS 128
27 #define CKSUM_BYTES (CKSUM_BITS / 8)
28 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
29 #define BASE64_CKSUM_BYTES ((ROUND_UP (CKSUM_BITS, 6)) / 6)
32 #define MIN(x,y) ( ((x) < (y)) ? (x) : (y))
41 static int md5_file(char *filename, char *md5, int verbose)
45 unsigned char file_md5[CKSUM_BYTES] = {0};
46 char *base64_md5 = NULL;
47 struct mk_MD5Context file_context;
53 mk_MD5Init(&file_context);
55 /* Check if we're reading from stdin */
56 if (!strcmp("-", filename))
60 file = fopen(filename, "rb");
69 fprintf(stderr, "Unable to open file %s; error %d\n", filename, errno);
78 fprintf(stderr, "Checking %s:\r", filename);
88 file_size = st.st_size;
89 fprintf(stderr, "Checking %s: 0 / %lld bytes\r", filename, (long long)file_size);
93 fprintf(stderr, "Checking stdin: 0 bytes\r");
101 memset(buf, 0, BUF_SIZE);
103 used = fread(buf, 1, BUF_SIZE, file);
106 mk_MD5Update(&file_context, (unsigned char *)buf, used);
109 if (ferror(file) && (EISDIR != errno))
111 fprintf(stderr, "Unable to read from file %s; error %d\n",
120 fprintf(stderr, "Checking %s: %lld / %lld bytes\r",
121 filename, (long long) bytes_read, (long long)file_size);
123 fprintf(stderr, "Checking stdin: %lld bytes\r", (long long) bytes_read);
128 fprintf(stderr, "\n");
130 mk_MD5Final(file_md5, &file_context);
131 base64_md5 = base64_dump(file_md5, CKSUM_BYTES);
132 memcpy(md5, base64_md5, BASE64_CKSUM_BYTES + 1);
142 static int md5_check(char *filename, int verbose)
148 char base64_md5[BASE64_CKSUM_BYTES + 1] = {0};
151 /* Check if we're reading from stdin */
152 if (!strcmp("-", filename))
156 file = fopen(filename, "rb");
165 fprintf(stderr, "Unable to open file %s; error %d\n", filename, errno);
172 while ((read = getline(&line, &len, file)) != -1) {
173 /* Check the format of the line we've read. Should be:
175 <N chars of sum><SPACE><SPACE><filename>
177 where N == BASE64_CKSUM_BYTES
179 Look for the spaces and length at least. Use the strings
180 directly in the buffer, add pointers to them in place.
186 if (read > (BASE64_CKSUM_BYTES + 2)
187 && line[BASE64_CKSUM_BYTES] == ' '
188 && line[BASE64_CKSUM_BYTES + 1] == ' ')
190 line[BASE64_CKSUM_BYTES] = 0;
192 this_filename = &line[BASE64_CKSUM_BYTES + 2];
193 if (line[read - 1] == '\n')
196 this_error = md5_file(this_filename, base64_md5, verbose);
199 fprintf(stderr, "Failed to read %s, error %d (%s)\n",
200 this_filename, this_error, strerror(errno));
204 if (strcmp(base64_md5, this_md5))
207 fprintf(stderr, "FAILED: %s\n", this_filename);
213 fprintf(stderr, "OK: %s\n", this_filename);
219 printf("ignoring malformed line %s\n", line);
230 int main(int argc, char **argv)
233 char base64_md5[BASE64_CKSUM_BYTES];
234 enum mode_e mode = MODE_CALC;
241 c = getopt(argc, argv, "cv");
256 if (mode == MODE_CALC)
260 if (!md5_file("-", base64_md5, verbose))
261 printf("%s %s\n", base64_md5, "-");
265 for (i = optind; i < argc; i++)
267 if (!md5_file(argv[i], base64_md5, verbose))
268 printf("%s %s\n", base64_md5, argv[i]);
277 error += md5_check("-", verbose);
281 for (i = optind; i < argc; i++)
282 error += md5_check(argv[i], verbose);