Imported Upstream version 3.7
[platform/upstream/ccache.git] / src / hash.c
1 // Copyright (C) 2002 Andrew Tridgell
2 // Copyright (C) 2010-2019 Joel Rosdahl
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License as published by the Free
6 // Software Foundation; either version 3 of the License, or (at your option)
7 // any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 // more details.
13 //
14 // You should have received a copy of the GNU General Public License along with
15 // this program; if not, write to the Free Software Foundation, Inc., 51
16 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 #include "ccache.h"
19 #include "hash.h"
20 #include "mdfour.h"
21
22 #define HASH_DELIMITER "\000cCaChE"
23
24 struct hash {
25         struct mdfour md;
26         FILE *debug_binary;
27         FILE *debug_text;
28 };
29
30 static void
31 do_hash_buffer(struct hash *hash, const void *s, size_t len)
32 {
33         assert(s);
34
35         mdfour_update(&hash->md, (const unsigned char *)s, len);
36         if (len > 0 && hash->debug_binary) {
37                 (void) fwrite(s, 1, len, hash->debug_binary);
38         }
39 }
40
41 static void
42 do_debug_text(struct hash *hash, const void *s, size_t len)
43 {
44         if (len > 0 && hash->debug_text) {
45                 (void) fwrite(s, 1, len, hash->debug_text);
46         }
47 }
48
49 struct hash *
50 hash_init(void)
51 {
52         struct hash *hash = malloc(sizeof(struct hash));
53         mdfour_begin(&hash->md);
54         hash->debug_binary = NULL;
55         hash->debug_text = NULL;
56         return hash;
57 }
58
59 struct hash *
60 hash_copy(struct hash *hash)
61 {
62         struct hash *result = malloc(sizeof(struct hash));
63         result->md = hash->md;
64         result->debug_binary = NULL;
65         result->debug_text = NULL;
66         return result;
67 }
68
69 void hash_free(struct hash *hash)
70 {
71         free(hash);
72 }
73
74 void hash_enable_debug(
75         struct hash *hash, const char *section_name,
76         FILE *debug_binary, FILE *debug_text)
77 {
78         hash->debug_binary = debug_binary;
79         hash->debug_text = debug_text;
80
81         do_debug_text(hash, "=== ", 4);
82         do_debug_text(hash, section_name, strlen(section_name));
83         do_debug_text(hash, " ===\n", 5);
84 }
85
86 size_t
87 hash_input_size(struct hash *hash)
88 {
89         return hash->md.totalN + hash->md.tail_len;
90 }
91
92 void
93 hash_buffer(struct hash *hash, const void *s, size_t len)
94 {
95         do_hash_buffer(hash, s, len);
96         do_debug_text(hash, s, len);
97 }
98
99 char *
100 hash_result(struct hash *hash)
101 {
102         unsigned char sum[16];
103
104         hash_result_as_bytes(hash, sum);
105         return format_hash_as_string(sum, hash_input_size(hash));
106 }
107
108 void
109 hash_result_as_bytes(struct hash *hash, unsigned char *out)
110 {
111         mdfour_result(&hash->md, out);
112 }
113
114 bool
115 hash_equal(struct hash *hash1, struct hash *hash2)
116 {
117         unsigned char sum1[16];
118         hash_result_as_bytes(hash1, sum1);
119         unsigned char sum2[16];
120         hash_result_as_bytes(hash2, sum2);
121         return memcmp(sum1, sum2, sizeof(sum1)) == 0;
122 }
123
124 void
125 hash_delimiter(struct hash *hash, const char *type)
126 {
127         do_hash_buffer(hash, HASH_DELIMITER, sizeof(HASH_DELIMITER));
128         do_hash_buffer(hash, type, strlen(type) + 1); // Include NUL.
129         do_debug_text(hash, "### ", 4);
130         do_debug_text(hash, type, strlen(type));
131         do_debug_text(hash, "\n", 1);
132 }
133
134 void
135 hash_string(struct hash *hash, const char *s)
136 {
137         hash_string_buffer(hash, s, strlen(s));
138 }
139
140 void
141 hash_string_buffer(struct hash *hash, const char *s, int length)
142 {
143         hash_buffer(hash, s, length);
144         do_debug_text(hash, "\n", 1);
145 }
146
147 void
148 hash_int(struct hash *hash, int x)
149 {
150         do_hash_buffer(hash, (char *)&x, sizeof(x));
151
152         char buf[16];
153         snprintf(buf, sizeof(buf), "%d", x);
154         do_debug_text(hash, buf, strlen(buf));
155         do_debug_text(hash, "\n", 1);
156 }
157
158 bool
159 hash_fd(struct hash *hash, int fd)
160 {
161         char buf[READ_BUFFER_SIZE];
162         ssize_t n;
163
164         while ((n = read(fd, buf, sizeof(buf))) != 0) {
165                 if (n == -1 && errno != EINTR) {
166                         break;
167                 }
168                 if (n > 0) {
169                         do_hash_buffer(hash, buf, n);
170                         do_debug_text(hash, buf, n);
171                 }
172         }
173         return n == 0;
174 }
175
176 bool
177 hash_file(struct hash *hash, const char *fname)
178 {
179         int fd = open(fname, O_RDONLY|O_BINARY);
180         if (fd == -1) {
181                 cc_log("Failed to open %s: %s", fname, strerror(errno));
182                 return false;
183         }
184
185         bool ret = hash_fd(hash, fd);
186         close(fd);
187         return ret;
188 }