-
Notifications
You must be signed in to change notification settings - Fork 48
/
checksum.c
133 lines (114 loc) · 2.83 KB
/
checksum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
Copyright (c) 2011-2013 Ronald de Man
This file is distributed under the terms of the GNU GPL, version 2.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "defs.h"
#include "checksum.h"
#include "threads.h"
#include "citycrc.h"
#include "util.h"
#define CHUNK (1ULL << 24)
extern int total_work;
static uint64 checksum1[2];
static uint64 checksum2[2];
static uint64 *results = NULL;
static char *data;
static long64 size;
static int checksum_found;
static int checksum_match;
static long64 *work = NULL;
static void checksum_worker(struct thread_data *thread)
{
long64 idx;
long64 end = thread->end;
for (idx = thread->begin; idx < end; idx++) {
long64 start = idx * CHUNK;
long64 chunk = CHUNK;
if (start + chunk > size)
chunk = size - start;
CityHashCrc256(data + start, chunk, &results[4 * idx]);
}
}
static void calc_checksum(char *name)
{
long64 orig_size;
if (!work) work = alloc_work(total_work);
data = map_file(name, 0, &size);
orig_size = size;
if ((size & 0x3f) == 0x10) {
size &= ~0x3fULL;
memcpy(checksum1, data + size, 16);
checksum_found = 1;
} else {
if (size & 0x3f) {
fprintf(stderr, "Size of %s is not a multiple of 64.\n", name);
exit(1);
}
checksum_found = 0;
}
int chunks = (size + CHUNK - 1) / CHUNK;
results = (uint64 *)malloc(32 * chunks);
fill_work(total_work, chunks, 0, work);
run_threaded(checksum_worker, work, 0);
CityHashCrc128((char *)results, 32 * chunks, checksum2);
unmap_file(data, orig_size);
free(results);
if (checksum_found)
checksum_match = (checksum1[0] == checksum2[0]
&& checksum1[1] == checksum2[1]);
}
void print_checksum(char *name, char *sum)
{
data = map_file(name, 1, &size);
if ((size & 0x3f) == 0x10) {
memcpy(checksum1, data + (size & ~0x3fULL), 16);
} else {
fprintf(stderr, "No checksum found.\n");
exit(1);
}
unmap_file(data, size);
int i;
static char nibble[16] = "0123456789abcdef";
ubyte *c = (ubyte *)checksum1;
for (i = 0; i < 16; i++) {
ubyte b = c[i];
sum[2 * i] = nibble[b >> 4];
sum[2 * i + 1] = nibble[b & 0x0f];
}
sum[32] = 0;
}
void add_checksum(char *name)
{
calc_checksum(name);
if (checksum_found) {
fprintf(stderr, "%s checksum already present.\n", checksum_match ? "Matching" : "Non-matching");
exit(1);
}
FILE *F = fopen(name, "ab");
if (!F) {
fprintf(stderr, "Could not open %s for appending.\n", name);
exit(1);
}
fwrite(checksum2, 16, 1, F);
fclose(F);
}
void verify_checksum(char *name)
{
printf("%s: ", name);
calc_checksum(name);
if (!checksum_found) {
fprintf(stderr, "No checksum present.\n");
exit(1);
}
if (!checksum_match)
printf("FAIL!\n");
else
printf("OK!\n");
}