journal-verify.c revision e8c108ca9f11a382742f212f5b42a02536b3d40f
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen/***
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen This file is part of systemd.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Copyright 2012 Lennart Poettering
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen systemd is free software; you can redistribute it and/or modify it
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen under the terms of the GNU Lesser General Public License as published by
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (at your option) any later version.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen systemd is distributed in the hope that it will be useful, but
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Lesser General Public License for more details.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen You should have received a copy of the GNU Lesser General Public License
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen***/
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <unistd.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/mman.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <fcntl.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stddef.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "macro.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "journal-def.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "journal-file.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "journal-authenticate.h"
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "journal-verify.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "lookup3.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "compress.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "fsprg.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void draw_progress(uint64_t p, usec_t *last_usec) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering unsigned n, i, j, k;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen usec_t z, x;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!on_tty())
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen z = now(CLOCK_MONOTONIC);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen x = *last_usec;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (x != 0 && x + 40 * USEC_PER_MSEC > z)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen *last_usec = z;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen n = (3 * columns()) / 4;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen j = (n * (unsigned) p) / 65535ULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen k = n - j;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < j; i++)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fputs("\xe2\x96\x88", stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fputs(ANSI_HIGHLIGHT_OFF, stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < k; i++)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fputs("\xe2\x96\x91", stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen printf(" %3"PRIu64"%%", 100U * p / 65535U);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fputs("\r\x1B[?25h", stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fflush(stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void flush_progress(void) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen unsigned n, i;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!on_tty())
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen n = (3 * columns()) / 4;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen putchar('\r');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < n + 5; i++)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen putchar(' ');
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen putchar('\r');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen fflush(stdout);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#define debug(_offset, _fmt, ...) do{ \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen flush_progress(); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen } while(0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#define warning(_offset, _fmt, ...) do{ \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen flush_progress(); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen } while(0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#define error(_offset, _fmt, ...) do{ \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen flush_progress(); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen } while(0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t i;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(f);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(o);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* This does various superficial tests about the length an
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * possible field values. It does not follow any references to
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * other objects. */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->object.type != OBJECT_DATA)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen switch (o->object.type) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_DATA: {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t h1, h2;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int compression, r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->data.entry_offset) == 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen warning(offset, "unused data (entry_offset==0)");
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset, "bad n_entries: %"PRIu64, o->data.n_entries);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset, "bad object size (<= %zu): %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen offsetof(DataObject, payload),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen h1 = le64toh(o->data.hash);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen compression = o->object.flags & OBJECT_COMPRESSION_MASK;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (compression) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen _cleanup_free_ void *b = NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t alloc = 0, b_size;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = decompress_blob(compression,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->data.payload,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size) - offsetof(Object, data.payload),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen &b, &alloc, &b_size, 0);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset, "%s decompression failed: %s",
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen object_compressed_to_string(compression), strerror(-r));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen h2 = hash64(b, b_size);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen } else
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (h1 != h2) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID64(o->data.next_hash_offset) ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(o->data.next_field_offset) ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(o->data.entry_offset) ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(o->data.entry_array_offset)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->data.next_hash_offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->data.next_field_offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->data.entry_offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->data.entry_array_offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_FIELD:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "bad field size (<= %zu): %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen offsetof(FieldObject, payload),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID64(o->field.next_hash_offset) ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(o->field.head_data_offset)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->field.next_hash_offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->field.head_data_offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_ENTRY:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "bad entry size (<= %zu): %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen offsetof(EntryObject, items),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid number items in entry: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->entry.seqnum) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid entry seqnum: %"PRIx64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->entry.seqnum));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid entry realtime timestamp: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->entry.realtime));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid entry monotonic timestamp: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->entry.monotonic));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < journal_file_entry_n_items(o); i++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (o->entry.items[i].object_offset == 0 ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(o->entry.items[i].object_offset)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i, journal_file_entry_n_items(o),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->entry.items[i].object_offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_DATA_HASH_TABLE:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_FIELD_HASH_TABLE:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid %s hash table size: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (o->hash_table.items[i].head_hash_offset != 0 &&
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i, journal_file_hash_table_n_items(o),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->hash_table.items[i].head_hash_offset));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (o->hash_table.items[i].tail_hash_offset != 0 &&
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering error(offset,
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i, journal_file_hash_table_n_items(o),
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering le64toh(o->hash_table.items[i].tail_hash_offset));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((o->hash_table.items[i].head_hash_offset != 0) !=
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering (o->hash_table.items[i].tail_hash_offset != 0)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i, journal_file_hash_table_n_items(o),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->hash_table.items[i].head_hash_offset),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->hash_table.items[i].tail_hash_offset));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_ENTRY_ARRAY:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid object entry array size: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID64(o->entry_array.next_entry_array_offset)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid object entry array next_entry_array_offset: "OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->entry_array.next_entry_array_offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < journal_file_entry_array_n_items(o); i++)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->entry_array.items[i]) != 0 &&
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen !VALID64(le64toh(o->entry_array.items[i]))) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i, journal_file_entry_array_n_items(o),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->entry_array.items[i]));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
7e518afab9fb55b8052f68888210927259275560Thomas Hindoe Paaboel Andersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen case OBJECT_TAG:
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->object.size) != sizeof(TagObject)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek "invalid object tag size: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(o->object.size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!VALID_EPOCH(o->tag.epoch)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(offset,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "invalid object tag epoch: %"PRIu64,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen o->tag.epoch);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int write_uint64(int fd, uint64_t p) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen ssize_t k;
f0c4b1c3fd827b429ba36aa45fd39e0a023cbf2cTom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen k = write(fd, &p, sizeof(p));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (k < 0)
74ca738f6a01fb5fc19c5c3899f5cb1fdc1d7f68Lennart Poettering return -errno;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (k != sizeof(p))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EIO;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t a, b;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(m);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(fd >= 0);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* Bisection ... */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen a = 0; b = n;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen while (a < b) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t c, *z;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen c = (a + b) / 2;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (*z == p)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 1;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (a + 1 >= b)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (p < *z)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen b = c;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen else
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen a = c;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int entry_points_to_data(
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen JournalFile *f,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int entry_fd,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t n_entries,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t entry_p,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t data_p) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t i, n, a;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Object *o;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen bool found = false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(f);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(entry_fd >= 0);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(data_p,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "data object references invalid entry at "OFSfmt, entry_p);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen n = journal_file_entry_n_items(o);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < n; i++)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->entry.items[i].object_offset) == data_p) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen found = true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!found) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(entry_p,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen "data object at "OFSfmt" not referenced by linked entry", data_p);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* Check if this entry is also in main entry array. Since the
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * main entry array has already been verified we can rely on
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * its consistency.*/
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen n = le64toh(f->header->n_entries);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen a = le64toh(f->header->entry_array_offset);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen while (i < n) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t m, u;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen m = journal_file_entry_array_n_items(o);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen u = MIN(n - i, m);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (entry_p <= le64toh(o->entry_array.items[u-1])) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint64_t x, y, z;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen x = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen y = u;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann while (x < y) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann z = (x + y) / 2;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(o->entry_array.items[z]) == entry_p)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (x + 1 >= y)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (entry_p < le64toh(o->entry_array.items[z]))
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann y = z;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen else
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen x = z;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen error(entry_p, "entry object doesn't exist in main entry array");
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EBADMSG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
i += u;
a = le64toh(o->entry_array.next_entry_array_offset);
}
return 0;
}
static int verify_data(
JournalFile *f,
Object *o, uint64_t p,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays) {
uint64_t i, n, a, last, q;
int r;
assert(f);
assert(o);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
n = le64toh(o->data.n_entries);
a = le64toh(o->data.entry_array_offset);
/* Entry array means at least two objects */
if (a && n < 2) {
error(p,
"entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")",
a, n);
return -EBADMSG;
}
if (n == 0)
return 0;
/* We already checked that earlier */
assert(o->data.entry_offset);
last = q = le64toh(o->data.entry_offset);
r = entry_points_to_data(f, entry_fd, n_entries, q, p);
if (r < 0)
return r;
i = 1;
while (i < n) {
uint64_t next, m, j;
if (a == 0) {
error(p, "array chain too short");
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
error(p, "invalid array offset "OFSfmt, a);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")",
a, next);
return -EBADMSG;
}
m = journal_file_entry_array_n_items(o);
for (j = 0; i < n && j < m; i++, j++) {
q = le64toh(o->entry_array.items[j]);
if (q <= last) {
error(p, "data object's entry array not sorted");
return -EBADMSG;
}
last = q;
r = entry_points_to_data(f, entry_fd, n_entries, q, p);
if (r < 0)
return r;
/* Pointer might have moved, reposition */
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
}
a = next;
}
return 0;
}
static int verify_hash_table(
JournalFile *f,
int data_fd, uint64_t n_data,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays,
usec_t *last_usec,
bool show_progress) {
uint64_t i, n;
int r;
assert(f);
assert(data_fd >= 0);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
assert(last_usec);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
for (i = 0; i < n; i++) {
uint64_t last = 0, p;
if (show_progress)
draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
p = le64toh(f->data_hash_table[i].head_hash_offset);
while (p != 0) {
Object *o;
uint64_t next;
if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64,
i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
next = le64toh(o->data.next_hash_offset);
if (next != 0 && next <= p) {
error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
i, n);
return -EBADMSG;
}
if (le64toh(o->data.hash) % n != i) {
error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
i, n);
return -EBADMSG;
}
r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
if (r < 0)
return r;
last = p;
p = next;
}
if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
error(p, "tail hash pointer mismatch in hash table");
return -EBADMSG;
}
}
return 0;
}
static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
uint64_t n, h, q;
int r;
assert(f);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
h = hash % n;
q = le64toh(f->data_hash_table[h].head_hash_offset);
while (q != 0) {
Object *o;
if (p == q)
return 1;
r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
if (r < 0)
return r;
q = le64toh(o->data.next_hash_offset);
}
return 0;
}
static int verify_entry(
JournalFile *f,
Object *o, uint64_t p,
int data_fd, uint64_t n_data) {
uint64_t i, n;
int r;
assert(f);
assert(o);
assert(data_fd >= 0);
n = journal_file_entry_n_items(o);
for (i = 0; i < n; i++) {
uint64_t q, h;
Object *u;
q = le64toh(o->entry.items[i].object_offset);
h = le64toh(o->entry.items[i].hash);
if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
error(p, "invalid data object of entry");
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
if (r < 0)
return r;
if (le64toh(u->data.hash) != h) {
error(p, "hash mismatch for data object of entry");
return -EBADMSG;
}
r = data_object_in_hash_table(f, h, q);
if (r < 0)
return r;
if (r == 0) {
error(p, "data object missing from hash table");
return -EBADMSG;
}
}
return 0;
}
static int verify_entry_array(
JournalFile *f,
int data_fd, uint64_t n_data,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays,
usec_t *last_usec,
bool show_progress) {
uint64_t i = 0, a, n, last = 0;
int r;
assert(f);
assert(data_fd >= 0);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
assert(last_usec);
n = le64toh(f->header->n_entries);
a = le64toh(f->header->entry_array_offset);
while (i < n) {
uint64_t next, m, j;
Object *o;
if (show_progress)
draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
if (a == 0) {
error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
error(a, "invalid array %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
error(a,
"array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")",
i, n, next);
return -EBADMSG;
}
m = journal_file_entry_array_n_items(o);
for (j = 0; i < n && j < m; i++, j++) {
uint64_t p;
p = le64toh(o->entry_array.items[j]);
if (p <= last) {
error(a, "entry array not sorted at %"PRIu64" of %"PRIu64,
i, n);
return -EBADMSG;
}
last = p;
if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
error(a, "invalid array entry at %"PRIu64" of %"PRIu64,
i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
r = verify_entry(f, o, p, data_fd, n_data);
if (r < 0)
return r;
/* Pointer might have moved, reposition */
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
}
a = next;
}
return 0;
}
int journal_file_verify(
JournalFile *f,
const char *key,
usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
bool show_progress) {
int r;
Object *o;
uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
sd_id128_t entry_boot_id;
bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
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;
usec_t last_usec = 0;
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
unsigned i;
bool found_last = false;
#ifdef HAVE_GCRYPT
uint64_t last_tag = 0;
#endif
assert(f);
if (key) {
#ifdef HAVE_GCRYPT
r = journal_file_parse_verification_key(f, key);
if (r < 0) {
log_error("Failed to parse seed.");
return r;
}
#else
return -ENOTSUP;
#endif
} else if (f->seal)
return -ENOKEY;
data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
log_error("Failed to create data file: %m");
r = -errno;
goto fail;
}
entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
log_error("Failed to create entry file: %m");
r = -errno;
goto fail;
}
entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
log_error("Failed to create entry array file: %m");
r = -errno;
goto fail;
}
if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
log_error("Cannot verify file with unknown extensions.");
r = -ENOTSUP;
goto fail;
}
for (i = 0; i < sizeof(f->header->reserved); i++)
if (f->header->reserved[i] != 0) {
error(offsetof(Header, reserved[i]), "reserved field is non-zero");
r = -EBADMSG;
goto fail;
}
/* First iteration: we go through all objects, verify the
* superficial structure, headers, hashes. */
p = le64toh(f->header->header_size);
while (p != 0) {
if (show_progress)
draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0) {
error(p, "invalid object");
goto fail;
}
if (p > le64toh(f->header->tail_object_offset)) {
error(offsetof(Header, tail_object_offset), "invalid tail object pointer");
r = -EBADMSG;
goto fail;
}
if (p == le64toh(f->header->tail_object_offset))
found_last = true;
n_objects ++;
r = journal_file_object_verify(f, p, o);
if (r < 0) {
error(p, "invalid object contents: %s", strerror(-r));
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
(o->object.flags & OBJECT_COMPRESSED_LZ4)) {
error(p, "objected with double compression");
r = -EINVAL;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
error(p, "XZ compressed object in file without XZ compression");
r = -EBADMSG;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
error(p, "LZ4 compressed object in file without LZ4 compression");
r = -EBADMSG;
goto fail;
}
switch (o->object.type) {
case OBJECT_DATA:
r = write_uint64(data_fd, p);
if (r < 0)
goto fail;
n_data++;
break;
case OBJECT_FIELD:
n_fields++;
break;
case OBJECT_ENTRY:
if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
error(p, "first entry before first tag");
r = -EBADMSG;
goto fail;
}
r = write_uint64(entry_fd, p);
if (r < 0)
goto fail;
if (le64toh(o->entry.realtime) < last_tag_realtime) {
error(p, "older entry after newer tag");
r = -EBADMSG;
goto fail;
}
if (!entry_seqnum_set &&
le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
error(p, "head entry sequence number incorrect");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum >= le64toh(o->entry.seqnum)) {
error(p, "entry sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
entry_seqnum = le64toh(o->entry.seqnum);
entry_seqnum_set = true;
if (entry_monotonic_set &&
sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
entry_monotonic > le64toh(o->entry.monotonic)) {
error(p, "entry timestamp out of synchronization");
r = -EBADMSG;
goto fail;
}
entry_monotonic = le64toh(o->entry.monotonic);
entry_boot_id = o->entry.boot_id;
entry_monotonic_set = true;
if (!entry_realtime_set &&
le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
error(p, "head entry realtime timestamp incorrect");
r = -EBADMSG;
goto fail;
}
entry_realtime = le64toh(o->entry.realtime);
entry_realtime_set = true;
n_entries ++;
break;
case OBJECT_DATA_HASH_TABLE:
if (n_data_hash_tables > 1) {
error(p, "more than one data hash table");
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
error(p, "header fields for data hash table invalid");
r = -EBADMSG;
goto fail;
}
n_data_hash_tables++;
break;
case OBJECT_FIELD_HASH_TABLE:
if (n_field_hash_tables > 1) {
error(p, "more than one field hash table");
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
error(p, "header fields for field hash table invalid");
r = -EBADMSG;
goto fail;
}
n_field_hash_tables++;
break;
case OBJECT_ENTRY_ARRAY:
r = write_uint64(entry_array_fd, p);
if (r < 0)
goto fail;
if (p == le64toh(f->header->entry_array_offset)) {
if (found_main_entry_array) {
error(p, "more than one main entry array");
r = -EBADMSG;
goto fail;
}
found_main_entry_array = true;
}
n_entry_arrays++;
break;
case OBJECT_TAG:
if (!JOURNAL_HEADER_SEALED(f->header)) {
error(p, "tag object in file without sealing");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.seqnum) != n_tags + 1) {
error(p, "tag sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.epoch) < last_epoch) {
error(p, "epoch sequence out of synchronization");
r = -EBADMSG;
goto fail;
}
#ifdef HAVE_GCRYPT
if (f->seal) {
uint64_t q, rt;
debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
error(p, "tag/entry realtime timestamp out of synchronization");
r = -EBADMSG;
goto fail;
}
/* OK, now we know the epoch. So let's now set
* it, and calculate the HMAC for everything
* since the last tag. */
r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
if (r < 0)
goto fail;
r = journal_file_hmac_start(f);
if (r < 0)
goto fail;
if (last_tag == 0) {
r = journal_file_hmac_put_header(f);
if (r < 0)
goto fail;
q = le64toh(f->header->header_size);
} else
q = last_tag;
while (q <= p) {
r = journal_file_move_to_object(f, -1, q, &o);
if (r < 0)
goto fail;
r = journal_file_hmac_put_object(f, -1, o, q);
if (r < 0)
goto fail;
q = q + ALIGN64(le64toh(o->object.size));
}
/* Position might have changed, let's reposition things */
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0)
goto fail;
if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
error(p, "tag failed verification");
r = -EBADMSG;
goto fail;
}
f->hmac_running = false;
last_tag_realtime = rt;
last_sealed_realtime = entry_realtime;
}
last_tag = p + ALIGN64(le64toh(o->object.size));
#endif
last_epoch = le64toh(o->tag.epoch);
n_tags ++;
break;
default:
n_weird ++;
}
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
p = p + ALIGN64(le64toh(o->object.size));
}
if (!found_last) {
error(le64toh(f->header->tail_object_offset), "tail object pointer dead");
r = -EBADMSG;
goto fail;
}
if (n_objects != le64toh(f->header->n_objects)) {
error(offsetof(Header, n_objects), "object number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_entries != le64toh(f->header->n_entries)) {
error(offsetof(Header, n_entries), "entry number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
n_data != le64toh(f->header->n_data)) {
error(offsetof(Header, n_data), "data number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
n_fields != le64toh(f->header->n_fields)) {
error(offsetof(Header, n_fields), "field number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
n_tags != le64toh(f->header->n_tags)) {
error(offsetof(Header, n_tags), "tag number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
error(offsetof(Header, n_entry_arrays), "entry array number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_data_hash_tables != 1) {
error(0, "missing data hash table");
r = -EBADMSG;
goto fail;
}
if (n_field_hash_tables != 1) {
error(0, "missing field hash table");
r = -EBADMSG;
goto fail;
}
if (!found_main_entry_array) {
error(0, "missing entry array");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum");
r = -EBADMSG;
goto fail;
}
if (entry_monotonic_set &&
(!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
error(0, "invalid tail monotonic timestamp");
r = -EBADMSG;
goto fail;
}
if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
error(0, "invalid tail realtime timestamp");
r = -EBADMSG;
goto fail;
}
/* Second iteration: we follow all objects referenced from the
* two entry points: the object hash table and the entry
* array. We also check that everything referenced (directly
* or indirectly) in the data hash table also exists in the
* entry array, and vice versa. Note that we do not care for
* unreferenced objects. We only care that everything that is
* referenced is consistent. */
r = verify_entry_array(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
r = verify_hash_table(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
if (show_progress)
flush_progress();
mmap_cache_close_fd(f->mmap, data_fd);
mmap_cache_close_fd(f->mmap, entry_fd);
mmap_cache_close_fd(f->mmap, entry_array_fd);
safe_close(data_fd);
safe_close(entry_fd);
safe_close(entry_array_fd);
if (first_contained)
*first_contained = le64toh(f->header->head_entry_realtime);
if (last_validated)
*last_validated = last_sealed_realtime;
if (last_contained)
*last_contained = le64toh(f->header->tail_entry_realtime);
return 0;
fail:
if (show_progress)
flush_progress();
log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
f->path,
p,
(unsigned long long) f->last_stat.st_size,
100 * p / f->last_stat.st_size);
if (data_fd >= 0) {
mmap_cache_close_fd(f->mmap, data_fd);
safe_close(data_fd);
}
if (entry_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_fd);
safe_close(entry_fd);
}
if (entry_array_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_array_fd);
safe_close(entry_array_fd);
}
return r;
}