journal-verify.c revision 1ec7120e50bc084342f8c44aea771c79aaeb774d
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <unistd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/mman.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fcntl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stddef.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "macro.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "journal-def.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "journal-file.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "journal-authenticate.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "journal-verify.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "lookup3.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "compress.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "fsprg.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(offset);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering assert(o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* This does various superficial tests about the length an
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * possible field values. It does not follow any references to
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * other objects. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->object.type != OBJECT_DATA)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering switch (o->object.type) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case OBJECT_DATA: {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t h1, h2;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int compression, r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (le64toh(o->data.entry_offset) == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_warning(OFSfmt": unused data (entry_offset==0)", offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": bad n_entries: %"PRIu64, offset, o->data.n_entries);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error(OFSfmt": bad object size (<= %zu): %"PRIu64,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offsetof(DataObject, payload),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->object.size));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen h1 = le64toh(o->data.hash);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen compression = o->object.flags & OBJECT_COMPRESSION_MASK;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (compression) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_free_ void *b = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen uint64_t alloc = 0, b_size;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = decompress_blob(compression,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen o->data.payload,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen le64toh(o->object.size) - offsetof(Object, data.payload),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering &b, &alloc, &b_size, 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": %s decompression failed: %s", offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering object_compressed_to_string(compression), strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen h2 = hash64(b, b_size);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen } else
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (h1 != h2) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!VALID64(o->data.next_hash_offset) ||
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen !VALID64(o->data.next_field_offset) ||
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen !VALID64(o->data.entry_offset) ||
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen !VALID64(o->data.entry_array_offset)) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->data.next_hash_offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->data.next_field_offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->data.entry_offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->data.entry_array_offset);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EBADMSG;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen case OBJECT_FIELD:
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error(OFSfmt": bad field size (<= %zu): %"PRIu64,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offsetof(FieldObject, payload),
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering le64toh(o->object.size));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -EBADMSG;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!VALID64(o->field.next_hash_offset) ||
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering !VALID64(o->field.head_data_offset)) {
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering o->field.next_hash_offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering o->field.head_data_offset);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -EBADMSG;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case OBJECT_ENTRY:
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64,
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering offset,
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering offsetof(EntryObject, items),
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering le64toh(o->object.size));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EBADMSG;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error(OFSfmt": invalid number items in entry: %"PRIu64,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return -EBADMSG;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (le64toh(o->entry.seqnum) <= 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error(OFSfmt": invalid entry seqnum: %"PRIx64,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering le64toh(o->entry.seqnum));
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering return -EBADMSG;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering }
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering le64toh(o->entry.realtime));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -EBADMSG;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering offset,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering le64toh(o->entry.monotonic));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -EBADMSG;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering for (i = 0; i < journal_file_entry_n_items(o); i++) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (o->entry.items[i].object_offset == 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !VALID64(o->entry.items[i].object_offset)) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers i, journal_file_entry_n_items(o),
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers o->entry.items[i].object_offset);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen case OBJECT_DATA_HASH_TABLE:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case OBJECT_FIELD_HASH_TABLE:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid %s hash table size: %"PRIu64,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->object.size));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (o->hash_table.items[i].head_hash_offset != 0 &&
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, journal_file_hash_table_n_items(o),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->hash_table.items[i].head_hash_offset));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (o->hash_table.items[i].tail_hash_offset != 0 &&
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, journal_file_hash_table_n_items(o),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->hash_table.items[i].tail_hash_offset));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((o->hash_table.items[i].head_hash_offset != 0) !=
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (o->hash_table.items[i].tail_hash_offset != 0)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, journal_file_hash_table_n_items(o),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->hash_table.items[i].head_hash_offset),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->hash_table.items[i].tail_hash_offset));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case OBJECT_ENTRY_ARRAY:
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid object entry array size: %"PRIu64,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->object.size));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (!VALID64(o->entry_array.next_entry_array_offset)) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers offset,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers o->entry_array.next_entry_array_offset);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers for (i = 0; i < journal_file_entry_array_n_items(o); i++)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (le64toh(o->entry_array.items[i]) != 0 &&
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers !VALID64(le64toh(o->entry_array.items[i]))) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, journal_file_entry_array_n_items(o),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->entry_array.items[i]));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers break;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers case OBJECT_TAG:
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (le64toh(o->object.size) != sizeof(TagObject)) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers log_error(OFSfmt": invalid object tag size: %"PRIu64,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(o->object.size));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!VALID_EPOCH(o->tag.epoch)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error(OFSfmt": invalid object tag epoch: %"PRIu64,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering o->tag.epoch);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers break;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic void draw_progress(uint64_t p, usec_t *last_usec) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers unsigned n, i, j, k;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering usec_t z, x;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (!on_tty())
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen z = now(CLOCK_MONOTONIC);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers x = *last_usec;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (x != 0 && x + 40 * USEC_PER_MSEC > z)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *last_usec = z;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen n = (3 * columns()) / 4;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen j = (n * (unsigned) p) / 65535ULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen k = n - j;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < j; i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fputs("\xe2\x96\x88", stdout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fputs(ANSI_HIGHLIGHT_OFF, stdout);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < k; i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fputs("\xe2\x96\x91", stdout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers printf(" %3"PRIu64"%%", 100U * p / 65535U);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers fputs("\r\x1B[?25h", stdout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fflush(stdout);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic void flush_progress(void) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers unsigned n, i;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!on_tty())
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n = (3 * columns()) / 4;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen putchar('\r');
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (i = 0; i < n + 5; i++)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen putchar(' ');
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen putchar('\r');
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen fflush(stdout);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int write_uint64(int fd, uint64_t p) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen ssize_t k;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen k = write(fd, &p, sizeof(p));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (k < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -errno;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (k != sizeof(p))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EIO;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers uint64_t a, b;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(m);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert(fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Bisection ... */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen a = 0; b = n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (a < b) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t c, *z;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering c = (a + b) / 2;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (*z == p)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 1;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (a + 1 >= b)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (p < *z)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen b = c;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen else
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen a = c;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int entry_points_to_data(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering JournalFile *f,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int entry_fd,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t n_entries,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen uint64_t entry_p,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen uint64_t data_p) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t i, n, a;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Object *o;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool found = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(f);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(entry_fd >= 0);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Data object references invalid entry at %"PRIu64, data_p);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EBADMSG;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n = journal_file_entry_n_items(o);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (i = 0; i < n; i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (le64toh(o->entry.items[i].object_offset) == data_p) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering found = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!found) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* Check if this entry is also in main entry array. Since the
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * main entry array has already been verified we can rely on
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * its consistency.*/
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i = 0;
f69157a66ffe413b4cf8bd79057487fc8921e78bThomas Hindoe Paaboel Andersen n = le64toh(f->header->n_entries);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a = le64toh(f->header->entry_array_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering while (i < n) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t m, u;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m = journal_file_entry_array_n_items(o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering u = MIN(n - i, m);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (entry_p <= le64toh(o->entry_array.items[u-1])) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t x, y, z;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering x = 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering y = u;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering while (x < y) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering z = (x + y) / 2;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (le64toh(o->entry_array.items[z]) == entry_p)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (x + 1 >= y)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (entry_p < le64toh(o->entry_array.items[z]))
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering y = z;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering else
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering x = z;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i += u;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a = le64toh(o->entry_array.next_entry_array_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int verify_data(
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering JournalFile *f,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering Object *o, uint64_t p,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int entry_fd, uint64_t n_entries,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t i, n, a, last, q;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(f);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(entry_fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(entry_array_fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering n = le64toh(o->data.n_entries);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a = le64toh(o->data.entry_array_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* Entry array means at least two objects */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (a && n < 2) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a, n);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (n == 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* We already checked that earlier */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(o->data.entry_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering last = q = le64toh(o->data.entry_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i = 1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering while (i < n) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t next, m, j;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (a == 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Array chain too short at %"PRIu64, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Invalid array at %"PRIu64, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (next != 0 && next <= a) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Array chain has cycle at %"PRIu64, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m = journal_file_entry_array_n_items(o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering for (j = 0; i < n && j < m; i++, j++) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering q = le64toh(o->entry_array.items[j]);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (q <= last) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Data object's entry array not sorted at %"PRIu64, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering last = q;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* Pointer might have moved, reposition */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering a = next;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int verify_hash_table(
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering JournalFile *f,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int data_fd, uint64_t n_data,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int entry_fd, uint64_t n_entries,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering usec_t *last_usec,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering bool show_progress) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t i, n;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(f);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(data_fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(entry_fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(entry_array_fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(last_usec);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering for (i = 0; i < n; i++) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t last = 0, p;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (show_progress)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering p = le64toh(f->data_hash_table[i].head_hash_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering while (p != 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering Object *o;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t next;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i, n);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering next = le64toh(o->data.next_hash_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (next != 0 && next <= p) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i, n);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (le64toh(o->data.hash) % n != i) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering i, n);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering last = p;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering p = next;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Tail hash pointer mismatch in hash table");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -EBADMSG;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint64_t n, h, q;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(f);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering h = hash % n;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering q = le64toh(f->data_hash_table[h].head_hash_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering while (q != 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering Object *o;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (p == q)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering q = le64toh(o->data.next_hash_offset);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int verify_entry(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering JournalFile *f,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Object *o, uint64_t p,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int data_fd, uint64_t n_data) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering uint64_t i, n;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering int r;
53755121e1c8ebd3db0330bc82965ecf9a986449Lennart Poettering
53755121e1c8ebd3db0330bc82965ecf9a986449Lennart Poettering assert(f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(data_fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering n = journal_file_entry_n_items(o);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering for (i = 0; i < n; i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t q, h;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Object *u;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek q = le64toh(o->entry.items[i].object_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering h = le64toh(o->entry.items[i].hash);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid data object at entry %"PRIu64, p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (le64toh(u->data.hash) != h) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Hash mismatch for data object at entry %"PRIu64, p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = data_object_in_hash_table(f, h, q);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r == 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Data object missing from hash at entry %"PRIu64, p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int verify_entry_array(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering JournalFile *f,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int data_fd, uint64_t n_data,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int entry_fd, uint64_t n_entries,
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering usec_t *last_usec,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool show_progress) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t i = 0, a, n, last = 0;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(data_fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(entry_fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(entry_array_fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(last_usec);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n = le64toh(f->header->n_entries);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = le64toh(f->header->entry_array_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (i < n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t next, m, j;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Object *o;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (show_progress)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (a == 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (next != 0 && next <= a) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m = journal_file_entry_array_n_items(o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (j = 0; i < n && j < m; i++, j++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = le64toh(o->entry_array.items[j]);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (p <= last) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering last = p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering }
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (r < 0)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return r;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering r = verify_entry(f, o, p, data_fd, n_data);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Pointer might have moved, reposition */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint journal_file_verify(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering JournalFile *f,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *key,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool show_progress) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Object *o;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_id128_t entry_boot_id;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 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;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering usec_t last_usec = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned i;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering bool found_last;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#ifdef HAVE_GCRYPT
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t last_tag = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#endif
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (key) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#ifdef HAVE_GCRYPT
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_parse_verification_key(f, key);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to parse seed.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#else
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOTSUP;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#endif
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else if (f->seal)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOKEY;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (data_fd < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create data file: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (entry_fd < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create entry file: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (entry_array_fd < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create entry array file: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#ifdef HAVE_GCRYPT
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#else
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (f->header->compatible_flags != 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#endif
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Cannot verify file with unknown extensions.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -ENOTSUP;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < sizeof(f->header->reserved); i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (f->header->reserved[i] != 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Reserved field in non-zero.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -EBADMSG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* First iteration: we go through all objects, verify the
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * superficial structure, headers, hashes. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = le64toh(f->header->header_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (p != 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (show_progress)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, -1, p, &o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid object at "OFSfmt, p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto fail;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (p > le64toh(f->header->tail_object_offset)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid tail object pointer");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -EBADMSG;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering goto fail;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen }
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (p == le64toh(f->header->tail_object_offset))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen found_last = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering n_objects ++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_object_verify(f, p, o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r));
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering goto fail;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering }
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
(o->object.flags & OBJECT_COMPRESSED_LZ4)) {
log_error("Objected with double compression at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
log_error("XZ compressed object in file without XZ compression at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
log_error("LZ4 compressed object in file without LZ4 compression at "OFSfmt, p);
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) {
log_error("First entry before first tag at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
r = write_uint64(entry_fd, p);
if (r < 0)
goto fail;
if (le64toh(o->entry.realtime) < last_tag_realtime) {
log_error("Older entry after newer tag at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if (!entry_seqnum_set &&
le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
log_error("Head entry sequence number incorrect at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum >= le64toh(o->entry.seqnum)) {
log_error("Entry sequence number out of synchronization at "OFSfmt, p);
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)) {
log_error("Entry timestamp out of synchronization at "OFSfmt, p);
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)) {
log_error("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) {
log_error("More than one data hash table at "OFSfmt, p);
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)) {
log_error("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) {
log_error("More than one field hash table at "OFSfmt, p);
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)) {
log_error("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) {
log_error("More than one main entry array at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
found_main_entry_array = true;
}
n_entry_arrays++;
break;
case OBJECT_TAG:
if (!JOURNAL_HEADER_SEALED(f->header)) {
log_error("Tag object in file without sealing at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.seqnum) != n_tags + 1) {
log_error("Tag sequence number out of synchronization at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.epoch) < last_epoch) {
log_error("Epoch sequence out of synchronization at "OFSfmt, p);
r = -EBADMSG;
goto fail;
}
#ifdef HAVE_GCRYPT
if (f->seal) {
uint64_t q, rt;
log_debug("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) {
log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p);
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) {
log_error("Tag failed verification at "OFSfmt, p);
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) {
log_error("Tail object pointer dead");
r = -EBADMSG;
goto fail;
}
if (n_objects != le64toh(f->header->n_objects)) {
log_error("Object number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_entries != le64toh(f->header->n_entries)) {
log_error("Entry number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
n_data != le64toh(f->header->n_data)) {
log_error("Data number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
n_fields != le64toh(f->header->n_fields)) {
log_error("Field number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
n_tags != le64toh(f->header->n_tags)) {
log_error("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)) {
log_error("Entry array number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_data_hash_tables != 1) {
log_error("Missing data hash table");
r = -EBADMSG;
goto fail;
}
if (n_field_hash_tables != 1) {
log_error("Missing field hash table");
r = -EBADMSG;
goto fail;
}
if (!found_main_entry_array) {
log_error("Missing entry array");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
log_error("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))) {
log_error("Invalid tail monotonic timestamp");
r = -EBADMSG;
goto fail;
}
if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
log_error("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;
}