Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2018 Andrew Kelley
3 : : *
4 : : * This file is part of zig, which is MIT licensed.
5 : : * See http://opensource.org/licenses/MIT
6 : : */
7 : :
8 : : #include "userland.h"
9 : : #include "cache_hash.hpp"
10 : : #include "all_types.hpp"
11 : : #include "buffer.hpp"
12 : : #include "os.hpp"
13 : :
14 : : #include <stdio.h>
15 : :
16 : 171 : void cache_init(CacheHash *ch, Buf *manifest_dir) {
17 : 171 : int rc = blake2b_init(&ch->blake, 48);
18 : 171 : assert(rc == 0);
19 : 171 : ch->files = {};
20 : 171 : ch->manifest_dir = manifest_dir;
21 : 171 : ch->manifest_file_path = nullptr;
22 : 171 : ch->manifest_dirty = false;
23 : 171 : ch->force_check_manifest = false;
24 : 171 : ch->b64_digest = BUF_INIT;
25 : 171 : }
26 : :
27 : 3568 : void cache_str(CacheHash *ch, const char *ptr) {
28 : 3568 : assert(ch->manifest_file_path == nullptr);
29 : 3568 : assert(ptr != nullptr);
30 : : // + 1 to include the null byte
31 : 3568 : blake2b_update(&ch->blake, ptr, strlen(ptr) + 1);
32 : 3568 : }
33 : :
34 : 1446 : void cache_int(CacheHash *ch, int x) {
35 : 1446 : assert(ch->manifest_file_path == nullptr);
36 : : // + 1 to include the null byte
37 : : uint8_t buf[sizeof(int) + 1];
38 : 1446 : memcpy(buf, &x, sizeof(int));
39 : 1446 : buf[sizeof(int)] = 0;
40 : 1446 : blake2b_update(&ch->blake, buf, sizeof(int) + 1);
41 : 1446 : }
42 : :
43 : 228 : void cache_usize(CacheHash *ch, size_t x) {
44 : 228 : assert(ch->manifest_file_path == nullptr);
45 : : // + 1 to include the null byte
46 : : uint8_t buf[sizeof(size_t) + 1];
47 : 228 : memcpy(buf, &x, sizeof(size_t));
48 : 228 : buf[sizeof(size_t)] = 0;
49 : 228 : blake2b_update(&ch->blake, buf, sizeof(size_t) + 1);
50 : 228 : }
51 : :
52 : 1406 : void cache_bool(CacheHash *ch, bool x) {
53 : 1406 : assert(ch->manifest_file_path == nullptr);
54 : 1406 : blake2b_update(&ch->blake, &x, 1);
55 : 1406 : }
56 : :
57 : 833 : void cache_buf(CacheHash *ch, Buf *buf) {
58 : 833 : assert(ch->manifest_file_path == nullptr);
59 : 833 : assert(buf != nullptr);
60 : : // + 1 to include the null byte
61 : 833 : blake2b_update(&ch->blake, buf_ptr(buf), buf_len(buf) + 1);
62 : 833 : }
63 : :
64 : 336 : void cache_buf_opt(CacheHash *ch, Buf *buf) {
65 : 336 : assert(ch->manifest_file_path == nullptr);
66 [ + + ]: 336 : if (buf == nullptr) {
67 : 268 : cache_str(ch, "");
68 : 268 : cache_str(ch, "");
69 : : } else {
70 : 68 : cache_buf(ch, buf);
71 : : }
72 : 336 : }
73 : :
74 : 76 : void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len) {
75 : 76 : assert(ch->manifest_file_path == nullptr);
76 [ + + ]: 90 : for (size_t i = 0; i < len; i += 1) {
77 : 14 : LinkLib *lib = ptr[i];
78 [ + + ]: 14 : if (lib->provided_explicitly) {
79 : 6 : cache_buf(ch, lib->name);
80 : : }
81 : : }
82 : 76 : cache_str(ch, "");
83 : 76 : }
84 : :
85 : 282 : void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len) {
86 : 282 : assert(ch->manifest_file_path == nullptr);
87 [ + + ]: 346 : for (size_t i = 0; i < len; i += 1) {
88 : 64 : Buf *buf = ptr[i];
89 : 64 : cache_buf(ch, buf);
90 : : }
91 : 282 : cache_str(ch, "");
92 : 282 : }
93 : :
94 : 76 : void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len) {
95 : 76 : assert(ch->manifest_file_path == nullptr);
96 : :
97 [ + + ]: 164 : for (size_t i = 0; i < len; i += 1) {
98 : 88 : Buf *buf = ptr[i];
99 : 88 : cache_file(ch, buf);
100 : : }
101 : 76 : cache_str(ch, "");
102 : 76 : }
103 : :
104 : 304 : void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len) {
105 : 304 : assert(ch->manifest_file_path == nullptr);
106 : :
107 [ - + ]: 304 : for (size_t i = 0; i < len; i += 1) {
108 : 0 : const char *s = ptr[i];
109 : 0 : cache_str(ch, s);
110 : : }
111 : 304 : cache_str(ch, "");
112 : 304 : }
113 : :
114 : 260 : void cache_file(CacheHash *ch, Buf *file_path) {
115 : 260 : assert(ch->manifest_file_path == nullptr);
116 : 260 : assert(file_path != nullptr);
117 : 260 : Buf *resolved_path = buf_alloc();
118 : 260 : *resolved_path = os_path_resolve(&file_path, 1);
119 : 260 : CacheHashFile *chf = ch->files.add_one();
120 : 260 : chf->path = resolved_path;
121 : 260 : cache_buf(ch, resolved_path);
122 : 260 : }
123 : :
124 : 0 : void cache_file_opt(CacheHash *ch, Buf *file_path) {
125 : 0 : assert(ch->manifest_file_path == nullptr);
126 [ # # ]: 0 : if (file_path == nullptr) {
127 : 0 : cache_str(ch, "");
128 : 0 : cache_str(ch, "");
129 : : } else {
130 : 0 : cache_file(ch, file_path);
131 : : }
132 : 0 : }
133 : :
134 : : // Ported from std/base64.zig
135 : : static uint8_t base64_fs_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
136 : 3294 : static void base64_encode(Slice<uint8_t> dest, Slice<uint8_t> source) {
137 : 3294 : size_t dest_len = ((source.len + 2) / 3) * 4;
138 : 3294 : assert(dest.len == dest_len);
139 : :
140 : 3294 : size_t i = 0;
141 : 3294 : size_t out_index = 0;
142 [ + + ]: 55998 : for (; i + 2 < source.len; i += 3) {
143 : 52704 : dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f];
144 : 52704 : out_index += 1;
145 : :
146 : 52704 : dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)];
147 : 52704 : out_index += 1;
148 : :
149 : 52704 : dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i + 1] & 0xf) << 2) | ((source.ptr[i + 2] & 0xc0) >> 6)];
150 : 52704 : out_index += 1;
151 : :
152 : 52704 : dest.ptr[out_index] = base64_fs_alphabet[source.ptr[i + 2] & 0x3f];
153 : 52704 : out_index += 1;
154 : : }
155 : :
156 : : // Assert that we never need pad characters.
157 : 3294 : assert(i == source.len);
158 : 3294 : }
159 : :
160 : : // Ported from std/base64.zig
161 : 2502 : static Error base64_decode(Slice<uint8_t> dest, Slice<uint8_t> source) {
162 [ - + ]: 2502 : if (source.len % 4 != 0)
163 : 0 : return ErrorInvalidFormat;
164 [ - + ]: 2502 : if (dest.len != (source.len / 4) * 3)
165 : 0 : return ErrorInvalidFormat;
166 : :
167 : : // In Zig this is comptime computed. In C++ it's not worth it to do that.
168 : : uint8_t char_to_index[256];
169 : 2502 : bool char_in_alphabet[256] = {0};
170 [ + + ]: 162630 : for (size_t i = 0; i < 64; i += 1) {
171 : 160128 : uint8_t c = base64_fs_alphabet[i];
172 : 160128 : assert(!char_in_alphabet[c]);
173 : 160128 : char_in_alphabet[c] = true;
174 : 160128 : char_to_index[c] = i;
175 : : }
176 : :
177 : 2502 : size_t src_cursor = 0;
178 : 2502 : size_t dest_cursor = 0;
179 : :
180 [ + + ]: 42534 : for (;src_cursor < source.len; src_cursor += 4) {
181 [ - + ]: 40032 : if (!char_in_alphabet[source.ptr[src_cursor + 0]]) return ErrorInvalidFormat;
182 [ - + ]: 40032 : if (!char_in_alphabet[source.ptr[src_cursor + 1]]) return ErrorInvalidFormat;
183 [ - + ]: 40032 : if (!char_in_alphabet[source.ptr[src_cursor + 2]]) return ErrorInvalidFormat;
184 [ - + ]: 40032 : if (!char_in_alphabet[source.ptr[src_cursor + 3]]) return ErrorInvalidFormat;
185 : 40032 : dest.ptr[dest_cursor + 0] = (char_to_index[source.ptr[src_cursor + 0]] << 2) | (char_to_index[source.ptr[src_cursor + 1]] >> 4);
186 : 40032 : dest.ptr[dest_cursor + 1] = (char_to_index[source.ptr[src_cursor + 1]] << 4) | (char_to_index[source.ptr[src_cursor + 2]] >> 2);
187 : 40032 : dest.ptr[dest_cursor + 2] = (char_to_index[source.ptr[src_cursor + 2]] << 6) | (char_to_index[source.ptr[src_cursor + 3]]);
188 : 40032 : dest_cursor += 3;
189 : : }
190 : :
191 : 2502 : assert(src_cursor == source.len);
192 : 2502 : assert(dest_cursor == dest.len);
193 : 2502 : return ErrorNone;
194 : : }
195 : :
196 : 2952 : static Error hash_file(uint8_t *digest, OsFile handle, Buf *contents) {
197 : : Error err;
198 : :
199 [ + + ]: 2952 : if (contents) {
200 : 1763 : buf_resize(contents, 0);
201 : : }
202 : :
203 : : blake2b_state blake;
204 : 2952 : int rc = blake2b_init(&blake, 48);
205 : 2952 : assert(rc == 0);
206 : :
207 : : for (;;) {
208 : : uint8_t buf[4096];
209 : 65089 : size_t amt = 4096;
210 [ - + ]: 65089 : if ((err = os_file_read(handle, buf, &amt)))
211 : 2952 : return err;
212 [ + + ]: 65089 : if (amt == 0) {
213 : 2952 : rc = blake2b_final(&blake, digest, 48);
214 : 2952 : assert(rc == 0);
215 : 2952 : return ErrorNone;
216 : : }
217 : 62137 : blake2b_update(&blake, buf, amt);
218 [ + + ]: 62137 : if (contents) {
219 : 4619 : buf_append_mem(contents, (char*)buf, amt);
220 : : }
221 : 62137 : }
222 : : }
223 : :
224 : : // If the wall clock time, rounded to the same precision as the
225 : : // mtime, is equal to the mtime, then we cannot rely on this mtime
226 : : // yet. We will instead save an mtime value that indicates the hash
227 : : // must be unconditionally computed.
228 : 2952 : static bool is_problematic_timestamp(const OsTimeStamp *fs_clock) {
229 : 2952 : OsTimeStamp wall_clock = os_timestamp_calendar();
230 : : // First make all the least significant zero bits in the fs_clock, also zero bits in the wall clock.
231 [ + + ]: 2952 : if (fs_clock->nsec == 0) {
232 : 8 : wall_clock.nsec = 0;
233 [ - + ]: 8 : if (fs_clock->sec == 0) {
234 : 0 : wall_clock.sec = 0;
235 : : } else {
236 : 8 : wall_clock.sec &= (-1ull) << ctzll(fs_clock->sec);
237 : : }
238 : : } else {
239 : 2944 : wall_clock.nsec &= (-1ull) << ctzll(fs_clock->nsec);
240 : : }
241 [ + + ][ - + ]: 2952 : return wall_clock.nsec == fs_clock->nsec && wall_clock.sec == fs_clock->sec;
242 : : }
243 : :
244 : 2952 : static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents) {
245 : : Error err;
246 : :
247 : 2952 : assert(chf->path != nullptr);
248 : :
249 : : OsFile this_file;
250 [ - + ]: 2952 : if ((err = os_file_open_r(chf->path, &this_file, &chf->attr)))
251 : 0 : return err;
252 : :
253 [ - + ]: 2952 : if (is_problematic_timestamp(&chf->attr.mtime)) {
254 : 0 : chf->attr.mtime.sec = 0;
255 : 0 : chf->attr.mtime.nsec = 0;
256 : 0 : chf->attr.inode = 0;
257 : : }
258 : :
259 [ - + ]: 2952 : if ((err = hash_file(chf->bin_digest, this_file, contents))) {
260 : 0 : os_file_close(&this_file);
261 : 0 : return err;
262 : : }
263 : 2952 : os_file_close(&this_file);
264 : :
265 : 2952 : blake2b_update(&ch->blake, chf->bin_digest, 48);
266 : :
267 : 2952 : return ErrorNone;
268 : : }
269 : :
270 : 171 : Error cache_hit(CacheHash *ch, Buf *out_digest) {
271 : : Error err;
272 : :
273 : : uint8_t bin_digest[48];
274 : 171 : int rc = blake2b_final(&ch->blake, bin_digest, 48);
275 : 171 : assert(rc == 0);
276 : :
277 : 171 : buf_resize(&ch->b64_digest, 64);
278 : 171 : base64_encode(buf_to_slice(&ch->b64_digest), {bin_digest, 48});
279 : :
280 [ + - ][ + + ]: 171 : if (ch->files.length == 0 && !ch->force_check_manifest) {
281 : 23 : buf_resize(out_digest, 64);
282 : 23 : base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
283 : 23 : return ErrorNone;
284 : : }
285 : :
286 : 148 : rc = blake2b_init(&ch->blake, 48);
287 : 148 : assert(rc == 0);
288 : 148 : blake2b_update(&ch->blake, bin_digest, 48);
289 : :
290 : 148 : ch->manifest_file_path = buf_alloc();
291 : 148 : os_path_join(ch->manifest_dir, &ch->b64_digest, ch->manifest_file_path);
292 : :
293 : 148 : buf_append_str(ch->manifest_file_path, ".txt");
294 : :
295 [ - + ]: 148 : if ((err = os_make_path(ch->manifest_dir)))
296 : 0 : return err;
297 : :
298 [ - + ]: 148 : if ((err = os_file_open_lock_rw(ch->manifest_file_path, &ch->manifest_file)))
299 : 0 : return err;
300 : :
301 : 148 : Buf line_buf = BUF_INIT;
302 : 148 : buf_resize(&line_buf, 512);
303 [ - + ]: 148 : if ((err = os_file_read_all(ch->manifest_file, &line_buf))) {
304 : 0 : os_file_close(&ch->manifest_file);
305 : 0 : return err;
306 : : }
307 : :
308 : 148 : size_t input_file_count = ch->files.length;
309 : 148 : bool any_file_changed = false;
310 : 148 : Error return_code = ErrorNone;
311 : 148 : size_t file_i = 0;
312 : 148 : SplitIterator line_it = memSplit(buf_to_slice(&line_buf), str("\n"));
313 : 2502 : for (;; file_i += 1) {
314 : 2650 : Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&line_it);
315 : :
316 : : CacheHashFile *chf;
317 [ + + ]: 2650 : if (file_i < input_file_count) {
318 : 197 : chf = &ch->files.at(file_i);
319 [ - + ]: 2453 : } else if (any_file_changed) {
320 : : // cache miss.
321 : : // keep the manifest file open with the rw lock
322 : : // reset the hash
323 : 0 : rc = blake2b_init(&ch->blake, 48);
324 : 0 : assert(rc == 0);
325 : 0 : blake2b_update(&ch->blake, bin_digest, 48);
326 : 0 : ch->files.resize(input_file_count);
327 : : // bring the hash up to the input file hashes
328 [ # # ]: 0 : for (file_i = 0; file_i < input_file_count; file_i += 1) {
329 : 0 : blake2b_update(&ch->blake, ch->files.at(file_i).bin_digest, 48);
330 : : }
331 : : // caller can notice that out_digest is unmodified.
332 : 0 : return return_code;
333 [ + + ]: 2453 : } else if (!opt_line.is_some) {
334 : 74 : break;
335 : : } else {
336 : 2379 : chf = ch->files.add_one();
337 : 2379 : chf->path = nullptr;
338 : : }
339 : :
340 [ + + ]: 2576 : if (!opt_line.is_some)
341 : 74 : break;
342 : :
343 : 2502 : SplitIterator it = memSplit(opt_line.value, str(" "));
344 : :
345 : 2502 : Optional<Slice<uint8_t>> opt_inode = SplitIterator_next(&it);
346 [ - + ]: 2502 : if (!opt_inode.is_some) {
347 : 0 : return_code = ErrorInvalidFormat;
348 : 0 : break;
349 : : }
350 : 2502 : chf->attr.inode = strtoull((const char *)opt_inode.value.ptr, nullptr, 10);
351 : :
352 : 2502 : Optional<Slice<uint8_t>> opt_mtime_sec = SplitIterator_next(&it);
353 [ - + ]: 2502 : if (!opt_mtime_sec.is_some) {
354 : 0 : return_code = ErrorInvalidFormat;
355 : 0 : break;
356 : : }
357 : 2502 : chf->attr.mtime.sec = strtoull((const char *)opt_mtime_sec.value.ptr, nullptr, 10);
358 : :
359 : 2502 : Optional<Slice<uint8_t>> opt_mtime_nsec = SplitIterator_next(&it);
360 [ - + ]: 2502 : if (!opt_mtime_nsec.is_some) {
361 : 0 : return_code = ErrorInvalidFormat;
362 : 0 : break;
363 : : }
364 : 2502 : chf->attr.mtime.nsec = strtoull((const char *)opt_mtime_nsec.value.ptr, nullptr, 10);
365 : :
366 : 2502 : Optional<Slice<uint8_t>> opt_digest = SplitIterator_next(&it);
367 [ - + ]: 2502 : if (!opt_digest.is_some) {
368 : 0 : return_code = ErrorInvalidFormat;
369 : 0 : break;
370 : : }
371 [ - + ]: 2502 : if ((err = base64_decode({chf->bin_digest, 48}, opt_digest.value))) {
372 : 0 : return_code = ErrorInvalidFormat;
373 : 0 : break;
374 : : }
375 : :
376 : 2502 : Slice<uint8_t> file_path = SplitIterator_rest(&it);
377 [ - + ]: 2502 : if (file_path.len == 0) {
378 : 0 : return_code = ErrorInvalidFormat;
379 : 0 : break;
380 : : }
381 : 2502 : Buf *this_path = buf_create_from_slice(file_path);
382 [ - + ][ - + ]: 2502 : if (chf->path != nullptr && !buf_eql_buf(this_path, chf->path)) {
[ + + ]
383 : 0 : return_code = ErrorInvalidFormat;
384 : 0 : break;
385 : : }
386 : 2502 : chf->path = this_path;
387 : :
388 : : // if the mtime matches we can trust the digest
389 : : OsFile this_file;
390 : : OsFileAttr actual_attr;
391 [ - + ]: 2502 : if ((err = os_file_open_r(chf->path, &this_file, &actual_attr))) {
392 : 0 : fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err));
393 : 0 : os_file_close(&ch->manifest_file);
394 : 0 : return ErrorCacheUnavailable;
395 : : }
396 [ + - ][ + - ]: 2502 : if (chf->attr.mtime.sec == actual_attr.mtime.sec &&
397 [ + - ]: 2502 : chf->attr.mtime.nsec == actual_attr.mtime.nsec &&
398 : 2502 : chf->attr.inode == actual_attr.inode)
399 : : {
400 : 2502 : os_file_close(&this_file);
401 : : } else {
402 : : // we have to recompute the digest.
403 : : // later we'll rewrite the manifest with the new mtime/digest values
404 : 0 : ch->manifest_dirty = true;
405 : 0 : chf->attr = actual_attr;
406 : :
407 [ # # ]: 0 : if (is_problematic_timestamp(&actual_attr.mtime)) {
408 : 0 : chf->attr.mtime.sec = 0;
409 : 0 : chf->attr.mtime.nsec = 0;
410 : 0 : chf->attr.inode = 0;
411 : : }
412 : :
413 : : uint8_t actual_digest[48];
414 [ # # ]: 0 : if ((err = hash_file(actual_digest, this_file, nullptr))) {
415 : 0 : os_file_close(&this_file);
416 : 0 : os_file_close(&ch->manifest_file);
417 : 0 : return err;
418 : : }
419 : 0 : os_file_close(&this_file);
420 [ # # ]: 0 : if (memcmp(chf->bin_digest, actual_digest, 48) != 0) {
421 : 0 : memcpy(chf->bin_digest, actual_digest, 48);
422 : : // keep going until we have the input file digests
423 : 0 : any_file_changed = true;
424 : : }
425 : : }
426 [ + - ]: 2502 : if (!any_file_changed) {
427 : 2502 : blake2b_update(&ch->blake, chf->bin_digest, 48);
428 : : }
429 : 2502 : }
430 [ + + ][ + - ]: 148 : if (file_i < input_file_count || file_i == 0 || return_code != ErrorNone) {
[ - + ]
431 : : // manifest file is empty or missing entries, so this is a cache miss
432 : 74 : ch->manifest_dirty = true;
433 [ + + ]: 211 : for (; file_i < input_file_count; file_i += 1) {
434 : 137 : CacheHashFile *chf = &ch->files.at(file_i);
435 [ - + ]: 137 : if ((err = populate_file_hash(ch, chf, nullptr))) {
436 : 0 : fprintf(stderr, "Unable to hash %s: %s\n", buf_ptr(chf->path), err_str(err));
437 : 0 : os_file_close(&ch->manifest_file);
438 : 0 : return ErrorCacheUnavailable;
439 : : }
440 : : }
441 [ - + ][ # # ]: 74 : if (return_code != ErrorNone && return_code != ErrorInvalidFormat) {
442 : 0 : os_file_close(&ch->manifest_file);
443 : : }
444 : 74 : return return_code;
445 : : }
446 : : // Cache Hit
447 : 171 : return cache_final(ch, out_digest);
448 : : }
449 : :
450 : 2815 : Error cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents) {
451 : : Error err;
452 : :
453 : 2815 : assert(ch->manifest_file_path != nullptr);
454 : 2815 : CacheHashFile *chf = ch->files.add_one();
455 : 2815 : chf->path = resolved_path;
456 [ - + ]: 2815 : if ((err = populate_file_hash(ch, chf, contents))) {
457 : 0 : os_file_close(&ch->manifest_file);
458 : 0 : return err;
459 : : }
460 : :
461 : 2815 : return ErrorNone;
462 : : }
463 : :
464 : 1052 : Error cache_add_file(CacheHash *ch, Buf *path) {
465 : 1052 : Buf *resolved_path = buf_alloc();
466 : 1052 : *resolved_path = os_path_resolve(&path, 1);
467 : 1052 : return cache_add_file_fetch(ch, resolved_path, nullptr);
468 : : }
469 : :
470 : 35 : Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
471 : : Error err;
472 : 35 : Buf *contents = buf_alloc();
473 [ - + ]: 35 : if ((err = os_fetch_file_path(dep_file_path, contents))) {
474 [ # # ]: 0 : if (err == ErrorFileNotFound)
475 : 0 : return err;
476 [ # # ]: 0 : if (verbose) {
477 : 0 : fprintf(stderr, "%s: unable to read .d file: %s\n", err_str(err), buf_ptr(dep_file_path));
478 : : }
479 : 0 : return ErrorReadingDepFile;
480 : : }
481 : 35 : auto it = stage2_DepTokenizer_init(buf_ptr(contents), buf_len(contents));
482 : : // skip first token: target
483 : : {
484 : 35 : auto result = stage2_DepTokenizer_next(&it);
485 [ - - + - ]: 35 : switch (result.type_id) {
486 : 0 : case stage2_DepNextResult::error:
487 [ # # ]: 0 : if (verbose) {
488 : 0 : fprintf(stderr, "%s: failed processing .d file: %s\n", result.textz, buf_ptr(dep_file_path));
489 : : }
490 : 0 : err = ErrorInvalidDepFile;
491 : 0 : goto finish;
492 : 0 : case stage2_DepNextResult::null:
493 : 0 : err = ErrorNone;
494 : 0 : goto finish;
495 : 35 : case stage2_DepNextResult::target:
496 : : case stage2_DepNextResult::prereq:
497 : 35 : err = ErrorNone;
498 : 35 : break;
499 : : }
500 : : }
501 : : // Process 0+ preqreqs.
502 : : // clang is invoked in single-source mode so we never get more targets.
503 : : for (;;) {
504 : 1079 : auto result = stage2_DepTokenizer_next(&it);
505 [ - + + - ]: 1079 : switch (result.type_id) {
506 : 0 : case stage2_DepNextResult::error:
507 [ # # ]: 0 : if (verbose) {
508 : 0 : fprintf(stderr, "%s: failed processing .d file: %s\n", result.textz, buf_ptr(dep_file_path));
509 : : }
510 : 0 : err = ErrorInvalidDepFile;
511 : 35 : goto finish;
512 : 35 : case stage2_DepNextResult::null:
513 : : case stage2_DepNextResult::target:
514 : 35 : err = ErrorNone;
515 : 35 : goto finish;
516 : 1044 : case stage2_DepNextResult::prereq:
517 : 1044 : break;
518 : : }
519 : 1044 : auto textbuf = buf_alloc();
520 : 1044 : buf_init_from_str(textbuf, result.textz);
521 [ - + ]: 1044 : if ((err = cache_add_file(ch, textbuf))) {
522 [ # # ]: 0 : if (verbose) {
523 : 0 : fprintf(stderr, "unable to add %s to cache: %s\n", result.textz, err_str(err));
524 : 0 : fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
525 : : }
526 : 0 : goto finish;
527 : : }
528 : 1044 : }
529 : :
530 : 35 : finish:
531 : 35 : stage2_DepTokenizer_deinit(&it);
532 : 35 : return err;
533 : : }
534 : :
535 : 74 : static Error write_manifest_file(CacheHash *ch) {
536 : : Error err;
537 : 74 : Buf contents = BUF_INIT;
538 : 74 : buf_resize(&contents, 0);
539 : : uint8_t encoded_digest[65];
540 : 74 : encoded_digest[64] = 0;
541 [ + + ]: 3026 : for (size_t i = 0; i < ch->files.length; i += 1) {
542 : 2952 : CacheHashFile *chf = &ch->files.at(i);
543 : 2952 : base64_encode({encoded_digest, 64}, {chf->bin_digest, 48});
544 : 2952 : buf_appendf(&contents, "%" ZIG_PRI_u64 " %" ZIG_PRI_u64 " %" ZIG_PRI_u64 " %s %s\n",
545 : : chf->attr.inode, chf->attr.mtime.sec, chf->attr.mtime.nsec, encoded_digest, buf_ptr(chf->path));
546 : : }
547 [ - + ]: 74 : if ((err = os_file_overwrite(ch->manifest_file, &contents)))
548 : 0 : return err;
549 : :
550 : 74 : return ErrorNone;
551 : : }
552 : :
553 : 148 : Error cache_final(CacheHash *ch, Buf *out_digest) {
554 : 148 : assert(ch->manifest_file_path != nullptr);
555 : :
556 : : // We don't close the manifest file yet, because we want to
557 : : // keep it locked until the API user is done using it.
558 : : // We also don't write out the manifest yet, because until
559 : : // cache_release is called we still might be working on creating
560 : : // the artifacts to cache.
561 : :
562 : : uint8_t bin_digest[48];
563 : 148 : int rc = blake2b_final(&ch->blake, bin_digest, 48);
564 : 148 : assert(rc == 0);
565 : 148 : buf_resize(out_digest, 64);
566 : 148 : base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
567 : :
568 : 148 : return ErrorNone;
569 : : }
570 : :
571 : 148 : void cache_release(CacheHash *ch) {
572 : 148 : assert(ch->manifest_file_path != nullptr);
573 : :
574 : : Error err;
575 : :
576 [ + + ]: 148 : if (ch->manifest_dirty) {
577 [ - + ]: 74 : if ((err = write_manifest_file(ch))) {
578 : 0 : fprintf(stderr, "Warning: Unable to write cache file '%s': %s\n",
579 : : buf_ptr(ch->manifest_file_path), err_str(err));
580 : : }
581 : : }
582 : :
583 : 148 : os_file_close(&ch->manifest_file);
584 : 148 : }
585 : :
|