forked from ccache/ccache
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hash.c
128 lines (112 loc) · 3.17 KB
/
hash.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
// Copyright (C) 2002 Andrew Tridgell
// Copyright (C) 2010-2016 Joel Rosdahl
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ccache.h"
#define HASH_DELIMITER "\000cCaChE"
void
hash_start(struct mdfour *md)
{
mdfour_begin(md);
}
void
hash_buffer(struct mdfour *md, const void *s, size_t len)
{
mdfour_update(md, (unsigned char *)s, len);
}
// Return the hash result as a hex string. Caller frees.
char *
hash_result(struct mdfour *md)
{
unsigned char sum[16];
hash_result_as_bytes(md, sum);
return format_hash_as_string(sum, (unsigned) md->totalN);
}
// Return the hash result as 16 binary bytes.
void
hash_result_as_bytes(struct mdfour *md, unsigned char *out)
{
hash_buffer(md, NULL, 0);
mdfour_result(md, out);
}
bool
hash_equal(struct mdfour *md1, struct mdfour *md2)
{
unsigned char sum1[16];
hash_result_as_bytes(md1, sum1);
unsigned char sum2[16];
hash_result_as_bytes(md2, sum2);
return memcmp(sum1, sum2, sizeof(sum1)) == 0;
}
// Hash some data that is unlikely to occur in the input. The idea is twofold:
//
// - Delimit things like arguments from each other (e.g., so that -I -O2 and
// -I-O2 hash differently).
// - Tag different types of hashed information so that it's possible to do
// conditional hashing of information in a safe way (e.g., if we want to hash
// information X if CCACHE_A is set and information Y if CCACHE_B is set,
// there should never be a hash collision risk).
void
hash_delimiter(struct mdfour *md, const char *type)
{
hash_buffer(md, HASH_DELIMITER, sizeof(HASH_DELIMITER));
hash_buffer(md, type, strlen(type) + 1); // Include NUL.
}
void
hash_string(struct mdfour *md, const char *s)
{
hash_string_length(md, s, strlen(s));
}
void
hash_string_length(struct mdfour *md, const char *s, int length)
{
hash_buffer(md, s, length);
}
void
hash_int(struct mdfour *md, int x)
{
hash_buffer(md, (char *)&x, sizeof(x));
}
// Add contents of an open file to the hash. Returns true on success, otherwise
// false.
bool
hash_fd(struct mdfour *md, int fd)
{
char buf[READ_BUFFER_SIZE];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) != 0) {
if (n == -1 && errno != EINTR) {
break;
}
if (n > 0) {
hash_buffer(md, buf, n);
}
}
return n == 0;
}
// Add contents of a file to the hash. Returns true on success, otherwise
// false.
bool
hash_file(struct mdfour *md, const char *fname)
{
int fd = open(fname, O_RDONLY|O_BINARY);
if (fd == -1) {
cc_log("Failed to open %s: %s", fname, strerror(errno));
return false;
}
bool ret = hash_fd(md, fd);
close(fd);
return ret;
}