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
| | /*
* Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
* License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
*/
#include "cmogstored.h"
#include "digest.h"
__attribute__((constructor)) static void digest_init(void)
{
CHECK(Gc_rc, GC_OK, gc_init());
atexit(gc_done);
}
void mog_digest_init(struct mog_digest *digest, enum Gc_hash alg)
{
digest->alg = alg;
CHECK(Gc_rc, GC_OK, gc_hash_open(alg, 0, &digest->ctx));
}
enum mog_digest_next mog_digest_read(struct mog_digest *digest, int fd)
{
size_t len;
char *buf = mog_fsbuf_get(&len);
size_t i = 1024;
while (--i > 0) {
ssize_t r = read(fd, buf, len);
if (r > 0) { /* most likely */
gc_hash_write(digest->ctx, r, buf);
if (mog_thr_prepare_quit())
return MOG_DIGEST_YIELD;
} else if (r == 0) {
/* wait for user to call mog_digest_hex() */
return MOG_DIGEST_EOF;
} else {
assert(r < 0 && errno && "buggy read(2)?");
/* may happen on crazy FSes */
if (errno == EINTR)
continue;
/* bail on EAGAIN, not possible on regular files */
return MOG_DIGEST_ERROR;
}
}
return MOG_DIGEST_CONTINUE;
}
void mog_digest_hex(struct mog_digest *digest, char *buf, size_t len)
{
static const char hex[] = "0123456789abcdef";
char *out = buf;
size_t hashlen = gc_hash_digest_length(digest->alg);
union { const char *s; const unsigned char *u; } result;
result.s = gc_hash_read(digest->ctx);
/* hashlen = 16 for MD5, 20 for SHA-1 */
if (digest->alg == GC_MD5)
assert(hashlen == 16 && "bad hashlen");
assert(len >= (hashlen * 2) && "hex buffer too small");
assert(hashlen != 0 && "bad hashlen");
while (hashlen--) {
*out++ = hex[*result.u >> 4];
*out++ = hex[*result.u & 0x0f];
result.u++;
}
}
void mog_digest_destroy(struct mog_digest *digest)
{
if (digest->ctx)
gc_hash_close(digest->ctx);
}
|