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/>.
29 #include "journal-def.h"
30 #include "journal-file.h"
31 #include "journal-authenticate.h"
32 #include "journal-verify.h"
37 static int journal_file_object_verify(JournalFile *f, Object *o) {
43 /* This does various superficial tests about the length an
44 * possible field values. It does not follow any references to
47 if ((o->object.flags & OBJECT_COMPRESSED) &&
48 o->object.type != OBJECT_DATA)
51 switch (o->object.type) {
56 if (le64toh(o->data.entry_offset) <= 0 ||
57 le64toh(o->data.n_entries) <= 0)
60 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
63 h1 = le64toh(o->data.hash);
65 if (o->object.flags & OBJECT_COMPRESSED) {
67 uint64_t alloc = 0, b_size;
69 if (!uncompress_blob(o->data.payload,
70 le64toh(o->object.size) - offsetof(Object, data.payload),
74 h2 = hash64(b, b_size);
77 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
82 if (!VALID64(o->data.next_hash_offset) ||
83 !VALID64(o->data.next_field_offset) ||
84 !VALID64(o->data.entry_offset) ||
85 !VALID64(o->data.entry_array_offset))
92 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
95 if (!VALID64(o->field.next_hash_offset) ||
96 !VALID64(o->field.head_data_offset))
101 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
104 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
107 if (le64toh(o->entry.seqnum) <= 0 ||
108 !VALID_REALTIME(le64toh(o->entry.realtime)) ||
109 !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
112 for (i = 0; i < journal_file_entry_n_items(o); i++) {
113 if (o->entry.items[i].object_offset == 0 ||
114 !VALID64(o->entry.items[i].object_offset))
120 case OBJECT_DATA_HASH_TABLE:
121 case OBJECT_FIELD_HASH_TABLE:
122 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
125 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
128 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
129 if (o->hash_table.items[i].head_hash_offset != 0 &&
130 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
132 if (o->hash_table.items[i].tail_hash_offset != 0 &&
133 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
136 if ((o->hash_table.items[i].head_hash_offset != 0) !=
137 (o->hash_table.items[i].tail_hash_offset != 0))
143 case OBJECT_ENTRY_ARRAY:
144 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
147 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
150 if (!VALID64(o->entry_array.next_entry_array_offset))
153 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
154 if (o->entry_array.items[i] != 0 &&
155 !VALID64(o->entry_array.items[i]))
161 if (le64toh(o->object.size) != sizeof(TagObject))
164 if (!VALID_EPOCH(o->tag.epoch))
173 static void draw_progress(uint64_t p, usec_t *last_usec) {
177 if (!isatty(STDOUT_FILENO))
180 z = now(CLOCK_MONOTONIC);
183 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
188 n = (3 * columns()) / 4;
189 j = (n * (unsigned) p) / 65535ULL;
192 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
194 for (i = 0; i < j; i++)
195 fputs("\xe2\x96\x88", stdout);
197 fputs(ANSI_HIGHLIGHT_OFF, stdout);
199 for (i = 0; i < k; i++)
200 fputs("\xe2\x96\x91", stdout);
202 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
204 fputs("\r\x1B[?25h", stdout);
208 static void flush_progress(void) {
211 if (!isatty(STDOUT_FILENO))
214 n = (3 * columns()) / 4;
218 for (i = 0; i < n + 5; i++)
225 static int write_uint64(int fd, uint64_t p) {
228 k = write(fd, &p, sizeof(p));
237 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
252 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
271 static int entry_points_to_data(
284 assert(entry_fd >= 0);
286 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
287 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
291 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
295 n = journal_file_entry_n_items(o);
296 for (i = 0; i < n; i++)
297 if (le64toh(o->entry.items[i].object_offset) == data_p) {
303 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
307 /* Check if this entry is also in main entry array. Since the
308 * main entry array has already been verified we can rely on
312 n = le64toh(f->header->n_entries);
313 a = le64toh(f->header->entry_array_offset);
318 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
322 m = journal_file_entry_array_n_items(o);
325 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
334 if (le64toh(o->entry_array.items[z]) == entry_p)
340 if (entry_p < le64toh(o->entry_array.items[z]))
346 log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
351 a = le64toh(o->entry_array.next_entry_array_offset);
357 static int verify_data(
359 Object *o, uint64_t p,
360 int entry_fd, uint64_t n_entries,
361 int entry_array_fd, uint64_t n_entry_arrays) {
363 uint64_t i, n, a, last, q;
368 assert(entry_fd >= 0);
369 assert(entry_array_fd >= 0);
371 n = le64toh(o->data.n_entries);
372 a = le64toh(o->data.entry_array_offset);
374 /* We already checked this earlier */
377 last = q = le64toh(o->data.entry_offset);
378 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
387 log_error("Array chain too short at %llu", (unsigned long long) p);
391 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
392 log_error("Invalid array at %llu", (unsigned long long) p);
396 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
400 next = le64toh(o->entry_array.next_entry_array_offset);
401 if (next != 0 && next <= a) {
402 log_error("Array chain has cycle at %llu", (unsigned long long) p);
406 m = journal_file_entry_array_n_items(o);
407 for (j = 0; i < n && j < m; i++, j++) {
409 q = le64toh(o->entry_array.items[j]);
411 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
416 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
420 /* Pointer might have moved, reposition */
421 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
432 static int verify_hash_table(
434 int data_fd, uint64_t n_data,
435 int entry_fd, uint64_t n_entries,
436 int entry_array_fd, uint64_t n_entry_arrays,
438 bool show_progress) {
444 assert(data_fd >= 0);
445 assert(entry_fd >= 0);
446 assert(entry_array_fd >= 0);
449 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
450 for (i = 0; i < n; i++) {
451 uint64_t last = 0, p;
454 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
456 p = le64toh(f->data_hash_table[i].head_hash_offset);
461 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
462 log_error("Invalid data object at hash entry %llu of %llu",
463 (unsigned long long) i, (unsigned long long) n);
467 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
471 next = le64toh(o->data.next_hash_offset);
472 if (next != 0 && next <= p) {
473 log_error("Hash chain has a cycle in hash entry %llu of %llu",
474 (unsigned long long) i, (unsigned long long) n);
478 if (le64toh(o->data.hash) % n != i) {
479 log_error("Hash value mismatch in hash entry %llu of %llu",
480 (unsigned long long) i, (unsigned long long) n);
484 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
492 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
493 log_error("Tail hash pointer mismatch in hash table");
501 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
506 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
509 q = le64toh(f->data_hash_table[h].head_hash_offset);
516 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
520 q = le64toh(o->data.next_hash_offset);
526 static int verify_entry(
528 Object *o, uint64_t p,
529 int data_fd, uint64_t n_data) {
536 assert(data_fd >= 0);
538 n = journal_file_entry_n_items(o);
539 for (i = 0; i < n; i++) {
543 q = le64toh(o->entry.items[i].object_offset);
544 h = le64toh(o->entry.items[i].hash);
546 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
547 log_error("Invalid data object at entry %llu",
548 (unsigned long long) p);
552 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
556 if (le64toh(u->data.hash) != h) {
557 log_error("Hash mismatch for data object at entry %llu",
558 (unsigned long long) p);
562 r = data_object_in_hash_table(f, h, q);
566 log_error("Data object missing from hash at entry %llu",
567 (unsigned long long) p);
575 static int verify_entry_array(
577 int data_fd, uint64_t n_data,
578 int entry_fd, uint64_t n_entries,
579 int entry_array_fd, uint64_t n_entry_arrays,
581 bool show_progress) {
583 uint64_t i = 0, a, n, last = 0;
587 assert(data_fd >= 0);
588 assert(entry_fd >= 0);
589 assert(entry_array_fd >= 0);
592 n = le64toh(f->header->n_entries);
593 a = le64toh(f->header->entry_array_offset);
599 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
602 log_error("Array chain too short at %llu of %llu",
603 (unsigned long long) i, (unsigned long long) n);
607 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
608 log_error("Invalid array at %llu of %llu",
609 (unsigned long long) i, (unsigned long long) n);
613 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
617 next = le64toh(o->entry_array.next_entry_array_offset);
618 if (next != 0 && next <= a) {
619 log_error("Array chain has cycle at %llu of %llu",
620 (unsigned long long) i, (unsigned long long) n);
624 m = journal_file_entry_array_n_items(o);
625 for (j = 0; i < n && j < m; i++, j++) {
628 p = le64toh(o->entry_array.items[j]);
630 log_error("Entry array not sorted at %llu of %llu",
631 (unsigned long long) i, (unsigned long long) n);
636 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
637 log_error("Invalid array entry at %llu of %llu",
638 (unsigned long long) i, (unsigned long long) n);
642 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
646 r = verify_entry(f, o, p, data_fd, n_data);
650 /* Pointer might have moved, reposition */
651 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
662 int journal_file_verify(
665 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
666 bool show_progress) {
669 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
670 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
671 sd_id128_t entry_boot_id;
672 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
673 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;
674 usec_t last_usec = 0;
675 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
676 char data_path[] = "/var/tmp/journal-data-XXXXXX",
677 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
678 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
686 r = journal_file_parse_verification_key(f, key);
688 log_error("Failed to parse seed.");
697 data_fd = mkostemp(data_path, O_CLOEXEC);
699 log_error("Failed to create data file: %m");
705 entry_fd = mkostemp(entry_path, O_CLOEXEC);
707 log_error("Failed to create entry file: %m");
713 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
714 if (entry_array_fd < 0) {
715 log_error("Failed to create entry array file: %m");
719 unlink(entry_array_path);
722 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
724 if (f->header->compatible_flags != 0)
727 log_error("Cannot verify file with unknown extensions.");
732 for (i = 0; i < sizeof(f->header->reserved); i++)
733 if (f->header->reserved[i] != 0) {
734 log_error("Reserved field in non-zero.");
739 /* First iteration: we go through all objects, verify the
740 * superficial structure, headers, hashes. */
742 p = le64toh(f->header->header_size);
745 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
747 r = journal_file_move_to_object(f, -1, p, &o);
749 log_error("Invalid object at %llu", (unsigned long long) p);
753 if (p > le64toh(f->header->tail_object_offset)) {
754 log_error("Invalid tail object pointer");
759 if (p == le64toh(f->header->tail_object_offset))
764 r = journal_file_object_verify(f, o);
766 log_error("Invalid object contents at %llu", (unsigned long long) p);
770 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
771 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
776 switch (o->object.type) {
779 r = write_uint64(data_fd, p);
791 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
792 log_error("First entry before first tag at %llu", (unsigned long long) p);
797 r = write_uint64(entry_fd, p);
801 if (le64toh(o->entry.realtime) < last_tag_realtime) {
802 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
807 if (!entry_seqnum_set &&
808 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
809 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
814 if (entry_seqnum_set &&
815 entry_seqnum >= le64toh(o->entry.seqnum)) {
816 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
821 entry_seqnum = le64toh(o->entry.seqnum);
822 entry_seqnum_set = true;
824 if (entry_monotonic_set &&
825 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
826 entry_monotonic > le64toh(o->entry.monotonic)) {
827 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
832 entry_monotonic = le64toh(o->entry.monotonic);
833 entry_boot_id = o->entry.boot_id;
834 entry_monotonic_set = true;
836 if (!entry_realtime_set &&
837 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
838 log_error("Head entry realtime timestamp incorrect");
843 entry_realtime = le64toh(o->entry.realtime);
844 entry_realtime_set = true;
849 case OBJECT_DATA_HASH_TABLE:
850 if (n_data_hash_tables > 1) {
851 log_error("More than one data hash table at %llu", (unsigned long long) p);
856 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
857 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
858 log_error("Header fields for data hash table invalid");
863 n_data_hash_tables++;
866 case OBJECT_FIELD_HASH_TABLE:
867 if (n_field_hash_tables > 1) {
868 log_error("More than one field hash table at %llu", (unsigned long long) p);
873 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
874 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
875 log_error("Header fields for field hash table invalid");
880 n_field_hash_tables++;
883 case OBJECT_ENTRY_ARRAY:
884 r = write_uint64(entry_array_fd, p);
888 if (p == le64toh(f->header->entry_array_offset)) {
889 if (found_main_entry_array) {
890 log_error("More than one main entry array at %llu", (unsigned long long) p);
895 found_main_entry_array = true;
902 if (!JOURNAL_HEADER_SEALED(f->header)) {
903 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
908 if (le64toh(o->tag.seqnum) != n_tags + 1) {
909 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
914 if (le64toh(o->tag.epoch) < last_epoch) {
915 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
924 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
926 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
927 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
928 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
933 /* OK, now we know the epoch. So let's now set
934 * it, and calculate the HMAC for everything
935 * since the last tag. */
936 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
940 r = journal_file_hmac_start(f);
945 r = journal_file_hmac_put_header(f);
949 q = le64toh(f->header->header_size);
954 r = journal_file_move_to_object(f, -1, q, &o);
958 r = journal_file_hmac_put_object(f, -1, q);
962 q = q + ALIGN64(le64toh(o->object.size));
965 /* Position might have changed, let's reposition things */
966 r = journal_file_move_to_object(f, -1, p, &o);
970 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
971 log_error("Tag failed verification at %llu", (unsigned long long) p);
976 f->hmac_running = false;
977 last_tag_realtime = rt;
978 last_sealed_realtime = entry_realtime;
982 last_tag = p + ALIGN64(le64toh(o->object.size));
983 last_epoch = le64toh(o->tag.epoch);
992 if (p == le64toh(f->header->tail_object_offset))
995 p = p + ALIGN64(le64toh(o->object.size));
999 log_error("Tail object pointer dead");
1004 if (n_objects != le64toh(f->header->n_objects)) {
1005 log_error("Object number mismatch");
1010 if (n_entries != le64toh(f->header->n_entries)) {
1011 log_error("Entry number mismatch");
1016 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1017 n_data != le64toh(f->header->n_data)) {
1018 log_error("Data number mismatch");
1023 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1024 n_fields != le64toh(f->header->n_fields)) {
1025 log_error("Field number mismatch");
1030 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1031 n_tags != le64toh(f->header->n_tags)) {
1032 log_error("Tag number mismatch");
1037 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1038 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1039 log_error("Entry array number mismatch");
1044 if (n_data_hash_tables != 1) {
1045 log_error("Missing data hash table");
1050 if (n_field_hash_tables != 1) {
1051 log_error("Missing field hash table");
1056 if (!found_main_entry_array) {
1057 log_error("Missing entry array");
1062 if (entry_seqnum_set &&
1063 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1064 log_error("Invalid tail seqnum");
1069 if (entry_monotonic_set &&
1070 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1071 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1072 log_error("Invalid tail monotonic timestamp");
1077 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1078 log_error("Invalid tail realtime timestamp");
1083 /* Second iteration: we follow all objects referenced from the
1084 * two entry points: the object hash table and the entry
1085 * array. We also check that everything referenced (directly
1086 * or indirectly) in the data hash table also exists in the
1087 * entry array, and vice versa. Note that we do not care for
1088 * unreferenced objects. We only care that everything that is
1089 * referenced is consistent. */
1091 r = verify_entry_array(f,
1093 entry_fd, n_entries,
1094 entry_array_fd, n_entry_arrays,
1100 r = verify_hash_table(f,
1102 entry_fd, n_entries,
1103 entry_array_fd, n_entry_arrays,
1112 mmap_cache_close_fd(f->mmap, data_fd);
1113 mmap_cache_close_fd(f->mmap, entry_fd);
1114 mmap_cache_close_fd(f->mmap, entry_array_fd);
1116 close_nointr_nofail(data_fd);
1117 close_nointr_nofail(entry_fd);
1118 close_nointr_nofail(entry_array_fd);
1120 if (first_validated)
1121 *first_validated = last_sealed_realtime > 0 ? le64toh(f->header->head_entry_realtime) : 0;
1123 *last_validated = last_sealed_realtime;
1125 *last_contained = le64toh(f->header->tail_entry_realtime);
1133 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1135 (unsigned long long) p,
1136 (unsigned long long) f->last_stat.st_size,
1137 (unsigned long long) (100 * p / f->last_stat.st_size));
1140 mmap_cache_close_fd(f->mmap, data_fd);
1141 close_nointr_nofail(data_fd);
1144 if (entry_fd >= 0) {
1145 mmap_cache_close_fd(f->mmap, entry_fd);
1146 close_nointr_nofail(entry_fd);
1149 if (entry_array_fd >= 0) {
1150 mmap_cache_close_fd(f->mmap, entry_array_fd);
1151 close_nointr_nofail(entry_array_fd);