4 * (c) Copyright 1997-1999 by Matthew Dillon and Dima Ruban. Permission to
5 * use and distribute based on the FreeBSD copyright. Supplied as-is,
6 * USE WITH EXTREME CAUTION.
14 #include <openssl/md5.h>
17 typedef struct MD5Node {
18 struct MD5Node *md_Next;
24 static MD5Node *md5_lookup(const char *sfile);
25 static void md5_cache(const char *spath, int sdirlen);
26 static char *doMD5File(const char *filename, char *buf, int is_target);
28 static char *MD5SCache; /* cache source directory name */
29 static MD5Node *MD5Base;
30 static int MD5SCacheDirLen;
31 static int MD5SCacheDirty;
36 if (MD5SCacheDirty && MD5SCache && NotForRealOpt == 0) {
39 if ((fo = fopen(MD5SCache, "w")) != NULL) {
42 for (node = MD5Base; node; node = node->md_Next) {
43 if (node->md_Accessed && node->md_Code) {
44 fprintf(fo, "%s %zu %s\n",
46 strlen(node->md_Name),
60 while ((node = MD5Base) != NULL) {
61 MD5Base = node->md_Next;
75 md5_cache(const char *spath, int sdirlen)
85 sdirlen == MD5SCacheDirLen &&
86 strncmp(spath, MD5SCache, sdirlen) == 0
92 * Different cache, flush old cache
95 if (MD5SCache != NULL)
102 MD5SCacheDirLen = sdirlen;
103 MD5SCache = mprintf("%*.*s%s", sdirlen, sdirlen, spath, MD5CacheFile);
105 if ((fi = fopen(MD5SCache, "r")) != NULL) {
106 MD5Node **pnode = &MD5Base;
111 MD5Node *node = *pnode = malloc(sizeof(MD5Node));
117 if (pnode == NULL || node == NULL) {
118 fprintf(stderr, "out of memory\n");
122 bzero(node, sizeof(MD5Node));
123 node->md_Code = fextract(fi, -1, &c, ' ');
124 node->md_Accessed = 1;
125 if ((s = fextract(fi, -1, &c, ' ')) != NULL) {
126 nlen = strtol(s, NULL, 0);
130 * extracting md_Name - name may contain embedded control
133 CountSourceReadBytes += nlen+1;
134 node->md_Name = fextract(fi, nlen, &c, EOF);
136 fprintf(stderr, "Error parsing MD5 Cache: %s (%c)\n", MD5SCache, c);
137 while (c != EOF && c != '\n')
142 pnode = &node->md_Next;
149 * md5_lookup: lookup/create md5 entry
153 md5_lookup(const char *sfile)
158 for (pnode = &MD5Base; (node = *pnode) != NULL; pnode = &node->md_Next) {
159 if (strcmp(sfile, node->md_Name) == 0) {
165 if ((node = *pnode = malloc(sizeof(MD5Node))) == NULL) {
166 fprintf(stderr,"out of memory\n");
170 bzero(node, sizeof(MD5Node));
171 node->md_Name = strdup(sfile);
173 node->md_Accessed = 1;
178 * md5_check: check MD5 against file
180 * Return -1 if check failed
181 * Return 0 if check succeeded
183 * dpath can be NULL, in which case we are force-updating
187 md5_check(const char *spath, const char *dpath)
197 if ((sfile = strrchr(spath, '/')) != NULL)
201 sdirlen = sfile - spath;
203 md5_cache(spath, sdirlen);
205 node = md5_lookup(sfile);
208 * If dpath == NULL, we are force-updating the source .MD5* files
212 char *scode = doMD5File(spath, NULL, 0);
215 if (node->md_Code == NULL) {
217 node->md_Code = scode;
219 } else if (strcmp(scode, node->md_Code) != 0) {
222 node->md_Code = scode;
231 * Otherwise the .MD5* file is used as a cache.
234 if (node->md_Code == NULL) {
235 node->md_Code = doMD5File(spath, NULL, 0);
239 dcode = doMD5File(dpath, NULL, 1);
241 if (strcmp(node->md_Code, dcode) == 0) {
244 char *scode = doMD5File(spath, NULL, 0);
246 if (strcmp(node->md_Code, scode) == 0) {
250 node->md_Code = scode;
252 if (strcmp(node->md_Code, dcode) == 0)
263 md5_file(const char *filename, char *buf)
265 unsigned char digest[MD5_DIGEST_LENGTH];
266 static const char hex[]="0123456789abcdef";
268 unsigned char buffer[4096];
273 fd = open(filename, O_RDONLY);
276 if (fstat(fd, &st) < 0) {
285 if ((size_t)size > sizeof(buffer))
286 bytes = read(fd, buffer, sizeof(buffer));
288 bytes = read(fd, buffer, size);
291 MD5_Update(&ctx, buffer, bytes);
301 buf = malloc(MD5_DIGEST_LENGTH * 2 + 1);
305 MD5_Final(digest, &ctx);
306 for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
307 buf[2*i] = hex[digest[i] >> 4];
308 buf[2*i+1] = hex[digest[i] & 0x0f];
310 buf[MD5_DIGEST_LENGTH * 2] = '\0';
317 doMD5File(const char *filename, char *buf, int is_target)
321 if (stat(filename, &st) == 0) {
322 uint64_t size = st.st_size;
324 CountTargetReadBytes += size;
326 CountSourceReadBytes += size;
330 return MD5File(filename, buf);
332 return md5_file(filename, buf);