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
39 * - add macro for accessing flags
41 * - Allow building without libgcrypt
47 static int journal_file_object_verify(JournalFile *f, Object *o) {
53 /* This does various superficial tests about the length an
54 * possible field values. It does not follow any references to
57 if ((o->object.flags & OBJECT_COMPRESSED) &&
58 o->object.type != OBJECT_DATA)
61 switch (o->object.type) {
66 if (le64toh(o->data.entry_offset) <= 0 ||
67 le64toh(o->data.n_entries) <= 0)
70 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
73 h1 = le64toh(o->data.hash);
75 if (o->object.flags & OBJECT_COMPRESSED) {
77 uint64_t alloc = 0, b_size;
79 if (!uncompress_blob(o->data.payload,
80 le64toh(o->object.size) - offsetof(Object, data.payload),
84 h2 = hash64(b, b_size);
87 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
92 if (!VALID64(o->data.next_hash_offset) ||
93 !VALID64(o->data.next_field_offset) ||
94 !VALID64(o->data.entry_offset) ||
95 !VALID64(o->data.entry_array_offset))
102 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
105 if (!VALID64(o->field.next_hash_offset) ||
106 !VALID64(o->field.head_data_offset))
111 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
114 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
117 if (le64toh(o->entry.seqnum) <= 0 ||
118 !VALID_REALTIME(le64toh(o->entry.realtime)) ||
119 !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
122 for (i = 0; i < journal_file_entry_n_items(o); i++) {
123 if (o->entry.items[i].object_offset == 0 ||
124 !VALID64(o->entry.items[i].object_offset))
130 case OBJECT_DATA_HASH_TABLE:
131 case OBJECT_FIELD_HASH_TABLE:
132 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
135 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
138 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
139 if (o->hash_table.items[i].head_hash_offset != 0 &&
140 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
142 if (o->hash_table.items[i].tail_hash_offset != 0 &&
143 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
146 if ((o->hash_table.items[i].head_hash_offset != 0) !=
147 (o->hash_table.items[i].tail_hash_offset != 0))
153 case OBJECT_ENTRY_ARRAY:
154 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
157 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
160 if (!VALID64(o->entry_array.next_entry_array_offset))
163 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
164 if (o->entry_array.items[i] != 0 &&
165 !VALID64(o->entry_array.items[i]))
171 if (le64toh(o->object.size) != sizeof(TagObject))
174 if (!VALID_EPOCH(o->tag.epoch))
183 static void draw_progress(uint64_t p, usec_t *last_usec) {
187 if (!isatty(STDOUT_FILENO))
190 z = now(CLOCK_MONOTONIC);
193 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
198 n = (3 * columns()) / 4;
199 j = (n * (unsigned) p) / 65535ULL;
202 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
204 for (i = 0; i < j; i++)
205 fputs("\xe2\x96\x88", stdout);
207 fputs(ANSI_HIGHLIGHT_OFF, stdout);
209 for (i = 0; i < k; i++)
210 fputs("\xe2\x96\x91", stdout);
212 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
214 fputs("\r\x1B[?25h", stdout);
218 static void flush_progress(void) {
221 if (!isatty(STDOUT_FILENO))
224 n = (3 * columns()) / 4;
228 for (i = 0; i < n + 5; i++)
235 static int write_uint64(int fd, uint64_t p) {
238 k = write(fd, &p, sizeof(p));
247 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
262 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
282 static int entry_points_to_data(
295 assert(entry_fd >= 0);
297 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
298 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
302 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
306 n = journal_file_entry_n_items(o);
307 for (i = 0; i < n; i++)
308 if (le64toh(o->entry.items[i].object_offset) == data_p) {
314 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
318 /* Check if this entry is also in main entry array. Since the
319 * main entry array has already been verified we can rely on
322 n = le64toh(f->header->n_entries);
323 a = le64toh(f->header->entry_array_offset);
329 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
333 m = journal_file_entry_array_n_items(o);
334 for (j = 0; i < n && j < m; i++, j++)
335 if (le64toh(o->entry_array.items[j]) == entry_p)
338 a = le64toh(o->entry_array.next_entry_array_offset);
344 static int verify_data(
346 Object *o, uint64_t p,
347 int entry_fd, uint64_t n_entries,
348 int entry_array_fd, uint64_t n_entry_arrays) {
350 uint64_t i, n, a, last, q;
355 assert(entry_fd >= 0);
356 assert(entry_array_fd >= 0);
358 n = le64toh(o->data.n_entries);
359 a = le64toh(o->data.entry_array_offset);
361 /* We already checked this earlier */
364 last = q = le64toh(o->data.entry_offset);
365 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
374 log_error("Array chain too short at %llu", (unsigned long long) p);
378 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
379 log_error("Invalid array at %llu", (unsigned long long) p);
383 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
387 next = le64toh(o->entry_array.next_entry_array_offset);
388 if (next != 0 && next <= a) {
389 log_error("Array chain has cycle at %llu", (unsigned long long) p);
393 m = journal_file_entry_array_n_items(o);
394 for (j = 0; i < n && j < m; i++, j++) {
396 q = le64toh(o->entry_array.items[j]);
398 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
403 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
407 /* Pointer might have moved, reposition */
408 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
419 static int verify_hash_table(
421 int data_fd, uint64_t n_data,
422 int entry_fd, uint64_t n_entries,
423 int entry_array_fd, uint64_t n_entry_arrays,
425 bool show_progress) {
431 assert(data_fd >= 0);
432 assert(entry_fd >= 0);
433 assert(entry_array_fd >= 0);
436 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
437 for (i = 0; i < n; i++) {
438 uint64_t last = 0, p;
441 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
443 p = le64toh(f->data_hash_table[i].head_hash_offset);
448 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
449 log_error("Invalid data object at hash entry %llu of %llu",
450 (unsigned long long) i, (unsigned long long) n);
454 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
458 next = le64toh(o->data.next_hash_offset);
459 if (next != 0 && next <= p) {
460 log_error("Hash chain has a cycle in hash entry %llu of %llu",
461 (unsigned long long) i, (unsigned long long) n);
465 if (le64toh(o->data.hash) % n != i) {
466 log_error("Hash value mismatch in hash entry %llu of %llu",
467 (unsigned long long) i, (unsigned long long) n);
471 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
479 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
480 log_error("Tail hash pointer mismatch in hash table");
488 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
493 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
496 q = le64toh(f->data_hash_table[h].head_hash_offset);
503 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
507 q = le64toh(o->data.next_hash_offset);
513 static int verify_entry(
515 Object *o, uint64_t p,
516 int data_fd, uint64_t n_data) {
523 assert(data_fd >= 0);
525 n = journal_file_entry_n_items(o);
526 for (i = 0; i < n; i++) {
530 q = le64toh(o->entry.items[i].object_offset);
531 h = le64toh(o->entry.items[i].hash);
533 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
534 log_error("Invalid data object at entry %llu",
535 (unsigned long long) p);
539 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
543 if (le64toh(u->data.hash) != h) {
544 log_error("Hash mismatch for data object at entry %llu",
545 (unsigned long long) p);
549 r = data_object_in_hash_table(f, h, q);
553 log_error("Data object missing from hash at entry %llu",
554 (unsigned long long) p);
562 static int verify_entry_array(
564 int data_fd, uint64_t n_data,
565 int entry_fd, uint64_t n_entries,
566 int entry_array_fd, uint64_t n_entry_arrays,
568 bool show_progress) {
570 uint64_t i = 0, a, n, last = 0;
574 assert(data_fd >= 0);
575 assert(entry_fd >= 0);
576 assert(entry_array_fd >= 0);
579 n = le64toh(f->header->n_entries);
580 a = le64toh(f->header->entry_array_offset);
586 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
589 log_error("Array chain too short at %llu of %llu",
590 (unsigned long long) i, (unsigned long long) n);
594 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
595 log_error("Invalid array at %llu of %llu",
596 (unsigned long long) i, (unsigned long long) n);
600 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
604 next = le64toh(o->entry_array.next_entry_array_offset);
605 if (next != 0 && next <= a) {
606 log_error("Array chain has cycle at %llu of %llu",
607 (unsigned long long) i, (unsigned long long) n);
611 m = journal_file_entry_array_n_items(o);
612 for (j = 0; i < n && j < m; i++, j++) {
615 p = le64toh(o->entry_array.items[j]);
617 log_error("Entry array not sorted at %llu of %llu",
618 (unsigned long long) i, (unsigned long long) n);
623 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
624 log_error("Invalid array entry at %llu of %llu",
625 (unsigned long long) i, (unsigned long long) n);
629 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
633 r = verify_entry(f, o, p, data_fd, n_data);
637 /* Pointer might have moved, reposition */
638 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
649 static int journal_file_parse_verification_key(JournalFile *f, const char *key) {
654 unsigned long long start, interval;
656 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
657 seed = malloc(seed_size);
662 for (c = 0; c < seed_size; c++) {
681 seed[c] = (uint8_t) (x * 16 + y);
690 r = sscanf(k, "%llx-%llx", &start, &interval);
696 f->fsprg_seed = seed;
697 f->fsprg_seed_size = seed_size;
699 f->fss_start_usec = start * interval;
700 f->fss_interval_usec = interval;
705 int journal_file_verify(
708 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
709 bool show_progress) {
712 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
713 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
714 sd_id128_t entry_boot_id;
715 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
716 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;
717 usec_t last_usec = 0;
718 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
719 char data_path[] = "/var/tmp/journal-data-XXXXXX",
720 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
721 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
728 r = journal_file_parse_verification_key(f, key);
730 log_error("Failed to parse seed.");
736 data_fd = mkostemp(data_path, O_CLOEXEC);
738 log_error("Failed to create data file: %m");
744 entry_fd = mkostemp(entry_path, O_CLOEXEC);
746 log_error("Failed to create entry file: %m");
752 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
753 if (entry_array_fd < 0) {
754 log_error("Failed to create entry array file: %m");
758 unlink(entry_array_path);
761 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
763 if (f->header->compatible_flags != 0)
766 log_error("Cannot verify file with unknown extensions.");
771 for (i = 0; i < sizeof(f->header->reserved); i++)
772 if (f->header->reserved[i] != 0) {
773 log_error("Reserved field in non-zero.");
778 /* First iteration: we go through all objects, verify the
779 * superficial structure, headers, hashes. */
781 p = le64toh(f->header->header_size);
784 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
786 r = journal_file_move_to_object(f, -1, p, &o);
788 log_error("Invalid object at %llu", (unsigned long long) p);
792 if (p > le64toh(f->header->tail_object_offset)) {
793 log_error("Invalid tail object pointer");
798 if (p == le64toh(f->header->tail_object_offset))
803 r = journal_file_object_verify(f, o);
805 log_error("Invalid object contents at %llu", (unsigned long long) p);
809 if (o->object.flags & OBJECT_COMPRESSED &&
810 !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
811 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
816 switch (o->object.type) {
819 r = write_uint64(data_fd, p);
831 if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
832 log_error("First entry before first tag at %llu", (unsigned long long) p);
837 r = write_uint64(entry_fd, p);
841 if (le64toh(o->entry.realtime) < last_tag_realtime) {
842 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
847 if (!entry_seqnum_set &&
848 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
849 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
854 if (entry_seqnum_set &&
855 entry_seqnum >= le64toh(o->entry.seqnum)) {
856 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
861 entry_seqnum = le64toh(o->entry.seqnum);
862 entry_seqnum_set = true;
864 if (entry_monotonic_set &&
865 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
866 entry_monotonic > le64toh(o->entry.monotonic)) {
867 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
872 entry_monotonic = le64toh(o->entry.monotonic);
873 entry_boot_id = o->entry.boot_id;
874 entry_monotonic_set = true;
876 if (!entry_realtime_set &&
877 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
878 log_error("Head entry realtime timestamp incorrect");
883 entry_realtime = le64toh(o->entry.realtime);
884 entry_realtime_set = true;
889 case OBJECT_DATA_HASH_TABLE:
890 if (n_data_hash_tables > 1) {
891 log_error("More than one data hash table at %llu", (unsigned long long) p);
896 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
897 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
898 log_error("Header fields for data hash table invalid");
903 n_data_hash_tables++;
906 case OBJECT_FIELD_HASH_TABLE:
907 if (n_field_hash_tables > 1) {
908 log_error("More than one field hash table at %llu", (unsigned long long) p);
913 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
914 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
915 log_error("Header fields for field hash table invalid");
920 n_field_hash_tables++;
923 case OBJECT_ENTRY_ARRAY:
924 r = write_uint64(entry_array_fd, p);
928 if (p == le64toh(f->header->entry_array_offset)) {
929 if (found_main_entry_array) {
930 log_error("More than one main entry array at %llu", (unsigned long long) p);
935 found_main_entry_array = true;
944 if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
945 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
950 if (le64toh(o->tag.seqnum) != n_tags + 1) {
951 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
956 if (le64toh(o->tag.epoch) < last_epoch) {
957 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
963 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
965 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
966 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
967 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
972 /* OK, now we know the epoch. So let's now set
973 * it, and calculate the HMAC for everything
974 * since the last tag. */
975 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
979 r = journal_file_hmac_start(f);
984 r = journal_file_hmac_put_header(f);
988 q = le64toh(f->header->header_size);
993 r = journal_file_move_to_object(f, -1, q, &o);
997 r = journal_file_hmac_put_object(f, -1, q);
1001 q = q + ALIGN64(le64toh(o->object.size));
1004 /* Position might have changed, let's reposition things */
1005 r = journal_file_move_to_object(f, -1, p, &o);
1009 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1010 log_error("Tag failed verification at %llu", (unsigned long long) p);
1015 f->hmac_running = false;
1016 last_tag_realtime = rt;
1017 last_sealed_realtime = entry_realtime;
1020 last_tag = p + ALIGN64(le64toh(o->object.size));
1021 last_epoch = le64toh(o->tag.epoch);
1031 if (p == le64toh(f->header->tail_object_offset))
1034 p = p + ALIGN64(le64toh(o->object.size));
1038 log_error("Tail object pointer dead");
1043 if (n_objects != le64toh(f->header->n_objects)) {
1044 log_error("Object number mismatch");
1049 if (n_entries != le64toh(f->header->n_entries)) {
1050 log_error("Entry number mismatch");
1055 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1056 n_data != le64toh(f->header->n_data)) {
1057 log_error("Data number mismatch");
1062 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1063 n_fields != le64toh(f->header->n_fields)) {
1064 log_error("Field number mismatch");
1069 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1070 n_tags != le64toh(f->header->n_tags)) {
1071 log_error("Tag number mismatch");
1076 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1077 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1078 log_error("Entry array number mismatch");
1083 if (n_data_hash_tables != 1) {
1084 log_error("Missing data hash table");
1089 if (n_field_hash_tables != 1) {
1090 log_error("Missing field hash table");
1095 if (!found_main_entry_array) {
1096 log_error("Missing entry array");
1101 if (entry_seqnum_set &&
1102 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1103 log_error("Invalid tail seqnum");
1108 if (entry_monotonic_set &&
1109 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1110 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1111 log_error("Invalid tail monotonic timestamp");
1116 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1117 log_error("Invalid tail realtime timestamp");
1122 /* Second iteration: we follow all objects referenced from the
1123 * two entry points: the object hash table and the entry
1124 * array. We also check that everything referenced (directly
1125 * or indirectly) in the data hash table also exists in the
1126 * entry array, and vice versa. Note that we do not care for
1127 * unreferenced objects. We only care that everything that is
1128 * referenced is consistent. */
1130 r = verify_entry_array(f,
1132 entry_fd, n_entries,
1133 entry_array_fd, n_entry_arrays,
1139 r = verify_hash_table(f,
1141 entry_fd, n_entries,
1142 entry_array_fd, n_entry_arrays,
1151 mmap_cache_close_fd(f->mmap, data_fd);
1152 mmap_cache_close_fd(f->mmap, entry_fd);
1153 mmap_cache_close_fd(f->mmap, entry_array_fd);
1155 close_nointr_nofail(data_fd);
1156 close_nointr_nofail(entry_fd);
1157 close_nointr_nofail(entry_array_fd);
1159 if (first_validated)
1160 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
1162 *last_validated = last_sealed_realtime;
1164 *last_contained = le64toh(f->header->tail_entry_realtime);
1172 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1174 (unsigned long long) p,
1175 (unsigned long long) f->last_stat.st_size,
1176 (unsigned long long) (100 * p / f->last_stat.st_size));
1179 mmap_cache_close_fd(f->mmap, data_fd);
1180 close_nointr_nofail(data_fd);
1183 if (entry_fd >= 0) {
1184 mmap_cache_close_fd(f->mmap, entry_fd);
1185 close_nointr_nofail(entry_fd);
1188 if (entry_array_fd >= 0) {
1189 mmap_cache_close_fd(f->mmap, entry_array_fd);
1190 close_nointr_nofail(entry_array_fd);