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.1 2006/04/25 21:30:45 dillon 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
);
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 %d %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 CountReadBytes
+= 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
);
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
);
235 dcode
= doMD5File(dpath
, NULL
);
237 if (strcmp(node
->md_Code
, dcode
) == 0) {
240 char *scode
= doMD5File(spath
, NULL
);
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
)
262 if (stat(filename
, &st
) == 0) {
263 u_int64_t size
= st
.st_blocks
* 512;
264 if (st
.st_size
% 512)
265 size
+= st
.st_size
% 512 - 512;
266 CountReadBytes
+= size
;
269 return MD5File(filename
, buf
);