MFC r1.6 (HEAD):
[dragonfly.git] / bin / cpdup / md5.c
blob3dbfc659433f9ae67ea8ebe933bef958a3aa079e
1 /*-
2 * MD5.C
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.2 2008/03/22 18:09:16 dillon Exp $
9 */
11 #include "cpdup.h"
13 typedef struct MD5Node {
14 struct MD5Node *md_Next;
15 char *md_Name;
16 char *md_Code;
17 int md_Accessed;
18 } MD5Node;
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;
29 void
30 md5_flush(void)
32 if (MD5SCacheDirty && MD5SCache) {
33 FILE *fo;
35 if ((fo = fopen(MD5SCache, "w")) != NULL) {
36 MD5Node *node;
38 for (node = MD5Base; node; node = node->md_Next) {
39 if (node->md_Accessed && node->md_Code) {
40 fprintf(fo, "%s %d %s\n",
41 node->md_Code,
42 strlen(node->md_Name),
43 node->md_Name
47 fclose(fo);
51 MD5SCacheDirty = 0;
53 if (MD5SCache) {
54 MD5Node *node;
56 while ((node = MD5Base) != NULL) {
57 MD5Base = node->md_Next;
59 if (node->md_Code)
60 free(node->md_Code);
61 if (node->md_Name)
62 free(node->md_Name);
63 free(node);
65 free(MD5SCache);
66 MD5SCache = NULL;
70 static void
71 md5_cache(const char *spath, int sdirlen)
73 FILE *fi;
76 * Already cached
79 if (
80 MD5SCache &&
81 sdirlen == MD5SCacheDirLen &&
82 strncmp(spath, MD5SCache, sdirlen) == 0
83 ) {
84 return;
88 * Different cache, flush old cache
91 if (MD5SCache != NULL)
92 md5_flush();
95 * Create new cache
98 MD5SCacheDirLen = sdirlen;
99 MD5SCache = mprintf("%*.*s%s", sdirlen, sdirlen, spath, MD5CacheFile);
101 if ((fi = fopen(MD5SCache, "r")) != NULL) {
102 MD5Node **pnode = &MD5Base;
103 int c;
105 c = fgetc(fi);
106 while (c != EOF) {
107 MD5Node *node = *pnode = malloc(sizeof(MD5Node));
108 char *s;
109 int nlen;
111 nlen = 0;
113 if (pnode == NULL || node == NULL) {
114 fprintf(stderr, "out of memory\n");
115 exit(EXIT_FAILURE);
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);
123 free(s);
126 * extracting md_Name - name may contain embedded control
127 * characters.
129 CountSourceReadBytes += nlen+1;
130 node->md_Name = fextract(fi, nlen, &c, EOF);
131 if (c != '\n') {
132 fprintf(stderr, "Error parsing MD5 Cache: %s (%c)\n", MD5SCache, c);
133 while (c != EOF && c != '\n')
134 c = fgetc(fi);
136 if (c != EOF)
137 c = fgetc(fi);
138 pnode = &node->md_Next;
140 fclose(fi);
145 * md5_lookup: lookup/create md5 entry
148 static MD5Node *
149 md5_lookup(const char *sfile)
151 MD5Node **pnode;
152 MD5Node *node;
154 for (pnode = &MD5Base; (node = *pnode) != NULL; pnode = &node->md_Next) {
155 if (strcmp(sfile, node->md_Name) == 0) {
156 break;
159 if (node == NULL) {
161 if ((node = *pnode = malloc(sizeof(MD5Node))) == NULL) {
162 fprintf(stderr,"out of memory\n");
163 exit(EXIT_FAILURE);
166 bzero(node, sizeof(MD5Node));
167 node->md_Name = strdup(sfile);
169 node->md_Accessed = 1;
170 return(node);
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
180 * the source MD5.
183 md5_check(const char *spath, const char *dpath)
185 const char *sfile;
186 char *dcode;
187 int sdirlen;
188 int r;
189 MD5Node *node;
191 r = -1;
193 if ((sfile = strrchr(spath, '/')) != NULL)
194 ++sfile;
195 else
196 sfile = spath;
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
207 if (dpath == NULL) {
208 char *scode = doMD5File(spath, NULL, 0);
210 r = 0;
211 if (node->md_Code == NULL) {
212 r = -1;
213 node->md_Code = scode;
214 MD5SCacheDirty = 1;
215 } else if (strcmp(scode, node->md_Code) != 0) {
216 r = -1;
217 free(node->md_Code);
218 node->md_Code = scode;
219 MD5SCacheDirty = 1;
220 } else {
221 free(scode);
223 return(r);
227 * Otherwise the .MD5* file is used as a cache.
230 if (node->md_Code == NULL) {
231 node->md_Code = doMD5File(spath, NULL, 0);
232 MD5SCacheDirty = 1;
235 dcode = doMD5File(dpath, NULL, 1);
236 if (dcode) {
237 if (strcmp(node->md_Code, dcode) == 0) {
238 r = 0;
239 } else {
240 char *scode = doMD5File(spath, NULL, 0);
242 if (strcmp(node->md_Code, scode) == 0) {
243 free(scode);
244 } else {
245 free(node->md_Code);
246 node->md_Code = scode;
247 MD5SCacheDirty = 1;
248 if (strcmp(node->md_Code, dcode) == 0)
249 r = 0;
252 free(dcode);
254 return(r);
257 char *
258 doMD5File(const char *filename, char *buf, int is_target)
260 if (SummaryOpt) {
261 struct stat st;
262 if (stat(filename, &st) == 0) {
263 u_int64_t size = st.st_size;
264 if (is_target)
265 CountTargetReadBytes += size;
266 else
267 CountSourceReadBytes += size;
270 return MD5File(filename, buf);