Skip to content

Commit 228afa4

Browse files
committed
Convert to LibreSSL/OpenSSL EVP hash API
Add option "-c digest" to use any of supported EVP message digests instead of MD5. This generates checksum files named by the digest by default, e.g .SHA256.CHECKSUMS The "-M filename" option to rename the checksum file remains untouched
1 parent 68cb3cb commit 228afa4

File tree

5 files changed

+428
-364
lines changed

5 files changed

+428
-364
lines changed

src/checksum.c

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
/*-
2+
* checksum.c
3+
*
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.
7+
*/
8+
9+
#include "cpdup.h"
10+
11+
#include <openssl/evp.h>
12+
13+
typedef struct CSUMNode {
14+
struct CSUMNode *csum_Next;
15+
char *csum_Name;
16+
char *csum_Code;
17+
int csum_Accessed;
18+
} CSUMNode;
19+
20+
static CSUMNode *csum_lookup(const char *sfile);
21+
static void csum_cache(const char *spath, int sdirlen);
22+
static char *doCsumFile(const EVP_MD *algo, const char *filename, char *buf, int is_target);
23+
24+
static char *CSUMSCache; /* cache source directory name */
25+
static CSUMNode *CSUMBase;
26+
static int CSUMSCacheDirLen;
27+
static int CSUMSCacheDirty;
28+
29+
void
30+
csum_flush(void)
31+
{
32+
if (CSUMSCacheDirty && CSUMSCache && NotForRealOpt == 0) {
33+
FILE *fo;
34+
35+
if ((fo = fopen(CSUMSCache, "w")) != NULL) {
36+
CSUMNode *node;
37+
38+
for (node = CSUMBase; node; node = node->csum_Next) {
39+
if (node->csum_Accessed && node->csum_Code) {
40+
fprintf(fo, "%s %zu %s\n",
41+
node->csum_Code,
42+
strlen(node->csum_Name),
43+
node->csum_Name
44+
);
45+
}
46+
}
47+
fclose(fo);
48+
}
49+
}
50+
51+
CSUMSCacheDirty = 0;
52+
53+
if (CSUMSCache) {
54+
CSUMNode *node;
55+
56+
while ((node = CSUMBase) != NULL) {
57+
CSUMBase = node->csum_Next;
58+
59+
if (node->csum_Code)
60+
free(node->csum_Code);
61+
if (node->csum_Name)
62+
free(node->csum_Name);
63+
free(node);
64+
}
65+
free(CSUMSCache);
66+
CSUMSCache = NULL;
67+
}
68+
}
69+
70+
static void
71+
csum_cache(const char *spath, int sdirlen)
72+
{
73+
FILE *fi;
74+
75+
/*
76+
* Already cached
77+
*/
78+
79+
if (
80+
CSUMSCache &&
81+
sdirlen == CSUMSCacheDirLen &&
82+
strncmp(spath, CSUMSCache, sdirlen) == 0
83+
) {
84+
return;
85+
}
86+
87+
/*
88+
* Different cache, flush old cache
89+
*/
90+
91+
if (CSUMSCache != NULL)
92+
csum_flush();
93+
94+
/*
95+
* Create new cache
96+
*/
97+
98+
CSUMSCacheDirLen = sdirlen;
99+
CSUMSCache = mprintf("%*.*s%s", sdirlen, sdirlen, spath, CsumCacheFile);
100+
101+
if ((fi = fopen(CSUMSCache, "r")) != NULL) {
102+
CSUMNode **pnode = &CSUMBase;
103+
int c;
104+
105+
c = fgetc(fi);
106+
while (c != EOF) {
107+
CSUMNode *node = *pnode = malloc(sizeof(CSUMNode));
108+
char *s;
109+
int nlen;
110+
111+
nlen = 0;
112+
113+
if (pnode == NULL || node == NULL) {
114+
fprintf(stderr, "out of memory\n");
115+
exit(EXIT_FAILURE);
116+
}
117+
118+
bzero(node, sizeof(CSUMNode));
119+
node->csum_Code = fextract(fi, -1, &c, ' ');
120+
node->csum_Accessed = 1;
121+
if ((s = fextract(fi, -1, &c, ' ')) != NULL) {
122+
nlen = strtol(s, NULL, 0);
123+
free(s);
124+
}
125+
/*
126+
* extracting csum_Name - name may contain embedded control
127+
* characters.
128+
*/
129+
CountSourceReadBytes += nlen+1;
130+
node->csum_Name = fextract(fi, nlen, &c, EOF);
131+
if (c != '\n') {
132+
fprintf(stderr, "Error parsing CSUM Cache: %s (%c)\n", CSUMSCache, c);
133+
while (c != EOF && c != '\n')
134+
c = fgetc(fi);
135+
}
136+
if (c != EOF)
137+
c = fgetc(fi);
138+
pnode = &node->csum_Next;
139+
}
140+
fclose(fi);
141+
}
142+
}
143+
144+
/*
145+
* csum_lookup: lookup/create csum entry
146+
*/
147+
148+
static CSUMNode *
149+
csum_lookup(const char *sfile)
150+
{
151+
CSUMNode **pnode;
152+
CSUMNode *node;
153+
154+
for (pnode = &CSUMBase; (node = *pnode) != NULL; pnode = &node->csum_Next) {
155+
if (strcmp(sfile, node->csum_Name) == 0) {
156+
break;
157+
}
158+
}
159+
if (node == NULL) {
160+
161+
if ((node = *pnode = malloc(sizeof(CSUMNode))) == NULL) {
162+
fprintf(stderr,"out of memory\n");
163+
exit(EXIT_FAILURE);
164+
}
165+
166+
bzero(node, sizeof(CSUMNode));
167+
node->csum_Name = strdup(sfile);
168+
}
169+
node->csum_Accessed = 1;
170+
return(node);
171+
}
172+
173+
/*
174+
* csum_check: check CSUM against file
175+
*
176+
* Return -1 if check failed
177+
* Return 0 if check succeeded
178+
*
179+
* dpath can be NULL, in which case we are force-updating
180+
* the source CSUM.
181+
*/
182+
int
183+
csum_check(const EVP_MD *algo, const char *spath, const char *dpath)
184+
{
185+
const char *sfile;
186+
char *dcode;
187+
int sdirlen;
188+
int r;
189+
CSUMNode *node;
190+
191+
r = -1;
192+
193+
if ((sfile = strrchr(spath, '/')) != NULL)
194+
++sfile;
195+
else
196+
sfile = spath;
197+
sdirlen = sfile - spath;
198+
199+
csum_cache(spath, sdirlen);
200+
201+
node = csum_lookup(sfile);
202+
203+
/*
204+
* If dpath == NULL, we are force-updating the source .CSUM* files
205+
*/
206+
207+
if (dpath == NULL) {
208+
char *scode = doCsumFile(algo, spath, NULL, 0);
209+
210+
r = 0;
211+
if (node->csum_Code == NULL) {
212+
r = -1;
213+
node->csum_Code = scode;
214+
CSUMSCacheDirty = 1;
215+
} else if (strcmp(scode, node->csum_Code) != 0) {
216+
r = -1;
217+
free(node->csum_Code);
218+
node->csum_Code = scode;
219+
CSUMSCacheDirty = 1;
220+
} else {
221+
free(scode);
222+
}
223+
return(r);
224+
}
225+
226+
/*
227+
* Otherwise the .CSUM* file is used as a cache.
228+
*/
229+
230+
if (node->csum_Code == NULL) {
231+
node->csum_Code = doCsumFile(algo, spath, NULL, 0);
232+
CSUMSCacheDirty = 1;
233+
}
234+
235+
dcode = doCsumFile(algo, dpath, NULL, 1);
236+
if (dcode) {
237+
if (strcmp(node->csum_Code, dcode) == 0) {
238+
r = 0;
239+
} else {
240+
char *scode = doCsumFile(algo, spath, NULL, 0);
241+
242+
if (strcmp(node->csum_Code, scode) == 0) {
243+
free(scode);
244+
} else {
245+
free(node->csum_Code);
246+
node->csum_Code = scode;
247+
CSUMSCacheDirty = 1;
248+
if (strcmp(node->csum_Code, dcode) == 0)
249+
r = 0;
250+
}
251+
}
252+
free(dcode);
253+
}
254+
return(r);
255+
}
256+
257+
static char *
258+
csum_file(const EVP_MD *algo, const char *filename, char *buf)
259+
{
260+
unsigned char digest[EVP_MAX_MD_SIZE];
261+
static const char hex[] = "0123456789abcdef";
262+
EVP_MD_CTX *ctx;
263+
unsigned char buffer[4096];
264+
struct stat st;
265+
off_t size;
266+
int fd, bytes;
267+
unsigned int i, csum_len;
268+
269+
fd = open(filename, O_RDONLY);
270+
if (fd < 0)
271+
return NULL;
272+
if (fstat(fd, &st) < 0) {
273+
bytes = -1;
274+
goto err;
275+
}
276+
277+
ctx = EVP_MD_CTX_new();
278+
if (!EVP_DigestInit_ex(ctx, algo, NULL)) {
279+
fprintf(stderr, "Unable to initialize CSUM digest.\n");
280+
exit(1);
281+
}
282+
size = st.st_size;
283+
bytes = 0;
284+
while (size > 0) {
285+
if ((size_t)size > sizeof(buffer))
286+
bytes = read(fd, buffer, sizeof(buffer));
287+
else
288+
bytes = read(fd, buffer, size);
289+
if (bytes < 0)
290+
break;
291+
if (!EVP_DigestUpdate(ctx, buffer, bytes)) {
292+
EVP_MD_CTX_free(ctx);
293+
fprintf(stderr, "Unable to update CSUM digest.\n");
294+
exit(1);
295+
}
296+
size -= bytes;
297+
}
298+
299+
err:
300+
close(fd);
301+
if (bytes < 0)
302+
return NULL;
303+
304+
if (!EVP_DigestFinal(ctx, digest, &csum_len)) {
305+
EVP_MD_CTX_free(ctx);
306+
fprintf(stderr, "Unable to finalize CSUM digest.\n");
307+
exit(1);
308+
}
309+
EVP_MD_CTX_free(ctx);
310+
311+
if (!buf)
312+
buf = malloc(csum_len * 2 + 1);
313+
if (!buf)
314+
return NULL;
315+
316+
for (i = 0; i < csum_len; i++) {
317+
buf[2*i] = hex[digest[i] >> 4];
318+
buf[2*i+1] = hex[digest[i] & 0x0f];
319+
}
320+
buf[csum_len * 2] = '\0';
321+
322+
return buf;
323+
}
324+
325+
char *
326+
doCsumFile(const EVP_MD *algo, const char *filename, char *buf, int is_target)
327+
{
328+
if (SummaryOpt) {
329+
struct stat st;
330+
if (stat(filename, &st) == 0) {
331+
uint64_t size = st.st_size;
332+
if (is_target)
333+
CountTargetReadBytes += size;
334+
else
335+
CountSourceReadBytes += size;
336+
}
337+
}
338+
return csum_file(algo, filename, buf);
339+
}

0 commit comments

Comments
 (0)