bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "lib.h"
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen#include "array.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ioloop.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "file-dotlock.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "nfs-workarounds.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "read-full.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "write-full.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mmap-util.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-index-private.h"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen#include "mail-index-modseq.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-transaction-log-private.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
1d738cce754bc64bbc66d3355ebdaf3f6eac55f1Timo Sirainen#define LOG_PREFETCH IO_BLOCK_SIZE
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainenstatic int
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen bool *retry_r, const char **reason_r);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenstatic void
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainenlog_file_set_syscall_error(struct mail_transaction_log_file *file,
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen const char *function)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen{
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen file->filepath, function);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen}
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic void
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenmail_transaction_log_mark_corrupted(struct mail_transaction_log_file *file)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen{
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen unsigned int offset =
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen offsetof(struct mail_transaction_log_header, indexid);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen int flags;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file) ||
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen file->log->index->readonly)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen return;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen /* indexid=0 marks the log file as corrupted. we opened the file with
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen O_APPEND, and now we need to drop it for pwrite() to work (at least
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen in Linux) */
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen flags = fcntl(file->fd, F_GETFL, 0);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (flags < 0) {
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen file->filepath, "fcntl(F_GETFL)");
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen return;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen }
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (fcntl(file->fd, F_SETFL, flags & ~O_APPEND) < 0) {
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen file->filepath, "fcntl(F_SETFL)");
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen return;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen }
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen sizeof(file->hdr.indexid), offset) < 0) {
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen file->filepath, "pwrite()");
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen }
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen}
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *fmt, ...)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_list va;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen file->corrupted = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->hdr.indexid = 0;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen mail_transaction_log_mark_corrupted(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_start(va, fmt);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_index_set_error(file->log->index,
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen "Corrupted transaction log file %s seq %u: %s "
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen "(sync_offset=%"PRIuUOFF_T")",
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen file->filepath, file->hdr.file_seq,
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen t_strdup_vprintf(fmt, va), file->sync_offset);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_end(va);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct mail_transaction_log_file *
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *path)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file *file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file = i_new(struct mail_transaction_log_file, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log = log;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath = i_strdup(path);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->fd = -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_transaction_log_file *file = *_file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file **p;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int old_errno = errno;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *_file = NULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
da4376093d4e1b26b14ea1e945689fb7056fe0a0Timo Sirainen i_assert(!file->locked);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (*p == file) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *p = file->next;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file == file->log->head)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->head = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek buffer_free(&file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_base != NULL) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "munmap()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->fd != -1) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (close(file->fd) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "close()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_free(file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_free(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen errno = old_errno;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenmail_transaction_log_file_skip_to_head(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log *log = file->log;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index_map *map = log->index->map;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen const struct mail_index_modseq_header *modseq_hdr;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen uoff_t head_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (map == NULL || file->hdr.file_seq != map->hdr.log_file_seq ||
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen map->hdr.log_file_head_offset == 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* we can get a valid log offset from index file. initialize
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen sync_offset from it so we don't have to read the whole log
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file from beginning. */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen head_offset = map->hdr.log_file_head_offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen modseq_hdr = mail_index_map_get_modseq_header(map);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (head_offset < file->hdr.hdr_size) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_set_error(log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "%s: log_file_head_offset too small",
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen log->index->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->sync_offset = file->hdr.hdr_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else if (modseq_hdr == NULL && file->hdr.initial_modseq == 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* modseqs not used yet */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_offset = head_offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_highest_modseq = 0;
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen } else if (modseq_hdr == NULL ||
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen modseq_hdr->log_seq != file->hdr.file_seq) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* highest_modseq not synced, start from beginning */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_offset = file->hdr.hdr_size;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else if (modseq_hdr->log_offset > head_offset) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_set_error(log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "%s: modseq_hdr.log_offset too large",
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen log->index->filepath);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_offset = file->hdr.hdr_size;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* start from where we last stopped tracking modseqs */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_offset = modseq_hdr->log_offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_highest_modseq = modseq_hdr->highest_modseq;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (file->hdr.file_seq == log->index->map->hdr.log_file_seq) {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->saved_tail_offset =
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen log->index->map->hdr.log_file_tail_offset;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->saved_tail_sync_offset = file->saved_tail_offset;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen }
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen if (file->saved_tail_offset > file->max_tail_offset)
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen file->max_tail_offset = file->saved_tail_offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic void
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct mail_transaction_log_file **p;
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char *reason;
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen bool retry;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_offset = file->hdr.hdr_size;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_transaction_log_file_skip_to_head(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* insert it to correct position */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if ((*p)->hdr.file_seq > file->hdr.file_seq)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->next = *p;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *p = file;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen if (file->buffer != NULL) {
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen /* if we read any unfinished data, make sure the buffer gets
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen truncated. */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen (void)mail_transaction_log_file_sync(file, &retry, &reason);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen buffer_set_used_size(file->buffer,
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen file->sync_offset - file->buffer_offset);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_header *hdr)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_index *index = log->index;
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen struct mail_transaction_log_file *file;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen i_assert(index->indexid != 0);
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(hdr);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->indexid = log->index->indexid;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->create_stamp = ioloop_time;
d61f31663f3debf9e49d1e0d8ef3c9fb13aad6c4Martti Rannanjärvi#ifndef WORDS_BIGENDIAN
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen hdr->compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen#endif
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (index->fd != -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* not creating index - make sure we have latest header */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (!index->mapping) {
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen if (mail_index_map(index,
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return -1;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen } else {
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* if we got here from mapping, the .log file is
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen corrupted. use whatever values we got from index
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen file */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (index->map != NULL) {
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen hdr->prev_file_seq = index->map->hdr.log_file_seq;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen hdr->prev_file_offset = index->map->hdr.log_file_head_offset;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen hdr->file_seq = index->map->hdr.log_file_seq + 1;
b6612c334604eeb27e1ca2bd804ac66dcbc2eaadTimo Sirainen hdr->initial_modseq =
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_map_modseq_get_highest(index->map);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->file_seq = 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen if (hdr->initial_modseq == 0) {
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen /* modseq tracking in log files is required for many reasons
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen nowadays, even if per-message modseqs aren't enabled in
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen dovecot.index. */
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen hdr->initial_modseq = 1;
1ff03d2244dd08effadfecec365bec28793a1aa0Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (log->head != NULL) {
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen /* make sure the sequence always increases to avoid crashes
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen later. this catches the buggy case where two processes
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen happen to replace the same log file. */
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen for (file = log->head->next; file != NULL; file = file->next) {
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen if (hdr->file_seq <= file->hdr.file_seq)
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen hdr->file_seq = file->hdr.file_seq + 1;
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen }
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (hdr->file_seq <= log->head->hdr.file_seq) {
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen /* make sure the sequence grows */
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen hdr->file_seq = log->head->hdr.file_seq+1;
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen }
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (hdr->initial_modseq < log->head->sync_highest_modseq) {
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen /* this should be always up-to-date */
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen hdr->initial_modseq = log->head->sync_highest_modseq;
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct mail_transaction_log_file *
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file *file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file = mail_transaction_log_file_alloc(log, MEMORY_LOG_NAME);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_init_hdr(log, &file->hdr) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_free(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset = sizeof(file->hdr);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_add_to_list(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen struct dotlock_settings dotlock_set;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->dotlock_count > 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else {
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen mail_transaction_log_get_dotlock_set(file->log, &dotlock_set);
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen ret = file_dotlock_create(&dotlock_set, file->filepath, 0,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen &file->log->dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->dotlock_count++;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = TRUE;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen file->lock_created = time(NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "file_dotlock_create()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen "Timeout (%us) while waiting for "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "dotlock for transaction log file %s",
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen dotlock_set.timeout, file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->index->index_lock_timeout = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (--file->log->dotlock_count > 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "file_dotlock_delete()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Dotlock was lost for transaction log file %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_transaction_log_file_lock(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen unsigned int lock_timeout_secs;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->locked)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return mail_transaction_log_file_dotlock(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen if (file->log->index->readonly) {
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen mail_index_set_error(file->log->index,
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen "Index is read-only, can't write-lock %s",
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen file->filepath);
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen return -1;
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen }
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->file_lock == NULL);
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen lock_timeout_secs = I_MIN(MAIL_TRANSACTION_LOG_LOCK_TIMEOUT,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen file->log->index->max_lock_timeout_secs);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen F_WRLCK, lock_timeout_secs,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen &file->file_lock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = TRUE;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen file->lock_created = time(NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "mail_index_wait_lock_fd()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen "Timeout (%us) while waiting for lock for "
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen "transaction log file %s%s",
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen lock_timeout_secs, file->filepath,
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen file_lock_find(file->fd, file->log->index->lock_method, F_WRLCK));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->index->index_lock_timeout = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file,
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen const char *lock_reason)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen unsigned int lock_time;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!file->locked)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = FALSE;
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen file->locked_sync_offset_updated = FALSE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen lock_time = time(NULL) - file->lock_created;
4eccf5310af7bed72cd6f7a559a93165c516e514Timo Sirainen if (lock_time >= MAIL_TRANSACTION_LOG_LOCK_WARN_SECS && lock_reason != NULL) {
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen i_warning("Transaction log file %s was locked for %u seconds (%s)",
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen file->filepath, lock_time, lock_reason);
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen }
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)mail_transaction_log_file_undotlock(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file_unlock(&file->file_lock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainenstatic ssize_t
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainenmail_transaction_log_file_read_header(struct mail_transaction_log_file *file)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen{
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen void *dest;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen size_t pos, dest_size;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ssize_t ret;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen i_assert(file->buffer == NULL && file->mmap_base == NULL);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&file->hdr);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen if (file->last_size < mmap_get_page_size() && file->last_size > 0) {
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen /* just read the entire transaction log to memory.
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen note that if some of the data hasn't been fully committed
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen yet (hdr.size=0), the buffer must be truncated later */
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->buffer_offset = 0;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen dest_size = file->last_size;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen dest = buffer_append_space_unsafe(file->buffer, dest_size);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen } else {
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen /* read only the header */
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen dest = &file->hdr;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen dest_size = sizeof(file->hdr);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen /* it's not necessarily an error to read less than wanted header size,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen since older versions of the log format used smaller headers. */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen pos = 0;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen do {
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ret = pread(file->fd, PTR_OFFSET(dest, pos),
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen dest_size - pos, pos);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (ret > 0)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen pos += ret;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen } while (ret > 0 && pos < dest_size);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen if (file->buffer != NULL) {
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen buffer_set_used_size(file->buffer, pos);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen memcpy(&file->hdr, file->buffer->data,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen I_MIN(pos, sizeof(file->hdr)));
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen }
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen return ret < 0 ? -1 : (ssize_t)pos;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen}
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainenstatic int
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainenmail_transaction_log_file_fail_dupe(struct mail_transaction_log_file *file)
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen{
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen int ret;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* mark the old file corrupted. we can't safely remove
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen it from the list however, so return failure. */
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->hdr.indexid = 0;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (strcmp(file->filepath, file->log->head->filepath) != 0) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* only mark .2 corrupted, just to make sure we don't lose any
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen changes from .log in case we're somehow wrong */
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen mail_transaction_log_mark_corrupted(file);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen ret = 0;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen } else {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen ret = -1;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (!file->corrupted) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->corrupted = TRUE;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen mail_index_set_error(file->log->index,
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen "Transaction log %s: "
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen "duplicate transaction log sequence (%u)",
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->filepath, file->hdr.file_seq);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen return ret;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen}
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bool ignore_estale)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file *f;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (file->corrupted)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return 0;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen ret = mail_transaction_log_file_read_header(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (errno != ESTALE || !ignore_estale)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "pread()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* incompatible version - fix silently */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return 0;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (ret < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "unexpected end of file while reading header");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen const unsigned int hdr_version =
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&file->hdr);
e0f4fbf127b192667c62af7875c4f2ca294b6c7aTimo Sirainen if (MAIL_TRANSACTION_LOG_VERSION_HAVE(hdr_version, COMPAT_FLAGS)) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* we have compatibility flags */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen enum mail_index_header_compat_flags compat_flags = 0;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
debc93e622751c6c09e8105e504c5833f1ca0d6dMartti Rannanjärvi#ifndef WORDS_BIGENDIAN
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen#endif
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (file->hdr.compat_flags != compat_flags) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* architecture change */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen mail_index_set_error(file->log->index,
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen "Rebuilding index file %s: "
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen "CPU architecture changed",
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen file->log->index->filepath);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return 0;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Header size too small");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.hdr_size < sizeof(file->hdr)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen shouldn't have filled */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sizeof(file->hdr) - file->hdr.hdr_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.indexid == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* corrupted */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen file->corrupted = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Transaction log file %s: marked corrupted",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen if (file->log->index->indexid != 0 &&
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen !file->log->index->initial_create) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* index file was probably just rebuilt and we don't
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen know about it yet */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
e653e88f7058237047a98313140d67d40cb56b74Aki Tuomi "indexid changed: %u -> %u",
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen file->log->index->indexid, file->hdr.indexid);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* creating index file. since transaction log is created
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen first, use the indexid in it to create the main index
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen to avoid races. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->index->indexid = file->hdr.indexid;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure we already don't have a file with the same sequence
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen opened. it shouldn't happen unless the old log file was
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen corrupted. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainen if (f->hdr.file_seq == file->hdr.file_seq) {
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen if (strcmp(f->filepath, f->log->head->filepath) != 0) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* old "f" is the .log.2 */
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen return mail_transaction_log_file_fail_dupe(f);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen } else {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* new "file" is probably the .log.2 */
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen return mail_transaction_log_file_fail_dupe(file);
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->sync_highest_modseq = file->hdr.initial_modseq;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenmail_transaction_log_file_stat(struct mail_transaction_log_file *file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bool ignore_estale)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct stat st;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (fstat(file->fd, &st) < 0) {
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen if (!ESTALE_FSTAT(errno) || !ignore_estale)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->st_dev = st.st_dev;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->st_ino = st.st_ino;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->last_mtime = st.st_mtime;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->last_size = st.st_size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic bool
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenmail_transaction_log_file_is_dupe(struct mail_transaction_log_file *file)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_transaction_log_file *tmp;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (tmp = file->log->files; tmp != NULL; tmp = tmp->next) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (tmp->st_ino == file->st_ino &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen CMP_DEV_T(tmp->st_dev, file->st_dev))
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return FALSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenstatic void log_write_ext_hdr_init_data(struct mail_index *index, buffer_t *buf)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen const struct mail_index_registered_ext *rext;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_transaction_header *hdr;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_transaction_ext_intro *intro;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_transaction_ext_hdr_update *ext_hdr;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen unsigned int hdr_offset;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen rext = array_idx(&index->extensions, index->ext_hdr_init_id);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen /* introduce the extension */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr_offset = buf->used;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr = buffer_append_space_unsafe(buf, sizeof(*hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr->type = MAIL_TRANSACTION_EXT_INTRO;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro = buffer_append_space_unsafe(buf, sizeof(*intro));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro->ext_id = (uint32_t)-1;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro->hdr_size = rext->hdr_size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro->record_size = rext->record_size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro->record_align = rext->record_align;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen intro->name_size = strlen(rext->name);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen buffer_append(buf, rext->name, intro->name_size);
5921647936e3d9a2dc60c0e49c66dd33efca234dTimo Sirainen if (buf->used % 4 != 0)
5921647936e3d9a2dc60c0e49c66dd33efca234dTimo Sirainen buffer_append_zero(buf, 4 - buf->used % 4);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr = buffer_get_space_unsafe(buf, hdr_offset, sizeof(*hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr->size = mail_index_uint32_to_offset(buf->used - hdr_offset);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen /* add the extension header data */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr_offset = buf->used;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr = buffer_append_space_unsafe(buf, sizeof(*hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr->type = MAIL_TRANSACTION_EXT_HDR_UPDATE;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen ext_hdr = buffer_append_space_unsafe(buf, sizeof(*ext_hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen ext_hdr->size = rext->hdr_size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen buffer_append(buf, index->ext_hdr_init_data, rext->hdr_size);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr = buffer_get_space_unsafe(buf, hdr_offset, sizeof(*hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen hdr->size = mail_index_uint32_to_offset(buf->used - hdr_offset);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log_file *file,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int new_fd, bool reset,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct dotlock **dotlock)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_index *index = file->log->index;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct stat st;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *path2;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen buffer_t *writebuf;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int fd, ret;
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen bool rename_existing, need_lock;
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen need_lock = file->log->head != NULL && file->log->head->locked;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen if (fcntl(new_fd, F_SETFL, O_APPEND) < 0) {
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen log_file_set_syscall_error(file, "fcntl(O_APPEND)");
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen return -1;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen }
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (file->log->nfs_flush) {
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen /* although we check also mtime and file size below, it's done
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen only to fix broken log files. we don't bother flushing
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen attribute cache just for that. */
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen nfs_flush_file_handle_cache(file->filepath);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* log creation is locked now - see if someone already created it.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen note that if we're rotating, we need to keep the log locked until
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen the file has been rewritten. and because fcntl() locks are stupid,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if we go and open()+close() the file and we had it already opened,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen its locks are lost. so we use stat() to check if the file has been
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen recreated, although it almost never is. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (reset)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen rename_existing = FALSE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (nfs_safe_stat(file->filepath, &st) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (errno != ENOENT) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "stat()");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen rename_existing = FALSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else if (st.st_ino == file->st_ino &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen CMP_DEV_T(st.st_dev, file->st_dev) &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* inode/dev checks are enough when we're rotating the file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen but not when we're replacing a broken log file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen st.st_mtime == file->last_mtime &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (uoff_t)st.st_size == file->last_size) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* no-one else recreated the file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen rename_existing = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* recreated. use the file if its header is ok */
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen fd = nfs_safe_open(file->filepath, O_RDWR | O_APPEND);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (fd == -1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ENOENT) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "open()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = fd;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->last_size = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_file_read_hdr(file,
347acd14d8da653ce3757b3e29981326502bed6bTimo Sirainen FALSE) > 0 &&
347acd14d8da653ce3757b3e29981326502bed6bTimo Sirainen mail_transaction_log_file_stat(file, FALSE) == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* yes, it was ok */
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen file_dotlock_delete(dotlock);
8cd0a1a2200e65cd134d03fe3f93ec02f1746359Timo Sirainen mail_transaction_log_file_add_to_list(file);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = -1;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (close(fd) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "close()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen rename_existing = FALSE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (index->fd == -1 && !rename_existing) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen /* creating the initial index */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen reset = TRUE;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (reset) {
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen /* don't reset modseqs. if we're reseting due to rebuilding
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen indexes we'll probably want to keep uidvalidity and in such
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen cases we really don't want to shrink modseqs. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->hdr.prev_file_seq = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->hdr.prev_file_offset = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi writebuf = t_buffer_create(128);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen buffer_append(writebuf, &file->hdr, sizeof(file->hdr));
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (index->ext_hdr_init_data != NULL && reset)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen log_write_ext_hdr_init_data(index, writebuf);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (write_full(new_fd, writebuf->data, writebuf->used) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "write_full()");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (file->log->index->fsync_mode == FSYNC_MODE_ALWAYS) {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen /* the header isn't important, so don't bother calling
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen fdatasync() unless it's required */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (fdatasync(new_fd) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "fdatasync()");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = new_fd;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen if (need_lock && ret == 0) {
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen /* we'll need to preserve the lock */
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen if (mail_transaction_log_file_lock(file) < 0)
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen ret = -1;
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen }
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if we return -1 the dotlock deletion code closes the fd */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* keep two log files */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (rename_existing) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* rename() would be nice and easy way to do this, except then
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen there's a race condition between the rename and
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file_dotlock_replace(). during that time the log file
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen doesn't exist, which could cause problems. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen path2 = t_strconcat(file->filepath, ".2", NULL);
39087f589d24f3072f220c2ed4528ee323f129ffTimo Sirainen if (i_unlink_if_exists(path2) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* try to link() anyway */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
9716b2665ee3938d3dfe64bda44d7c3ae3b55d30Timo Sirainen if (nfs_safe_link(file->filepath, path2, FALSE) < 0 &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen errno != ENOENT && errno != EEXIST) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, path2);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* ignore the error. we don't care that much about the
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen second log file and we're going to overwrite this
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen first one. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen /* NOTE: here's a race condition where both .log and .log.2
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen point to the same file. our reading code should ignore that
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen though by comparing the inodes. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file_dotlock_replace(dotlock,
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0) {
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen /* need to unlock to avoid assert-crash in
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen mail_transaction_log_file_free() */
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen mail_transaction_log_file_unlock(file, "creation failed");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
ce2312763f6b5fd2da8bfb20847b87f29b063fa8Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* success */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->fd = new_fd;
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen mail_transaction_log_file_add_to_list(file);
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen
1bea995196e46157e495a78b8f93780c576b3ef8Timo Sirainen i_assert(!need_lock || file->locked);
e1ad2d13f5f154ee975eed5c8e7f1a7823082685Timo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen bool reset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_index *index = file->log->index;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen struct dotlock_settings new_dotlock_set;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct dotlock *dotlock;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mode_t old_mask;
e1ad2d13f5f154ee975eed5c8e7f1a7823082685Timo Sirainen int fd, ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen if (file->log->index->readonly) {
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen mail_index_set_error(index,
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen "Can't create log file %s: Index is read-only",
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen file->filepath);
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen return -1;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen if (index->indexid == 0) {
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen mail_index_set_error(index,
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen "Can't create log file %s: Index is marked corrupted",
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen file->filepath);
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen return -1;
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen }
57dd2621d4230bc2e06c69a4b9f8cf8f0ff2bc93Timo Sirainen
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen mail_transaction_log_get_dotlock_set(file->log, &new_dotlock_set);
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen new_dotlock_set.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* With dotlocking we might already have path.lock created, so this
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen filename has to be different. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen old_mask = umask(index->mode ^ 0666);
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen fd = file_dotlock_open(&new_dotlock_set, file->filepath, 0, &dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen umask(old_mask);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (fd == -1) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "file_dotlock_open()");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen mail_index_fchown(index, fd, file_dotlock_get_lock_path(dotlock));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen is for the existing file */
e1ad2d13f5f154ee975eed5c8e7f1a7823082685Timo Sirainen ret = mail_transaction_log_file_create2(file, fd, reset, &dotlock);
e1ad2d13f5f154ee975eed5c8e7f1a7823082685Timo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (dotlock != NULL)
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen file_dotlock_delete(&dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
e1ad2d13f5f154ee975eed5c8e7f1a7823082685Timo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen const char **reason_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen struct mail_index *index = file->log->index;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bool ignore_estale;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0;; i++) {
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen if (!index->readonly) {
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen file->fd = nfs_safe_open(file->filepath,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen O_RDWR | O_APPEND);
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen } else {
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDONLY);
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen }
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen if (file->fd == -1 && errno == EACCES) {
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDONLY);
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen index->readonly = TRUE;
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen }
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen if (file->fd == -1) {
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen if (errno == ENOENT) {
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen *reason_r = "File doesn't exist";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "open()");
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen *reason_r = t_strdup_printf("open() failed: %m");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ignore_estale = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_file_stat(file, ignore_estale) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = -1;
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen else if (mail_transaction_log_file_is_dupe(file)) {
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen /* probably our already opened .log file has been
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen renamed to .log.2 and we're trying to reopen it.
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen also possible that hit a race condition where .log
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen and .log.2 are linked. */
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen *reason_r = "File is already open";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_read_hdr(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ignore_estale);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret > 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* success */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* corrupted */
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen if (index->readonly) {
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen /* don't delete */
39087f589d24f3072f220c2ed4528ee323f129ffTimo Sirainen } else {
39087f589d24f3072f220c2ed4528ee323f129ffTimo Sirainen i_unlink_if_exists(file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen *reason_r = "File is corrupted";
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ESTALE ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* syscall error */
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen *reason_r = t_strdup_printf("fstat() failed: %m");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* ESTALE - try again */
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek buffer_free(&file->buffer);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_add_to_list(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenlog_file_track_mailbox_sync_offset_hdr(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const void *data, unsigned int trans_size,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **error_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_header_update *u = data;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_index_header *ihdr;
537598efa668f2277b429bfe35a342a7036e04d0Timo Sirainen const unsigned int size = trans_size - sizeof(struct mail_transaction_header);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const unsigned int offset_pos =
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen offsetof(struct mail_index_header, log_file_tail_offset);
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_tail_offset);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen uint32_t tail_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen i_assert(offset_size == sizeof(tail_offset));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *error_r = "header update extends beyond record size";
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *error_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (u->offset <= offset_pos &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen u->offset + u->size >= offset_pos + offset_size) {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen memcpy(&tail_offset,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen sizeof(tail_offset));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (tail_offset < file->saved_tail_offset) {
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen /* ignore shrinking tail offsets */
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen return 1;
537598efa668f2277b429bfe35a342a7036e04d0Timo Sirainen } else if (tail_offset > file->sync_offset + trans_size) {
537598efa668f2277b429bfe35a342a7036e04d0Timo Sirainen mail_transaction_log_file_set_corrupted(file,
537598efa668f2277b429bfe35a342a7036e04d0Timo Sirainen "log_file_tail_offset %u goes past sync offset %"PRIuUOFF_T,
537598efa668f2277b429bfe35a342a7036e04d0Timo Sirainen tail_offset, file->sync_offset + trans_size);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen } else {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->saved_tail_offset = tail_offset;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (tail_offset > file->max_tail_offset)
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->max_tail_offset = tail_offset;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen return 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainenstatic bool
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainenflag_updates_have_non_internal(const struct mail_transaction_flag_update *u,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen unsigned int count, unsigned int version)
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen{
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen /* Hide internal flags from modseqs if the log file's version
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen is new enough. This allows upgrading without the modseqs suddenly
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen shrinking. */
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen if (!MAIL_TRANSACTION_LOG_VERSION_HAVE(version, HIDE_INTERNAL_MODSEQS))
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen return TRUE;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen for (unsigned int i = 0; i < count; i++) {
ace341ac567376f37ded043c4c0f2c46b9aaecb1Timo Sirainen if (!MAIL_TRANSACTION_FLAG_UPDATE_IS_INTERNAL(&u[i]))
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen return TRUE;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen }
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen return FALSE;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen}
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenvoid mail_transaction_update_modseq(const struct mail_transaction_header *hdr,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen const void *data, uint64_t *cur_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen unsigned int version)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen uint32_t trans_size;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_assert(trans_size != 0);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (*cur_modseq != 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* tracking modseqs */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen MAIL_TRANSACTION_EXT_INTRO) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* modseqs not tracked yet. see if this is a modseq
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen extension introduction. */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen const struct mail_transaction_ext_intro *intro = data;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen const unsigned int modseq_ext_len =
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen strlen(MAIL_INDEX_MODSEQ_EXT_NAME);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (intro->name_size == modseq_ext_len &&
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen memcmp(intro + 1, MAIL_INDEX_MODSEQ_EXT_NAME,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen modseq_ext_len) == 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* modseq tracking started */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen *cur_modseq += 1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
eea8f295efb50d5ae6cfe056b20faa65b542a823Timo Sirainen return;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* not tracking modseqs */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen return;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen /* NOTE: keep in sync with mail_index_transaction_get_highest_modseq() */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen case MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT:
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen case MAIL_TRANSACTION_EXPUNGE_GUID | MAIL_TRANSACTION_EXPUNGE_PROT:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* ignore expunge requests */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen break;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
f784d5bb8edbec88829524135cfa100129f5384dTimo Sirainen /* fall through */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen case MAIL_TRANSACTION_APPEND:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET:
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* these changes increase modseq */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen *cur_modseq += 1;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen break;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE: {
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen const struct mail_transaction_flag_update *rec = data;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen unsigned int count;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen count = (trans_size - sizeof(*hdr)) / sizeof(*rec);
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen if (flag_updates_have_non_internal(rec, count, version))
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen *cur_modseq += 1;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen break;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen }
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen case MAIL_TRANSACTION_MODSEQ_UPDATE: {
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen const struct mail_transaction_modseq_update *rec, *end;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen end = CONST_PTR_OFFSET(data, trans_size - sizeof(*hdr));
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen for (rec = data; rec < end; rec++) {
76959d3d6fed45d5f5e1397fcdcf09a5adb87f24Timo Sirainen uint64_t modseq = ((uint64_t)rec->modseq_high32 << 32) |
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen rec->modseq_low32;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (*cur_modseq < modseq)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen *cur_modseq = modseq;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenstatic struct modseq_cache *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenmodseq_cache_hit(struct mail_transaction_log_file *file, unsigned int idx)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct modseq_cache cache;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (idx > 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* @UNSAFE: move it to top */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cache = file->modseq_cache[idx];
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen memmove(file->modseq_cache + 1, file->modseq_cache,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sizeof(*file->modseq_cache) * idx);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[0] = cache;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return &file->modseq_cache[0];
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenstatic struct modseq_cache *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenmodseq_cache_get_offset(struct mail_transaction_log_file *file, uoff_t offset)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen unsigned int i, best = UINT_MAX;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen for (i = 0; i < N_ELEMENTS(file->modseq_cache); i++) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (offset < file->modseq_cache[i].offset)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen continue;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (file->modseq_cache[i].offset == 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (offset == file->modseq_cache[i].offset) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* exact cache hit */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return modseq_cache_hit(file, i);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (best == UINT_MAX ||
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[i].offset <
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[best].offset)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen best = i;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (best == UINT_MAX)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return &file->modseq_cache[best];
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenstatic struct modseq_cache *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenmodseq_cache_get_modseq(struct mail_transaction_log_file *file, uint64_t modseq)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen unsigned int i, best = UINT_MAX;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen for (i = 0; i < N_ELEMENTS(file->modseq_cache); i++) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (modseq < file->modseq_cache[i].highest_modseq)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen continue;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (file->modseq_cache[i].offset == 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (modseq == file->modseq_cache[i].highest_modseq) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* exact cache hit */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return modseq_cache_hit(file, i);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (best == UINT_MAX ||
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[i].highest_modseq <
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[best].highest_modseq)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen best = i;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (best == UINT_MAX)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return &file->modseq_cache[best];
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenlog_get_synced_record(struct mail_transaction_log_file *file, uoff_t *offset,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen const struct mail_transaction_header **hdr_r,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen const char **error_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen const struct mail_transaction_header *hdr;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint32_t trans_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen hdr = CONST_PTR_OFFSET(file->buffer->data,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *offset - file->buffer_offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* we've already synced this record at some point. it should
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen be valid. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (trans_size < sizeof(*hdr) ||
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *offset - file->buffer_offset + trans_size > file->buffer->used) {
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen *error_r = t_strdup_printf(
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen "Transaction log corrupted unexpectedly at "
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen "%"PRIuUOFF_T": Invalid size %u (type=%x)",
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen *offset, trans_size, hdr->type);
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *error_r);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *offset += trans_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *hdr_r = hdr;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_file_get_highest_modseq_at(
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_transaction_log_file *file,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen uoff_t offset, uint64_t *highest_modseq_r,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen const char **error_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen const struct mail_transaction_header *hdr;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct modseq_cache *cache;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uoff_t cur_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint64_t cur_modseq;
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char *reason;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(offset <= file->sync_offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (offset == file->sync_offset) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *highest_modseq_r = file->sync_highest_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cache = modseq_cache_get_offset(file, offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (cache == NULL) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* nothing usable in cache - scan from beginning */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_offset = file->hdr.hdr_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_modseq = file->hdr.initial_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else if (cache->offset == offset) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* exact cache hit */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *highest_modseq_r = cache->highest_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* use cache to skip over some records */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_offset = cache->offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_modseq = cache->highest_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen ret = mail_transaction_log_file_map(file, cur_offset, offset, &reason);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret <= 0) {
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen *error_r = t_strdup_printf(
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen "Failed to map transaction log %s for getting modseq "
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen "at offset=%"PRIuUOFF_T" with start_offset=%"PRIuUOFF_T": %s",
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen file->filepath, offset, cur_offset, reason);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(cur_offset >= file->buffer_offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(cur_offset + file->buffer->used >= offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen while (cur_offset < offset) {
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen if (log_get_synced_record(file, &cur_offset, &hdr, error_r) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return- 1;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen mail_transaction_update_modseq(hdr, hdr + 1, &cur_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&file->hdr));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* @UNSAFE: cache the value */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen memmove(file->modseq_cache + 1, file->modseq_cache,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sizeof(*file->modseq_cache) *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (N_ELEMENTS(file->modseq_cache) - 1));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[0].offset = cur_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[0].highest_modseq = cur_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *highest_modseq_r = cur_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainenstatic int
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainenget_modseq_next_offset_at(struct mail_transaction_log_file *file,
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen uint64_t modseq, bool use_highest,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen uoff_t *cur_offset, uint64_t *cur_modseq,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen uoff_t *next_offset_r)
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen{
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen const struct mail_transaction_header *hdr;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen const char *reason;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen int ret;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen /* make sure we've read until end of file. this is especially important
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen with non-head logs which might only have been opened without being
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen synced. */
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen ret = mail_transaction_log_file_map(file, *cur_offset, (uoff_t)-1, &reason);
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen if (ret <= 0) {
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen mail_index_set_error(file->log->index,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen "Failed to map transaction log %s for getting offset "
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "for modseq=%"PRIu64" with start_offset=%"PRIuUOFF_T": %s",
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi file->filepath, modseq, *cur_offset, reason);
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen return -1;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen }
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen /* check sync_highest_modseq again in case sync_offset was updated */
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen if (modseq >= file->sync_highest_modseq && use_highest) {
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen *next_offset_r = file->sync_offset;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen return 0;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen }
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen i_assert(*cur_offset >= file->buffer_offset);
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen while (*cur_offset < file->sync_offset) {
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen if (log_get_synced_record(file, cur_offset, &hdr, &reason) < 0) {
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen mail_index_set_error(file->log->index,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen "%s: %s", file->filepath, reason);
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen return -1;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen }
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen mail_transaction_update_modseq(hdr, hdr + 1, cur_modseq,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&file->hdr));
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen if (*cur_modseq >= modseq)
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen break;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen }
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen return 1;
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen}
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_file_get_modseq_next_offset(
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_transaction_log_file *file,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint64_t modseq, uoff_t *next_offset_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct modseq_cache *cache;
6c77165712bcac2fd93a6a1b7c9460a3482a66b7Timo Sirainen uoff_t cur_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint64_t cur_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen int ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
2485e31c7ef8ac6656dd8b9def439fc6cf6f7598Timo Sirainen if (modseq == file->sync_highest_modseq) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *next_offset_r = file->sync_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
08e57864511e8ec1df7494fb69d8044aae778650Timo Sirainen if (modseq == file->hdr.initial_modseq) {
08e57864511e8ec1df7494fb69d8044aae778650Timo Sirainen *next_offset_r = file->hdr.hdr_size;
08e57864511e8ec1df7494fb69d8044aae778650Timo Sirainen return 0;
08e57864511e8ec1df7494fb69d8044aae778650Timo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cache = modseq_cache_get_modseq(file, modseq);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (cache == NULL) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* nothing usable in cache - scan from beginning */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_offset = file->hdr.hdr_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_modseq = file->hdr.initial_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else if (cache->highest_modseq == modseq) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* exact cache hit */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *next_offset_r = cache->offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* use cache to skip over some records */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_offset = cache->offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen cur_modseq = cache->highest_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen if ((ret = get_modseq_next_offset_at(file, modseq, TRUE, &cur_offset,
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen &cur_modseq, next_offset_r)) <= 0)
7e78f1cfc10cc0540134b5507e08524a0fdd5c93Timo Sirainen return ret;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (cur_offset == file->sync_offset) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* if we got to sync_offset, cur_modseq should be
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sync_highest_modseq */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_set_error(file->log->index,
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen "%s: Transaction log modseq tracking is corrupted - fixing",
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen file->filepath);
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen /* retry getting the offset by reading from the beginning
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen of the file */
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen cur_offset = file->hdr.hdr_size;
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen cur_modseq = file->hdr.initial_modseq;
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen ret = get_modseq_next_offset_at(file, modseq, FALSE,
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen &cur_offset, &cur_modseq,
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen next_offset_r);
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen if (ret < 0)
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen return -1;
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen i_assert(ret != 0);
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen /* get it fixed on the next sync */
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen file->log->index->need_recreate = TRUE;
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen file->need_rotate = TRUE;
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen /* clear cache, since it's unreliable */
5e03576913a0030de6f8d22c79e353a968a6a35fTimo Sirainen memset(file->modseq_cache, 0, sizeof(file->modseq_cache));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* @UNSAFE: cache the value */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen memmove(file->modseq_cache + 1, file->modseq_cache,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sizeof(*file->modseq_cache) *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (N_ELEMENTS(file->modseq_cache) - 1));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[0].offset = cur_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->modseq_cache[0].highest_modseq = cur_modseq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *next_offset_r = cur_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenstatic int
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenlog_file_track_sync(struct mail_transaction_log_file *file,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen const struct mail_transaction_header *hdr,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen unsigned int trans_size, const char **error_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen const void *data = hdr + 1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen int ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen mail_transaction_update_modseq(hdr, hdr + 1, &file->sync_highest_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&file->hdr));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0)
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen return 1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* external transactions: */
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen case MAIL_TRANSACTION_HEADER_UPDATE:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* see if this updates mailbox_sync_offset */
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, data,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen trans_size, error_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret != 0)
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen return ret < 0 ? -1 : 1;
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen break;
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen case MAIL_TRANSACTION_INDEX_DELETED:
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (file->sync_offset < file->index_undeleted_offset)
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen break;
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen file->log->index->index_deleted = TRUE;
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen file->log->index->index_delete_requested = FALSE;
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen file->index_deleted_offset = file->sync_offset + trans_size;
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen break;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen case MAIL_TRANSACTION_INDEX_UNDELETED:
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (file->sync_offset < file->index_deleted_offset)
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen break;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen file->log->index->index_deleted = FALSE;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen file->log->index->index_delete_requested = FALSE;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen file->index_undeleted_offset = file->sync_offset + trans_size;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen break;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen case MAIL_TRANSACTION_BOUNDARY: {
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen const struct mail_transaction_boundary *boundary =
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen (const void *)(hdr + 1);
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen size_t wanted_buffer_size;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen wanted_buffer_size = file->sync_offset - file->buffer_offset +
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen boundary->size;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen if (wanted_buffer_size > file->buffer->used) {
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen /* the full transaction hasn't been written yet */
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen return 0;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen }
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen break;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (file->max_tail_offset == file->sync_offset) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* external transactions aren't synced to mailbox. we can
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen update mailbox sync offset to skip this transaction to
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen avoid re-reading it at the next sync. */
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen file->max_tail_offset += trans_size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen bool *retry_r, const char **reason_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const struct mail_transaction_header *hdr;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const void *data;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen struct stat st;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size, avail;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t trans_size = 0;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen *retry_r = FALSE;
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen data = buffer_get_data(file->buffer, &size);
57549c98995eb312013f5d98ea6ccf25175a6f18Timo Sirainen if (file->buffer_offset + size < file->sync_offset) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
57549c98995eb312013f5d98ea6ccf25175a6f18Timo Sirainen "log file shrank (%"PRIuUOFF_T" < %"PRIuUOFF_T")",
57549c98995eb312013f5d98ea6ccf25175a6f18Timo Sirainen file->buffer_offset + (uoff_t)size, file->sync_offset);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
9018d05c381d859f4b856a5ea0cad3538092ba1cTimo Sirainen /* fix the sync_offset to avoid crashes later on */
9018d05c381d859f4b856a5ea0cad3538092ba1cTimo Sirainen file->sync_offset = file->buffer_offset + size;
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return 0;
57549c98995eb312013f5d98ea6ccf25175a6f18Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr = CONST_PTR_OFFSET(data, file->sync_offset -
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (trans_size == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* unfinished */
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (trans_size < sizeof(*hdr)) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "hdr.size too small (%u)", trans_size);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->sync_offset - file->buffer_offset + trans_size > size)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* transaction has been fully written */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen if ((ret = log_file_track_sync(file, hdr, trans_size, reason_r)) <= 0) {
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen if (ret < 0)
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return 0;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen break;
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->sync_offset += trans_size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen if (file->mmap_base != NULL && !file->locked) {
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen /* Now that all the mmaped pages have page faulted, check if
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen the file had changed while doing that. Only after the last
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen page has faulted, the size returned by fstat() can be
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen trusted. Otherwise it might point to a page boundary while
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen the next page is still being written.
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen Without this check we might see partial transactions,
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen sometimes causing "Extension record updated without intro
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen prefix" errors. */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (fstat(file->fd, &st) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "fstat()");
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("fstat() failed: %m");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen if ((uoff_t)st.st_size != file->last_size) {
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen file->last_size = st.st_size;
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen *retry_r = TRUE;
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = "File size changed - retrying";
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen return 0;
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen }
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen }
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen avail = file->sync_offset - file->buffer_offset;
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen if (avail != size) {
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen /* There's more data than we could sync at the moment. If the
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen last record's size wasn't valid, we can't know if it will
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen be updated unless we've locked the log. */
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen if (file->locked) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = "Unexpected garbage at EOF";
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* The size field will be updated soon */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen mail_index_flush_read_cache(file->log->index, file->filepath,
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen file->fd, file->locked);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen if (file->next != NULL &&
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen file->hdr.file_seq == file->next->hdr.prev_file_seq &&
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen file->next->hdr.prev_file_offset != file->sync_offset) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen "Invalid transaction log size "
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen "(%"PRIuUOFF_T" vs %u): %s", file->sync_offset,
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen file->log->head->hdr.prev_file_offset, file->filepath);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return 0;
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen }
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainenstatic int
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainenmail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen uoff_t offset, const char **reason_r)
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen{
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen void *data;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen size_t size;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen ssize_t ret;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen size = file->buffer_offset - offset;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen ret = pread_full(file->fd, data, size, offset);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (ret > 0) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* success */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->buffer_offset -= size;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 1;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* failure. don't leave ourself to inconsistent state */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen buffer_set_used_size(file->buffer, file->buffer->used - size);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (ret == 0) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = "file shrank unexpectedly";
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen } else if (errno == ESTALE) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* log file was deleted in NFS server, fail silently */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("read() failed: %m");
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen } else {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "pread()");
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("read() failed: %m");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen}
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainenstatic int
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainenmail_transaction_log_file_read_more(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **reason_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen void *data;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uint32_t read_offset;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen ssize_t ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d5d7890bd9b282eb1092fc788a2432a6c79a7adTimo Sirainen read_offset = file->buffer_offset + file->buffer->used;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen do {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen read_offset += ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size = read_offset - file->buffer_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_set_used_size(file->buffer, size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } while (ret > 0 || (ret < 0 && errno == EINTR));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->last_size = read_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen if (ret < 0) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("pread() failed: %m");
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen if (errno == ESTALE) {
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen /* log file was deleted in NFS server, fail silently */
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen return 0;
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "pread()");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen return 1;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen}
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainenstatic bool
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainenmail_transaction_log_file_need_nfs_flush(struct mail_transaction_log_file *file)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen{
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen const struct mail_index_header *hdr = &file->log->index->map->hdr;
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen uoff_t max_offset = file->last_size;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen if (file->next != NULL &&
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen file->hdr.file_seq == file->next->hdr.prev_file_seq &&
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen file->next->hdr.prev_file_offset != max_offset) {
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen /* we already have a newer log file which says that we haven't
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen synced the entire file. */
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return TRUE;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen }
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen if (file->hdr.file_seq == hdr->log_file_seq &&
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen max_offset < hdr->log_file_head_offset)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return TRUE;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return FALSE;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen}
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainenstatic int
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen uoff_t start_offset, bool nfs_flush,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **reason_r)
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen{
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen bool retry;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen int ret;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen i_assert(file->mmap_base == NULL);
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
837ea26bce080f166b2ec90d901faeff58beb22bTimo Sirainen /* NFS: if file isn't locked, we're optimistic that we can read enough
837ea26bce080f166b2ec90d901faeff58beb22bTimo Sirainen data without flushing attribute cache. if after reading we notice
837ea26bce080f166b2ec90d901faeff58beb22bTimo Sirainen that we really should have read more, flush the cache and try again.
837ea26bce080f166b2ec90d901faeff58beb22bTimo Sirainen if file is locked, the attribute cache was already flushed when
837ea26bce080f166b2ec90d901faeff58beb22bTimo Sirainen refreshing the log. */
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (file->log->nfs_flush && nfs_flush) {
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen if (!file->locked)
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen nfs_flush_attr_cache_unlocked(file->filepath);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen else
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen nfs_flush_attr_cache_fd_locked(file->filepath, file->fd);
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen }
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen if (file->buffer != NULL && file->buffer_offset > start_offset) {
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen /* we have to insert missing data to beginning of buffer */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset, reason_r);
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen if (ret <= 0)
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen return ret;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen }
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen if (file->buffer == NULL) {
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen file->buffer =
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen file->buffer_offset = start_offset;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen }
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen if ((ret = mail_transaction_log_file_read_more(file, reason_r)) <= 0)
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen ;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen else if (file->log->nfs_flush && !nfs_flush &&
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen mail_transaction_log_file_need_nfs_flush(file)) {
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen /* we didn't read enough data. flush and try again. */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen return mail_transaction_log_file_read(file, start_offset, TRUE, reason_r);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen } else if ((ret = mail_transaction_log_file_sync(file, &retry, reason_r)) == 0) {
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen i_assert(!retry); /* retry happens only with mmap */
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen }
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen buffer_set_used_size(file->buffer,
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen file->sync_offset - file->buffer_offset);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainenstatic bool
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainenlog_file_map_check_offsets(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen uoff_t start_offset, uoff_t end_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **reason_r)
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen{
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen struct stat st, st2;
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (start_offset > file->sync_offset) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* broken start offset */
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen *reason_r = t_strdup_printf(
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen "%s: start_offset (%"PRIuUOFF_T") > "
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen "current sync_offset (%"PRIuUOFF_T")",
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen file->filepath, start_offset, file->sync_offset);
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen return FALSE;
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen }
6d2f4a21bdfab2901b01f292b397256328e631beTimo Sirainen
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen if (fstat(file->fd, &st) < 0) {
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen log_file_set_syscall_error(file, "fstat()");
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen st.st_size = -1;
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen }
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "%s: start_offset (%"PRIuUOFF_T") > "
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen "current sync_offset (%"PRIuUOFF_T"), file size=%"PRIuUOFF_T,
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen file->filepath, start_offset, file->sync_offset,
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen st.st_size);
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen if (stat(file->filepath, &st2) == 0) {
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen if (st.st_ino != st2.st_ino) {
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen *reason_r = t_strdup_printf(
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen "%s, file unexpectedly replaced", *reason_r);
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen }
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen } else if (errno == ENOENT) {
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen *reason_r = t_strdup_printf(
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen "%s, file unexpectedly deleted", *reason_r);
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen } else {
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen log_file_set_syscall_error(file, "stat()");
0a1a4e586ced13635fc1b8f2c78c94cb35ef645aTimo Sirainen }
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen return FALSE;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "%s: end_offset (%"PRIuUOFF_T") > "
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "current sync_offset (%"PRIuUOFF_T")",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->filepath, start_offset, file->sync_offset);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen return FALSE;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen return TRUE;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen}
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainenstatic int
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainenmail_transaction_log_file_mmap(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **reason_r)
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen{
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek /* we may have switched to mmaping */
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek buffer_free(&file->buffer);
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_size = file->last_size;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ, MAP_SHARED,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->fd, 0);
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (file->mmap_base == MAP_FAILED) {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_base = NULL;
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi if (ioloop_time != file->last_mmap_error_time) {
9c7e81a1f5e629efa2324c6c22ce02f6f6e9c792Martti Rannanjärvi file->last_mmap_error_time = ioloop_time;
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi log_file_set_syscall_error(file, t_strdup_printf(
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi "mmap(size=%"PRIuSIZE_T")", file->mmap_size));
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi }
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("mmap(size=%"PRIuSIZE_T") failed: %m",
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen file->mmap_size);
8e90ca575864d29d0ded6ea71cd9747aab0a38f4Martti Rannanjärvi file->mmap_size = 0;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (file->mmap_size > mmap_get_page_size()) {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (madvise(file->mmap_base, file->mmap_size,
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen MADV_SEQUENTIAL) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "madvise()");
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_const_data(&file->mmap_buffer,
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen file->mmap_base, file->mmap_size);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen file->buffer = &file->mmap_buffer;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->buffer_offset = 0;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen return 0;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen}
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainenstatic void
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainenmail_transaction_log_file_munmap(struct mail_transaction_log_file *file)
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen{
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (file->mmap_base == NULL)
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen return;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
8409959d66804dc963bc6fcdcc9a01da0d56a978Timo Sirainen i_assert(file->buffer != NULL);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "munmap()");
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_base = NULL;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_size = 0;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&file->buffer);
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen}
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainenstatic int
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainenmail_transaction_log_file_map_mmap(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen uoff_t start_offset, const char **reason_r)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen{
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen struct stat st;
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen bool retry;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen int ret;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen /* we are going to mmap() this file, but it's not necessarily
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen mmaped currently. */
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen i_assert(file->buffer_offset == 0 || file->mmap_base == NULL);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen i_assert(file->mmap_size == 0 || file->mmap_base != NULL);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (fstat(file->fd, &st) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen log_file_set_syscall_error(file, "fstat()");
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf("fstat() failed: %m");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen file->last_size = st.st_size;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if ((uoff_t)st.st_size < file->sync_offset) {
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = t_strdup_printf(
a32ac1ad1ccc36d29f30b017197bb2a57feacd1aTimo Sirainen "file size shrank (%"PRIuUOFF_T" < %"PRIuUOFF_T")",
a32ac1ad1ccc36d29f30b017197bb2a57feacd1aTimo Sirainen (uoff_t)st.st_size, file->sync_offset);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen mail_transaction_log_file_set_corrupted(file, "%s", *reason_r);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return 0;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen }
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
7184b2f499d5b8977671e92310148da72170edcaTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset &&
c026384095b555cc86d032b043d107cc371aacecTimo Sirainen (uoff_t)st.st_size == file->buffer_offset + file->buffer->used) {
c026384095b555cc86d032b043d107cc371aacecTimo Sirainen /* we already have the whole file mapped */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen if ((ret = mail_transaction_log_file_sync(file, &retry, reason_r)) != 0 ||
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen !retry)
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return ret;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen /* size changed, re-mmap */
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen }
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen do {
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen mail_transaction_log_file_munmap(file);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen if (file->last_size - start_offset < mmap_get_page_size()) {
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen /* just reading the file is probably faster */
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen return mail_transaction_log_file_read(file,
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen start_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen FALSE, reason_r);
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen }
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen if (mail_transaction_log_file_mmap(file, reason_r) < 0)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return -1;
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen ret = mail_transaction_log_file_sync(file, &retry, reason_r);
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen } while (retry);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
f9f30736bc6e4cf535085824e7e124506fe2dbbbTimo Sirainen return ret;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen}
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen uoff_t start_offset, uoff_t end_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char **reason_r)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
6e1a910370a55db38b97e12026cd69b2dab38befTimo Sirainen uoff_t map_start_offset = start_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.indexid == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* corrupted */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = "corrupted, indexid=0";
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen i_assert(start_offset >= file->hdr.hdr_size);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen i_assert(start_offset <= end_offset);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen i_assert(file->buffer == NULL || file->mmap_base != NULL ||
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen file->sync_offset >= file->buffer_offset + file->buffer->used);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen if (file->locked_sync_offset_updated && file == file->log->head &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen end_offset == (uoff_t)-1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we're not interested of going further than sync_offset */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen if (!log_file_map_check_offsets(file, start_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen end_offset, reason_r))
6f5d19886f36fb20777618ef9362be39d3dc4182Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(start_offset <= file->sync_offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen end_offset = file->sync_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* see if we already have it */
2d5d7890bd9b282eb1092fc788a2432a6c79a7adTimo Sirainen size = file->buffer->used;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer_offset + size >= end_offset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen if (file->locked) {
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen /* set this only when we've synced to end of file while locked
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen (either end_offset=(uoff_t)-1 or we had to read anyway) */
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen file->locked_sync_offset_updated = TRUE;
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen }
f34227d18c5458c5a8bfe576ecf8d7bb4e75162eTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
2dadd5dacee37d409fa699597bfddc03074e4853Timo Sirainen if (start_offset < file->buffer_offset || file->buffer == NULL) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* we had moved the log to memory but failed to read
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen the beginning of the log file */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen *reason_r = "Beginning of the log isn't available";
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return log_file_map_check_offsets(file, start_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen end_offset, reason_r) ? 1 : 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (start_offset > file->sync_offset)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_transaction_log_file_skip_to_head(file);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (start_offset > file->sync_offset) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen /* although we could just skip over the unwanted data, we have
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen to sync everything so that modseqs are calculated
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen correctly */
6e1a910370a55db38b97e12026cd69b2dab38befTimo Sirainen map_start_offset = file->sync_offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if ((file->log->index->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0)
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen ret = mail_transaction_log_file_map_mmap(file, map_start_offset, reason_r);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen else {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen mail_transaction_log_file_munmap(file);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen ret = mail_transaction_log_file_read(file, map_start_offset, FALSE, reason_r);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen i_assert(file->buffer == NULL || file->mmap_base != NULL ||
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen file->sync_offset >= file->buffer_offset + file->buffer->used);
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen if (ret <= 0)
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen return ret;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen i_assert(file->buffer != NULL);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen return log_file_map_check_offsets(file, start_offset, end_offset,
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen reason_r) ? 1 : 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainenint mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file *file)
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen{
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen const char *error;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen buffer_t *buf;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen int ret = 0;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen return 0;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen if (file->mmap_base != NULL) {
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen /* just copy to memory */
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen i_assert(file->buffer_offset == 0);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen buf = buffer_create_dynamic(default_pool, file->mmap_size);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen buffer_append(buf, file->mmap_base, file->mmap_size);
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&file->buffer);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->buffer = buf;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen /* and lose the mmap */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "munmap()");
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->mmap_base = NULL;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen } else if (file->buffer_offset != 0) {
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen /* we don't have the full log in the memory. read it. */
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen ret = mail_transaction_log_file_read(file, 0, FALSE, &error);
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen if (ret <= 0) {
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen mail_index_set_error(file->log->index,
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen "%s: Failed to read into memory: %s", file->filepath, error);
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen }
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen file->last_size = 0;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (close(file->fd) < 0)
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen log_file_set_syscall_error(file, "close()");
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->fd = -1;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen i_free(file->filepath);
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen file->filepath = i_strdup(file->log->filepath);
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen return ret < 0 ? -1 : 0;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen}