Imported Upstream version 3.3.2
[platform/upstream/ccache.git] / manifest.c
1 // Copyright (C) 2009-2016 Joel Rosdahl
2 //
3 // This program is free software; you can redistribute it and/or modify it
4 // under the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3 of the License, or (at your option)
6 // any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 // more details.
12 //
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, write to the Free Software Foundation, Inc., 51
15 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17 #include "ccache.h"
18 #include "hashtable_itr.h"
19 #include "hashutil.h"
20 #include "manifest.h"
21 #include "murmurhashneutral2.h"
22
23 #include <zlib.h>
24
25 // Sketchy specification of the manifest disk format:
26 //
27 // <magic>         magic number                        (4 bytes)
28 // <version>       file format version                 (1 byte unsigned int)
29 // <hash_size>     size of the hash fields (in bytes)  (1 byte unsigned int)
30 // <reserved>      reserved for future use             (2 bytes)
31 // ----------------------------------------------------------------------------
32 // <n>             number of include file paths        (4 bytes unsigned int)
33 // <path_0>        path to include file                (NUL-terminated string,
34 // ...                                                  at most 1024 bytes)
35 // <path_n-1>
36 // ----------------------------------------------------------------------------
37 // <n>             number of include file hash entries (4 bytes unsigned int)
38 // <index[0]>      index of include file path          (4 bytes unsigned int)
39 // <hash[0]>       hash of include file                (<hash_size> bytes)
40 // <size[0]>       size of include file                (4 bytes unsigned int)
41 // <mtime[0]>      mtime of include file               (8 bytes signed int)
42 // <ctime[0]>      ctime of include file               (8 bytes signed int)
43 // ...
44 // <index[n-1]>
45 // <hash[n-1]>
46 // <size[n-1]>
47 // <mtime[n-1]>
48 // <ctime[n-1]>
49 // ----------------------------------------------------------------------------
50 // <n>             number of object name entries       (4 bytes unsigned int)
51 // <m[0]>          number of include file hash indexes (4 bytes unsigned int)
52 // <index[0][0]>   include file hash index             (4 bytes unsigned int)
53 // ...
54 // <index[0][m[0]-1]>
55 // <hash[0]>       hash part of object name            (<hash_size> bytes)
56 // <size[0]>       size part of object name            (4 bytes unsigned int)
57 // ...
58 // <m[n-1]>        number of include file hash indexes
59 // <index[n-1][0]> include file hash index
60 // ...
61 // <index[n-1][m[n-1]]>
62 // <hash[n-1]>
63 // <size[n-1]>
64
65 static const uint32_t MAGIC = 0x63436d46U;
66 static const uint32_t MAX_MANIFEST_ENTRIES = 100;
67 static const uint32_t MAX_MANIFEST_FILE_INFO_ENTRIES = 10000;
68
69 #define ccache_static_assert(e) \
70   do { enum { ccache_static_assert__ = 1/(e) }; } while (false)
71
72 struct file_info {
73         // Index to n_files.
74         uint32_t index;
75         // Hash of referenced file.
76         uint8_t hash[16];
77         // Size of referenced file.
78         uint32_t size;
79         // mtime of referenced file.
80         int64_t mtime;
81         // ctime of referenced file.
82         int64_t ctime;
83 };
84
85 struct object {
86         // Number of entries in file_info_indexes.
87         uint32_t n_file_info_indexes;
88         // Indexes to file_infos.
89         uint32_t *file_info_indexes;
90         // Hash of the object itself.
91         struct file_hash hash;
92 };
93
94 struct manifest {
95         // Version of decoded file.
96         uint8_t version;
97
98         // Reserved for future use.
99         uint16_t reserved;
100
101         // Size of hash fields (in bytes).
102         uint8_t hash_size;
103
104         // Referenced include files.
105         uint32_t n_files;
106         char **files;
107
108         // Information about referenced include files.
109         uint32_t n_file_infos;
110         struct file_info *file_infos;
111
112         // Object names plus references to include file hashes.
113         uint32_t n_objects;
114         struct object *objects;
115 };
116
117 struct file_stats {
118         uint32_t size;
119         int64_t mtime;
120         int64_t ctime;
121 };
122
123 static unsigned int
124 hash_from_file_info(void *key)
125 {
126         ccache_static_assert(sizeof(struct file_info) == 40); // No padding.
127         return murmurhashneutral2(key, sizeof(struct file_info), 0);
128 }
129
130 static int
131 file_infos_equal(void *key1, void *key2)
132 {
133         struct file_info *fi1 = (struct file_info *)key1;
134         struct file_info *fi2 = (struct file_info *)key2;
135         return fi1->index == fi2->index
136                && memcmp(fi1->hash, fi2->hash, 16) == 0
137                && fi1->size == fi2->size
138                && fi1->mtime == fi2->mtime
139                && fi1->ctime == fi2->ctime;
140 }
141
142 static void
143 free_manifest(struct manifest *mf)
144 {
145         for (uint32_t i = 0; i < mf->n_files; i++) {
146                 free(mf->files[i]);
147         }
148         free(mf->files);
149         free(mf->file_infos);
150         for (uint32_t i = 0; i < mf->n_objects; i++) {
151                 free(mf->objects[i].file_info_indexes);
152         }
153         free(mf->objects);
154         free(mf);
155 }
156
157 #define READ_BYTE(var) \
158   do { \
159                 int ch_ = gzgetc(f); \
160                 if (ch_ == EOF) { \
161                         goto error; \
162                 } \
163                 (var) = ch_ & 0xFF; \
164         } while (false)
165
166 #define READ_INT(size, var) \
167   do { \
168                 (var) = 0; \
169                 for (size_t i_ = 0; i_ < (size); i_++) { \
170                         int ch_ = gzgetc(f); \
171                         if (ch_ == EOF) { \
172                                 goto error; \
173                         } \
174                         (var) <<= 8; \
175                         (var) |= ch_ & 0xFF; \
176                 } \
177         } while (false)
178
179 #define READ_STR(var) \
180   do { \
181                 char buf_[1024]; \
182                 size_t i_; \
183                 for (i_ = 0; i_ < sizeof(buf_); i_++) { \
184                         int ch_ = gzgetc(f); \
185                         if (ch_ == EOF) { \
186                                 goto error; \
187                         } \
188                         buf_[i_] = ch_; \
189                         if (ch_ == '\0') { \
190                                 break; \
191                         } \
192                 } \
193                 if (i_ == sizeof(buf_)) { \
194                         goto error; \
195                 } \
196                 (var) = x_strdup(buf_); \
197         } while (false)
198
199 #define READ_BYTES(n, var) \
200   do { \
201                 for (size_t i_ = 0; i_ < (n); i_++) { \
202                         int ch_ = gzgetc(f); \
203                         if (ch_ == EOF) { \
204                                 goto error; \
205                         } \
206                         (var)[i_] = ch_; \
207                 } \
208         } while (false)
209
210 static struct manifest *
211 create_empty_manifest(void)
212 {
213         struct manifest *mf = x_malloc(sizeof(*mf));
214         mf->hash_size = 16;
215         mf->n_files = 0;
216         mf->files = NULL;
217         mf->n_file_infos = 0;
218         mf->file_infos = NULL;
219         mf->n_objects = 0;
220         mf->objects = NULL;
221
222         return mf;
223 }
224
225 static struct manifest *
226 read_manifest(gzFile f)
227 {
228         struct manifest *mf = create_empty_manifest();
229
230         uint32_t magic;
231         READ_INT(4, magic);
232         if (magic != MAGIC) {
233                 cc_log("Manifest file has bad magic number %u", magic);
234                 goto error;
235         }
236
237         READ_BYTE(mf->version);
238         if (mf->version != MANIFEST_VERSION) {
239                 cc_log("Manifest file has unknown version %u", mf->version);
240                 goto error;
241         }
242
243         READ_BYTE(mf->hash_size);
244         if (mf->hash_size != 16) {
245                 // Temporary measure until we support different hash algorithms.
246                 cc_log("Manifest file has unsupported hash size %u", mf->hash_size);
247                 goto error;
248         }
249
250         READ_INT(2, mf->reserved);
251
252         READ_INT(4, mf->n_files);
253         mf->files = x_calloc(mf->n_files, sizeof(*mf->files));
254         for (uint32_t i = 0; i < mf->n_files; i++) {
255                 READ_STR(mf->files[i]);
256         }
257
258         READ_INT(4, mf->n_file_infos);
259         mf->file_infos = x_calloc(mf->n_file_infos, sizeof(*mf->file_infos));
260         for (uint32_t i = 0; i < mf->n_file_infos; i++) {
261                 READ_INT(4, mf->file_infos[i].index);
262                 READ_BYTES(mf->hash_size, mf->file_infos[i].hash);
263                 READ_INT(4, mf->file_infos[i].size);
264                 READ_INT(8, mf->file_infos[i].mtime);
265                 READ_INT(8, mf->file_infos[i].ctime);
266         }
267
268         READ_INT(4, mf->n_objects);
269         mf->objects = x_calloc(mf->n_objects, sizeof(*mf->objects));
270         for (uint32_t i = 0; i < mf->n_objects; i++) {
271                 READ_INT(4, mf->objects[i].n_file_info_indexes);
272                 mf->objects[i].file_info_indexes =
273                   x_calloc(mf->objects[i].n_file_info_indexes,
274                            sizeof(*mf->objects[i].file_info_indexes));
275                 for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
276                         READ_INT(4, mf->objects[i].file_info_indexes[j]);
277                 }
278                 READ_BYTES(mf->hash_size, mf->objects[i].hash.hash);
279                 READ_INT(4, mf->objects[i].hash.size);
280         }
281
282         return mf;
283
284 error:
285         cc_log("Corrupt manifest file");
286         free_manifest(mf);
287         return NULL;
288 }
289
290 #define WRITE_INT(size, var) \
291   do { \
292                 uint8_t ch_; \
293                 size_t i_; \
294                 for (i_ = 0; i_ < (size); i_++) { \
295                         ch_ = ((var) >> (8 * ((size) - i_ - 1))); \
296                         if (gzputc(f, ch_) == EOF) { \
297                                 goto error; \
298                         } \
299                 } \
300         } while (false)
301
302 #define WRITE_STR(var) \
303   do { \
304                 if (gzputs(f, var) == EOF || gzputc(f, '\0') == EOF) { \
305                         goto error; \
306                 } \
307         } while (false)
308
309 #define WRITE_BYTES(n, var) \
310   do { \
311                 size_t i_; \
312                 for (i_ = 0; i_ < (n); i_++) { \
313                         if (gzputc(f, (var)[i_]) == EOF) { \
314                                 goto error; \
315                         } \
316                 } \
317         } while (false)
318
319 static int
320 write_manifest(gzFile f, const struct manifest *mf)
321 {
322         WRITE_INT(4, MAGIC);
323         WRITE_INT(1, MANIFEST_VERSION);
324         WRITE_INT(1, 16);
325         WRITE_INT(2, 0);
326
327         WRITE_INT(4, mf->n_files);
328         for (uint32_t i = 0; i < mf->n_files; i++) {
329                 WRITE_STR(mf->files[i]);
330         }
331
332         WRITE_INT(4, mf->n_file_infos);
333         for (uint32_t i = 0; i < mf->n_file_infos; i++) {
334                 WRITE_INT(4, mf->file_infos[i].index);
335                 WRITE_BYTES(mf->hash_size, mf->file_infos[i].hash);
336                 WRITE_INT(4, mf->file_infos[i].size);
337                 WRITE_INT(8, mf->file_infos[i].mtime);
338                 WRITE_INT(8, mf->file_infos[i].ctime);
339         }
340
341         WRITE_INT(4, mf->n_objects);
342         for (uint32_t i = 0; i < mf->n_objects; i++) {
343                 WRITE_INT(4, mf->objects[i].n_file_info_indexes);
344                 for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
345                         WRITE_INT(4, mf->objects[i].file_info_indexes[j]);
346                 }
347                 WRITE_BYTES(mf->hash_size, mf->objects[i].hash.hash);
348                 WRITE_INT(4, mf->objects[i].hash.size);
349         }
350
351         return 1;
352
353 error:
354         cc_log("Error writing to manifest file");
355         return 0;
356 }
357
358 static int
359 verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
360               struct hashtable *stated_files, struct hashtable *hashed_files)
361 {
362         for (uint32_t i = 0; i < obj->n_file_info_indexes; i++) {
363                 struct file_info *fi = &mf->file_infos[obj->file_info_indexes[i]];
364                 char *path = mf->files[fi->index];
365                 struct file_stats *st = hashtable_search(stated_files, path);
366                 if (!st) {
367                         struct stat file_stat;
368                         if (x_stat(path, &file_stat) != 0) {
369                                 return 0;
370                         }
371                         st = x_malloc(sizeof(*st));
372                         st->size = file_stat.st_size;
373                         st->mtime = file_stat.st_mtime;
374                         st->ctime = file_stat.st_ctime;
375                         hashtable_insert(stated_files, x_strdup(path), st);
376                 }
377
378                 if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
379                         // st->ctime is sometimes 0, so we can't check that both st->ctime and
380                         // st->mtime are greater than time_of_compilation. But it's sufficient to
381                         // check that either is.
382                         if (fi->size == st->size
383                             && fi->mtime == st->mtime
384                             && fi->ctime == st->ctime
385                             && MAX(st->mtime, st->ctime) >= time_of_compilation) {
386                                 cc_log("size/mtime/ctime hit for %s", path);
387                                 continue;
388                         } else {
389                                 cc_log("size/mtime/ctime miss for %s", path);
390                         }
391                 }
392
393                 struct file_hash *actual = hashtable_search(hashed_files, path);
394                 if (!actual) {
395                         struct mdfour hash;
396                         hash_start(&hash);
397                         int result = hash_source_code_file(conf, &hash, path);
398                         if (result & HASH_SOURCE_CODE_ERROR) {
399                                 cc_log("Failed hashing %s", path);
400                                 return 0;
401                         }
402                         if (result & HASH_SOURCE_CODE_FOUND_TIME) {
403                                 return 0;
404                         }
405                         actual = x_malloc(sizeof(*actual));
406                         hash_result_as_bytes(&hash, actual->hash);
407                         actual->size = hash.totalN;
408                         hashtable_insert(hashed_files, x_strdup(path), actual);
409                 }
410                 if (memcmp(fi->hash, actual->hash, mf->hash_size) != 0
411                     || fi->size != actual->size) {
412                         return 0;
413                 }
414         }
415
416         return 1;
417 }
418
419 static struct hashtable *
420 create_string_index_map(char **strings, uint32_t len)
421 {
422         struct hashtable *h =
423           create_hashtable(1000, hash_from_string, strings_equal);
424         for (uint32_t i = 0; i < len; i++) {
425                 uint32_t *index = x_malloc(sizeof(*index));
426                 *index = i;
427                 hashtable_insert(h, x_strdup(strings[i]), index);
428         }
429         return h;
430 }
431
432 static struct hashtable *
433 create_file_info_index_map(struct file_info *infos, uint32_t len)
434 {
435         struct hashtable *h =
436           create_hashtable(1000, hash_from_file_info, file_infos_equal);
437         for (uint32_t i = 0; i < len; i++) {
438                 struct file_info *fi = x_malloc(sizeof(*fi));
439                 *fi = infos[i];
440                 uint32_t *index = x_malloc(sizeof(*index));
441                 *index = i;
442                 hashtable_insert(h, fi, index);
443         }
444         return h;
445 }
446
447 static uint32_t
448 get_include_file_index(struct manifest *mf, char *path,
449                        struct hashtable *mf_files)
450 {
451         uint32_t *index = hashtable_search(mf_files, path);
452         if (index) {
453                 return *index;
454         }
455
456         uint32_t n = mf->n_files;
457         mf->files = x_realloc(mf->files, (n + 1) * sizeof(*mf->files));
458         mf->n_files++;
459         mf->files[n] = x_strdup(path);
460         return n;
461 }
462
463 static uint32_t
464 get_file_hash_index(struct manifest *mf,
465                     char *path,
466                     struct file_hash *file_hash,
467                     struct hashtable *mf_files,
468                     struct hashtable *mf_file_infos)
469 {
470         struct file_info fi;
471         fi.index = get_include_file_index(mf, path, mf_files);
472         memcpy(fi.hash, file_hash->hash, sizeof(fi.hash));
473         fi.size = file_hash->size;
474
475         // file_stat.st_{m,c}time has a resolution of 1 second, so we can cache the
476         // file's mtime and ctime only if they're at least one second older than
477         // time_of_compilation.
478         //
479         // st->ctime may be 0, so we have to check time_of_compilation against
480         // MAX(mtime, ctime).
481
482         struct stat file_stat;
483         if (stat(path, &file_stat) != -1
484             && time_of_compilation > MAX(file_stat.st_mtime, file_stat.st_ctime)) {
485                 fi.mtime = file_stat.st_mtime;
486                 fi.ctime = file_stat.st_ctime;
487         } else {
488                 fi.mtime = -1;
489                 fi.ctime = -1;
490         }
491
492         uint32_t *fi_index = hashtable_search(mf_file_infos, &fi);
493         if (fi_index) {
494                 return *fi_index;
495         }
496
497         uint32_t n = mf->n_file_infos;
498         mf->file_infos = x_realloc(mf->file_infos, (n + 1) * sizeof(*mf->file_infos));
499         mf->n_file_infos++;
500         mf->file_infos[n] = fi;
501         return n;
502 }
503
504 static void
505 add_file_info_indexes(uint32_t *indexes, uint32_t size,
506                       struct manifest *mf, struct hashtable *included_files)
507 {
508         if (size == 0) {
509                 return;
510         }
511
512         // path --> index
513         struct hashtable *mf_files =
514           create_string_index_map(mf->files, mf->n_files);
515         // struct file_info --> index
516         struct hashtable *mf_file_infos =
517           create_file_info_index_map(mf->file_infos, mf->n_file_infos);
518         struct hashtable_itr *iter = hashtable_iterator(included_files);
519         uint32_t i = 0;
520         do {
521                 char *path = hashtable_iterator_key(iter);
522                 struct file_hash *file_hash = hashtable_iterator_value(iter);
523                 indexes[i] = get_file_hash_index(mf, path, file_hash, mf_files,
524                                                  mf_file_infos);
525                 i++;
526         } while (hashtable_iterator_advance(iter));
527         assert(i == size);
528
529         hashtable_destroy(mf_file_infos, 1);
530         hashtable_destroy(mf_files, 1);
531 }
532
533 static void
534 add_object_entry(struct manifest *mf,
535                  struct file_hash *object_hash,
536                  struct hashtable *included_files)
537 {
538         uint32_t n_objs = mf->n_objects;
539         mf->objects = x_realloc(mf->objects, (n_objs + 1) * sizeof(*mf->objects));
540         mf->n_objects++;
541         struct object *obj = &mf->objects[n_objs];
542
543         uint32_t n_fii = hashtable_count(included_files);
544         obj->n_file_info_indexes = n_fii;
545         obj->file_info_indexes = x_malloc(n_fii * sizeof(*obj->file_info_indexes));
546         add_file_info_indexes(obj->file_info_indexes, n_fii, mf, included_files);
547         memcpy(obj->hash.hash, object_hash->hash, mf->hash_size);
548         obj->hash.size = object_hash->size;
549 }
550
551 // Try to get the object hash from a manifest file. Caller frees. Returns NULL
552 // on failure.
553 struct file_hash *
554 manifest_get(struct conf *conf, const char *manifest_path)
555 {
556         gzFile f = NULL;
557         struct manifest *mf = NULL;
558         struct hashtable *hashed_files = NULL; // path --> struct file_hash
559         struct hashtable *stated_files = NULL; // path --> struct file_stats
560         struct file_hash *fh = NULL;
561
562         int fd = open(manifest_path, O_RDONLY | O_BINARY);
563         if (fd == -1) {
564                 // Cache miss.
565                 cc_log("No such manifest file");
566                 goto out;
567         }
568         f = gzdopen(fd, "rb");
569         if (!f) {
570                 close(fd);
571                 cc_log("Failed to gzdopen manifest file");
572                 goto out;
573         }
574         mf = read_manifest(f);
575         if (!mf) {
576                 cc_log("Error reading manifest file");
577                 goto out;
578         }
579
580         hashed_files = create_hashtable(1000, hash_from_string, strings_equal);
581         stated_files = create_hashtable(1000, hash_from_string, strings_equal);
582
583         // Check newest object first since it's a bit more likely to match.
584         for (uint32_t i = mf->n_objects; i > 0; i--) {
585                 if (verify_object(conf, mf, &mf->objects[i - 1],
586                                   stated_files, hashed_files)) {
587                         fh = x_malloc(sizeof(*fh));
588                         *fh = mf->objects[i - 1].hash;
589                         goto out;
590                 }
591         }
592
593 out:
594         if (hashed_files) {
595                 hashtable_destroy(hashed_files, 1);
596         }
597         if (stated_files) {
598                 hashtable_destroy(stated_files, 1);
599         }
600         if (f) {
601                 gzclose(f);
602         }
603         if (mf) {
604                 free_manifest(mf);
605         }
606         return fh;
607 }
608
609 // Put the object name into a manifest file given a set of included files.
610 // Returns true on success, otherwise false.
611 bool
612 manifest_put(const char *manifest_path, struct file_hash *object_hash,
613              struct hashtable *included_files)
614 {
615         int ret = 0;
616         gzFile f2 = NULL;
617         struct manifest *mf = NULL;
618         char *tmp_file = NULL;
619
620         // We don't bother to acquire a lock when writing the manifest to disk. A
621         // race between two processes will only result in one lost entry, which is
622         // not a big deal, and it's also very unlikely.
623
624         int fd1 = open(manifest_path, O_RDONLY | O_BINARY);
625         if (fd1 == -1) {
626                 // New file.
627                 mf = create_empty_manifest();
628         } else {
629                 gzFile f1 = gzdopen(fd1, "rb");
630                 if (!f1) {
631                         cc_log("Failed to gzdopen manifest file");
632                         close(fd1);
633                         goto out;
634                 }
635                 mf = read_manifest(f1);
636                 gzclose(f1);
637                 if (!mf) {
638                         cc_log("Failed to read manifest file; deleting it");
639                         x_unlink(manifest_path);
640                         mf = create_empty_manifest();
641                 }
642         }
643
644         if (mf->n_objects > MAX_MANIFEST_ENTRIES) {
645                 // Normally, there shouldn't be many object entries in the manifest since
646                 // new entries are added only if an include file has changed but not the
647                 // source file, and you typically change source files more often than
648                 // header files. However, it's certainly possible to imagine cases where
649                 // the manifest will grow large (for instance, a generated header file that
650                 // changes for every build), and this must be taken care of since
651                 // processing an ever growing manifest eventually will take too much time.
652                 // A good way of solving this would be to maintain the object entries in
653                 // LRU order and discarding the old ones. An easy way is to throw away all
654                 // entries when there are too many. Let's do that for now.
655                 cc_log("More than %u entries in manifest file; discarding",
656                        MAX_MANIFEST_ENTRIES);
657                 free_manifest(mf);
658                 mf = create_empty_manifest();
659         } else if (mf->n_file_infos > MAX_MANIFEST_FILE_INFO_ENTRIES) {
660                 // Rarely, file_info entries can grow large in pathological cases where
661                 // many included files change, but the main file does not. This also puts
662                 // an upper bound on the number of file_info entries.
663                 cc_log("More than %u file_info entries in manifest file; discarding",
664                        MAX_MANIFEST_FILE_INFO_ENTRIES);
665                 free_manifest(mf);
666                 mf = create_empty_manifest();
667         }
668
669         tmp_file = format("%s.tmp", manifest_path);
670         int fd2 = create_tmp_fd(&tmp_file);
671         f2 = gzdopen(fd2, "wb");
672         if (!f2) {
673                 cc_log("Failed to gzdopen %s", tmp_file);
674                 goto out;
675         }
676
677         add_object_entry(mf, object_hash, included_files);
678         if (write_manifest(f2, mf)) {
679                 gzclose(f2);
680                 f2 = NULL;
681                 if (x_rename(tmp_file, manifest_path) == 0) {
682                         ret = 1;
683                 } else {
684                         cc_log("Failed to rename %s to %s", tmp_file, manifest_path);
685                         goto out;
686                 }
687         } else {
688                 cc_log("Failed to write manifest file");
689                 goto out;
690         }
691
692 out:
693         if (mf) {
694                 free_manifest(mf);
695         }
696         if (tmp_file) {
697                 free(tmp_file);
698         }
699         if (f2) {
700                 gzclose(f2);
701         }
702         return ret;
703 }
704
705 bool
706 manifest_dump(const char *manifest_path, FILE *stream)
707 {
708         struct manifest *mf = NULL;
709         gzFile f = NULL;
710         bool ret = false;
711
712         int fd = open(manifest_path, O_RDONLY | O_BINARY);
713         if (fd == -1) {
714                 fprintf(stderr, "No such manifest file: %s\n", manifest_path);
715                 goto out;
716         }
717         f = gzdopen(fd, "rb");
718         if (!f) {
719                 fprintf(stderr, "Failed to dzopen manifest file\n");
720                 close(fd);
721                 goto out;
722         }
723         mf = read_manifest(f);
724         if (!mf) {
725                 fprintf(stderr, "Error reading manifest file\n");
726                 goto out;
727         }
728
729         fprintf(stream, "Magic: %c%c%c%c\n",
730                 (MAGIC >> 24) & 0xFF,
731                 (MAGIC >> 16) & 0xFF,
732                 (MAGIC >> 8) & 0xFF,
733                 MAGIC & 0xFF);
734         fprintf(stream, "Version: %u\n", mf->version);
735         fprintf(stream, "Hash size: %u\n", (unsigned)mf->hash_size);
736         fprintf(stream, "Reserved field: %u\n", (unsigned)mf->reserved);
737         fprintf(stream, "File paths (%u):\n", (unsigned)mf->n_files);
738         for (unsigned i = 0; i < mf->n_files; ++i) {
739                 fprintf(stream, "  %u: %s\n", i, mf->files[i]);
740         }
741         fprintf(stream, "File infos (%u):\n", (unsigned)mf->n_file_infos);
742         for (unsigned i = 0; i < mf->n_file_infos; ++i) {
743                 char *hash;
744                 fprintf(stream, "  %u:\n", i);
745                 fprintf(stream, "    Path index: %u\n", mf->file_infos[i].index);
746                 hash = format_hash_as_string(mf->file_infos[i].hash, -1);
747                 fprintf(stream, "    Hash: %s\n", hash);
748                 free(hash);
749                 fprintf(stream, "    Size: %u\n", mf->file_infos[i].size);
750                 fprintf(stream, "    Mtime: %lld\n", (long long)mf->file_infos[i].mtime);
751                 fprintf(stream, "    Ctime: %lld\n", (long long)mf->file_infos[i].ctime);
752         }
753         fprintf(stream, "Results (%u):\n", (unsigned)mf->n_objects);
754         for (unsigned i = 0; i < mf->n_objects; ++i) {
755                 char *hash;
756                 fprintf(stream, "  %u:\n", i);
757                 fprintf(stream, "    File info indexes:");
758                 for (unsigned j = 0; j < mf->objects[i].n_file_info_indexes; ++j) {
759                         fprintf(stream, " %u", mf->objects[i].file_info_indexes[j]);
760                 }
761                 fprintf(stream, "\n");
762                 hash = format_hash_as_string(mf->objects[i].hash.hash, -1);
763                 fprintf(stream, "    Hash: %s\n", hash);
764                 free(hash);
765                 fprintf(stream, "    Size: %u\n", (unsigned)mf->objects[i].hash.size);
766         }
767
768         ret = true;
769
770 out:
771         if (mf) {
772                 free_manifest(mf);
773         }
774         if (f) {
775                 gzclose(f);
776         }
777         return ret;
778 }