1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "journal-def.h"
29 #include "journal-file.h"
30 #include "journal-authenticate.h"
31 #include "journal-verify.h"
38 * - evolve key even if nothing happened in regular intervals
40 * - Allow building without libgcrypt
46 static int journal_file_object_verify(JournalFile *f, Object *o) {
52 /* This does various superficial tests about the length an
53 * possible field values. It does not follow any references to
56 if ((o->object.flags & OBJECT_COMPRESSED) &&
57 o->object.type != OBJECT_DATA)
60 switch (o->object.type) {
65 if (le64toh(o->data.entry_offset) <= 0 ||
66 le64toh(o->data.n_entries) <= 0)
69 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
72 h1 = le64toh(o->data.hash);
74 if (o->object.flags & OBJECT_COMPRESSED) {
76 uint64_t alloc = 0, b_size;
78 if (!uncompress_blob(o->data.payload,
79 le64toh(o->object.size) - offsetof(Object, data.payload),
83 h2 = hash64(b, b_size);
86 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
91 if (!VALID64(o->data.next_hash_offset) ||
92 !VALID64(o->data.next_field_offset) ||
93 !VALID64(o->data.entry_offset) ||
94 !VALID64(o->data.entry_array_offset))
101 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
104 if (!VALID64(o->field.next_hash_offset) ||
105 !VALID64(o->field.head_data_offset))
110 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
113 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
116 if (le64toh(o->entry.seqnum) <= 0 ||
117 !VALID_REALTIME(le64toh(o->entry.realtime)) ||
118 !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
121 for (i = 0; i < journal_file_entry_n_items(o); i++) {
122 if (o->entry.items[i].object_offset == 0 ||
123 !VALID64(o->entry.items[i].object_offset))
129 case OBJECT_DATA_HASH_TABLE:
130 case OBJECT_FIELD_HASH_TABLE:
131 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
134 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
137 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
138 if (o->hash_table.items[i].head_hash_offset != 0 &&
139 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
141 if (o->hash_table.items[i].tail_hash_offset != 0 &&
142 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
145 if ((o->hash_table.items[i].head_hash_offset != 0) !=
146 (o->hash_table.items[i].tail_hash_offset != 0))
152 case OBJECT_ENTRY_ARRAY:
153 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
156 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
159 if (!VALID64(o->entry_array.next_entry_array_offset))
162 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
163 if (o->entry_array.items[i] != 0 &&
164 !VALID64(o->entry_array.items[i]))
170 if (le64toh(o->object.size) != sizeof(TagObject))
173 if (!VALID_EPOCH(o->tag.epoch))
182 static void draw_progress(uint64_t p, usec_t *last_usec) {
186 if (!isatty(STDOUT_FILENO))
189 z = now(CLOCK_MONOTONIC);
192 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
197 n = (3 * columns()) / 4;
198 j = (n * (unsigned) p) / 65535ULL;
201 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
203 for (i = 0; i < j; i++)
204 fputs("\xe2\x96\x88", stdout);
206 fputs(ANSI_HIGHLIGHT_OFF, stdout);
208 for (i = 0; i < k; i++)
209 fputs("\xe2\x96\x91", stdout);
211 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
213 fputs("\r\x1B[?25h", stdout);
217 static void flush_progress(void) {
220 if (!isatty(STDOUT_FILENO))
223 n = (3 * columns()) / 4;
227 for (i = 0; i < n + 5; i++)
234 static int write_uint64(int fd, uint64_t p) {
237 k = write(fd, &p, sizeof(p));
246 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
261 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
281 static int entry_points_to_data(
294 assert(entry_fd >= 0);
296 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
297 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
301 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
305 n = journal_file_entry_n_items(o);
306 for (i = 0; i < n; i++)
307 if (le64toh(o->entry.items[i].object_offset) == data_p) {
313 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
317 /* Check if this entry is also in main entry array. Since the
318 * main entry array has already been verified we can rely on
321 n = le64toh(f->header->n_entries);
322 a = le64toh(f->header->entry_array_offset);
328 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
332 m = journal_file_entry_array_n_items(o);
333 for (j = 0; i < n && j < m; i++, j++)
334 if (le64toh(o->entry_array.items[j]) == entry_p)
337 a = le64toh(o->entry_array.next_entry_array_offset);
343 static int verify_data(
345 Object *o, uint64_t p,
346 int entry_fd, uint64_t n_entries,
347 int entry_array_fd, uint64_t n_entry_arrays) {
349 uint64_t i, n, a, last, q;
354 assert(entry_fd >= 0);
355 assert(entry_array_fd >= 0);
357 n = le64toh(o->data.n_entries);
358 a = le64toh(o->data.entry_array_offset);
360 /* We already checked this earlier */
363 last = q = le64toh(o->data.entry_offset);
364 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
373 log_error("Array chain too short at %llu", (unsigned long long) p);
377 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
378 log_error("Invalid array at %llu", (unsigned long long) p);
382 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
386 next = le64toh(o->entry_array.next_entry_array_offset);
387 if (next != 0 && next <= a) {
388 log_error("Array chain has cycle at %llu", (unsigned long long) p);
392 m = journal_file_entry_array_n_items(o);
393 for (j = 0; i < n && j < m; i++, j++) {
395 q = le64toh(o->entry_array.items[j]);
397 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
402 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
406 /* Pointer might have moved, reposition */
407 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
418 static int verify_hash_table(
420 int data_fd, uint64_t n_data,
421 int entry_fd, uint64_t n_entries,
422 int entry_array_fd, uint64_t n_entry_arrays,
424 bool show_progress) {
430 assert(data_fd >= 0);
431 assert(entry_fd >= 0);
432 assert(entry_array_fd >= 0);
435 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
436 for (i = 0; i < n; i++) {
437 uint64_t last = 0, p;
440 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
442 p = le64toh(f->data_hash_table[i].head_hash_offset);
447 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
448 log_error("Invalid data object at hash entry %llu of %llu",
449 (unsigned long long) i, (unsigned long long) n);
453 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
457 next = le64toh(o->data.next_hash_offset);
458 if (next != 0 && next <= p) {
459 log_error("Hash chain has a cycle in hash entry %llu of %llu",
460 (unsigned long long) i, (unsigned long long) n);
464 if (le64toh(o->data.hash) % n != i) {
465 log_error("Hash value mismatch in hash entry %llu of %llu",
466 (unsigned long long) i, (unsigned long long) n);
470 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
478 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
479 log_error("Tail hash pointer mismatch in hash table");
487 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
492 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
495 q = le64toh(f->data_hash_table[h].head_hash_offset);
502 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
506 q = le64toh(o->data.next_hash_offset);
512 static int verify_entry(
514 Object *o, uint64_t p,
515 int data_fd, uint64_t n_data) {
522 assert(data_fd >= 0);
524 n = journal_file_entry_n_items(o);
525 for (i = 0; i < n; i++) {
529 q = le64toh(o->entry.items[i].object_offset);
530 h = le64toh(o->entry.items[i].hash);
532 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
533 log_error("Invalid data object at entry %llu",
534 (unsigned long long) p);
538 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
542 if (le64toh(u->data.hash) != h) {
543 log_error("Hash mismatch for data object at entry %llu",
544 (unsigned long long) p);
548 r = data_object_in_hash_table(f, h, q);
552 log_error("Data object missing from hash at entry %llu",
553 (unsigned long long) p);
561 static int verify_entry_array(
563 int data_fd, uint64_t n_data,
564 int entry_fd, uint64_t n_entries,
565 int entry_array_fd, uint64_t n_entry_arrays,
567 bool show_progress) {
569 uint64_t i = 0, a, n, last = 0;
573 assert(data_fd >= 0);
574 assert(entry_fd >= 0);
575 assert(entry_array_fd >= 0);
578 n = le64toh(f->header->n_entries);
579 a = le64toh(f->header->entry_array_offset);
585 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
588 log_error("Array chain too short at %llu of %llu",
589 (unsigned long long) i, (unsigned long long) n);
593 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
594 log_error("Invalid array at %llu of %llu",
595 (unsigned long long) i, (unsigned long long) n);
599 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
603 next = le64toh(o->entry_array.next_entry_array_offset);
604 if (next != 0 && next <= a) {
605 log_error("Array chain has cycle at %llu of %llu",
606 (unsigned long long) i, (unsigned long long) n);
610 m = journal_file_entry_array_n_items(o);
611 for (j = 0; i < n && j < m; i++, j++) {
614 p = le64toh(o->entry_array.items[j]);
616 log_error("Entry array not sorted at %llu of %llu",
617 (unsigned long long) i, (unsigned long long) n);
622 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
623 log_error("Invalid array entry at %llu of %llu",
624 (unsigned long long) i, (unsigned long long) n);
628 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
632 r = verify_entry(f, o, p, data_fd, n_data);
636 /* Pointer might have moved, reposition */
637 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
648 static int journal_file_parse_verification_key(JournalFile *f, const char *key) {
653 unsigned long long start, interval;
655 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
656 seed = malloc(seed_size);
661 for (c = 0; c < seed_size; c++) {
680 seed[c] = (uint8_t) (x * 16 + y);
689 r = sscanf(k, "%llx-%llx", &start, &interval);
695 f->fsprg_seed = seed;
696 f->fsprg_seed_size = seed_size;
698 f->fss_start_usec = start * interval;
699 f->fss_interval_usec = interval;
704 int journal_file_verify(
707 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
708 bool show_progress) {
711 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
712 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
713 sd_id128_t entry_boot_id;
714 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
715 uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0;
716 usec_t last_usec = 0;
717 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
718 char data_path[] = "/var/tmp/journal-data-XXXXXX",
719 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
720 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
727 r = journal_file_parse_verification_key(f, key);
729 log_error("Failed to parse seed.");
735 data_fd = mkostemp(data_path, O_CLOEXEC);
737 log_error("Failed to create data file: %m");
743 entry_fd = mkostemp(entry_path, O_CLOEXEC);
745 log_error("Failed to create entry file: %m");
751 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
752 if (entry_array_fd < 0) {
753 log_error("Failed to create entry array file: %m");
757 unlink(entry_array_path);
760 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
762 if (f->header->compatible_flags != 0)
765 log_error("Cannot verify file with unknown extensions.");
770 for (i = 0; i < sizeof(f->header->reserved); i++)
771 if (f->header->reserved[i] != 0) {
772 log_error("Reserved field in non-zero.");
777 /* First iteration: we go through all objects, verify the
778 * superficial structure, headers, hashes. */
780 p = le64toh(f->header->header_size);
783 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
785 r = journal_file_move_to_object(f, -1, p, &o);
787 log_error("Invalid object at %llu", (unsigned long long) p);
791 if (p > le64toh(f->header->tail_object_offset)) {
792 log_error("Invalid tail object pointer");
797 if (p == le64toh(f->header->tail_object_offset))
802 r = journal_file_object_verify(f, o);
804 log_error("Invalid object contents at %llu", (unsigned long long) p);
808 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
809 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
814 switch (o->object.type) {
817 r = write_uint64(data_fd, p);
829 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
830 log_error("First entry before first tag at %llu", (unsigned long long) p);
835 r = write_uint64(entry_fd, p);
839 if (le64toh(o->entry.realtime) < last_tag_realtime) {
840 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
845 if (!entry_seqnum_set &&
846 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
847 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
852 if (entry_seqnum_set &&
853 entry_seqnum >= le64toh(o->entry.seqnum)) {
854 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
859 entry_seqnum = le64toh(o->entry.seqnum);
860 entry_seqnum_set = true;
862 if (entry_monotonic_set &&
863 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
864 entry_monotonic > le64toh(o->entry.monotonic)) {
865 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
870 entry_monotonic = le64toh(o->entry.monotonic);
871 entry_boot_id = o->entry.boot_id;
872 entry_monotonic_set = true;
874 if (!entry_realtime_set &&
875 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
876 log_error("Head entry realtime timestamp incorrect");
881 entry_realtime = le64toh(o->entry.realtime);
882 entry_realtime_set = true;
887 case OBJECT_DATA_HASH_TABLE:
888 if (n_data_hash_tables > 1) {
889 log_error("More than one data hash table at %llu", (unsigned long long) p);
894 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
895 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
896 log_error("Header fields for data hash table invalid");
901 n_data_hash_tables++;
904 case OBJECT_FIELD_HASH_TABLE:
905 if (n_field_hash_tables > 1) {
906 log_error("More than one field hash table at %llu", (unsigned long long) p);
911 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
912 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
913 log_error("Header fields for field hash table invalid");
918 n_field_hash_tables++;
921 case OBJECT_ENTRY_ARRAY:
922 r = write_uint64(entry_array_fd, p);
926 if (p == le64toh(f->header->entry_array_offset)) {
927 if (found_main_entry_array) {
928 log_error("More than one main entry array at %llu", (unsigned long long) p);
933 found_main_entry_array = true;
942 if (!JOURNAL_HEADER_SEALED(f->header)) {
943 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
948 if (le64toh(o->tag.seqnum) != n_tags + 1) {
949 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
954 if (le64toh(o->tag.epoch) < last_epoch) {
955 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
961 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
963 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
964 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
965 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
970 /* OK, now we know the epoch. So let's now set
971 * it, and calculate the HMAC for everything
972 * since the last tag. */
973 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
977 r = journal_file_hmac_start(f);
982 r = journal_file_hmac_put_header(f);
986 q = le64toh(f->header->header_size);
991 r = journal_file_move_to_object(f, -1, q, &o);
995 r = journal_file_hmac_put_object(f, -1, q);
999 q = q + ALIGN64(le64toh(o->object.size));
1002 /* Position might have changed, let's reposition things */
1003 r = journal_file_move_to_object(f, -1, p, &o);
1007 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1008 log_error("Tag failed verification at %llu", (unsigned long long) p);
1013 f->hmac_running = false;
1014 last_tag_realtime = rt;
1015 last_sealed_realtime = entry_realtime;
1018 last_tag = p + ALIGN64(le64toh(o->object.size));
1019 last_epoch = le64toh(o->tag.epoch);
1029 if (p == le64toh(f->header->tail_object_offset))
1032 p = p + ALIGN64(le64toh(o->object.size));
1036 log_error("Tail object pointer dead");
1041 if (n_objects != le64toh(f->header->n_objects)) {
1042 log_error("Object number mismatch");
1047 if (n_entries != le64toh(f->header->n_entries)) {
1048 log_error("Entry number mismatch");
1053 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1054 n_data != le64toh(f->header->n_data)) {
1055 log_error("Data number mismatch");
1060 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1061 n_fields != le64toh(f->header->n_fields)) {
1062 log_error("Field number mismatch");
1067 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1068 n_tags != le64toh(f->header->n_tags)) {
1069 log_error("Tag number mismatch");
1074 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1075 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1076 log_error("Entry array number mismatch");
1081 if (n_data_hash_tables != 1) {
1082 log_error("Missing data hash table");
1087 if (n_field_hash_tables != 1) {
1088 log_error("Missing field hash table");
1093 if (!found_main_entry_array) {
1094 log_error("Missing entry array");
1099 if (entry_seqnum_set &&
1100 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1101 log_error("Invalid tail seqnum");
1106 if (entry_monotonic_set &&
1107 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1108 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1109 log_error("Invalid tail monotonic timestamp");
1114 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1115 log_error("Invalid tail realtime timestamp");
1120 /* Second iteration: we follow all objects referenced from the
1121 * two entry points: the object hash table and the entry
1122 * array. We also check that everything referenced (directly
1123 * or indirectly) in the data hash table also exists in the
1124 * entry array, and vice versa. Note that we do not care for
1125 * unreferenced objects. We only care that everything that is
1126 * referenced is consistent. */
1128 r = verify_entry_array(f,
1130 entry_fd, n_entries,
1131 entry_array_fd, n_entry_arrays,
1137 r = verify_hash_table(f,
1139 entry_fd, n_entries,
1140 entry_array_fd, n_entry_arrays,
1149 mmap_cache_close_fd(f->mmap, data_fd);
1150 mmap_cache_close_fd(f->mmap, entry_fd);
1151 mmap_cache_close_fd(f->mmap, entry_array_fd);
1153 close_nointr_nofail(data_fd);
1154 close_nointr_nofail(entry_fd);
1155 close_nointr_nofail(entry_array_fd);
1157 if (first_validated)
1158 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
1160 *last_validated = last_sealed_realtime;
1162 *last_contained = le64toh(f->header->tail_entry_realtime);
1170 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1172 (unsigned long long) p,
1173 (unsigned long long) f->last_stat.st_size,
1174 (unsigned long long) (100 * p / f->last_stat.st_size));
1177 mmap_cache_close_fd(f->mmap, data_fd);
1178 close_nointr_nofail(data_fd);
1181 if (entry_fd >= 0) {
1182 mmap_cache_close_fd(f->mmap, entry_fd);
1183 close_nointr_nofail(entry_fd);
1186 if (entry_array_fd >= 0) {
1187 mmap_cache_close_fd(f->mmap, entry_array_fd);
1188 close_nointr_nofail(entry_array_fd);