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.
8 * $DragonFly: src/bin/cpdup/md5.c,v 1.3 2008/11/10 14:30:02 swildner Exp $
13 typedef struct MD5Node {
14 struct MD5Node *md_Next;
20 static MD5Node *md5_lookup(const char *sfile);
21 static void md5_cache(const char *spath, int sdirlen);
22 static char *doMD5File(const char *filename, char *buf, int is_target);
24 static char *MD5SCache; /* cache source directory name */
25 static MD5Node *MD5Base;
26 static int MD5SCacheDirLen;
27 static int MD5SCacheDirty;
32 if (MD5SCacheDirty && MD5SCache) {
35 if ((fo = fopen(MD5SCache, "w")) != NULL) {
38 for (node = MD5Base; node; node = node->md_Next) {
39 if (node->md_Accessed && node->md_Code) {
40 fprintf(fo, "%s %zu %s\n",
42 strlen(node->md_Name),
56 while ((node = MD5Base) != NULL) {
57 MD5Base = node->md_Next;
71 md5_cache(const char *spath, int sdirlen)
81 sdirlen == MD5SCacheDirLen &&
82 strncmp(spath, MD5SCache, sdirlen) == 0
88 * Different cache, flush old cache
91 if (MD5SCache != NULL)
98 MD5SCacheDirLen = sdirlen;
99 MD5SCache = mprintf("%*.*s%s", sdirlen, sdirlen, spath, MD5CacheFile);
101 if ((fi = fopen(MD5SCache, "r")) != NULL) {
102 MD5Node **pnode = &MD5Base;
107 MD5Node *node = *pnode = malloc(sizeof(MD5Node));
113 if (pnode == NULL || node == NULL) {
114 fprintf(stderr, "out of memory\n");
118 bzero(node, sizeof(MD5Node));
119 node->md_Code = fextract(fi, -1, &c, ' ');
120 node->md_Accessed = 1;
121 if ((s = fextract(fi, -1, &c, ' ')) != NULL) {
122 nlen = strtol(s, NULL, 0);
126 * extracting md_Name - name may contain embedded control
129 CountSourceReadBytes += nlen+1;
130 node->md_Name = fextract(fi, nlen, &c, EOF);
132 fprintf(stderr, "Error parsing MD5 Cache: %s (%c)\n", MD5SCache, c);
133 while (c != EOF && c != '\n')
138 pnode = &node->md_Next;
145 * md5_lookup: lookup/create md5 entry
149 md5_lookup(const char *sfile)
154 for (pnode = &MD5Base; (node = *pnode) != NULL; pnode = &node->md_Next) {
155 if (strcmp(sfile, node->md_Name) == 0) {
161 if ((node = *pnode = malloc(sizeof(MD5Node))) == NULL) {
162 fprintf(stderr,"out of memory\n");
166 bzero(node, sizeof(MD5Node));
167 node->md_Name = strdup(sfile);
169 node->md_Accessed = 1;
174 * md5_check: check MD5 against file
176 * Return -1 if check failed
177 * Return 0 if check succeeded
179 * dpath can be NULL, in which case we are force-updating
183 md5_check(const char *spath, const char *dpath)
193 if ((sfile = strrchr(spath, '/')) != NULL)
197 sdirlen = sfile - spath;
199 md5_cache(spath, sdirlen);
201 node = md5_lookup(sfile);
204 * If dpath == NULL, we are force-updating the source .MD5* files
208 char *scode = doMD5File(spath, NULL, 0);
211 if (node->md_Code == NULL) {
213 node->md_Code = scode;
215 } else if (strcmp(scode, node->md_Code) != 0) {
218 node->md_Code = scode;
227 * Otherwise the .MD5* file is used as a cache.
230 if (node->md_Code == NULL) {
231 node->md_Code = doMD5File(spath, NULL, 0);
235 dcode = doMD5File(dpath, NULL, 1);
237 if (strcmp(node->md_Code, dcode) == 0) {
240 char *scode = doMD5File(spath, NULL, 0);
242 if (strcmp(node->md_Code, scode) == 0) {
246 node->md_Code = scode;
248 if (strcmp(node->md_Code, dcode) == 0)
258 doMD5File(const char *filename, char *buf, int is_target)
262 if (stat(filename, &st) == 0) {
263 u_int64_t size = st.st_size;
265 CountTargetReadBytes += size;
267 CountSourceReadBytes += size;
270 return MD5File(filename, buf);