journal-file.c revision d98cc1f29fbf31ccc500d6e20c29b636b9af7e0f
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/***
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2011 Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering***/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering#include <sys/mman.h>
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering#include <errno.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include <sys/uio.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include <unistd.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include <sys/statvfs.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include <fcntl.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include <stddef.h>
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include "journal-def.h"
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering#include "journal-file.h"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include "lookup3.h"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include "compress.h"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#include "fsprg.h"
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define DEFAULT_WINDOW_SIZE (8ULL*1024ULL*1024ULL)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define COMPRESSION_SIZE_THRESHOLD (512ULL)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/* This is the minimum journal file size */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define JOURNAL_FILE_SIZE_MIN (64ULL*1024ULL) /* 64 KiB */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/* These are the lower and upper bounds if we deduce the max_use value
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * from the file system size */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/* This is the upper bound if we deduce max_size from max_use */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering/* This is the upper bound if we deduce the keep_free value from the
4f10118016f9b2fd7e1d26c9ef7d91eb33fba694Lennart Poettering * file system size */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define DEFAULT_KEEP_FREE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering/* This is the keep_free value when we can't determine the system
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * size */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering/* n_data was the first entry we added after the initial file format design */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define ALIGN64(x) (((x) + 7ULL) & ~7ULL)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define JOURNAL_HEADER_CONTAINS(h, field) \
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering (le64toh((h)->header_size) >= offsetof(Header, field) + sizeof((h)->field))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid journal_file_close(JournalFile *f) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int t;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Write the final tag */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->authenticate)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering journal_file_append_tag(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Sync everything to disk, before we mark the file offline */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering for (t = 0; t < _WINDOW_MAX; t++)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->windows[t].ptr)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering munmap(f->windows[t].ptr, f->windows[t].size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->writable && f->fd >= 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fdatasync(f->fd);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->header) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Mark the file offline. Don't override the archived state if it already is set */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->writable && f->header->state == STATE_ONLINE)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f->header->state = STATE_OFFLINE;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering munmap(f->header, PAGE_ALIGN(sizeof(Header)));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->fd >= 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering close_nointr_nofail(f->fd);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering free(f->path);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#ifdef HAVE_XZ
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering free(f->compress_buffer);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#endif
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#ifdef HAVE_GCRYPT
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->fsprg_header)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering munmap(f->fsprg_header, PAGE_ALIGN(f->fsprg_size));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->hmac)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering gcry_md_close(f->hmac);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#endif
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering free(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_init_header(JournalFile *f, JournalFile *template) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Header h;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering ssize_t k;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering zero(h);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering memcpy(h.signature, HEADER_SIGNATURE, 8);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering h.header_size = htole64(ALIGN64(sizeof(h)));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering h.incompatible_flags =
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering htole32(f->compress ? HEADER_INCOMPATIBLE_COMPRESSED : 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h.compatible_flags =
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering htole32(f->authenticate ? HEADER_COMPATIBLE_AUTHENTICATED : 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = sd_id128_randomize(&h.file_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (template) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h.seqnum_id = template->header->seqnum_id;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h.tail_seqnum = template->header->tail_seqnum;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h.seqnum_id = h.file_id;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering k = pwrite(f->fd, &h, sizeof(h), 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (k < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -errno;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (k != sizeof(h))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EIO;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_refresh_header(JournalFile *f) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering sd_id128_t boot_id;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = sd_id128_get_machine(&f->header->machine_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = sd_id128_get_boot(&boot_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack if (sd_id128_equal(boot_id, f->header->boot_id))
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack f->tail_entry_monotonic_valid = true;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->boot_id = boot_id;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack f->header->state = STATE_ONLINE;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack /* Sync the online state to disk */
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack msync(f->header, PAGE_ALIGN(sizeof(Header)), MS_SYNC);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack fdatasync(f->fd);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_verify_header(JournalFile *f) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (memcmp(f->header->signature, HEADER_SIGNATURE, 8))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBADMSG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* In both read and write mode we refuse to open files with
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * incompatible flags we don't know */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#ifdef HAVE_XZ
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) != 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EPROTONOSUPPORT;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#else
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->header->incompatible_flags != 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EPROTONOSUPPORT;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#endif
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* When open for writing we refuse to open files with
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * compatible flags, too */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->writable) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#ifdef HAVE_GCRYPT
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_AUTHENTICATED) != 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EPROTONOSUPPORT;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#else
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->header->compatible_flags != 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EPROTONOSUPPORT;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#endif
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* The first addition was n_data, so check that we are at least this large */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (le64toh(f->header->header_size) < HEADER_SIZE_MIN)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBADMSG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((uint64_t) f->last_stat.st_size < (le64toh(f->header->header_size) + le64toh(f->header->arena_size)))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -ENODATA;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->writable) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint8_t state;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering sd_id128_t machine_id;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = sd_id128_get_machine(&machine_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!sd_id128_equal(machine_id, f->header->machine_id))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EHOSTDOWN;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering state = f->header->state;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (state == STATE_ONLINE) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Journal file %s is already online. Assuming unclean closing.", f->path);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBUSY;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else if (state == STATE_ARCHIVED)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -ESHUTDOWN;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering else if (state != STATE_OFFLINE) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Journal file %s has unknown state %u.", f->path, state);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBUSY;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->compress = !!(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->authenticate = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering return 0;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack}
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t old_size, new_size;
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering int r;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* We assume that this file is not sparse, and we know that
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * for sure, since we always call posix_fallocate()
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * ourselves */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering old_size =
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64toh(f->header->header_size) +
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64toh(f->header->arena_size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering new_size = PAGE_ALIGN(offset + size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (new_size < le64toh(f->header->header_size))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering new_size = le64toh(f->header->header_size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (new_size <= old_size)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->metrics.max_size > 0 &&
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering new_size > f->metrics.max_size)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -E2BIG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (new_size > f->metrics.min_size &&
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->metrics.keep_free > 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering struct statvfs svfs;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (fstatvfs(f->fd, &svfs) >= 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t available;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering available = svfs.f_bfree * svfs.f_bsize;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (available >= f->metrics.keep_free)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering available -= f->metrics.keep_free;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering else
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering available = 0;
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (new_size - old_size > available)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -E2BIG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Note that the glibc fallocate() fallback is very
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering inefficient, hence we try to minimize the allocation area
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering as we can. */
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek r = posix_fallocate(f->fd, old_size, new_size - old_size);
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek if (r != 0)
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek return -r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (fstat(f->fd, &f->last_stat) < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -errno;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek return 0;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt}
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_map(
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering JournalFile *f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t offset,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t size,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering void **_window,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t *_woffset,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t *_wsize,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering void **ret) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t woffset, wsize;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering void *window;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(size > 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(ret);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering woffset = offset & ~((uint64_t) page_size() - 1ULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering wsize = size + (offset - woffset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering wsize = PAGE_ALIGN(wsize);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Avoid SIGBUS on invalid accesses */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (woffset + wsize > (uint64_t) PAGE_ALIGN(f->last_stat.st_size))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EADDRNOTAVAIL;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering window = mmap(NULL, wsize, f->prot, MAP_SHARED, f->fd, woffset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (window == MAP_FAILED)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -errno;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_window)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *_window = window;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_woffset)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *_woffset = woffset;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_wsize)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *_wsize = wsize;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *ret = (uint8_t*) window + (offset - woffset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_move_to(JournalFile *f, int wt, uint64_t offset, uint64_t size, void **ret) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering void *p = NULL;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t delta;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Window *w;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(ret);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(wt >= 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(wt < _WINDOW_MAX);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (offset + size > (uint64_t) f->last_stat.st_size) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Hmm, out of range? Let's refresh the fstat() data
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * first, before we trust that check. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (fstat(f->fd, &f->last_stat) < 0 ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering offset + size > (uint64_t) f->last_stat.st_size)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EADDRNOTAVAIL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering w = f->windows + wt;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (_likely_(w->ptr &&
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering w->offset <= offset &&
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering w->offset + w->size >= offset + size)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *ret = (uint8_t*) w->ptr + (offset - w->offset);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (w->ptr) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (munmap(w->ptr, w->size) < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return -errno;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering w->ptr = NULL;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering w->size = w->offset = 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (size < DEFAULT_WINDOW_SIZE) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* If the default window size is larger then what was
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * asked for extend the mapping a bit in the hope to
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * minimize needed remappings later on. We add half
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * the window space before and half behind the
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * requested mapping */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering delta = (DEFAULT_WINDOW_SIZE - size) / 2;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (delta > offset)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering delta = offset;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering offset -= delta;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering size = DEFAULT_WINDOW_SIZE;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering } else
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering delta = 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (offset + size > (uint64_t) f->last_stat.st_size)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering size = (uint64_t) f->last_stat.st_size - offset;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (size <= 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return -EADDRNOTAVAIL;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_map(f,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering offset, size,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering &w->ptr, &w->offset, &w->size,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering &p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *ret = (uint8_t*) p + delta;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic bool verify_hash(Object *o) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t h1, h2;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (o->object.type == OBJECT_DATA && !(o->object.flags & OBJECT_COMPRESSED)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h1 = le64toh(o->data.hash);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else if (o->object.type == OBJECT_FIELD) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h1 = le64toh(o->field.hash);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h2 = hash64(o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return true;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return h1 == h2;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering void *t;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Object *o;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t s;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(ret);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(type < _OBJECT_TYPE_MAX);
db2cb23b5b179707000d28a11efb3d888d06ee80Umut Tezduyar Lindskog
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to(f, type >= 0 ? type : WINDOW_UNKNOWN, offset, sizeof(ObjectHeader), &t);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt o = (Object*) t;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s = le64toh(o->object.size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (s < sizeof(ObjectHeader))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return -EBADMSG;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (type >= 0 && o->object.type != type)
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt return -EBADMSG;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (s > sizeof(ObjectHeader)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to(f, o->object.type, offset, s, &t);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering o = (Object*) t;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (!verify_hash(o))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return -EBADMSG;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *ret = o;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack r = le64toh(f->header->tail_seqnum) + 1;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt if (seqnum) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack /* If an external seqnum counter was passed, we update
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack * both the local and the external one, and set it to
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack * the maximum of both */
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack if (*seqnum + 1 > r)
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack r = *seqnum + 1;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *seqnum = r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f->header->tail_seqnum = htole64(r);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->header->head_seqnum == 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f->header->head_seqnum = htole64(r);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t p;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Object *tail, *o;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering void *t;
8d0e0ddda6501479eb69164687c83c1a7667b33aJan Engelhardt
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(size >= sizeof(ObjectHeader));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(offset);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(ret);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering p = le64toh(f->header->tail_object_offset);
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt if (p == 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering p = le64toh(f->header->header_size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering else {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to_object(f, -1, p, &tail);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
8d0e0ddda6501479eb69164687c83c1a7667b33aJan Engelhardt
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering p += ALIGN64(le64toh(tail->object.size));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_allocate(f, p, size);
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to(f, type, p, size, &t);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering o = (Object*) t;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering zero(o->object);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->object.type = type;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->object.size = htole64(size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->tail_object_offset = htole64(p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->n_objects = htole64(le64toh(f->header->n_objects) + 1);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *ret = o;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *offset = p;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mackstatic int journal_file_setup_data_hash_table(JournalFile *f) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack uint64_t s, p;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack Object *o;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering /* We estimate that we need 1 hash table entry per 768 of
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering journal file and we want to make sure we never get beyond
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering 75% fill level. Calculate the hash table size for the
ff975efb2e88dcd5221a2f0d76c4c87e85b821a8Lennart Poettering maximum file size based on these metrics. */
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s = DEFAULT_DATA_HASH_TABLE_SIZE;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_info("Reserving %llu entries in hash table.", (unsigned long long) (s / sizeof(HashItem)));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_append_object(f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering OBJECT_DATA_HASH_TABLE,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering offsetof(Object, hash_table.items) + s,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering &o, &p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering memset(o->hash_table.items, 0, s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->data_hash_table_offset = htole64(p + offsetof(Object, hash_table.items));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->data_hash_table_size = htole64(s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_setup_field_hash_table(JournalFile *f) {
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering uint64_t s, p;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Object *o;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s = DEFAULT_FIELD_HASH_TABLE_SIZE;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_append_object(f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering OBJECT_FIELD_HASH_TABLE,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering offsetof(Object, hash_table.items) + s,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering &o, &p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering memset(o->hash_table.items, 0, s);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f->header->field_hash_table_offset = htole64(p + offsetof(Object, hash_table.items));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f->header->field_hash_table_size = htole64(s);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_map_data_hash_table(JournalFile *f) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t s, p;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering void *t;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p = le64toh(f->header->data_hash_table_offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s = le64toh(f->header->data_hash_table_size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to(f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WINDOW_DATA_HASH_TABLE,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p, s,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering &t);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->data_hash_table = t;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_map_field_hash_table(JournalFile *f) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t s, p;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering void *t;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering p = le64toh(f->header->field_hash_table_offset);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering s = le64toh(f->header->field_hash_table_size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to(f,
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack WINDOW_FIELD_HASH_TABLE,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p, s,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering &t);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->field_hash_table = t;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int journal_file_link_data(JournalFile *f, Object *o, uint64_t offset, uint64_t hash) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t p, h;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(o);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(offset > 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o->object.type == OBJECT_DATA);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* This might alter the window we are looking at */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->data.next_hash_offset = o->data.next_field_offset = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->data.entry_offset = o->data.entry_array_offset = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->data.n_entries = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p = le64toh(f->data_hash_table[h].tail_hash_offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (p == 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Only entry in the hash table is easy */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->data_hash_table[h].head_hash_offset = htole64(offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering } else {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Move back to the previous data object, to patch in
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * pointer */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->data.next_hash_offset = htole64(offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->data_hash_table[h].tail_hash_offset = htole64(offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering f->header->n_data = htole64(le64toh(f->header->n_data) + 1);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint journal_file_find_data_object_with_hash(
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering JournalFile *f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const void *data, uint64_t size, uint64_t hash,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Object **ret, uint64_t *offset) {
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t p, osize, h;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(data || size == 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering osize = offsetof(Object, data.payload) + size;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (f->header->data_hash_table_size == 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return -EBADMSG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p = le64toh(f->data_hash_table[h].head_hash_offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering while (p > 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Object *o;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (le64toh(o->data.hash) != hash)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering goto next;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (o->object.flags & OBJECT_COMPRESSED) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#ifdef HAVE_XZ
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t l, rsize;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering l = le64toh(o->object.size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (l <= offsetof(Object, data.payload))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBADMSG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering l -= offsetof(Object, data.payload);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return -EBADMSG;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (rsize == size &&
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering memcmp(f->compress_buffer, data, size) == 0) {
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (ret)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering *ret = o;
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (offset)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering *offset = p;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return 1;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering }
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering#else
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return -EPROTONOSUPPORT;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering#endif
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering } else if (le64toh(o->object.size) == osize &&
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering memcmp(o->data.payload, data, size) == 0) {
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (ret)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering *ret = o;
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering if (offset)
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering *offset = p;
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering return 1;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering }
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering next:
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering p = le64toh(o->data.next_hash_offset);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering }
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering return 0;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering}
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringint journal_file_find_data_object(
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering JournalFile *f,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering const void *data, uint64_t size,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering Object **ret, uint64_t *offset) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering uint64_t hash;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering assert(f);
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann assert(data || size == 0);
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann hash = hash64(data, size);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return journal_file_find_data_object_with_hash(f,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering data, size, hash,
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering ret, offset);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering}
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringstatic int journal_file_append_data(
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering JournalFile *f,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering const void *data, uint64_t size,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering Object **ret, uint64_t *offset) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering uint64_t hash, p;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering uint64_t osize;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering Object *o;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering int r;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering bool compressed = false;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering assert(f);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering assert(data || size == 0);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering hash = hash64(data, size);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering if (r < 0)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return r;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering else if (r > 0) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (ret)
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering *ret = o;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering if (offset)
94e15fdc4d9d96fa6607bfb4eaaea164a3aec417David Herrmann *offset = p;
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering return 0;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering }
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering osize = offsetof(Object, data.payload) + size;
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = journal_file_append_object(f, OBJECT_DATA, osize, &o, &p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->data.hash = htole64(hash);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#ifdef HAVE_XZ
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->compress &&
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering size >= COMPRESSION_SIZE_THRESHOLD) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t rsize;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering compressed = compress_blob(data, size, o->data.payload, &rsize);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering if (compressed) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->object.size = htole64(offsetof(Object, data.payload) + rsize);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->object.flags |= OBJECT_COMPRESSED;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Compressed data object %lu -> %lu", (unsigned long) size, (unsigned long) rsize);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#endif
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!compressed && size > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering memcpy(o->data.payload, data, size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_link_data(f, o, p, hash);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_hmac_put_object(f, OBJECT_DATA, p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* The linking might have altered the window, so let's
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * refresh our pointer */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (ret)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *ret = o;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (offset)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *offset = p;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
deffddf1df29a5ed047feff3a0f2b765006fb71bLukas Nykryn return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringuint64_t journal_file_entry_n_items(Object *o) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering assert(o->object.type == OBJECT_ENTRY);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic uint64_t journal_file_entry_array_n_items(Object *o) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o->object.type == OBJECT_ENTRY_ARRAY);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int link_entry_into_array(JournalFile *f,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering le64_t *first,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering le64_t *idx,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t p) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t n = 0, ap = 0, q, i, a, hidx;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Object *o;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(first);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(idx);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(p > 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering a = le64toh(*first);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering i = hidx = le64toh(*idx);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering while (a > 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering n = journal_file_entry_array_n_items(o);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (i < n) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering o->entry_array.items[i] = htole64(p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *idx = htole64(hidx + 1);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering i -= n;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering ap = a;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering a = le64toh(o->entry_array.next_entry_array_offset);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (hidx > n)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering n = (hidx+1) * 2;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering else
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering n = n * 2;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (n < 4)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering n = 4;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_append_object(f, OBJECT_ENTRY_ARRAY,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering offsetof(Object, entry_array.items) + n * sizeof(uint64_t),
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering &o, &q);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, q);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry_array.items[i] = htole64(p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (ap == 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *first = htole64(q);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering else {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, ap, &o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry_array.next_entry_array_offset = htole64(q);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *idx = htole64(hidx + 1);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int link_entry_into_array_plus_one(JournalFile *f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64_t *extra,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64_t *first,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64_t *idx,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t p) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering int r;
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering assert(f);
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering assert(extra);
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering assert(first);
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering assert(idx);
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering assert(p > 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (*idx == 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *extra = htole64(p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering else {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering le64_t i;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering i = htole64(le64toh(*idx) - 1);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = link_entry_into_array(f, first, &i, p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (r < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering *idx = htole64(le64toh(*idx) + 1);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t p;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(f);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert(o);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering assert(offset > 0);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering p = le64toh(o->entry.items[i].object_offset);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering if (p == 0)
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering return -EINVAL;
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering if (r < 0)
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering return r;
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return link_entry_into_array_plus_one(f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering &o->data.entry_offset,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering &o->data.entry_array_offset,
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack &o->data.n_entries,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t n, i;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(offset > 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(o->object.type == OBJECT_ENTRY);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering __sync_synchronize();
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Link up the entry itself */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = link_entry_into_array(f,
700ff4d97311902a440109a2c081731ab6ae8a20Lennart Poettering &f->header->entry_array_offset,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering &f->header->n_entries,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering offset);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* log_debug("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) f->header->n_entries); */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (f->header->head_entry_realtime == 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->head_entry_realtime = o->entry.realtime;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->tail_entry_realtime = o->entry.realtime;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->header->tail_entry_monotonic = o->entry.monotonic;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering f->tail_entry_monotonic_valid = true;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Link up the items */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering n = journal_file_entry_n_items(o);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (i = 0; i < n; i++) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_link_entry_item(f, o, offset, i);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering }
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering}
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int journal_file_append_entry_internal(
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering JournalFile *f,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const dual_timestamp *ts,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t xor_hash,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const EntryItem items[], unsigned n_items,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t *seqnum,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Object **ret, uint64_t *offset) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering uint64_t np;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering uint64_t osize;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering Object *o;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(f);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(items || n_items == 0);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering assert(ts);
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering osize = offsetof(Object, entry.items) + (n_items * sizeof(EntryItem));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_append_object(f, OBJECT_ENTRY, osize, &o, &np);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering memcpy(o->entry.items, items, n_items * sizeof(EntryItem));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry.realtime = htole64(ts->realtime);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry.monotonic = htole64(ts->monotonic);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry.xor_hash = htole64(xor_hash);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o->entry.boot_id = f->header->boot_id;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = journal_file_hmac_put_object(f, OBJECT_ENTRY, np);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return r;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering
r = journal_file_link_entry(f, o, np);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = np;
return 0;
}
void journal_file_post_change(JournalFile *f) {
assert(f);
/* inotify() does not receive IN_MODIFY events from file
* accesses done via mmap(). After each access we hence
* trigger IN_MODIFY by truncating the journal file to its
* current size which triggers IN_MODIFY. */
__sync_synchronize();
if (ftruncate(f->fd, f->last_stat.st_size) < 0)
log_error("Failed to to truncate file to its own size: %m");
}
int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqnum, Object **ret, uint64_t *offset) {
unsigned i;
EntryItem *items;
int r;
uint64_t xor_hash = 0;
struct dual_timestamp _ts;
assert(f);
assert(iovec || n_iovec == 0);
if (!f->writable)
return -EPERM;
if (!ts) {
dual_timestamp_get(&_ts);
ts = &_ts;
}
if (f->tail_entry_monotonic_valid &&
ts->monotonic < le64toh(f->header->tail_entry_monotonic))
return -EINVAL;
r = journal_file_maybe_append_tag(f, ts->realtime);
if (r < 0)
return r;
/* alloca() can't take 0, hence let's allocate at least one */
items = alloca(sizeof(EntryItem) * MAX(1, n_iovec));
for (i = 0; i < n_iovec; i++) {
uint64_t p;
Object *o;
r = journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p);
if (r < 0)
return r;
xor_hash ^= le64toh(o->data.hash);
items[i].object_offset = htole64(p);
items[i].hash = o->data.hash;
}
r = journal_file_append_entry_internal(f, ts, xor_hash, items, n_iovec, seqnum, ret, offset);
journal_file_post_change(f);
return r;
}
static int generic_array_get(JournalFile *f,
uint64_t first,
uint64_t i,
Object **ret, uint64_t *offset) {
Object *o;
uint64_t p = 0, a;
int r;
assert(f);
a = first;
while (a > 0) {
uint64_t n;
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
n = journal_file_entry_array_n_items(o);
if (i < n) {
p = le64toh(o->entry_array.items[i]);
break;
}
i -= n;
a = le64toh(o->entry_array.next_entry_array_offset);
}
if (a <= 0 || p <= 0)
return 0;
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = p;
return 1;
}
static int generic_array_get_plus_one(JournalFile *f,
uint64_t extra,
uint64_t first,
uint64_t i,
Object **ret, uint64_t *offset) {
Object *o;
assert(f);
if (i == 0) {
int r;
r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = extra;
return 1;
}
return generic_array_get(f, first, i-1, ret, offset);
}
enum {
TEST_FOUND,
TEST_LEFT,
TEST_RIGHT
};
static int generic_array_bisect(JournalFile *f,
uint64_t first,
uint64_t n,
uint64_t needle,
int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
direction_t direction,
Object **ret,
uint64_t *offset,
uint64_t *idx) {
uint64_t a, p, t = 0, i = 0, last_p = 0;
bool subtract_one = false;
Object *o, *array = NULL;
int r;
assert(f);
assert(test_object);
a = first;
while (a > 0) {
uint64_t left, right, k, lp;
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
if (r < 0)
return r;
k = journal_file_entry_array_n_items(array);
right = MIN(k, n);
if (right <= 0)
return 0;
i = right - 1;
lp = p = le64toh(array->entry_array.items[i]);
if (p <= 0)
return -EBADMSG;
r = test_object(f, p, needle);
if (r < 0)
return r;
if (r == TEST_FOUND)
r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
if (r == TEST_RIGHT) {
left = 0;
right -= 1;
for (;;) {
if (left == right) {
if (direction == DIRECTION_UP)
subtract_one = true;
i = left;
goto found;
}
assert(left < right);
i = (left + right) / 2;
p = le64toh(array->entry_array.items[i]);
if (p <= 0)
return -EBADMSG;
r = test_object(f, p, needle);
if (r < 0)
return r;
if (r == TEST_FOUND)
r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
if (r == TEST_RIGHT)
right = i;
else
left = i + 1;
}
}
if (k > n) {
if (direction == DIRECTION_UP) {
i = n;
subtract_one = true;
goto found;
}
return 0;
}
last_p = lp;
n -= k;
t += k;
a = le64toh(array->entry_array.next_entry_array_offset);
}
return 0;
found:
if (subtract_one && t == 0 && i == 0)
return 0;
if (subtract_one && i == 0)
p = last_p;
else if (subtract_one)
p = le64toh(array->entry_array.items[i-1]);
else
p = le64toh(array->entry_array.items[i]);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = p;
if (idx)
*idx = t + i + (subtract_one ? -1 : 0);
return 1;
}
static int generic_array_bisect_plus_one(JournalFile *f,
uint64_t extra,
uint64_t first,
uint64_t n,
uint64_t needle,
int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
direction_t direction,
Object **ret,
uint64_t *offset,
uint64_t *idx) {
int r;
bool step_back = false;
Object *o;
assert(f);
assert(test_object);
if (n <= 0)
return 0;
/* This bisects the array in object 'first', but first checks
* an extra */
r = test_object(f, extra, needle);
if (r < 0)
return r;
if (r == TEST_FOUND)
r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
/* if we are looking with DIRECTION_UP then we need to first
see if in the actual array there is a matching entry, and
return the last one of that. But if there isn't any we need
to return this one. Hence remember this, and return it
below. */
if (r == TEST_LEFT)
step_back = direction == DIRECTION_UP;
if (r == TEST_RIGHT) {
if (direction == DIRECTION_DOWN)
goto found;
else
return 0;
}
r = generic_array_bisect(f, first, n-1, needle, test_object, direction, ret, offset, idx);
if (r == 0 && step_back)
goto found;
if (r > 0 && idx)
(*idx) ++;
return r;
found:
r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = extra;
if (idx)
*idx = 0;
return 1;
}
static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) {
assert(f);
assert(p > 0);
if (p == needle)
return TEST_FOUND;
else if (p < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_offset(
JournalFile *f,
uint64_t p,
direction_t direction,
Object **ret,
uint64_t *offset) {
return generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
p,
test_object_offset,
direction,
ret, offset, NULL);
}
static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.seqnum) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.seqnum) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_seqnum(
JournalFile *f,
uint64_t seqnum,
direction_t direction,
Object **ret,
uint64_t *offset) {
return generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
seqnum,
test_object_seqnum,
direction,
ret, offset, NULL);
}
static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.realtime) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.realtime) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_realtime(
JournalFile *f,
uint64_t realtime,
direction_t direction,
Object **ret,
uint64_t *offset) {
return generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
realtime,
test_object_realtime,
direction,
ret, offset, NULL);
}
static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.monotonic) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.monotonic) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_monotonic(
JournalFile *f,
sd_id128_t boot_id,
uint64_t monotonic,
direction_t direction,
Object **ret,
uint64_t *offset) {
char t[9+32+1] = "_BOOT_ID=";
Object *o;
int r;
assert(f);
sd_id128_to_string(boot_id, t + 9);
r = journal_file_find_data_object(f, t, strlen(t), &o, NULL);
if (r < 0)
return r;
if (r == 0)
return -ENOENT;
return generic_array_bisect_plus_one(f,
le64toh(o->data.entry_offset),
le64toh(o->data.entry_array_offset),
le64toh(o->data.n_entries),
monotonic,
test_object_monotonic,
direction,
ret, offset, NULL);
}
int journal_file_next_entry(
JournalFile *f,
Object *o, uint64_t p,
direction_t direction,
Object **ret, uint64_t *offset) {
uint64_t i, n;
int r;
assert(f);
assert(p > 0 || !o);
n = le64toh(f->header->n_entries);
if (n <= 0)
return 0;
if (!o)
i = direction == DIRECTION_DOWN ? 0 : n - 1;
else {
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
if (direction == DIRECTION_DOWN) {
if (i >= n - 1)
return 0;
i++;
} else {
if (i <= 0)
return 0;
i--;
}
}
/* And jump to it */
return generic_array_get(f,
le64toh(f->header->entry_array_offset),
i,
ret, offset);
}
int journal_file_skip_entry(
JournalFile *f,
Object *o, uint64_t p,
int64_t skip,
Object **ret, uint64_t *offset) {
uint64_t i, n;
int r;
assert(f);
assert(o);
assert(p > 0);
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
/* Calculate new index */
if (skip < 0) {
if ((uint64_t) -skip >= i)
i = 0;
else
i = i - (uint64_t) -skip;
} else
i += (uint64_t) skip;
n = le64toh(f->header->n_entries);
if (n <= 0)
return -EBADMSG;
if (i >= n)
i = n-1;
return generic_array_get(f,
le64toh(f->header->entry_array_offset),
i,
ret, offset);
}
int journal_file_next_entry_for_data(
JournalFile *f,
Object *o, uint64_t p,
uint64_t data_offset,
direction_t direction,
Object **ret, uint64_t *offset) {
uint64_t n, i;
int r;
Object *d;
assert(f);
assert(p > 0 || !o);
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
n = le64toh(d->data.n_entries);
if (n <= 0)
return n;
if (!o)
i = direction == DIRECTION_DOWN ? 0 : n - 1;
else {
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
if (direction == DIRECTION_DOWN) {
if (i >= n - 1)
return 0;
i++;
} else {
if (i <= 0)
return 0;
i--;
}
}
return generic_array_get_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
i,
ret, offset);
}
int journal_file_move_to_entry_by_offset_for_data(
JournalFile *f,
uint64_t data_offset,
uint64_t p,
direction_t direction,
Object **ret, uint64_t *offset) {
int r;
Object *d;
assert(f);
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
return generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
p,
test_object_offset,
direction,
ret, offset, NULL);
}
int journal_file_move_to_entry_by_monotonic_for_data(
JournalFile *f,
uint64_t data_offset,
sd_id128_t boot_id,
uint64_t monotonic,
direction_t direction,
Object **ret, uint64_t *offset) {
char t[9+32+1] = "_BOOT_ID=";
Object *o, *d;
int r;
uint64_t b, z;
assert(f);
/* First, seek by time */
sd_id128_to_string(boot_id, t + 9);
r = journal_file_find_data_object(f, t, strlen(t), &o, &b);
if (r < 0)
return r;
if (r == 0)
return -ENOENT;
r = generic_array_bisect_plus_one(f,
le64toh(o->data.entry_offset),
le64toh(o->data.entry_array_offset),
le64toh(o->data.n_entries),
monotonic,
test_object_monotonic,
direction,
NULL, &z, NULL);
if (r <= 0)
return r;
/* And now, continue seeking until we find an entry that
* exists in both bisection arrays */
for (;;) {
Object *qo;
uint64_t p, q;
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
r = generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
z,
test_object_offset,
direction,
NULL, &p, NULL);
if (r <= 0)
return r;
r = journal_file_move_to_object(f, OBJECT_DATA, b, &o);
if (r < 0)
return r;
r = generic_array_bisect_plus_one(f,
le64toh(o->data.entry_offset),
le64toh(o->data.entry_array_offset),
le64toh(o->data.n_entries),
p,
test_object_offset,
direction,
&qo, &q, NULL);
if (r <= 0)
return r;
if (p == q) {
if (ret)
*ret = qo;
if (offset)
*offset = q;
return 1;
}
z = q;
}
return 0;
}
int journal_file_move_to_entry_by_seqnum_for_data(
JournalFile *f,
uint64_t data_offset,
uint64_t seqnum,
direction_t direction,
Object **ret, uint64_t *offset) {
Object *d;
int r;
assert(f);
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
return generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
seqnum,
test_object_seqnum,
direction,
ret, offset, NULL);
}
int journal_file_move_to_entry_by_realtime_for_data(
JournalFile *f,
uint64_t data_offset,
uint64_t realtime,
direction_t direction,
Object **ret, uint64_t *offset) {
Object *d;
int r;
assert(f);
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
return generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
realtime,
test_object_realtime,
direction,
ret, offset, NULL);
}
static void *fsprg_state(JournalFile *f) {
uint64_t a, b;
assert(f);
if (!f->authenticate)
return NULL;
a = le64toh(f->fsprg_header->header_size);
b = le64toh(f->fsprg_header->state_size);
if (a + b > f->fsprg_size)
return NULL;
return (uint8_t*) f->fsprg_header + a;
}
static uint64_t journal_file_tag_seqnum(JournalFile *f) {
uint64_t r;
assert(f);
r = le64toh(f->header->n_tags) + 1;
f->header->n_tags = htole64(r);
return r;
}
int journal_file_append_tag(JournalFile *f) {
Object *o;
uint64_t p;
int r;
assert(f);
if (!f->authenticate)
return 0;
if (!f->hmac_running)
return 0;
log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(fsprg_state(f)));
assert(f->hmac);
r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
if (r < 0)
return r;
o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
/* Add the tag object itself, so that we can protect its
* header. This will exclude the actual hash value in it */
r = journal_file_hmac_put_object(f, OBJECT_TAG, p);
if (r < 0)
return r;
/* Get the HMAC tag and store it in the object */
memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
f->hmac_running = false;
return 0;
}
static int journal_file_hmac_start(JournalFile *f) {
uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
assert(f);
if (!f->authenticate)
return 0;
if (f->hmac_running)
return 0;
/* Prepare HMAC for next cycle */
gcry_md_reset(f->hmac);
FSPRG_GetKey(fsprg_state(f), key, sizeof(key), 0);
gcry_md_setkey(f->hmac, key, sizeof(key));
f->hmac_running = true;
return 0;
}
static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
uint64_t t;
assert(f);
assert(epoch);
assert(f->authenticate);
if (le64toh(f->fsprg_header->fsprg_start_usec) == 0 ||
le64toh(f->fsprg_header->fsprg_interval_usec) == 0)
return -ENOTSUP;
if (realtime < le64toh(f->fsprg_header->fsprg_start_usec))
return -ESTALE;
t = realtime - le64toh(f->fsprg_header->fsprg_start_usec);
t = t / le64toh(f->fsprg_header->fsprg_interval_usec);
*epoch = t;
return 0;
}
static int journal_file_need_evolve(JournalFile *f, uint64_t realtime) {
uint64_t goal, epoch;
int r;
assert(f);
if (!f->authenticate)
return 0;
r = journal_file_get_epoch(f, realtime, &goal);
if (r < 0)
return r;
epoch = FSPRG_GetEpoch(fsprg_state(f));
if (epoch > goal)
return -ESTALE;
return epoch != goal;
}
static int journal_file_evolve(JournalFile *f, uint64_t realtime) {
uint64_t goal, epoch;
int r;
assert(f);
if (!f->authenticate)
return 0;
r = journal_file_get_epoch(f, realtime, &goal);
if (r < 0)
return r;
epoch = FSPRG_GetEpoch(fsprg_state(f));
if (epoch < goal)
log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
for (;;) {
if (epoch > goal)
return -ESTALE;
if (epoch == goal)
return 0;
FSPRG_Evolve(fsprg_state(f));
epoch = FSPRG_GetEpoch(fsprg_state(f));
}
}
static int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
int r;
assert(f);
if (!f->authenticate)
return 0;
r = journal_file_need_evolve(f, realtime);
if (r <= 0)
return 0;
r = journal_file_append_tag(f);
if (r < 0)
return r;
r = journal_file_evolve(f, realtime);
if (r < 0)
return r;
r = journal_file_hmac_start(f);
if (r < 0)
return r;
return 0;
}
static int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) {
int r;
Object *o;
assert(f);
if (!f->authenticate)
return 0;
r = journal_file_hmac_start(f);
if (r < 0)
return r;
r = journal_file_move_to_object(f, type, p, &o);
if (r < 0)
return r;
gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
switch (o->object.type) {
case OBJECT_DATA:
/* All but: hash and payload are mutable */
gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
break;
case OBJECT_ENTRY:
/* All */
gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
break;
case OBJECT_FIELD_HASH_TABLE:
case OBJECT_DATA_HASH_TABLE:
case OBJECT_ENTRY_ARRAY:
/* Nothing: everything is mutable */
break;
case OBJECT_TAG:
/* All but the tag itself */
gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
break;
default:
return -EINVAL;
}
return 0;
}
static int journal_file_hmac_put_header(JournalFile *f) {
int r;
assert(f);
if (!f->authenticate)
return 0;
r = journal_file_hmac_start(f);
if (r < 0)
return r;
/* All but state+reserved, boot_id, arena_size,
* tail_object_offset, n_objects, n_entries, tail_seqnum,
* head_entry_realtime, tail_entry_realtime,
* tail_entry_monotonic, n_data, n_fields, header_tag */
gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
gcry_md_write(f->hmac, &f->header->head_seqnum, offsetof(Header, head_entry_realtime) - offsetof(Header, head_seqnum));
return 0;
}
static int journal_file_load_fsprg(JournalFile *f) {
int r, fd = -1;
char *p = NULL;
struct stat st;
FSPRGHeader *m = NULL;
sd_id128_t machine;
assert(f);
if (!f->authenticate)
return 0;
r = sd_id128_get_machine(&machine);
if (r < 0)
return r;
if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg",
SD_ID128_FORMAT_VAL(machine)) < 0)
return -ENOMEM;
fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
if (fd < 0) {
log_error("Failed to open %s: %m", p);
r = -errno;
goto finish;
}
if (fstat(fd, &st) < 0) {
r = -errno;
goto finish;
}
if (st.st_size < (off_t) sizeof(FSPRGHeader)) {
r = -ENODATA;
goto finish;
}
m = mmap(NULL, PAGE_ALIGN(sizeof(FSPRGHeader)), PROT_READ, MAP_SHARED, fd, 0);
if (m == MAP_FAILED) {
m = NULL;
r = -errno;
goto finish;
}
if (memcmp(m->signature, FSPRG_HEADER_SIGNATURE, 8) != 0) {
r = -EBADMSG;
goto finish;
}
if (m->incompatible_flags != 0) {
r = -EPROTONOSUPPORT;
goto finish;
}
if (le64toh(m->header_size) < sizeof(FSPRGHeader)) {
r = -EBADMSG;
goto finish;
}
if (le64toh(m->state_size) != FSPRG_stateinbytes(m->secpar)) {
r = -EBADMSG;
goto finish;
}
f->fsprg_size = le64toh(m->header_size) + le64toh(m->state_size);
if ((uint64_t) st.st_size < f->fsprg_size) {
r = -ENODATA;
goto finish;
}
if (!sd_id128_equal(machine, m->machine_id)) {
r = -EHOSTDOWN;
goto finish;
}
if (le64toh(m->fsprg_start_usec) <= 0 ||
le64toh(m->fsprg_interval_usec) <= 0) {
r = -EBADMSG;
goto finish;
}
f->fsprg_header = mmap(NULL, PAGE_ALIGN(f->fsprg_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (f->fsprg_header == MAP_FAILED) {
f->fsprg_header = NULL;
r = -errno;
goto finish;
}
r = 0;
finish:
if (m)
munmap(m, PAGE_ALIGN(sizeof(FSPRGHeader)));
if (fd >= 0)
close_nointr_nofail(fd);
free(p);
return r;
}
static int journal_file_setup_hmac(JournalFile *f) {
gcry_error_t e;
if (!f->authenticate)
return 0;
e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (e != 0)
return -ENOTSUP;
return 0;
}
static int journal_file_append_first_tag(JournalFile *f) {
int r;
uint64_t p;
if (!f->authenticate)
return 0;
log_debug("Calculating first tag...");
r = journal_file_hmac_put_header(f);
if (r < 0)
return r;
p = le64toh(f->header->field_hash_table_offset);
if (p < offsetof(Object, hash_table.items))
return -EINVAL;
p -= offsetof(Object, hash_table.items);
r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
if (r < 0)
return r;
p = le64toh(f->header->data_hash_table_offset);
if (p < offsetof(Object, hash_table.items))
return -EINVAL;
p -= offsetof(Object, hash_table.items);
r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
if (r < 0)
return r;
r = journal_file_append_tag(f);
if (r < 0)
return r;
return 0;
}
void journal_file_dump(JournalFile *f) {
Object *o;
int r;
uint64_t p;
assert(f);
journal_file_print_header(f);
p = le64toh(f->header->header_size);
while (p != 0) {
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0)
goto fail;
switch (o->object.type) {
case OBJECT_UNUSED:
printf("Type: OBJECT_UNUSED\n");
break;
case OBJECT_DATA:
printf("Type: OBJECT_DATA\n");
break;
case OBJECT_ENTRY:
printf("Type: OBJECT_ENTRY %llu %llu %llu\n",
(unsigned long long) le64toh(o->entry.seqnum),
(unsigned long long) le64toh(o->entry.monotonic),
(unsigned long long) le64toh(o->entry.realtime));
break;
case OBJECT_FIELD_HASH_TABLE:
printf("Type: OBJECT_FIELD_HASH_TABLE\n");
break;
case OBJECT_DATA_HASH_TABLE:
printf("Type: OBJECT_DATA_HASH_TABLE\n");
break;
case OBJECT_ENTRY_ARRAY:
printf("Type: OBJECT_ENTRY_ARRAY\n");
break;
case OBJECT_TAG:
printf("Type: OBJECT_TAG %llu\n",
(unsigned long long) le64toh(o->tag.seqnum));
break;
}
if (o->object.flags & OBJECT_COMPRESSED)
printf("Flags: COMPRESSED\n");
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
p = p + ALIGN64(le64toh(o->object.size));
}
return;
fail:
log_error("File corrupt");
}
void journal_file_print_header(JournalFile *f) {
char a[33], b[33], c[33];
char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX];
assert(f);
printf("File Path: %s\n"
"File ID: %s\n"
"Machine ID: %s\n"
"Boot ID: %s\n"
"Sequential Number ID: %s\n"
"State: %s\n"
"Compatible Flags:%s%s\n"
"Incompatible Flags:%s%s\n"
"Header size: %llu\n"
"Arena size: %llu\n"
"Data Hash Table Size: %llu\n"
"Field Hash Table Size: %llu\n"
"Objects: %llu\n"
"Entry Objects: %llu\n"
"Rotate Suggested: %s\n"
"Head Sequential Number: %llu\n"
"Tail Sequential Number: %llu\n"
"Head Realtime Timestamp: %s\n"
"Tail Realtime Timestamp: %s\n",
f->path,
sd_id128_to_string(f->header->file_id, a),
sd_id128_to_string(f->header->machine_id, b),
sd_id128_to_string(f->header->boot_id, c),
sd_id128_to_string(f->header->seqnum_id, c),
f->header->state == STATE_OFFLINE ? "offline" :
f->header->state == STATE_ONLINE ? "online" :
f->header->state == STATE_ARCHIVED ? "archived" : "unknown",
(f->header->compatible_flags & HEADER_COMPATIBLE_AUTHENTICATED) ? " AUTHENTICATED" : "",
(f->header->compatible_flags & ~HEADER_COMPATIBLE_AUTHENTICATED) ? " ???" : "",
(f->header->incompatible_flags & HEADER_INCOMPATIBLE_COMPRESSED) ? " COMPRESSED" : "",
(f->header->incompatible_flags & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
(unsigned long long) le64toh(f->header->header_size),
(unsigned long long) le64toh(f->header->arena_size),
(unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
(unsigned long long) le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
(unsigned long long) le64toh(f->header->n_objects),
(unsigned long long) le64toh(f->header->n_entries),
yes_no(journal_file_rotate_suggested(f)),
(unsigned long long) le64toh(f->header->head_seqnum),
(unsigned long long) le64toh(f->header->tail_seqnum),
format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
format_timestamp(y, sizeof(y), le64toh(f->header->tail_entry_realtime)));
if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
printf("Data Objects: %llu\n"
"Data Hash Table Fill: %.1f%%\n",
(unsigned long long) le64toh(f->header->n_data),
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))));
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
printf("Field Objects: %llu\n"
"Field Hash Table Fill: %.1f%%\n",
(unsigned long long) le64toh(f->header->n_fields),
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))));
}
int journal_file_open(
const char *fname,
int flags,
mode_t mode,
bool compress,
bool authenticate,
JournalMetrics *metrics,
JournalFile *template,
JournalFile **ret) {
JournalFile *f;
int r;
bool newly_created = false;
assert(fname);
if ((flags & O_ACCMODE) != O_RDONLY &&
(flags & O_ACCMODE) != O_RDWR)
return -EINVAL;
if (!endswith(fname, ".journal"))
return -EINVAL;
f = new0(JournalFile, 1);
if (!f)
return -ENOMEM;
f->fd = -1;
f->mode = mode;
f->flags = flags;
f->prot = prot_from_flags(flags);
f->writable = (flags & O_ACCMODE) != O_RDONLY;
f->compress = compress;
f->authenticate = authenticate;
f->path = strdup(fname);
if (!f->path) {
r = -ENOMEM;
goto fail;
}
f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
if (f->fd < 0) {
r = -errno;
goto fail;
}
if (fstat(f->fd, &f->last_stat) < 0) {
r = -errno;
goto fail;
}
if (f->last_stat.st_size == 0 && f->writable) {
newly_created = true;
/* Try to load the FSPRG state, and if we can't, then
* just don't do authentication */
r = journal_file_load_fsprg(f);
if (r < 0)
f->authenticate = false;
r = journal_file_init_header(f, template);
if (r < 0)
goto fail;
if (fstat(f->fd, &f->last_stat) < 0) {
r = -errno;
goto fail;
}
}
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
r = -EIO;
goto fail;
}
f->header = mmap(NULL, PAGE_ALIGN(sizeof(Header)), prot_from_flags(flags), MAP_SHARED, f->fd, 0);
if (f->header == MAP_FAILED) {
f->header = NULL;
r = -errno;
goto fail;
}
if (!newly_created) {
r = journal_file_verify_header(f);
if (r < 0)
goto fail;
}
if (!newly_created && f->writable) {
r = journal_file_load_fsprg(f);
if (r < 0)
goto fail;
}
if (f->writable) {
if (metrics) {
journal_default_metrics(metrics, f->fd);
f->metrics = *metrics;
} else if (template)
f->metrics = template->metrics;
r = journal_file_refresh_header(f);
if (r < 0)
goto fail;
r = journal_file_setup_hmac(f);
if (r < 0)
goto fail;
}
if (newly_created) {
r = journal_file_setup_field_hash_table(f);
if (r < 0)
goto fail;
r = journal_file_setup_data_hash_table(f);
if (r < 0)
goto fail;
r = journal_file_append_first_tag(f);
if (r < 0)
goto fail;
}
r = journal_file_map_field_hash_table(f);
if (r < 0)
goto fail;
r = journal_file_map_data_hash_table(f);
if (r < 0)
goto fail;
if (ret)
*ret = f;
return 0;
fail:
journal_file_close(f);
return r;
}
int journal_file_rotate(JournalFile **f, bool compress, bool authenticate) {
char *p;
size_t l;
JournalFile *old_file, *new_file = NULL;
int r;
assert(f);
assert(*f);
old_file = *f;
if (!old_file->writable)
return -EINVAL;
if (!endswith(old_file->path, ".journal"))
return -EINVAL;
l = strlen(old_file->path);
p = new(char, l + 1 + 32 + 1 + 16 + 1 + 16 + 1);
if (!p)
return -ENOMEM;
memcpy(p, old_file->path, l - 8);
p[l-8] = '@';
sd_id128_to_string(old_file->header->seqnum_id, p + l - 8 + 1);
snprintf(p + l - 8 + 1 + 32, 1 + 16 + 1 + 16 + 8 + 1,
"-%016llx-%016llx.journal",
(unsigned long long) le64toh((*f)->header->tail_seqnum),
(unsigned long long) le64toh((*f)->header->tail_entry_realtime));
r = rename(old_file->path, p);
free(p);
if (r < 0)
return -errno;
old_file->header->state = STATE_ARCHIVED;
r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, authenticate, NULL, old_file, &new_file);
journal_file_close(old_file);
*f = new_file;
return r;
}
int journal_file_open_reliably(
const char *fname,
int flags,
mode_t mode,
bool compress,
bool authenticate,
JournalMetrics *metrics,
JournalFile *template,
JournalFile **ret) {
int r;
size_t l;
char *p;
r = journal_file_open(fname, flags, mode, compress, authenticate, metrics, template, ret);
if (r != -EBADMSG && /* corrupted */
r != -ENODATA && /* truncated */
r != -EHOSTDOWN && /* other machine */
r != -EPROTONOSUPPORT && /* incompatible feature */
r != -EBUSY && /* unclean shutdown */
r != -ESHUTDOWN /* already archived */)
return r;
if ((flags & O_ACCMODE) == O_RDONLY)
return r;
if (!(flags & O_CREAT))
return r;
if (!endswith(fname, ".journal"))
return r;
/* The file is corrupted. Rotate it away and try it again (but only once) */
l = strlen(fname);
if (asprintf(&p, "%.*s@%016llx-%016llx.journal~",
(int) (l-8), fname,
(unsigned long long) now(CLOCK_REALTIME),
random_ull()) < 0)
return -ENOMEM;
r = rename(fname, p);
free(p);
if (r < 0)
return -errno;
log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
return journal_file_open(fname, flags, mode, compress, authenticate, metrics, template, ret);
}
struct vacuum_info {
off_t usage;
char *filename;
uint64_t realtime;
sd_id128_t seqnum_id;
uint64_t seqnum;
bool have_seqnum;
};
static int vacuum_compare(const void *_a, const void *_b) {
const struct vacuum_info *a, *b;
a = _a;
b = _b;
if (a->have_seqnum && b->have_seqnum &&
sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
if (a->seqnum < b->seqnum)
return -1;
else if (a->seqnum > b->seqnum)
return 1;
else
return 0;
}
if (a->realtime < b->realtime)
return -1;
else if (a->realtime > b->realtime)
return 1;
else if (a->have_seqnum && b->have_seqnum)
return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
else
return strcmp(a->filename, b->filename);
}
int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free) {
DIR *d;
int r = 0;
struct vacuum_info *list = NULL;
unsigned n_list = 0, n_allocated = 0, i;
uint64_t sum = 0;
assert(directory);
if (max_use <= 0)
return 0;
d = opendir(directory);
if (!d)
return -errno;
for (;;) {
int k;
struct dirent buf, *de;
size_t q;
struct stat st;
char *p;
unsigned long long seqnum = 0, realtime;
sd_id128_t seqnum_id;
bool have_seqnum;
k = readdir_r(d, &buf, &de);
if (k != 0) {
r = -k;
goto finish;
}
if (!de)
break;
if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
continue;
if (!S_ISREG(st.st_mode))
continue;
q = strlen(de->d_name);
if (endswith(de->d_name, ".journal")) {
/* Vacuum archived files */
if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
continue;
if (de->d_name[q-8-16-1] != '-' ||
de->d_name[q-8-16-1-16-1] != '-' ||
de->d_name[q-8-16-1-16-1-32-1] != '@')
continue;
p = strdup(de->d_name);
if (!p) {
r = -ENOMEM;
goto finish;
}
de->d_name[q-8-16-1-16-1] = 0;
if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
free(p);
continue;
}
if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
free(p);
continue;
}
have_seqnum = true;
} else if (endswith(de->d_name, ".journal~")) {
unsigned long long tmp;
/* Vacuum corrupted files */
if (q < 1 + 16 + 1 + 16 + 8 + 1)
continue;
if (de->d_name[q-1-8-16-1] != '-' ||
de->d_name[q-1-8-16-1-16-1] != '@')
continue;
p = strdup(de->d_name);
if (!p) {
r = -ENOMEM;
goto finish;
}
if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
free(p);
continue;
}
have_seqnum = false;
} else
continue;
if (n_list >= n_allocated) {
struct vacuum_info *j;
n_allocated = MAX(n_allocated * 2U, 8U);
j = realloc(list, n_allocated * sizeof(struct vacuum_info));
if (!j) {
free(p);
r = -ENOMEM;
goto finish;
}
list = j;
}
list[n_list].filename = p;
list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
list[n_list].seqnum = seqnum;
list[n_list].realtime = realtime;
list[n_list].seqnum_id = seqnum_id;
list[n_list].have_seqnum = have_seqnum;
sum += list[n_list].usage;
n_list ++;
}
if (n_list > 0)
qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
for(i = 0; i < n_list; i++) {
struct statvfs ss;
if (fstatvfs(dirfd(d), &ss) < 0) {
r = -errno;
goto finish;
}
if (sum <= max_use &&
(uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free)
break;
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
log_info("Deleted archived journal %s/%s.", directory, list[i].filename);
sum -= list[i].usage;
} else if (errno != ENOENT)
log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
}
finish:
for (i = 0; i < n_list; i++)
free(list[i].filename);
free(list);
if (d)
closedir(d);
return r;
}
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
uint64_t i, n;
uint64_t q, xor_hash = 0;
int r;
EntryItem *items;
dual_timestamp ts;
assert(from);
assert(to);
assert(o);
assert(p);
if (!to->writable)
return -EPERM;
ts.monotonic = le64toh(o->entry.monotonic);
ts.realtime = le64toh(o->entry.realtime);
if (to->tail_entry_monotonic_valid &&
ts.monotonic < le64toh(to->header->tail_entry_monotonic))
return -EINVAL;
n = journal_file_entry_n_items(o);
items = alloca(sizeof(EntryItem) * n);
for (i = 0; i < n; i++) {
uint64_t l, h;
le64_t le_hash;
size_t t;
void *data;
Object *u;
q = le64toh(o->entry.items[i].object_offset);
le_hash = o->entry.items[i].hash;
r = journal_file_move_to_object(from, OBJECT_DATA, q, &o);
if (r < 0)
return r;
if (le_hash != o->data.hash)
return -EBADMSG;
l = le64toh(o->object.size) - offsetof(Object, data.payload);
t = (size_t) l;
/* We hit the limit on 32bit machines */
if ((uint64_t) t != l)
return -E2BIG;
if (o->object.flags & OBJECT_COMPRESSED) {
#ifdef HAVE_XZ
uint64_t rsize;
if (!uncompress_blob(o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize))
return -EBADMSG;
data = from->compress_buffer;
l = rsize;
#else
return -EPROTONOSUPPORT;
#endif
} else
data = o->data.payload;
r = journal_file_append_data(to, data, l, &u, &h);
if (r < 0)
return r;
xor_hash ^= le64toh(u->data.hash);
items[i].object_offset = htole64(h);
items[i].hash = u->data.hash;
r = journal_file_move_to_object(from, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
}
return journal_file_append_entry_internal(to, &ts, xor_hash, items, n, seqnum, ret, offset);
}
void journal_default_metrics(JournalMetrics *m, int fd) {
uint64_t fs_size = 0;
struct statvfs ss;
char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX];
assert(m);
assert(fd >= 0);
if (fstatvfs(fd, &ss) >= 0)
fs_size = ss.f_frsize * ss.f_blocks;
if (m->max_use == (uint64_t) -1) {
if (fs_size > 0) {
m->max_use = PAGE_ALIGN(fs_size / 10); /* 10% of file system size */
if (m->max_use > DEFAULT_MAX_USE_UPPER)
m->max_use = DEFAULT_MAX_USE_UPPER;
if (m->max_use < DEFAULT_MAX_USE_LOWER)
m->max_use = DEFAULT_MAX_USE_LOWER;
} else
m->max_use = DEFAULT_MAX_USE_LOWER;
} else {
m->max_use = PAGE_ALIGN(m->max_use);
if (m->max_use < JOURNAL_FILE_SIZE_MIN*2)
m->max_use = JOURNAL_FILE_SIZE_MIN*2;
}
if (m->max_size == (uint64_t) -1) {
m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */
if (m->max_size > DEFAULT_MAX_SIZE_UPPER)
m->max_size = DEFAULT_MAX_SIZE_UPPER;
} else
m->max_size = PAGE_ALIGN(m->max_size);
if (m->max_size < JOURNAL_FILE_SIZE_MIN)
m->max_size = JOURNAL_FILE_SIZE_MIN;
if (m->max_size*2 > m->max_use)
m->max_use = m->max_size*2;
if (m->min_size == (uint64_t) -1)
m->min_size = JOURNAL_FILE_SIZE_MIN;
else {
m->min_size = PAGE_ALIGN(m->min_size);
if (m->min_size < JOURNAL_FILE_SIZE_MIN)
m->min_size = JOURNAL_FILE_SIZE_MIN;
if (m->min_size > m->max_size)
m->max_size = m->min_size;
}
if (m->keep_free == (uint64_t) -1) {
if (fs_size > 0) {
m->keep_free = PAGE_ALIGN(fs_size / 20); /* 5% of file system size */
if (m->keep_free > DEFAULT_KEEP_FREE_UPPER)
m->keep_free = DEFAULT_KEEP_FREE_UPPER;
} else
m->keep_free = DEFAULT_KEEP_FREE;
}
log_info("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s",
format_bytes(a, sizeof(a), m->max_use),
format_bytes(b, sizeof(b), m->max_size),
format_bytes(c, sizeof(c), m->min_size),
format_bytes(d, sizeof(d), m->keep_free));
}
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) {
assert(f);
assert(from || to);
if (from) {
if (f->header->head_entry_realtime == 0)
return -ENOENT;
*from = le64toh(f->header->head_entry_realtime);
}
if (to) {
if (f->header->tail_entry_realtime == 0)
return -ENOENT;
*to = le64toh(f->header->tail_entry_realtime);
}
return 1;
}
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, usec_t *from, usec_t *to) {
char t[9+32+1] = "_BOOT_ID=";
Object *o;
uint64_t p;
int r;
assert(f);
assert(from || to);
sd_id128_to_string(boot_id, t + 9);
r = journal_file_find_data_object(f, t, strlen(t), &o, &p);
if (r <= 0)
return r;
if (le64toh(o->data.n_entries) <= 0)
return 0;
if (from) {
r = journal_file_move_to_object(f, OBJECT_ENTRY, le64toh(o->data.entry_offset), &o);
if (r < 0)
return r;
*from = le64toh(o->entry.monotonic);
}
if (to) {
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
r = generic_array_get_plus_one(f,
le64toh(o->data.entry_offset),
le64toh(o->data.entry_array_offset),
le64toh(o->data.n_entries)-1,
&o, NULL);
if (r <= 0)
return r;
*to = le64toh(o->entry.monotonic);
}
return 1;
}
bool journal_file_rotate_suggested(JournalFile *f) {
assert(f);
/* If we gained new header fields we gained new features,
* hence suggest a rotation */
if (le64toh(f->header->header_size) < sizeof(Header)) {
log_debug("%s uses an outdated header, suggesting rotation.", f->path);
return true;
}
/* Let's check if the hash tables grew over a certain fill
* level (75%, borrowing this value from Java's hash table
* implementation), and if so suggest a rotation. To calculate
* the fill level we need the n_data field, which only exists
* in newer versions. */
if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Data hash table of %s has a fill level at %.1f (%llu of %llu items, %llu file size, %llu bytes per hash table item), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
(unsigned long long) le64toh(f->header->n_data),
(unsigned long long) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)),
(unsigned long long) (f->last_stat.st_size),
(unsigned long long) (f->last_stat.st_size / le64toh(f->header->n_data)));
return true;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Field hash table of %s has a fill level at %.1f (%llu of %llu items), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
(unsigned long long) le64toh(f->header->n_fields),
(unsigned long long) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)));
return true;
}
return false;
}