LCOV - code coverage report
Current view: top level - journal - journal-verify.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 378 718 52.6 %
Date: 2019-08-23 13:36:53 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 248 691 35.9 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <fcntl.h>
       4                 :            : #include <stddef.h>
       5                 :            : #include <sys/mman.h>
       6                 :            : #include <unistd.h>
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "compress.h"
      10                 :            : #include "fd-util.h"
      11                 :            : #include "fileio.h"
      12                 :            : #include "fs-util.h"
      13                 :            : #include "journal-authenticate.h"
      14                 :            : #include "journal-def.h"
      15                 :            : #include "journal-file.h"
      16                 :            : #include "journal-verify.h"
      17                 :            : #include "lookup3.h"
      18                 :            : #include "macro.h"
      19                 :            : #include "terminal-util.h"
      20                 :            : #include "tmpfile-util.h"
      21                 :            : #include "util.h"
      22                 :            : 
      23                 :      33804 : static void draw_progress(uint64_t p, usec_t *last_usec) {
      24                 :            :         unsigned n, i, j, k;
      25                 :            :         usec_t z, x;
      26                 :            : 
      27         [ +  - ]:      33804 :         if (!on_tty())
      28                 :      33804 :                 return;
      29                 :            : 
      30                 :          0 :         z = now(CLOCK_MONOTONIC);
      31                 :          0 :         x = *last_usec;
      32                 :            : 
      33   [ #  #  #  # ]:          0 :         if (x != 0 && x + 40 * USEC_PER_MSEC > z)
      34                 :          0 :                 return;
      35                 :            : 
      36                 :          0 :         *last_usec = z;
      37                 :            : 
      38                 :          0 :         n = (3 * columns()) / 4;
      39                 :          0 :         j = (n * (unsigned) p) / 65535ULL;
      40                 :          0 :         k = n - j;
      41                 :            : 
      42                 :          0 :         fputs("\r", stdout);
      43         [ #  # ]:          0 :         if (colors_enabled())
      44                 :          0 :                 fputs("\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout);
      45                 :            : 
      46         [ #  # ]:          0 :         for (i = 0; i < j; i++)
      47                 :          0 :                 fputs("\xe2\x96\x88", stdout);
      48                 :            : 
      49                 :          0 :         fputs(ansi_normal(), stdout);
      50                 :            : 
      51         [ #  # ]:          0 :         for (i = 0; i < k; i++)
      52                 :          0 :                 fputs("\xe2\x96\x91", stdout);
      53                 :            : 
      54                 :          0 :         printf(" %3"PRIu64"%%", 100U * p / 65535U);
      55                 :            : 
      56                 :          0 :         fputs("\r", stdout);
      57         [ #  # ]:          0 :         if (colors_enabled())
      58                 :          0 :                 fputs("\x1B[?25h", stdout);
      59                 :            : 
      60                 :          0 :         fflush(stdout);
      61                 :            : }
      62                 :            : 
      63                 :      33804 : static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) {
      64                 :            :         /* Calculates scale * p / m, but handles m == 0 safely, and saturates.
      65                 :            :          * Currently all callers use m >= 1, but we keep the check to be defensive.
      66                 :            :          */
      67                 :            : 
      68   [ +  +  -  + ]:      33804 :         if (p >= m || m == 0) // lgtm[cpp/constant-comparison]
      69                 :          4 :                 return scale;
      70                 :            : 
      71                 :      33800 :         return scale * p / m;
      72                 :            : }
      73                 :            : 
      74                 :          4 : static void flush_progress(void) {
      75                 :            :         unsigned n, i;
      76                 :            : 
      77         [ +  - ]:          4 :         if (!on_tty())
      78                 :          4 :                 return;
      79                 :            : 
      80                 :          0 :         n = (3 * columns()) / 4;
      81                 :            : 
      82                 :          0 :         putchar('\r');
      83                 :            : 
      84         [ #  # ]:          0 :         for (i = 0; i < n + 5; i++)
      85                 :          0 :                 putchar(' ');
      86                 :            : 
      87                 :          0 :         putchar('\r');
      88                 :          0 :         fflush(stdout);
      89                 :            : }
      90                 :            : 
      91                 :            : #define debug(_offset, _fmt, ...) do {                                  \
      92                 :            :                 flush_progress();                                       \
      93                 :            :                 log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__);     \
      94                 :            :         } while (0)
      95                 :            : 
      96                 :            : #define warning(_offset, _fmt, ...) do {                                \
      97                 :            :                 flush_progress();                                       \
      98                 :            :                 log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__);   \
      99                 :            :         } while (0)
     100                 :            : 
     101                 :            : #define error(_offset, _fmt, ...) do {                                  \
     102                 :            :                 flush_progress();                                       \
     103                 :            :                 log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
     104                 :            :         } while (0)
     105                 :            : 
     106                 :            : #define error_errno(_offset, error, _fmt, ...) do {               \
     107                 :            :                 flush_progress();                                       \
     108                 :            :                 log_error_errno(error, OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
     109                 :            :         } while (0)
     110                 :            : 
     111                 :      25584 : static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
     112                 :            :         uint64_t i;
     113                 :            : 
     114         [ -  + ]:      25584 :         assert(f);
     115         [ -  + ]:      25584 :         assert(offset);
     116         [ -  + ]:      25584 :         assert(o);
     117                 :            : 
     118                 :            :         /* This does various superficial tests about the length an
     119                 :            :          * possible field values. It does not follow any references to
     120                 :            :          * other objects. */
     121                 :            : 
     122         [ -  + ]:      25584 :         if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
     123         [ #  # ]:          0 :             o->object.type != OBJECT_DATA) {
     124         [ #  # ]:          0 :                 error(offset, "Found compressed object that isn't of type DATA, which is not allowed.");
     125                 :          0 :                 return -EBADMSG;
     126                 :            :         }
     127                 :            : 
     128   [ +  +  +  +  :      25584 :         switch (o->object.type) {
                +  -  - ]
     129                 :            : 
     130                 :        308 :         case OBJECT_DATA: {
     131                 :            :                 uint64_t h1, h2;
     132                 :            :                 int compression, r;
     133                 :            : 
     134         [ -  + ]:        308 :                 if (le64toh(o->data.entry_offset) == 0)
     135         [ #  # ]:          0 :                         warning(offset, "Unused data (entry_offset==0)");
     136                 :            : 
     137         [ -  + ]:        308 :                 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
     138         [ #  # ]:          0 :                         error(offset, "Bad n_entries: %"PRIu64, le64toh(o->data.n_entries));
     139                 :          0 :                         return -EBADMSG;
     140                 :            :                 }
     141                 :            : 
     142         [ -  + ]:        308 :                 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
     143         [ #  # ]:          0 :                         error(offset, "Bad object size (<= %zu): %"PRIu64,
     144                 :            :                               offsetof(DataObject, payload),
     145                 :            :                               le64toh(o->object.size));
     146                 :          0 :                         return -EBADMSG;
     147                 :            :                 }
     148                 :            : 
     149                 :        308 :                 h1 = le64toh(o->data.hash);
     150                 :            : 
     151                 :        308 :                 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
     152         [ -  + ]:        308 :                 if (compression) {
     153         [ #  # ]:          0 :                         _cleanup_free_ void *b = NULL;
     154                 :          0 :                         size_t alloc = 0, b_size;
     155                 :            : 
     156                 :          0 :                         r = decompress_blob(compression,
     157                 :          0 :                                             o->data.payload,
     158                 :          0 :                                             le64toh(o->object.size) - offsetof(Object, data.payload),
     159                 :            :                                             &b, &alloc, &b_size, 0);
     160         [ #  # ]:          0 :                         if (r < 0) {
     161         [ #  # ]:          0 :                                 error_errno(offset, r, "%s decompression failed: %m",
     162                 :            :                                             object_compressed_to_string(compression));
     163                 :          0 :                                 return r;
     164                 :            :                         }
     165                 :            : 
     166                 :          0 :                         h2 = hash64(b, b_size);
     167                 :            :                 } else
     168                 :        308 :                         h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
     169                 :            : 
     170         [ -  + ]:        308 :                 if (h1 != h2) {
     171         [ #  # ]:          0 :                         error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
     172                 :          0 :                         return -EBADMSG;
     173                 :            :                 }
     174                 :            : 
     175         [ +  - ]:        308 :                 if (!VALID64(le64toh(o->data.next_hash_offset)) ||
     176         [ +  - ]:        308 :                     !VALID64(le64toh(o->data.next_field_offset)) ||
     177         [ +  - ]:        308 :                     !VALID64(le64toh(o->data.entry_offset)) ||
     178         [ -  + ]:        308 :                     !VALID64(le64toh(o->data.entry_array_offset))) {
     179         [ #  # ]:          0 :                         error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
     180                 :            :                               le64toh(o->data.next_hash_offset),
     181                 :            :                               le64toh(o->data.next_field_offset),
     182                 :            :                               le64toh(o->data.entry_offset),
     183                 :            :                               le64toh(o->data.entry_array_offset));
     184                 :          0 :                         return -EBADMSG;
     185                 :            :                 }
     186                 :            : 
     187                 :        308 :                 break;
     188                 :            :         }
     189                 :            : 
     190                 :          4 :         case OBJECT_FIELD:
     191         [ -  + ]:          4 :                 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
     192         [ #  # ]:          0 :                         error(offset,
     193                 :            :                               "Bad field size (<= %zu): %"PRIu64,
     194                 :            :                               offsetof(FieldObject, payload),
     195                 :            :                               le64toh(o->object.size));
     196                 :          0 :                         return -EBADMSG;
     197                 :            :                 }
     198                 :            : 
     199         [ +  - ]:          4 :                 if (!VALID64(le64toh(o->field.next_hash_offset)) ||
     200         [ -  + ]:          4 :                     !VALID64(le64toh(o->field.head_data_offset))) {
     201         [ #  # ]:          0 :                         error(offset,
     202                 :            :                               "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
     203                 :            :                               le64toh(o->field.next_hash_offset),
     204                 :            :                               le64toh(o->field.head_data_offset));
     205                 :          0 :                         return -EBADMSG;
     206                 :            :                 }
     207                 :          4 :                 break;
     208                 :            : 
     209                 :      24000 :         case OBJECT_ENTRY:
     210         [ -  + ]:      24000 :                 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
     211         [ #  # ]:          0 :                         error(offset,
     212                 :            :                               "Bad entry size (<= %zu): %"PRIu64,
     213                 :            :                               offsetof(EntryObject, items),
     214                 :            :                               le64toh(o->object.size));
     215                 :          0 :                         return -EBADMSG;
     216                 :            :                 }
     217                 :            : 
     218         [ -  + ]:      24000 :                 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
     219         [ #  # ]:          0 :                         error(offset,
     220                 :            :                               "Invalid number items in entry: %"PRIu64,
     221                 :            :                               (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
     222                 :          0 :                         return -EBADMSG;
     223                 :            :                 }
     224                 :            : 
     225         [ -  + ]:      24000 :                 if (le64toh(o->entry.seqnum) <= 0) {
     226         [ #  # ]:          0 :                         error(offset,
     227                 :            :                               "Invalid entry seqnum: %"PRIx64,
     228                 :            :                               le64toh(o->entry.seqnum));
     229                 :          0 :                         return -EBADMSG;
     230                 :            :                 }
     231                 :            : 
     232         [ -  + ]:      24000 :                 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
     233         [ #  # ]:          0 :                         error(offset,
     234                 :            :                               "Invalid entry realtime timestamp: %"PRIu64,
     235                 :            :                               le64toh(o->entry.realtime));
     236                 :          0 :                         return -EBADMSG;
     237                 :            :                 }
     238                 :            : 
     239         [ -  + ]:      24000 :                 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
     240         [ #  # ]:          0 :                         error(offset,
     241                 :            :                               "Invalid entry monotonic timestamp: %"PRIu64,
     242                 :            :                               le64toh(o->entry.monotonic));
     243                 :          0 :                         return -EBADMSG;
     244                 :            :                 }
     245                 :            : 
     246         [ +  + ]:      48000 :                 for (i = 0; i < journal_file_entry_n_items(o); i++) {
     247         [ +  - ]:      24000 :                         if (le64toh(o->entry.items[i].object_offset) == 0 ||
     248         [ -  + ]:      24000 :                             !VALID64(le64toh(o->entry.items[i].object_offset))) {
     249         [ #  # ]:          0 :                                 error(offset,
     250                 :            :                                       "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
     251                 :            :                                       i, journal_file_entry_n_items(o),
     252                 :            :                                       le64toh(o->entry.items[i].object_offset));
     253                 :          0 :                                 return -EBADMSG;
     254                 :            :                         }
     255                 :            :                 }
     256                 :            : 
     257                 :      24000 :                 break;
     258                 :            : 
     259                 :          8 :         case OBJECT_DATA_HASH_TABLE:
     260                 :            :         case OBJECT_FIELD_HASH_TABLE:
     261         [ +  - ]:          8 :                 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
     262         [ -  + ]:          8 :                     (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
     263   [ #  #  #  # ]:          0 :                         error(offset,
     264                 :            :                               "Invalid %s hash table size: %"PRIu64,
     265                 :            :                               o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
     266                 :            :                               le64toh(o->object.size));
     267                 :          0 :                         return -EBADMSG;
     268                 :            :                 }
     269                 :            : 
     270         [ +  + ]:       9528 :                 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
     271         [ +  + ]:       9520 :                         if (o->hash_table.items[i].head_hash_offset != 0 &&
     272         [ -  + ]:        304 :                             !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
     273   [ #  #  #  # ]:          0 :                                 error(offset,
     274                 :            :                                       "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
     275                 :            :                                       o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
     276                 :            :                                       i, journal_file_hash_table_n_items(o),
     277                 :            :                                       le64toh(o->hash_table.items[i].head_hash_offset));
     278                 :          0 :                                 return -EBADMSG;
     279                 :            :                         }
     280         [ +  + ]:       9520 :                         if (o->hash_table.items[i].tail_hash_offset != 0 &&
     281         [ -  + ]:        304 :                             !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
     282   [ #  #  #  # ]:          0 :                                 error(offset,
     283                 :            :                                       "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
     284                 :            :                                       o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
     285                 :            :                                       i, journal_file_hash_table_n_items(o),
     286                 :            :                                       le64toh(o->hash_table.items[i].tail_hash_offset));
     287                 :          0 :                                 return -EBADMSG;
     288                 :            :                         }
     289                 :            : 
     290                 :      19040 :                         if ((o->hash_table.items[i].head_hash_offset != 0) !=
     291         [ -  + ]:       9520 :                             (o->hash_table.items[i].tail_hash_offset != 0)) {
     292   [ #  #  #  # ]:          0 :                                 error(offset,
     293                 :            :                                       "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
     294                 :            :                                       o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
     295                 :            :                                       i, journal_file_hash_table_n_items(o),
     296                 :            :                                       le64toh(o->hash_table.items[i].head_hash_offset),
     297                 :            :                                       le64toh(o->hash_table.items[i].tail_hash_offset));
     298                 :          0 :                                 return -EBADMSG;
     299                 :            :                         }
     300                 :            :                 }
     301                 :            : 
     302                 :          8 :                 break;
     303                 :            : 
     304                 :       1264 :         case OBJECT_ENTRY_ARRAY:
     305         [ +  - ]:       1264 :                 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
     306         [ -  + ]:       1264 :                     (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
     307         [ #  # ]:          0 :                         error(offset,
     308                 :            :                               "Invalid object entry array size: %"PRIu64,
     309                 :            :                               le64toh(o->object.size));
     310                 :          0 :                         return -EBADMSG;
     311                 :            :                 }
     312                 :            : 
     313         [ -  + ]:       1264 :                 if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) {
     314         [ #  # ]:          0 :                         error(offset,
     315                 :            :                               "Invalid object entry array next_entry_array_offset: "OFSfmt,
     316                 :            :                               le64toh(o->entry_array.next_entry_array_offset));
     317                 :          0 :                         return -EBADMSG;
     318                 :            :                 }
     319                 :            : 
     320         [ +  + ]:      74896 :                 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
     321         [ +  + ]:      73632 :                         if (le64toh(o->entry_array.items[i]) != 0 &&
     322         [ -  + ]:      47692 :                             !VALID64(le64toh(o->entry_array.items[i]))) {
     323         [ #  # ]:          0 :                                 error(offset,
     324                 :            :                                       "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
     325                 :            :                                       i, journal_file_entry_array_n_items(o),
     326                 :            :                                       le64toh(o->entry_array.items[i]));
     327                 :          0 :                                 return -EBADMSG;
     328                 :            :                         }
     329                 :            : 
     330                 :       1264 :                 break;
     331                 :            : 
     332                 :          0 :         case OBJECT_TAG:
     333         [ #  # ]:          0 :                 if (le64toh(o->object.size) != sizeof(TagObject)) {
     334         [ #  # ]:          0 :                         error(offset,
     335                 :            :                               "Invalid object tag size: %"PRIu64,
     336                 :            :                               le64toh(o->object.size));
     337                 :          0 :                         return -EBADMSG;
     338                 :            :                 }
     339                 :            : 
     340         [ #  # ]:          0 :                 if (!VALID_EPOCH(le64toh(o->tag.epoch))) {
     341         [ #  # ]:          0 :                         error(offset,
     342                 :            :                               "Invalid object tag epoch: %"PRIu64,
     343                 :            :                               le64toh(o->tag.epoch));
     344                 :          0 :                         return -EBADMSG;
     345                 :            :                 }
     346                 :            : 
     347                 :          0 :                 break;
     348                 :            :         }
     349                 :            : 
     350                 :      25584 :         return 0;
     351                 :            : }
     352                 :            : 
     353                 :      25572 : static int write_uint64(int fd, uint64_t p) {
     354                 :            :         ssize_t k;
     355                 :            : 
     356                 :      25572 :         k = write(fd, &p, sizeof(p));
     357         [ -  + ]:      25572 :         if (k < 0)
     358                 :          0 :                 return -errno;
     359         [ -  + ]:      25572 :         if (k != sizeof(p))
     360                 :          0 :                 return -EIO;
     361                 :            : 
     362                 :      25572 :         return 0;
     363                 :            : }
     364                 :            : 
     365                 :      73572 : static int contains_uint64(MMapCache *m, MMapFileDescriptor *f, uint64_t n, uint64_t p) {
     366                 :            :         uint64_t a, b;
     367                 :            :         int r;
     368                 :            : 
     369         [ -  + ]:      73572 :         assert(m);
     370         [ -  + ]:      73572 :         assert(f);
     371                 :            : 
     372                 :            :         /* Bisection ... */
     373                 :            : 
     374                 :      73572 :         a = 0; b = n;
     375         [ +  - ]:     700316 :         while (a < b) {
     376                 :            :                 uint64_t c, *z;
     377                 :            : 
     378                 :     700316 :                 c = (a + b) / 2;
     379                 :            : 
     380                 :     700316 :                 r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
     381         [ -  + ]:     700316 :                 if (r < 0)
     382                 :      73572 :                         return r;
     383                 :            : 
     384         [ +  + ]:     700316 :                 if (*z == p)
     385                 :      73572 :                         return 1;
     386                 :            : 
     387         [ -  + ]:     626744 :                 if (a + 1 >= b)
     388                 :          0 :                         return 0;
     389                 :            : 
     390         [ +  + ]:     626744 :                 if (p < *z)
     391                 :     298476 :                         b = c;
     392                 :            :                 else
     393                 :     328268 :                         a = c;
     394                 :            :         }
     395                 :            : 
     396                 :          0 :         return 0;
     397                 :            : }
     398                 :            : 
     399                 :      24000 : static int entry_points_to_data(
     400                 :            :                 JournalFile *f,
     401                 :            :                 MMapFileDescriptor *cache_entry_fd,
     402                 :            :                 uint64_t n_entries,
     403                 :            :                 uint64_t entry_p,
     404                 :            :                 uint64_t data_p) {
     405                 :            : 
     406                 :            :         int r;
     407                 :            :         uint64_t i, n, a;
     408                 :            :         Object *o;
     409                 :      24000 :         bool found = false;
     410                 :            : 
     411         [ -  + ]:      24000 :         assert(f);
     412         [ -  + ]:      24000 :         assert(cache_entry_fd);
     413                 :            : 
     414         [ -  + ]:      24000 :         if (!contains_uint64(f->mmap, cache_entry_fd, n_entries, entry_p)) {
     415         [ #  # ]:          0 :                 error(data_p, "Data object references invalid entry at "OFSfmt, entry_p);
     416                 :          0 :                 return -EBADMSG;
     417                 :            :         }
     418                 :            : 
     419                 :      24000 :         r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
     420         [ -  + ]:      24000 :         if (r < 0)
     421                 :          0 :                 return r;
     422                 :            : 
     423                 :      24000 :         n = journal_file_entry_n_items(o);
     424         [ +  - ]:      24000 :         for (i = 0; i < n; i++)
     425         [ +  - ]:      24000 :                 if (le64toh(o->entry.items[i].object_offset) == data_p) {
     426                 :      24000 :                         found = true;
     427                 :      24000 :                         break;
     428                 :            :                 }
     429                 :            : 
     430         [ -  + ]:      24000 :         if (!found) {
     431         [ #  # ]:          0 :                 error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p);
     432                 :          0 :                 return -EBADMSG;
     433                 :            :         }
     434                 :            : 
     435                 :            :         /* Check if this entry is also in main entry array. Since the
     436                 :            :          * main entry array has already been verified we can rely on
     437                 :            :          * its consistency. */
     438                 :            : 
     439                 :      24000 :         i = 0;
     440                 :      24000 :         n = le64toh(f->header->n_entries);
     441                 :      24000 :         a = le64toh(f->header->entry_array_offset);
     442                 :            : 
     443         [ +  - ]:     173080 :         while (i < n) {
     444                 :            :                 uint64_t m, u;
     445                 :            : 
     446                 :     173080 :                 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
     447         [ -  + ]:     173080 :                 if (r < 0)
     448                 :          0 :                         return r;
     449                 :            : 
     450                 :     173080 :                 m = journal_file_entry_array_n_items(o);
     451                 :     173080 :                 u = MIN(n - i, m);
     452                 :            : 
     453         [ +  + ]:     173080 :                 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
     454                 :            :                         uint64_t x, y, z;
     455                 :            : 
     456                 :      24000 :                         x = 0;
     457                 :      24000 :                         y = u;
     458                 :            : 
     459         [ +  - ]:     237604 :                         while (x < y) {
     460                 :     237604 :                                 z = (x + y) / 2;
     461                 :            : 
     462         [ +  + ]:     237604 :                                 if (le64toh(o->entry_array.items[z]) == entry_p)
     463                 :      24000 :                                         return 0;
     464                 :            : 
     465         [ -  + ]:     213604 :                                 if (x + 1 >= y)
     466                 :          0 :                                         break;
     467                 :            : 
     468         [ +  + ]:     213604 :                                 if (entry_p < le64toh(o->entry_array.items[z]))
     469                 :     102716 :                                         y = z;
     470                 :            :                                 else
     471                 :     110888 :                                         x = z;
     472                 :            :                         }
     473                 :            : 
     474         [ #  # ]:          0 :                         error(entry_p, "Entry object doesn't exist in main entry array");
     475                 :          0 :                         return -EBADMSG;
     476                 :            :                 }
     477                 :            : 
     478                 :     149080 :                 i += u;
     479                 :     149080 :                 a = le64toh(o->entry_array.next_entry_array_offset);
     480                 :            :         }
     481                 :            : 
     482                 :          0 :         return 0;
     483                 :            : }
     484                 :            : 
     485                 :        308 : static int verify_data(
     486                 :            :                 JournalFile *f,
     487                 :            :                 Object *o, uint64_t p,
     488                 :            :                 MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
     489                 :            :                 MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays) {
     490                 :            : 
     491                 :            :         uint64_t i, n, a, last, q;
     492                 :            :         int r;
     493                 :            : 
     494         [ -  + ]:        308 :         assert(f);
     495         [ -  + ]:        308 :         assert(o);
     496         [ -  + ]:        308 :         assert(cache_entry_fd);
     497         [ -  + ]:        308 :         assert(cache_entry_array_fd);
     498                 :            : 
     499                 :        308 :         n = le64toh(o->data.n_entries);
     500                 :        308 :         a = le64toh(o->data.entry_array_offset);
     501                 :            : 
     502                 :            :         /* Entry array means at least two objects */
     503   [ +  -  -  + ]:        308 :         if (a && n < 2) {
     504         [ #  # ]:          0 :                 error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n);
     505                 :          0 :                 return -EBADMSG;
     506                 :            :         }
     507                 :            : 
     508         [ -  + ]:        308 :         if (n == 0)
     509                 :          0 :                 return 0;
     510                 :            : 
     511                 :            :         /* We already checked that earlier */
     512         [ -  + ]:        308 :         assert(o->data.entry_offset);
     513                 :            : 
     514                 :        308 :         last = q = le64toh(o->data.entry_offset);
     515                 :        308 :         r = entry_points_to_data(f, cache_entry_fd, n_entries, q, p);
     516         [ -  + ]:        308 :         if (r < 0)
     517                 :          0 :                 return r;
     518                 :            : 
     519                 :        308 :         i = 1;
     520         [ +  + ]:       1540 :         while (i < n) {
     521                 :            :                 uint64_t next, m, j;
     522                 :            : 
     523         [ -  + ]:       1232 :                 if (a == 0) {
     524         [ #  # ]:          0 :                         error(p, "Array chain too short");
     525                 :          0 :                         return -EBADMSG;
     526                 :            :                 }
     527                 :            : 
     528         [ -  + ]:       1232 :                 if (!contains_uint64(f->mmap, cache_entry_array_fd, n_entry_arrays, a)) {
     529         [ #  # ]:          0 :                         error(p, "Invalid array offset "OFSfmt, a);
     530                 :          0 :                         return -EBADMSG;
     531                 :            :                 }
     532                 :            : 
     533                 :       1232 :                 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
     534         [ -  + ]:       1232 :                 if (r < 0)
     535                 :          0 :                         return r;
     536                 :            : 
     537                 :       1232 :                 next = le64toh(o->entry_array.next_entry_array_offset);
     538   [ +  +  -  + ]:       1232 :                 if (next != 0 && next <= a) {
     539         [ #  # ]:          0 :                         error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next);
     540                 :          0 :                         return -EBADMSG;
     541                 :            :                 }
     542                 :            : 
     543                 :       1232 :                 m = journal_file_entry_array_n_items(o);
     544   [ +  +  +  + ]:      24924 :                 for (j = 0; i < n && j < m; i++, j++) {
     545                 :            : 
     546                 :      23692 :                         q = le64toh(o->entry_array.items[j]);
     547         [ -  + ]:      23692 :                         if (q <= last) {
     548         [ #  # ]:          0 :                                 error(p, "Data object's entry array not sorted");
     549                 :          0 :                                 return -EBADMSG;
     550                 :            :                         }
     551                 :      23692 :                         last = q;
     552                 :            : 
     553                 :      23692 :                         r = entry_points_to_data(f, cache_entry_fd, n_entries, q, p);
     554         [ -  + ]:      23692 :                         if (r < 0)
     555                 :          0 :                                 return r;
     556                 :            : 
     557                 :            :                         /* Pointer might have moved, reposition */
     558                 :      23692 :                         r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
     559         [ -  + ]:      23692 :                         if (r < 0)
     560                 :          0 :                                 return r;
     561                 :            :                 }
     562                 :            : 
     563                 :       1232 :                 a = next;
     564                 :            :         }
     565                 :            : 
     566                 :        308 :         return 0;
     567                 :            : }
     568                 :            : 
     569                 :          4 : static int verify_hash_table(
     570                 :            :                 JournalFile *f,
     571                 :            :                 MMapFileDescriptor *cache_data_fd, uint64_t n_data,
     572                 :            :                 MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
     573                 :            :                 MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays,
     574                 :            :                 usec_t *last_usec,
     575                 :            :                 bool show_progress) {
     576                 :            : 
     577                 :            :         uint64_t i, n;
     578                 :            :         int r;
     579                 :            : 
     580         [ -  + ]:          4 :         assert(f);
     581         [ -  + ]:          4 :         assert(cache_data_fd);
     582         [ -  + ]:          4 :         assert(cache_entry_fd);
     583         [ -  + ]:          4 :         assert(cache_entry_array_fd);
     584         [ -  + ]:          4 :         assert(last_usec);
     585                 :            : 
     586                 :          4 :         n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
     587         [ -  + ]:          4 :         if (n <= 0)
     588                 :          0 :                 return 0;
     589                 :            : 
     590                 :          4 :         r = journal_file_map_data_hash_table(f);
     591         [ -  + ]:          4 :         if (r < 0)
     592         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to map data hash table: %m");
     593                 :            : 
     594         [ +  + ]:       8192 :         for (i = 0; i < n; i++) {
     595                 :       8188 :                 uint64_t last = 0, p;
     596                 :            : 
     597         [ +  - ]:       8188 :                 if (show_progress)
     598                 :       8188 :                         draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec);
     599                 :            : 
     600                 :       8188 :                 p = le64toh(f->data_hash_table[i].head_hash_offset);
     601         [ +  + ]:       8496 :                 while (p != 0) {
     602                 :            :                         Object *o;
     603                 :            :                         uint64_t next;
     604                 :            : 
     605         [ -  + ]:        308 :                         if (!contains_uint64(f->mmap, cache_data_fd, n_data, p)) {
     606         [ #  # ]:          0 :                                 error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n);
     607                 :          0 :                                 return -EBADMSG;
     608                 :            :                         }
     609                 :            : 
     610                 :        308 :                         r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
     611         [ -  + ]:        308 :                         if (r < 0)
     612                 :          0 :                                 return r;
     613                 :            : 
     614                 :        308 :                         next = le64toh(o->data.next_hash_offset);
     615   [ +  +  -  + ]:        308 :                         if (next != 0 && next <= p) {
     616         [ #  # ]:          0 :                                 error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n);
     617                 :          0 :                                 return -EBADMSG;
     618                 :            :                         }
     619                 :            : 
     620         [ -  + ]:        308 :                         if (le64toh(o->data.hash) % n != i) {
     621         [ #  # ]:          0 :                                 error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n);
     622                 :          0 :                                 return -EBADMSG;
     623                 :            :                         }
     624                 :            : 
     625                 :        308 :                         r = verify_data(f, o, p, cache_entry_fd, n_entries, cache_entry_array_fd, n_entry_arrays);
     626         [ -  + ]:        308 :                         if (r < 0)
     627                 :          0 :                                 return r;
     628                 :            : 
     629                 :        308 :                         last = p;
     630                 :        308 :                         p = next;
     631                 :            :                 }
     632                 :            : 
     633         [ -  + ]:       8188 :                 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
     634         [ #  # ]:          0 :                         error(p, "Tail hash pointer mismatch in hash table");
     635                 :          0 :                         return -EBADMSG;
     636                 :            :                 }
     637                 :            :         }
     638                 :            : 
     639                 :          4 :         return 0;
     640                 :            : }
     641                 :            : 
     642                 :      24000 : static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
     643                 :            :         uint64_t n, h, q;
     644                 :            :         int r;
     645         [ -  + ]:      24000 :         assert(f);
     646                 :            : 
     647                 :      24000 :         n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
     648         [ -  + ]:      24000 :         if (n <= 0)
     649                 :          0 :                 return 0;
     650                 :            : 
     651                 :      24000 :         r = journal_file_map_data_hash_table(f);
     652         [ -  + ]:      24000 :         if (r < 0)
     653         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to map data hash table: %m");
     654                 :            : 
     655                 :      24000 :         h = hash % n;
     656                 :            : 
     657                 :      24000 :         q = le64toh(f->data_hash_table[h].head_hash_offset);
     658         [ +  - ]:      24680 :         while (q != 0) {
     659                 :            :                 Object *o;
     660                 :            : 
     661         [ +  + ]:      24680 :                 if (p == q)
     662                 :      24000 :                         return 1;
     663                 :            : 
     664                 :        680 :                 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
     665         [ -  + ]:        680 :                 if (r < 0)
     666                 :          0 :                         return r;
     667                 :            : 
     668                 :        680 :                 q = le64toh(o->data.next_hash_offset);
     669                 :            :         }
     670                 :            : 
     671                 :          0 :         return 0;
     672                 :            : }
     673                 :            : 
     674                 :      24000 : static int verify_entry(
     675                 :            :                 JournalFile *f,
     676                 :            :                 Object *o, uint64_t p,
     677                 :            :                 MMapFileDescriptor *cache_data_fd, uint64_t n_data) {
     678                 :            : 
     679                 :            :         uint64_t i, n;
     680                 :            :         int r;
     681                 :            : 
     682         [ -  + ]:      24000 :         assert(f);
     683         [ -  + ]:      24000 :         assert(o);
     684         [ -  + ]:      24000 :         assert(cache_data_fd);
     685                 :            : 
     686                 :      24000 :         n = journal_file_entry_n_items(o);
     687         [ +  + ]:      48000 :         for (i = 0; i < n; i++) {
     688                 :            :                 uint64_t q, h;
     689                 :            :                 Object *u;
     690                 :            : 
     691                 :      24000 :                 q = le64toh(o->entry.items[i].object_offset);
     692                 :      24000 :                 h = le64toh(o->entry.items[i].hash);
     693                 :            : 
     694         [ -  + ]:      24000 :                 if (!contains_uint64(f->mmap, cache_data_fd, n_data, q)) {
     695         [ #  # ]:          0 :                         error(p, "Invalid data object of entry");
     696                 :          0 :                         return -EBADMSG;
     697                 :            :                 }
     698                 :            : 
     699                 :      24000 :                 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
     700         [ -  + ]:      24000 :                 if (r < 0)
     701                 :          0 :                         return r;
     702                 :            : 
     703         [ -  + ]:      24000 :                 if (le64toh(u->data.hash) != h) {
     704         [ #  # ]:          0 :                         error(p, "Hash mismatch for data object of entry");
     705                 :          0 :                         return -EBADMSG;
     706                 :            :                 }
     707                 :            : 
     708                 :      24000 :                 r = data_object_in_hash_table(f, h, q);
     709         [ -  + ]:      24000 :                 if (r < 0)
     710                 :          0 :                         return r;
     711         [ -  + ]:      24000 :                 if (r == 0) {
     712         [ #  # ]:          0 :                         error(p, "Data object missing from hash table");
     713                 :          0 :                         return -EBADMSG;
     714                 :            :                 }
     715                 :            :         }
     716                 :            : 
     717                 :      24000 :         return 0;
     718                 :            : }
     719                 :            : 
     720                 :          4 : static int verify_entry_array(
     721                 :            :                 JournalFile *f,
     722                 :            :                 MMapFileDescriptor *cache_data_fd, uint64_t n_data,
     723                 :            :                 MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
     724                 :            :                 MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays,
     725                 :            :                 usec_t *last_usec,
     726                 :            :                 bool show_progress) {
     727                 :            : 
     728                 :          4 :         uint64_t i = 0, a, n, last = 0;
     729                 :            :         int r;
     730                 :            : 
     731         [ -  + ]:          4 :         assert(f);
     732         [ -  + ]:          4 :         assert(cache_data_fd);
     733         [ -  + ]:          4 :         assert(cache_entry_fd);
     734         [ -  + ]:          4 :         assert(cache_entry_array_fd);
     735         [ -  + ]:          4 :         assert(last_usec);
     736                 :            : 
     737                 :          4 :         n = le64toh(f->header->n_entries);
     738                 :          4 :         a = le64toh(f->header->entry_array_offset);
     739         [ +  + ]:         36 :         while (i < n) {
     740                 :            :                 uint64_t next, m, j;
     741                 :            :                 Object *o;
     742                 :            : 
     743         [ +  - ]:         32 :                 if (show_progress)
     744                 :         32 :                         draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec);
     745                 :            : 
     746         [ -  + ]:         32 :                 if (a == 0) {
     747         [ #  # ]:          0 :                         error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n);
     748                 :          0 :                         return -EBADMSG;
     749                 :            :                 }
     750                 :            : 
     751         [ -  + ]:         32 :                 if (!contains_uint64(f->mmap, cache_entry_array_fd, n_entry_arrays, a)) {
     752         [ #  # ]:          0 :                         error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n);
     753                 :          0 :                         return -EBADMSG;
     754                 :            :                 }
     755                 :            : 
     756                 :         32 :                 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
     757         [ -  + ]:         32 :                 if (r < 0)
     758                 :          0 :                         return r;
     759                 :            : 
     760                 :         32 :                 next = le64toh(o->entry_array.next_entry_array_offset);
     761   [ +  +  -  + ]:         32 :                 if (next != 0 && next <= a) {
     762         [ #  # ]:          0 :                         error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next);
     763                 :          0 :                         return -EBADMSG;
     764                 :            :                 }
     765                 :            : 
     766                 :         32 :                 m = journal_file_entry_array_n_items(o);
     767   [ +  +  +  + ]:      24032 :                 for (j = 0; i < n && j < m; i++, j++) {
     768                 :            :                         uint64_t p;
     769                 :            : 
     770                 :      24000 :                         p = le64toh(o->entry_array.items[j]);
     771         [ -  + ]:      24000 :                         if (p <= last) {
     772         [ #  # ]:          0 :                                 error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n);
     773                 :          0 :                                 return -EBADMSG;
     774                 :            :                         }
     775                 :      24000 :                         last = p;
     776                 :            : 
     777         [ -  + ]:      24000 :                         if (!contains_uint64(f->mmap, cache_entry_fd, n_entries, p)) {
     778         [ #  # ]:          0 :                                 error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n);
     779                 :          0 :                                 return -EBADMSG;
     780                 :            :                         }
     781                 :            : 
     782                 :      24000 :                         r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
     783         [ -  + ]:      24000 :                         if (r < 0)
     784                 :          0 :                                 return r;
     785                 :            : 
     786                 :      24000 :                         r = verify_entry(f, o, p, cache_data_fd, n_data);
     787         [ -  + ]:      24000 :                         if (r < 0)
     788                 :          0 :                                 return r;
     789                 :            : 
     790                 :            :                         /* Pointer might have moved, reposition */
     791                 :      24000 :                         r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
     792         [ -  + ]:      24000 :                         if (r < 0)
     793                 :          0 :                                 return r;
     794                 :            :                 }
     795                 :            : 
     796                 :         32 :                 a = next;
     797                 :            :         }
     798                 :            : 
     799                 :          4 :         return 0;
     800                 :            : }
     801                 :            : 
     802                 :          4 : int journal_file_verify(
     803                 :            :                 JournalFile *f,
     804                 :            :                 const char *key,
     805                 :            :                 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
     806                 :            :                 bool show_progress) {
     807                 :            :         int r;
     808                 :            :         Object *o;
     809                 :          4 :         uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
     810                 :            : 
     811                 :          4 :         uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
     812                 :            :         sd_id128_t entry_boot_id;
     813                 :          4 :         bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
     814                 :          4 :         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;
     815                 :          4 :         usec_t last_usec = 0;
     816                 :          4 :         int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
     817                 :          4 :         MMapFileDescriptor *cache_data_fd = NULL, *cache_entry_fd = NULL, *cache_entry_array_fd = NULL;
     818                 :            :         unsigned i;
     819                 :          4 :         bool found_last = false;
     820                 :          4 :         const char *tmp_dir = NULL;
     821                 :            : 
     822                 :            : #if HAVE_GCRYPT
     823                 :          4 :         uint64_t last_tag = 0;
     824                 :            : #endif
     825         [ -  + ]:          4 :         assert(f);
     826                 :            : 
     827         [ -  + ]:          4 :         if (key) {
     828                 :            : #if HAVE_GCRYPT
     829                 :          0 :                 r = journal_file_parse_verification_key(f, key);
     830         [ #  # ]:          0 :                 if (r < 0) {
     831         [ #  # ]:          0 :                         log_error("Failed to parse seed.");
     832                 :          0 :                         return r;
     833                 :            :                 }
     834                 :            : #else
     835                 :            :                 return -EOPNOTSUPP;
     836                 :            : #endif
     837         [ -  + ]:          4 :         } else if (f->seal)
     838                 :          0 :                 return -ENOKEY;
     839                 :            : 
     840                 :          4 :         r = var_tmp_dir(&tmp_dir);
     841         [ -  + ]:          4 :         if (r < 0) {
     842         [ #  # ]:          0 :                 log_error_errno(r, "Failed to determine temporary directory: %m");
     843                 :          0 :                 goto fail;
     844                 :            :         }
     845                 :            : 
     846                 :          4 :         data_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
     847         [ -  + ]:          4 :         if (data_fd < 0) {
     848         [ #  # ]:          0 :                 r = log_error_errno(data_fd, "Failed to create data file: %m");
     849                 :          0 :                 goto fail;
     850                 :            :         }
     851                 :            : 
     852                 :          4 :         entry_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
     853         [ -  + ]:          4 :         if (entry_fd < 0) {
     854         [ #  # ]:          0 :                 r = log_error_errno(entry_fd, "Failed to create entry file: %m");
     855                 :          0 :                 goto fail;
     856                 :            :         }
     857                 :            : 
     858                 :          4 :         entry_array_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
     859         [ -  + ]:          4 :         if (entry_array_fd < 0) {
     860         [ #  # ]:          0 :                 r = log_error_errno(entry_array_fd,
     861                 :            :                                     "Failed to create entry array file: %m");
     862                 :          0 :                 goto fail;
     863                 :            :         }
     864                 :            : 
     865                 :          4 :         cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd);
     866         [ -  + ]:          4 :         if (!cache_data_fd) {
     867                 :          0 :                 r = log_oom();
     868                 :          0 :                 goto fail;
     869                 :            :         }
     870                 :            : 
     871                 :          4 :         cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd);
     872         [ -  + ]:          4 :         if (!cache_entry_fd) {
     873                 :          0 :                 r = log_oom();
     874                 :          0 :                 goto fail;
     875                 :            :         }
     876                 :            : 
     877                 :          4 :         cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd);
     878         [ -  + ]:          4 :         if (!cache_entry_array_fd) {
     879                 :          0 :                 r = log_oom();
     880                 :          0 :                 goto fail;
     881                 :            :         }
     882                 :            : 
     883         [ -  + ]:          4 :         if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
     884         [ #  # ]:          0 :                 log_error("Cannot verify file with unknown extensions.");
     885                 :          0 :                 r = -EOPNOTSUPP;
     886                 :          0 :                 goto fail;
     887                 :            :         }
     888                 :            : 
     889         [ +  + ]:         32 :         for (i = 0; i < sizeof(f->header->reserved); i++)
     890         [ -  + ]:         28 :                 if (f->header->reserved[i] != 0) {
     891         [ #  # ]:          0 :                         error(offsetof(Header, reserved[i]), "Reserved field is non-zero");
     892                 :          0 :                         r = -EBADMSG;
     893                 :          0 :                         goto fail;
     894                 :            :                 }
     895                 :            : 
     896                 :            :         /* First iteration: we go through all objects, verify the
     897                 :            :          * superficial structure, headers, hashes. */
     898                 :            : 
     899                 :          4 :         p = le64toh(f->header->header_size);
     900                 :            :         for (;;) {
     901                 :            :                 /* Early exit if there are no objects in the file, at all */
     902         [ -  + ]:      25584 :                 if (le64toh(f->header->tail_object_offset) == 0)
     903                 :          0 :                         break;
     904                 :            : 
     905         [ +  - ]:      25584 :                 if (show_progress)
     906                 :      25584 :                         draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec);
     907                 :            : 
     908                 :      25584 :                 r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
     909         [ -  + ]:      25584 :                 if (r < 0) {
     910         [ #  # ]:          0 :                         error(p, "Invalid object");
     911                 :          0 :                         goto fail;
     912                 :            :                 }
     913                 :            : 
     914         [ -  + ]:      25584 :                 if (p > le64toh(f->header->tail_object_offset)) {
     915         [ #  # ]:          0 :                         error(offsetof(Header, tail_object_offset), "Invalid tail object pointer");
     916                 :          0 :                         r = -EBADMSG;
     917                 :          0 :                         goto fail;
     918                 :            :                 }
     919                 :            : 
     920                 :      25584 :                 n_objects++;
     921                 :            : 
     922                 :      25584 :                 r = journal_file_object_verify(f, p, o);
     923         [ -  + ]:      25584 :                 if (r < 0) {
     924         [ #  # ]:          0 :                         error_errno(p, r, "Invalid object contents: %m");
     925                 :          0 :                         goto fail;
     926                 :            :                 }
     927                 :            : 
     928         [ -  + ]:      25584 :                 if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
     929         [ #  # ]:          0 :                     (o->object.flags & OBJECT_COMPRESSED_LZ4)) {
     930         [ #  # ]:          0 :                         error(p, "Objected with double compression");
     931                 :          0 :                         r = -EINVAL;
     932                 :          0 :                         goto fail;
     933                 :            :                 }
     934                 :            : 
     935   [ -  +  #  # ]:      25584 :                 if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
     936         [ #  # ]:          0 :                         error(p, "XZ compressed object in file without XZ compression");
     937                 :          0 :                         r = -EBADMSG;
     938                 :          0 :                         goto fail;
     939                 :            :                 }
     940                 :            : 
     941   [ -  +  #  # ]:      25584 :                 if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
     942         [ #  # ]:          0 :                         error(p, "LZ4 compressed object in file without LZ4 compression");
     943                 :          0 :                         r = -EBADMSG;
     944                 :          0 :                         goto fail;
     945                 :            :                 }
     946                 :            : 
     947   [ +  +  +  +  :      25584 :                 switch (o->object.type) {
             +  +  -  - ]
     948                 :            : 
     949                 :        308 :                 case OBJECT_DATA:
     950                 :        308 :                         r = write_uint64(data_fd, p);
     951         [ -  + ]:        308 :                         if (r < 0)
     952                 :          0 :                                 goto fail;
     953                 :            : 
     954                 :        308 :                         n_data++;
     955                 :        308 :                         break;
     956                 :            : 
     957                 :          4 :                 case OBJECT_FIELD:
     958                 :          4 :                         n_fields++;
     959                 :          4 :                         break;
     960                 :            : 
     961                 :      24000 :                 case OBJECT_ENTRY:
     962   [ -  +  #  # ]:      24000 :                         if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
     963         [ #  # ]:          0 :                                 error(p, "First entry before first tag");
     964                 :          0 :                                 r = -EBADMSG;
     965                 :          0 :                                 goto fail;
     966                 :            :                         }
     967                 :            : 
     968                 :      24000 :                         r = write_uint64(entry_fd, p);
     969         [ -  + ]:      24000 :                         if (r < 0)
     970                 :          0 :                                 goto fail;
     971                 :            : 
     972         [ -  + ]:      24000 :                         if (le64toh(o->entry.realtime) < last_tag_realtime) {
     973         [ #  # ]:          0 :                                 error(p, "Older entry after newer tag");
     974                 :          0 :                                 r = -EBADMSG;
     975                 :          0 :                                 goto fail;
     976                 :            :                         }
     977                 :            : 
     978   [ +  +  -  + ]:      24004 :                         if (!entry_seqnum_set &&
     979                 :          4 :                             le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
     980         [ #  # ]:          0 :                                 error(p, "Head entry sequence number incorrect");
     981                 :          0 :                                 r = -EBADMSG;
     982                 :          0 :                                 goto fail;
     983                 :            :                         }
     984                 :            : 
     985   [ +  +  -  + ]:      47996 :                         if (entry_seqnum_set &&
     986                 :      23996 :                             entry_seqnum >= le64toh(o->entry.seqnum)) {
     987         [ #  # ]:          0 :                                 error(p, "Entry sequence number out of synchronization");
     988                 :          0 :                                 r = -EBADMSG;
     989                 :          0 :                                 goto fail;
     990                 :            :                         }
     991                 :            : 
     992                 :      24000 :                         entry_seqnum = le64toh(o->entry.seqnum);
     993                 :      24000 :                         entry_seqnum_set = true;
     994                 :            : 
     995         [ +  + ]:      24000 :                         if (entry_monotonic_set &&
     996   [ +  -  -  + ]:      47992 :                             sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
     997                 :      23996 :                             entry_monotonic > le64toh(o->entry.monotonic)) {
     998         [ #  # ]:          0 :                                 error(p, "Entry timestamp out of synchronization");
     999                 :          0 :                                 r = -EBADMSG;
    1000                 :          0 :                                 goto fail;
    1001                 :            :                         }
    1002                 :            : 
    1003                 :      24000 :                         entry_monotonic = le64toh(o->entry.monotonic);
    1004                 :      24000 :                         entry_boot_id = o->entry.boot_id;
    1005                 :      24000 :                         entry_monotonic_set = true;
    1006                 :            : 
    1007   [ +  +  -  + ]:      24004 :                         if (!entry_realtime_set &&
    1008                 :          4 :                             le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
    1009         [ #  # ]:          0 :                                 error(p, "Head entry realtime timestamp incorrect");
    1010                 :          0 :                                 r = -EBADMSG;
    1011                 :          0 :                                 goto fail;
    1012                 :            :                         }
    1013                 :            : 
    1014                 :      24000 :                         entry_realtime = le64toh(o->entry.realtime);
    1015                 :      24000 :                         entry_realtime_set = true;
    1016                 :            : 
    1017                 :      24000 :                         n_entries++;
    1018                 :      24000 :                         break;
    1019                 :            : 
    1020                 :          4 :                 case OBJECT_DATA_HASH_TABLE:
    1021         [ -  + ]:          4 :                         if (n_data_hash_tables > 1) {
    1022         [ #  # ]:          0 :                                 error(p, "More than one data hash table");
    1023                 :          0 :                                 r = -EBADMSG;
    1024                 :          0 :                                 goto fail;
    1025                 :            :                         }
    1026                 :            : 
    1027         [ +  - ]:          4 :                         if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
    1028         [ -  + ]:          4 :                             le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
    1029         [ #  # ]:          0 :                                 error(p, "header fields for data hash table invalid");
    1030                 :          0 :                                 r = -EBADMSG;
    1031                 :          0 :                                 goto fail;
    1032                 :            :                         }
    1033                 :            : 
    1034                 :          4 :                         n_data_hash_tables++;
    1035                 :          4 :                         break;
    1036                 :            : 
    1037                 :          4 :                 case OBJECT_FIELD_HASH_TABLE:
    1038         [ -  + ]:          4 :                         if (n_field_hash_tables > 1) {
    1039         [ #  # ]:          0 :                                 error(p, "More than one field hash table");
    1040                 :          0 :                                 r = -EBADMSG;
    1041                 :          0 :                                 goto fail;
    1042                 :            :                         }
    1043                 :            : 
    1044         [ +  - ]:          4 :                         if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
    1045         [ -  + ]:          4 :                             le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
    1046         [ #  # ]:          0 :                                 error(p, "Header fields for field hash table invalid");
    1047                 :          0 :                                 r = -EBADMSG;
    1048                 :          0 :                                 goto fail;
    1049                 :            :                         }
    1050                 :            : 
    1051                 :          4 :                         n_field_hash_tables++;
    1052                 :          4 :                         break;
    1053                 :            : 
    1054                 :       1264 :                 case OBJECT_ENTRY_ARRAY:
    1055                 :       1264 :                         r = write_uint64(entry_array_fd, p);
    1056         [ -  + ]:       1264 :                         if (r < 0)
    1057                 :          0 :                                 goto fail;
    1058                 :            : 
    1059         [ +  + ]:       1264 :                         if (p == le64toh(f->header->entry_array_offset)) {
    1060         [ -  + ]:          4 :                                 if (found_main_entry_array) {
    1061         [ #  # ]:          0 :                                         error(p, "More than one main entry array");
    1062                 :          0 :                                         r = -EBADMSG;
    1063                 :          0 :                                         goto fail;
    1064                 :            :                                 }
    1065                 :            : 
    1066                 :          4 :                                 found_main_entry_array = true;
    1067                 :            :                         }
    1068                 :            : 
    1069                 :       1264 :                         n_entry_arrays++;
    1070                 :       1264 :                         break;
    1071                 :            : 
    1072                 :          0 :                 case OBJECT_TAG:
    1073         [ #  # ]:          0 :                         if (!JOURNAL_HEADER_SEALED(f->header)) {
    1074         [ #  # ]:          0 :                                 error(p, "Tag object in file without sealing");
    1075                 :          0 :                                 r = -EBADMSG;
    1076                 :          0 :                                 goto fail;
    1077                 :            :                         }
    1078                 :            : 
    1079         [ #  # ]:          0 :                         if (le64toh(o->tag.seqnum) != n_tags + 1) {
    1080         [ #  # ]:          0 :                                 error(p, "Tag sequence number out of synchronization");
    1081                 :          0 :                                 r = -EBADMSG;
    1082                 :          0 :                                 goto fail;
    1083                 :            :                         }
    1084                 :            : 
    1085         [ #  # ]:          0 :                         if (le64toh(o->tag.epoch) < last_epoch) {
    1086         [ #  # ]:          0 :                                 error(p, "Epoch sequence out of synchronization");
    1087                 :          0 :                                 r = -EBADMSG;
    1088                 :          0 :                                 goto fail;
    1089                 :            :                         }
    1090                 :            : 
    1091                 :            : #if HAVE_GCRYPT
    1092         [ #  # ]:          0 :                         if (f->seal) {
    1093                 :            :                                 uint64_t q, rt;
    1094                 :            : 
    1095         [ #  # ]:          0 :                                 debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
    1096                 :            : 
    1097                 :          0 :                                 rt = f->fss_start_usec + le64toh(o->tag.epoch) * f->fss_interval_usec;
    1098   [ #  #  #  # ]:          0 :                                 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
    1099         [ #  # ]:          0 :                                         error(p, "tag/entry realtime timestamp out of synchronization");
    1100                 :          0 :                                         r = -EBADMSG;
    1101                 :          0 :                                         goto fail;
    1102                 :            :                                 }
    1103                 :            : 
    1104                 :            :                                 /* OK, now we know the epoch. So let's now set
    1105                 :            :                                  * it, and calculate the HMAC for everything
    1106                 :            :                                  * since the last tag. */
    1107                 :          0 :                                 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
    1108         [ #  # ]:          0 :                                 if (r < 0)
    1109                 :          0 :                                         goto fail;
    1110                 :            : 
    1111                 :          0 :                                 r = journal_file_hmac_start(f);
    1112         [ #  # ]:          0 :                                 if (r < 0)
    1113                 :          0 :                                         goto fail;
    1114                 :            : 
    1115         [ #  # ]:          0 :                                 if (last_tag == 0) {
    1116                 :          0 :                                         r = journal_file_hmac_put_header(f);
    1117         [ #  # ]:          0 :                                         if (r < 0)
    1118                 :          0 :                                                 goto fail;
    1119                 :            : 
    1120                 :          0 :                                         q = le64toh(f->header->header_size);
    1121                 :            :                                 } else
    1122                 :          0 :                                         q = last_tag;
    1123                 :            : 
    1124         [ #  # ]:          0 :                                 while (q <= p) {
    1125                 :          0 :                                         r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o);
    1126         [ #  # ]:          0 :                                         if (r < 0)
    1127                 :          0 :                                                 goto fail;
    1128                 :            : 
    1129                 :          0 :                                         r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
    1130         [ #  # ]:          0 :                                         if (r < 0)
    1131                 :          0 :                                                 goto fail;
    1132                 :            : 
    1133                 :          0 :                                         q = q + ALIGN64(le64toh(o->object.size));
    1134                 :            :                                 }
    1135                 :            : 
    1136                 :            :                                 /* Position might have changed, let's reposition things */
    1137                 :          0 :                                 r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
    1138         [ #  # ]:          0 :                                 if (r < 0)
    1139                 :          0 :                                         goto fail;
    1140                 :            : 
    1141         [ #  # ]:          0 :                                 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
    1142         [ #  # ]:          0 :                                         error(p, "Tag failed verification");
    1143                 :          0 :                                         r = -EBADMSG;
    1144                 :          0 :                                         goto fail;
    1145                 :            :                                 }
    1146                 :            : 
    1147                 :          0 :                                 f->hmac_running = false;
    1148                 :          0 :                                 last_tag_realtime = rt;
    1149                 :          0 :                                 last_sealed_realtime = entry_realtime;
    1150                 :            :                         }
    1151                 :            : 
    1152                 :          0 :                         last_tag = p + ALIGN64(le64toh(o->object.size));
    1153                 :            : #endif
    1154                 :            : 
    1155                 :          0 :                         last_epoch = le64toh(o->tag.epoch);
    1156                 :            : 
    1157                 :          0 :                         n_tags++;
    1158                 :          0 :                         break;
    1159                 :            : 
    1160                 :          0 :                 default:
    1161                 :          0 :                         n_weird++;
    1162                 :            :                 }
    1163                 :            : 
    1164         [ +  + ]:      25584 :                 if (p == le64toh(f->header->tail_object_offset)) {
    1165                 :          4 :                         found_last = true;
    1166                 :          4 :                         break;
    1167                 :            :                 }
    1168                 :            : 
    1169                 :      25580 :                 p = p + ALIGN64(le64toh(o->object.size));
    1170                 :            :         };
    1171                 :            : 
    1172   [ -  +  #  # ]:          4 :         if (!found_last && le64toh(f->header->tail_object_offset) != 0) {
    1173         [ #  # ]:          0 :                 error(le64toh(f->header->tail_object_offset), "Tail object pointer dead");
    1174                 :          0 :                 r = -EBADMSG;
    1175                 :          0 :                 goto fail;
    1176                 :            :         }
    1177                 :            : 
    1178         [ -  + ]:          4 :         if (n_objects != le64toh(f->header->n_objects)) {
    1179         [ #  # ]:          0 :                 error(offsetof(Header, n_objects), "Object number mismatch");
    1180                 :          0 :                 r = -EBADMSG;
    1181                 :          0 :                 goto fail;
    1182                 :            :         }
    1183                 :            : 
    1184         [ -  + ]:          4 :         if (n_entries != le64toh(f->header->n_entries)) {
    1185         [ #  # ]:          0 :                 error(offsetof(Header, n_entries), "Entry number mismatch");
    1186                 :          0 :                 r = -EBADMSG;
    1187                 :          0 :                 goto fail;
    1188                 :            :         }
    1189                 :            : 
    1190   [ +  -  -  + ]:          8 :         if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
    1191                 :          4 :             n_data != le64toh(f->header->n_data)) {
    1192         [ #  # ]:          0 :                 error(offsetof(Header, n_data), "Data number mismatch");
    1193                 :          0 :                 r = -EBADMSG;
    1194                 :          0 :                 goto fail;
    1195                 :            :         }
    1196                 :            : 
    1197   [ +  -  -  + ]:          8 :         if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
    1198                 :          4 :             n_fields != le64toh(f->header->n_fields)) {
    1199         [ #  # ]:          0 :                 error(offsetof(Header, n_fields), "Field number mismatch");
    1200                 :          0 :                 r = -EBADMSG;
    1201                 :          0 :                 goto fail;
    1202                 :            :         }
    1203                 :            : 
    1204   [ +  -  -  + ]:          8 :         if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
    1205                 :          4 :             n_tags != le64toh(f->header->n_tags)) {
    1206         [ #  # ]:          0 :                 error(offsetof(Header, n_tags), "Tag number mismatch");
    1207                 :          0 :                 r = -EBADMSG;
    1208                 :          0 :                 goto fail;
    1209                 :            :         }
    1210                 :            : 
    1211   [ +  -  -  + ]:          8 :         if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
    1212                 :          4 :             n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
    1213         [ #  # ]:          0 :                 error(offsetof(Header, n_entry_arrays), "Entry array number mismatch");
    1214                 :          0 :                 r = -EBADMSG;
    1215                 :          0 :                 goto fail;
    1216                 :            :         }
    1217                 :            : 
    1218   [ -  +  #  # ]:          4 :         if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) {
    1219         [ #  # ]:          0 :                 error(0, "Missing entry array");
    1220                 :          0 :                 r = -EBADMSG;
    1221                 :          0 :                 goto fail;
    1222                 :            :         }
    1223                 :            : 
    1224   [ +  -  -  + ]:          8 :         if (entry_seqnum_set &&
    1225                 :          4 :             entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
    1226         [ #  # ]:          0 :                 error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum");
    1227                 :          0 :                 r = -EBADMSG;
    1228                 :          0 :                 goto fail;
    1229                 :            :         }
    1230                 :            : 
    1231         [ +  - ]:          4 :         if (entry_monotonic_set &&
    1232   [ +  -  -  + ]:          8 :             (sd_id128_equal(entry_boot_id, f->header->boot_id) &&
    1233                 :          4 :              entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
    1234         [ #  # ]:          0 :                 error(0, "Invalid tail monotonic timestamp");
    1235                 :          0 :                 r = -EBADMSG;
    1236                 :          0 :                 goto fail;
    1237                 :            :         }
    1238                 :            : 
    1239   [ +  -  -  + ]:          4 :         if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
    1240         [ #  # ]:          0 :                 error(0, "Invalid tail realtime timestamp");
    1241                 :          0 :                 r = -EBADMSG;
    1242                 :          0 :                 goto fail;
    1243                 :            :         }
    1244                 :            : 
    1245                 :            :         /* Second iteration: we follow all objects referenced from the
    1246                 :            :          * two entry points: the object hash table and the entry
    1247                 :            :          * array. We also check that everything referenced (directly
    1248                 :            :          * or indirectly) in the data hash table also exists in the
    1249                 :            :          * entry array, and vice versa. Note that we do not care for
    1250                 :            :          * unreferenced objects. We only care that everything that is
    1251                 :            :          * referenced is consistent. */
    1252                 :            : 
    1253                 :          4 :         r = verify_entry_array(f,
    1254                 :            :                                cache_data_fd, n_data,
    1255                 :            :                                cache_entry_fd, n_entries,
    1256                 :            :                                cache_entry_array_fd, n_entry_arrays,
    1257                 :            :                                &last_usec,
    1258                 :            :                                show_progress);
    1259         [ -  + ]:          4 :         if (r < 0)
    1260                 :          0 :                 goto fail;
    1261                 :            : 
    1262                 :          4 :         r = verify_hash_table(f,
    1263                 :            :                               cache_data_fd, n_data,
    1264                 :            :                               cache_entry_fd, n_entries,
    1265                 :            :                               cache_entry_array_fd, n_entry_arrays,
    1266                 :            :                               &last_usec,
    1267                 :            :                               show_progress);
    1268         [ -  + ]:          4 :         if (r < 0)
    1269                 :          0 :                 goto fail;
    1270                 :            : 
    1271         [ +  - ]:          4 :         if (show_progress)
    1272                 :          4 :                 flush_progress();
    1273                 :            : 
    1274                 :          4 :         mmap_cache_free_fd(f->mmap, cache_data_fd);
    1275                 :          4 :         mmap_cache_free_fd(f->mmap, cache_entry_fd);
    1276                 :          4 :         mmap_cache_free_fd(f->mmap, cache_entry_array_fd);
    1277                 :            : 
    1278                 :          4 :         safe_close(data_fd);
    1279                 :          4 :         safe_close(entry_fd);
    1280                 :          4 :         safe_close(entry_array_fd);
    1281                 :            : 
    1282         [ +  - ]:          4 :         if (first_contained)
    1283                 :          4 :                 *first_contained = le64toh(f->header->head_entry_realtime);
    1284         [ +  - ]:          4 :         if (last_validated)
    1285                 :          4 :                 *last_validated = last_sealed_realtime;
    1286         [ +  - ]:          4 :         if (last_contained)
    1287                 :          4 :                 *last_contained = le64toh(f->header->tail_entry_realtime);
    1288                 :            : 
    1289                 :          4 :         return 0;
    1290                 :            : 
    1291                 :          0 : fail:
    1292         [ #  # ]:          0 :         if (show_progress)
    1293                 :          0 :                 flush_progress();
    1294                 :            : 
    1295         [ #  # ]:          0 :         log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
    1296                 :            :                   f->path,
    1297                 :            :                   p,
    1298                 :            :                   (unsigned long long) f->last_stat.st_size,
    1299                 :            :                   100 * p / f->last_stat.st_size);
    1300                 :            : 
    1301         [ #  # ]:          0 :         if (data_fd >= 0)
    1302                 :          0 :                 safe_close(data_fd);
    1303                 :            : 
    1304         [ #  # ]:          0 :         if (entry_fd >= 0)
    1305                 :          0 :                 safe_close(entry_fd);
    1306                 :            : 
    1307         [ #  # ]:          0 :         if (entry_array_fd >= 0)
    1308                 :          0 :                 safe_close(entry_array_fd);
    1309                 :            : 
    1310         [ #  # ]:          0 :         if (cache_data_fd)
    1311                 :          0 :                 mmap_cache_free_fd(f->mmap, cache_data_fd);
    1312                 :            : 
    1313         [ #  # ]:          0 :         if (cache_entry_fd)
    1314                 :          0 :                 mmap_cache_free_fd(f->mmap, cache_entry_fd);
    1315                 :            : 
    1316         [ #  # ]:          0 :         if (cache_entry_array_fd)
    1317                 :          0 :                 mmap_cache_free_fd(f->mmap, cache_entry_array_fd);
    1318                 :            : 
    1319                 :          0 :         return r;
    1320                 :            : }

Generated by: LCOV version 1.14