Imported Upstream version 3.5.1
[platform/upstream/ccache.git] / src / hash.c
1 // Copyright (C) 2002 Andrew Tridgell
2 // Copyright (C) 2010-2018 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         mdfour_update(&hash->md, (const unsigned char *)s, len);
34         if (len > 0 && hash->debug_binary) {
35                 (void) fwrite(s, 1, len, hash->debug_binary);
36         }
37 }
38
39 static void
40 do_debug_text(struct hash *hash, const void *s, size_t len)
41 {
42         if (len > 0 && hash->debug_text) {
43                 (void) fwrite(s, 1, len, hash->debug_text);
44         }
45 }
46
47 struct hash *
48 hash_init(void)
49 {
50         struct hash *hash = malloc(sizeof(struct hash));
51         mdfour_begin(&hash->md);
52         hash->debug_binary = NULL;
53         hash->debug_text = NULL;
54         return hash;
55 }
56
57 struct hash *
58 hash_copy(struct hash *hash)
59 {
60         struct hash *result = malloc(sizeof(struct hash));
61         result->md = hash->md;
62         result->debug_binary = NULL;
63         result->debug_text = NULL;
64         return result;
65 }
66
67 void hash_free(struct hash *hash)
68 {
69         free(hash);
70 }
71
72 void hash_enable_debug(
73         struct hash *hash, const char *section_name,
74         FILE *debug_binary, FILE *debug_text)
75 {
76         hash->debug_binary = debug_binary;
77         hash->debug_text = debug_text;
78
79         do_debug_text(hash, "=== ", 4);
80         do_debug_text(hash, section_name, strlen(section_name));
81         do_debug_text(hash, " ===\n", 5);
82 }
83
84 size_t
85 hash_input_size(struct hash *hash)
86 {
87         return hash->md.totalN;
88 }
89
90 void
91 hash_buffer(struct hash *hash, const void *s, size_t len)
92 {
93         do_hash_buffer(hash, s, len);
94         do_debug_text(hash, s, len);
95 }
96
97 char *
98 hash_result(struct hash *hash)
99 {
100         unsigned char sum[16];
101
102         hash_result_as_bytes(hash, sum);
103         return format_hash_as_string(sum, (unsigned) hash->md.totalN);
104 }
105
106 void
107 hash_result_as_bytes(struct hash *hash, unsigned char *out)
108 {
109         mdfour_update(&hash->md, NULL, 0);
110         mdfour_result(&hash->md, out);
111 }
112
113 bool
114 hash_equal(struct hash *hash1, struct hash *hash2)
115 {
116         unsigned char sum1[16];
117         hash_result_as_bytes(hash1, sum1);
118         unsigned char sum2[16];
119         hash_result_as_bytes(hash2, sum2);
120         return memcmp(sum1, sum2, sizeof(sum1)) == 0;
121 }
122
123 void
124 hash_delimiter(struct hash *hash, const char *type)
125 {
126         do_hash_buffer(hash, HASH_DELIMITER, sizeof(HASH_DELIMITER));
127         do_hash_buffer(hash, type, strlen(type) + 1); // Include NUL.
128         do_debug_text(hash, "### ", 4);
129         do_debug_text(hash, type, strlen(type));
130         do_debug_text(hash, "\n", 1);
131 }
132
133 void
134 hash_string(struct hash *hash, const char *s)
135 {
136         hash_string_buffer(hash, s, strlen(s));
137 }
138
139 void
140 hash_string_buffer(struct hash *hash, const char *s, int length)
141 {
142         hash_buffer(hash, s, length);
143         do_debug_text(hash, "\n", 1);
144 }
145
146 void
147 hash_int(struct hash *hash, int x)
148 {
149         do_hash_buffer(hash, (char *)&x, sizeof(x));
150
151         char buf[16];
152         snprintf(buf, sizeof(buf), "%d", x);
153         do_debug_text(hash, buf, strlen(buf));
154         do_debug_text(hash, "\n", 1);
155 }
156
157 bool
158 hash_fd(struct hash *hash, int fd)
159 {
160         char buf[READ_BUFFER_SIZE];
161         ssize_t n;
162
163         while ((n = read(fd, buf, sizeof(buf))) != 0) {
164                 if (n == -1 && errno != EINTR) {
165                         break;
166                 }
167                 if (n > 0) {
168                         do_hash_buffer(hash, buf, n);
169                         do_debug_text(hash, buf, n);
170                 }
171         }
172         return n == 0;
173 }
174
175 bool
176 hash_file(struct hash *hash, const char *fname)
177 {
178         int fd = open(fname, O_RDONLY|O_BINARY);
179         if (fd == -1) {
180                 cc_log("Failed to open %s: %s", fname, strerror(errno));
181                 return false;
182         }
183
184         bool ret = hash_fd(hash, fd);
185         close(fd);
186         return ret;
187 }