"Fossies" - the Fresh Open Source Software Archive 
Member "xorriso-1.5.4/libjte/checksum.c" (30 Jan 2021, 16633 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "checksum.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /*
2 * checksum.c
3 *
4 * Copyright (c) 2008-2019 Steve McIntyre <steve@einval.com>
5 *
6 * Implementation of a generic checksum interface, used in JTE.
7 *
8 * GNU GPL v2+
9 */
10
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14
15 #include <sys/types.h>
16 #include <regex.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21
22 #ifdef HAVE_STDINT_H
23 #include <stdint.h>
24 #else
25 #ifdef HAVE_INTTYPES_H
26 #include <inttypes.h>
27 #endif
28 #endif
29
30 #include "md5.h"
31 #include "sha1.h"
32 #include "sha256.h"
33 #include "sha512.h"
34 #include "checksum.h"
35
36 #ifdef THREADED_CHECKSUMS
37 #include <pthread.h>
38 #endif
39
40 static void md5_init(void *context)
41 {
42 mk_MD5Init(context);
43 }
44 static void md5_update(void *context, unsigned char const *buf, unsigned int len)
45 {
46 mk_MD5Update(context, buf, len);
47 }
48 static void md5_final(unsigned char *digest, void *context)
49 {
50 mk_MD5Final(digest, context);
51 }
52
53 static void sha1_init(void *context)
54 {
55 sha1_init_ctx(context);
56 }
57 static void sha1_update(void *context, unsigned char const *buf, unsigned int len)
58 {
59 sha1_write(context, buf, len);
60 }
61 static void sha1_final(unsigned char *digest, void *context)
62 {
63 sha1_finish_ctx(context);
64 memcpy(digest, sha1_read(context), 20);
65 }
66
67 static void sha256_init(void *context)
68 {
69 sha256_init_ctx(context);
70 }
71 static void sha256_update(void *context, unsigned char const *buf, unsigned int len)
72 {
73 sha256_process_bytes(buf, len, context);
74 }
75 static void sha256_final(unsigned char *digest, void *context)
76 {
77 sha256_finish_ctx(context, digest);
78 }
79
80 static void sha512_init(void *context)
81 {
82 sha512_init_ctx(context);
83 }
84 static void sha512_update(void *context, unsigned char const *buf, unsigned int len)
85 {
86 sha512_process_bytes(buf, len, context);
87 }
88 static void sha512_final(unsigned char *digest, void *context)
89 {
90 sha512_finish_ctx(context, digest);
91 }
92
93 struct checksum_details
94 {
95 char *name;
96 char *prog;
97 int digest_size;
98 int context_size;
99 void (*init)(void *context);
100 void (*update)(void *context, unsigned char const *buf, unsigned int len);
101 void (*final)(unsigned char *digest, void *context);
102 int check_used_value;
103 };
104
105 static const struct checksum_details algorithms[] =
106 {
107 {
108 "MD5",
109 "md5sum",
110 16,
111 sizeof(struct mk_MD5Context),
112 md5_init,
113 md5_update,
114 md5_final,
115 CHECK_MD5_USED
116 },
117 {
118 "SHA1",
119 "sha1sum",
120 20,
121 sizeof(SHA1_CONTEXT),
122 sha1_init,
123 sha1_update,
124 sha1_final,
125 CHECK_SHA1_USED
126 },
127 {
128 "SHA256",
129 "sha256sum",
130 32,
131 sizeof(struct sha256_ctx),
132 sha256_init,
133 sha256_update,
134 sha256_final,
135 CHECK_SHA256_USED
136 },
137 {
138 "SHA512",
139 "sha512sum",
140 64,
141 sizeof(struct sha512_ctx),
142 sha512_init,
143 sha512_update,
144 sha512_final,
145 CHECK_SHA512_USED
146 }
147 };
148
149 struct algo_context
150 {
151 void *context;
152 unsigned char *digest;
153 int enabled;
154 int finalised;
155 char *hexdump;
156 #ifdef THREADED_CHECKSUMS
157 unsigned char const *buf;
158 unsigned int len;
159 int which;
160 pthread_t thread;
161 struct _checksum_context *parent;
162 pthread_mutex_t start_mutex;
163 pthread_cond_t start_cv;
164 #endif
165 };
166
167 struct _checksum_context
168 {
169 #ifdef THREADED_CHECKSUMS
170 unsigned int index;
171 unsigned int threads_running;
172 unsigned int threads_desired;
173 pthread_mutex_t done_mutex;
174 pthread_cond_t done_cv;
175 #endif
176 char *owner;
177 struct algo_context algo[NUM_CHECKSUMS];
178 };
179
180 struct checksum_info *checksum_information(enum checksum_types which)
181 {
182 return (struct checksum_info *)&algorithms[which];
183 }
184
185 /* Dump a buffer in hex */
186 static void hex_dump_to_buffer(char *output_buffer, unsigned char *buf, size_t buf_size)
187 {
188 unsigned int i;
189 char *p = output_buffer;
190
191 memset(output_buffer, 0, 1 + (2*buf_size));
192 for (i = 0; i < buf_size ; i++)
193 p += sprintf(p, "%2.2x", buf[i]);
194 }
195
196 #ifdef THREADED_CHECKSUMS
197 static void *checksum_thread(void *arg)
198 {
199 struct algo_context *a = arg;
200 struct _checksum_context *c = a->parent;
201 int num_blocks_summed = 0;
202
203 while (1)
204 {
205 /* wait to be given some work to do */
206 pthread_mutex_lock(&a->start_mutex);
207 while (a->buf == NULL)
208 {
209 pthread_cond_wait(&a->start_cv, &a->start_mutex);
210 }
211 pthread_mutex_unlock(&a->start_mutex);
212
213 /* if we're given a zero-length buffer, then that means we're
214 * done */
215 if (a->len == 0)
216 break;
217
218 /* actually do the checksum on the supplied buffer */
219 algorithms[a->which].update(a->context, a->buf, a->len);
220 num_blocks_summed++;
221 a->buf = NULL;
222
223 /* and tell the main thread that we're done with that
224 * buffer */
225 pthread_mutex_lock(&c->done_mutex);
226 c->threads_running--;
227 if (c->threads_running == 0)
228 pthread_cond_signal(&c->done_cv);
229 pthread_mutex_unlock(&c->done_mutex);
230 }
231
232 pthread_exit(NULL);
233 }
234 #endif
235
236 checksum_context_t *checksum_init_context(int checksums, const char *owner)
237 {
238 int i = 0;
239 #ifdef THREADED_CHECKSUMS
240 int ret = 0;
241 #endif
242
243 struct _checksum_context *context = calloc(1, sizeof(struct _checksum_context));
244
245 if (!context)
246 return NULL;
247
248 context->owner = strdup(owner);
249 if (!context->owner)
250 {
251 free(context);
252 return NULL;
253 }
254
255 #ifdef THREADED_CHECKSUMS
256 pthread_mutex_init(&context->done_mutex, NULL);
257 pthread_cond_init(&context->done_cv, NULL);
258 context->index = 0;
259 context->threads_running = 0;
260 context->threads_desired = 0;
261
262 for (i = 0; i < NUM_CHECKSUMS; i++)
263 if ( (1 << i) & checksums)
264 context->threads_desired++;
265 #endif
266
267 for (i = 0; i < NUM_CHECKSUMS; i++)
268 {
269 struct algo_context *a = &context->algo[i];
270 if ( (1 << i) & checksums)
271 {
272 a->context = malloc(algorithms[i].context_size);
273 if (!a->context)
274 {
275 checksum_free_context(context);
276 return NULL;
277 }
278 a->digest = malloc(algorithms[i].digest_size);
279 if (!a->digest)
280 {
281 checksum_free_context(context);
282 return NULL;
283 }
284 a->hexdump = malloc(1 + (2*algorithms[i].digest_size));
285 if (!a->hexdump)
286 {
287 checksum_free_context(context);
288 return NULL;
289 }
290 algorithms[i].init(a->context);
291 a->enabled = 1;
292 a->finalised = 0;
293 #ifdef THREADED_CHECKSUMS
294 a->which = i;
295 a->parent = context;
296 a->buf = NULL;
297 a->len = 0;
298 pthread_mutex_init(&a->start_mutex, NULL);
299 pthread_cond_init(&a->start_cv, NULL);
300 ret = pthread_create(&a->thread, NULL, checksum_thread, a);
301 if (ret != 0)
302 {
303 /* libjte issues an own message:
304 fprintf(stderr, "failed to create new thread: %d\n", ret);
305 */
306 checksum_free_context(context);
307 return NULL;
308 }
309 #endif
310 }
311 else
312 a->enabled = 0;
313 }
314
315 return context;
316 }
317
318 void checksum_free_context(checksum_context_t *context)
319 {
320 int i = 0;
321 struct _checksum_context *c = context;
322
323 for (i = 0; i < NUM_CHECKSUMS; i++)
324 {
325 struct algo_context *a = &c->algo[i];
326
327 #ifdef THREADED_CHECKSUMS
328 if (a->thread)
329 {
330 void *ret;
331 pthread_cancel(a->thread);
332 pthread_join(a->thread, &ret);
333 a->thread = 0;
334 }
335 #endif
336 free(a->context);
337 free(a->digest);
338 free(a->hexdump);
339 }
340 free(c->owner);
341 free(c);
342 }
343
344 #ifdef THREADED_CHECKSUMS
345 void checksum_update(checksum_context_t *context,
346 unsigned char const *buf, unsigned int len)
347 {
348 int i = 0;
349 struct _checksum_context *c = context;
350
351 /* >>> TODO : Find out for what purpose index shall serve.
352 It is defined here and incremented. Not more.
353 */
354 static int index = 0;
355
356 index++;
357
358 c->threads_running = c->threads_desired;
359 for (i = 0; i < NUM_CHECKSUMS; i++)
360 {
361 if (c->algo[i].enabled)
362 {
363 struct algo_context *a = &c->algo[i];
364 pthread_mutex_lock(&a->start_mutex);
365 a->len = len;
366 a->buf = buf;
367 pthread_cond_signal(&a->start_cv);
368 pthread_mutex_unlock(&a->start_mutex);
369 }
370 }
371
372 /* Should now all be running, wait on them all to return */
373 pthread_mutex_lock(&c->done_mutex);
374 while (c->threads_running > 0)
375 {
376 pthread_cond_wait(&c->done_cv, &c->done_mutex);
377 }
378 pthread_mutex_unlock(&c->done_mutex);
379 }
380
381 #else /* THREADED_CHECKSUMS */
382
383 void checksum_update(checksum_context_t *context,
384 unsigned char const *buf, unsigned int len)
385 {
386 int i = 0;
387 struct _checksum_context *c = context;
388
389 for (i = 0; i < NUM_CHECKSUMS; i++)
390 {
391 if (c->algo[i].enabled)
392 {
393 struct algo_context *a = &c->algo[i];
394 algorithms[i].update(a->context, buf, len);
395 }
396 }
397 }
398
399 #endif /* THREADED_CHECKSUMS */
400
401 void checksum_final(checksum_context_t *context)
402 {
403 int i = 0;
404 struct _checksum_context *c = context;
405
406 #ifdef THREADED_CHECKSUMS
407 /* Clean up the threads */
408 c->threads_running = c->threads_desired;
409
410 for (i = 0; i < NUM_CHECKSUMS; i++)
411 {
412 if (c->algo[i].enabled)
413 {
414 void *ret = NULL;
415 struct algo_context *a = &c->algo[i];
416
417 pthread_mutex_lock(&a->start_mutex);
418 a->len = 0;
419 a->buf = (unsigned char *)-1;
420 pthread_cond_signal(&a->start_cv);
421 pthread_mutex_unlock(&a->start_mutex);
422 pthread_join(a->thread, &ret);
423 a->thread = 0;
424 }
425 }
426 #endif
427
428 for (i = 0; i < NUM_CHECKSUMS; i++)
429 {
430 struct algo_context *a = &c->algo[i];
431 if (a->enabled)
432 {
433 algorithms[i].final(a->digest, a->context);
434 hex_dump_to_buffer(a->hexdump, a->digest, algorithms[i].digest_size);
435 a->finalised = 1;
436 }
437 }
438 }
439
440 void checksum_copy(checksum_context_t *context,
441 enum checksum_types which,
442 unsigned char *digest)
443 {
444 struct _checksum_context *c = context;
445
446 if (c->algo[which].enabled)
447 {
448 if (c->algo[which].finalised)
449 memcpy(digest, c->algo[which].digest, algorithms[which].digest_size);
450 else
451 memset(digest, 0, algorithms[which].digest_size);
452 }
453
454 else
455 /* >>> TODO : ??? Can this happen ? Why print and then go on ? */
456 fprintf(stderr, "Asked for %s checksum, not enabled!\n",
457 algorithms[which].name);
458 }
459
460 const char *checksum_hex(checksum_context_t *context,
461 enum checksum_types which)
462 {
463 struct _checksum_context *c = context;
464
465 if (c->algo[which].enabled && c->algo[which].finalised)
466 return c->algo[which].hexdump;
467
468 /* else */
469 return NULL;
470 }
471
472
473 /* Parse the command line options for which checksums to use */
474 int parse_checksum_algo(char *arg, int *algo)
475 {
476 int i = 0;
477 char *start_ptr = arg;
478 int len = 0;
479
480 (*algo) |= CHECK_MD5_USED;
481
482 if (!strcasecmp(arg, "all"))
483 {
484 *algo = 0xFF;
485 return 0;
486 }
487
488 while (*start_ptr != 0)
489 {
490 int match = 0;
491 len = 0;
492
493 while (start_ptr[len] != ',' && start_ptr[len] != 0)
494 len++;
495
496 if (len)
497 {
498 for (i = 0; i < NUM_CHECKSUMS; i++)
499 {
500 if (len == (int) strlen(algorithms[i].name) &&
501 !strncasecmp(start_ptr, algorithms[i].name, len))
502 {
503 match = 1;
504 *algo |= algorithms[i].check_used_value;
505 }
506 }
507
508 if (!match)
509 {
510 return EINVAL;
511 }
512 }
513
514 if (start_ptr[len] == 0)
515 break;
516
517 start_ptr += len + 1;
518 }
519
520 return 0;
521 }
522
523 /* Helper function: Simply calculate the checksum of the first "size"
524 * bytes of a file using the specified algorithm. If size == -1,
525 * calculate the checksum for the whole of the file. The caller is
526 * responsible for passing in a large enough buffer as "digest", based
527 * on their choice of algorithm. */
528 int checksum_calculate(char *filename,
529 int64_t size,
530 unsigned char *out,
531 enum checksum_types which)
532 {
533 char buffer[32768];
534 FILE *infile = NULL;
535 int64_t remain = 0;
536 int use;
537 struct checksum_context_t *context;
538
539 context = checksum_init_context(1 << which, "misc");
540 if (!context)
541 {
542 errno = ENOMEM;
543 return -1;
544 }
545
546 infile = fopen(filename, "rb");
547 if (!infile)
548 return -1;
549
550 if (-1 == size)
551 {
552 struct stat st;
553 stat(filename, &st);
554 size = st.st_size;
555 }
556
557 remain = size;
558 while (remain > 0)
559 {
560 use = (remain > (int) sizeof(buffer) ? (int) sizeof(buffer)
561 : remain);
562 if (fread(buffer, 1, use, infile) == 0)
563 return -1;
564 /* Update the checksum */
565 checksum_update(context, (unsigned char *)buffer, use);
566 remain -= use;
567 }
568 fclose(infile);
569 checksum_final(context);
570 checksum_copy(context, which, out);
571 checksum_free_context(context);
572 return 0;
573 }
574
575 /* Read in a hex-dumped checksum and parse it */
576 int checksum_parse_hex(char *in, unsigned char *out, int size)
577 {
578 int i = 0;
579
580 if (size % 2) /* odd number */
581 return EINVAL;
582
583 for (i = 0; i < size / 2; i++)
584 {
585 if (in[2*i] >= '0' && in[2*i] <= '9')
586 in[2*i] -= '0';
587 else if (in[2*i] >= 'A' && in[2*i] <= 'F')
588 in[2*i] += 10 - 'A';
589 else if (in[2*i] >= 'a' && in[2*i] <= 'f')
590 in[2*i] += 10 - 'a';
591 else
592 return 1;
593 if (in[1+(2*i)] >= '0' && in[1+(2*i)] <= '9')
594 in[1+(2*i)] -= '0';
595 else if (in[1+(2*i)] >= 'A' && in[1+(2*i)] <= 'F')
596 in[1+(2*i)] += 10 - 'A';
597 else if (in[1+(2*i)] >= 'a' && in[1+(2*i)] <= 'f')
598 in[1+(2*i)] += 10 - 'a';
599 else
600 return 1;
601 out[i] = in[2*i] << 4 | in[1+(2*i)];
602 }
603 return 0;
604 }
605
606 #ifdef CHECKSUM_SELF_TEST
607 #include <sys/types.h>
608 #include <sys/stat.h>
609 #include <fcntl.h>
610 #include <unistd.h>
611 #include <errno.h>
612 #include <stdlib.h>
613
614 int main(int argc, char **argv)
615 {
616 char buf[1024];
617 int fd = -1;
618 char *filename;
619 int err = 0;
620 static checksum_context_t *test_context = NULL;
621 int i = 0;
622
623 if (argc != 2)
624 {
625 fprintf(stderr, "Need a filename to act on!\n");
626 return 1;
627 }
628
629 filename = argv[1];
630 fd = open(filename, O_RDONLY);
631 if (fd < 0)
632 {
633 fprintf(stderr, "Unable to open file %s, errno %d\n", filename, errno);
634 return 1;
635 }
636
637 test_context = checksum_init_context(CHECK_ALL_USED, "test");
638 if (!test_context)
639 {
640 fprintf(stderr, "Unable to initialise checksum context\n");
641 close(fd);
642 return 1;
643 }
644
645 while(1)
646 {
647 err = read(fd, buf, sizeof(buf));
648 if (err < 0)
649 {
650 fprintf(stderr, "Failed to read from file, errno %d\n", errno);
651 return 1;
652 }
653
654 if (err == 0)
655 break; /* EOF */
656
657 /* else */
658 checksum_update(test_context, buf, err);
659 }
660 close(fd);
661 checksum_final(test_context);
662
663 for (i = 0; i < NUM_CHECKSUMS; i++)
664 {
665 struct checksum_info *info;
666 unsigned char r[64];
667 int j = 0;
668
669 info = checksum_information(i);
670 memset(r, 0, sizeof(r));
671
672 checksum_copy(test_context, i, r);
673
674 printf("OUR %s:\n", info->name);
675 for (j = 0; j < info->digest_size; j++)
676 printf("%2.2x", r[j]);
677 printf(" %s\n", filename);
678 printf("system checksum program (%s):\n", info->prog);
679 sprintf(buf, "%s %s", info->prog, filename);
680 system(buf);
681 printf("\n");
682 }
683 return 0;
684 }
685 #endif /* CHECKSUM_SELF_TEST */
686