mail-transaction-log-file.c revision 7184b2f499d5b8977671e92310148da72170edca
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "lib.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ioloop.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "buffer.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"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-transaction-log-private.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#define LOG_PREFETCH 1024
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* indexid=0 marks the log file as corrupted */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sizeof(file->hdr.indexid),
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen offsetof(struct mail_transaction_log_header,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen indexid)) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, "pwrite()");
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_start(va, fmt);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_index_set_error(file->log->index,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "Corrupted transaction log file %s: %s",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_unlock(file);
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL)
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_base != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "munmap()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->fd != -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (close(file->fd) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "close()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log *log = file->log;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file **p;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index_map *map = log->index->map;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (map != NULL && file->hdr.file_seq == map->hdr.log_file_seq &&
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen map->hdr.log_file_head_offset != 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we can get a valid log offset from index file. initialize
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sync_offset from it so we don't have to read the whole log
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file from beginning. */
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (map->hdr.log_file_head_offset >= file->hdr.hdr_size)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen file->sync_offset = map->hdr.log_file_head_offset;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen else {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_index_set_error(log->index,
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen "%s: log_file_head_offset too small",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen log->index->filepath);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->sync_offset = file->hdr.hdr_size;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen file->saved_tail_offset = map->hdr.log_file_tail_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->sync_offset = file->hdr.hdr_size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* insert it to correct position */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (p = &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;
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;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen memset(hdr, 0, sizeof(*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;
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;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->file_seq = 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure the sequence grows */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr->file_seq = log->head->hdr.file_seq+1;
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{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->dotlock_count > 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen 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;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "file_dotlock_create()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
5707510e5d1c8aa79a0acf737ee1429caf3d59c2Timo Sirainen "Timeout while waiting for "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "dotlock for transaction log file %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen 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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, "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{
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->file_lock == NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
cc833a7a4e2258afdc834ace4bfe6579820a1df3Timo Sirainen F_WRLCK, MAIL_TRANSCATION_LOG_LOCK_TIMEOUT,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen &file->file_lock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "mail_index_wait_lock_fd()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Timeout while waiting for lock for transaction log file %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->index->index_lock_timeout = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!file->locked)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->locked = FALSE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_undotlock(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file_unlock(&file->file_lock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (errno != ESTALE || !ignore_estale) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "pread_full()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0) {
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* incompatible version - fix silently */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
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) {
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (file->log->index->indexid != 0) {
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,
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen "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) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (f->hdr.file_seq == file->hdr.file_seq) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* mark the old file corrupted. we can't safely remove
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen it from the list however, so return failure. */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_transaction_log_file_set_corrupted(f,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "duplicate transaction log sequence (%u)",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen f->hdr.file_seq);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
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) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ESTALE || !ignore_estale) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->filepath, "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
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
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;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int fd, ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen bool rename_existing;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen if (index->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) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ENOENT) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "stat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen fd = nfs_safe_open(file->filepath, O_RDWR);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (fd == -1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ENOENT) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->filepath, "open()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = fd;
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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)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;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (close(fd) < 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->filepath, "close()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen rename_existing = FALSE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (reset) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->hdr.prev_file_seq = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->hdr.prev_file_offset = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "write_full()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (index->nfs_flush) {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen /* the header isn't important, so don't bother calling
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen fdatasync() unless NFS is used */
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (fdatasync(new_fd) < 0) {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen "fdatasync()");
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen return -1;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = new_fd;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen if (file->log->head != NULL && file->log->head->locked) {
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);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlink(path2) < 0 && errno != ENOENT) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen path2);
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 }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file_dotlock_replace(dotlock,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* success */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->fd = new_fd;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_add_to_list(file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
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;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct dotlock *dotlock;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mode_t old_mask;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int fd;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = file_dotlock_open(&file->log->new_dotlock_settings,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, 0, &dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen umask(old_mask);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fd == -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "file_dotlock_open()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (index->gid != (gid_t)-1 &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fchown(fd, (uid_t)-1, index->gid) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "fchown()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)file_dotlock_delete(&dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen is for the existing file */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (mail_transaction_log_file_create2(file, fd, reset, &dotlock) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (dotlock != NULL)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)file_dotlock_delete(&dotlock);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bool check_existing)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bool ignore_estale;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0;; i++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDWR);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->fd == -1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno == ENOENT)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->filepath, "open()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo 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;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else if (check_existing &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_is_dupe(file))
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (unlink(file->filepath) < 0 && errno != ENOENT) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(file->log->index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "unlink(%s) failed: %m",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->filepath);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno != ESTALE ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* syscall error */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* ESTALE - try again */
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,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const void *data, unsigned int size)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_header_update *u = data;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_index_header *ihdr;
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);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t sync_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(offset_size == sizeof(sync_offset));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "header update extends beyond record size");
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) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen memcpy(&sync_offset,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sizeof(sync_offset));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (sync_offset < file->saved_tail_offset) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
f87702d8d147f66d3fb6c41e5695c67f6d00612eTimo Sirainen "log_file_tail_offset shrank");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen file->saved_tail_offset = sync_offset;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (sync_offset > file->max_tail_offset)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen file->max_tail_offset = sync_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenlog_file_track_mailbox_sync_offset(struct mail_transaction_log_file *file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_header *hdr,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int trans_size)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen MAIL_TRANSACTION_HEADER_UPDATE) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* see if this updates mailbox_sync_offset */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, hdr + 1,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen trans_size -
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sizeof(*hdr));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret < 0 ? -1 : 0;
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 }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
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;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen data = buffer_get_data(file->buffer, &size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->sync_offset < file->buffer_offset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->sync_offset = file->buffer_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "hdr.size too small (%u)", trans_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (log_file_track_mailbox_sync_offset(file, hdr,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen trans_size) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->sync_offset += trans_size;
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen trans_size = 0;
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. */
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen if (fstat(file->fd, &st) < 0) {
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen file->filepath,
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen "fstat()");
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen return -1;
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen }
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen if ((uoff_t)st.st_size != file->last_size) {
e777a43ec49dd968b9b6064030fb40ce9e14097eTimo Sirainen file->last_size = st.st_size;
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. */
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen if (trans_size != 0) {
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen /* pread()s or the above fstat() check for mmaps should
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen have guaranteed that this doesn't happen */
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen mail_transaction_log_file_set_corrupted(file,
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen "hdr.size too large (%u)", trans_size);
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen return -1;
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen } else if (file->locked) {
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen mail_transaction_log_file_set_corrupted(file,
b7c051d9dd7ec0526f3c2c1f09f00d3a61c6576dTimo Sirainen "Unexpected garbage at EOF");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo 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) {
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen mail_index_set_error(file->log->index,
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);
de14556e542b2a75a3a2118f76241f3c85313ebdTimo Sirainen return -1;
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,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen uoff_t offset)
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) {
f87702d8d147f66d3fb6c41e5695c67f6d00612eTimo Sirainen mail_transaction_log_file_set_corrupted(file, "file shrank");
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen } else if (errno == ESTALE) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* log file was deleted in NFS server, fail silently */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen } else {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->filepath, "pread()");
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return -1;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen}
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainenstatic int
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainenmail_transaction_log_file_read_more(struct mail_transaction_log_file *file)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen void *data;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uint32_t read_offset;
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen ssize_t ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
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) {
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen if (errno == ESTALE) {
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen /* log file was deleted in NFS server, fail silently */
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen return 0;
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen file->filepath, "pread()");
8c7000574087d5702cc3830e7f80c695ff8e9221Timo 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,
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen uoff_t start_offset, bool nfs_flush)
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen{
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. */
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen if (file->log->index->nfs_flush && nfs_flush) {
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen if (!file->locked)
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen nfs_flush_attr_cache_unlocked(file->filepath);
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen else {
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen nfs_flush_attr_cache_fd_locked(file->filepath,
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen file->fd);
470365df69b5a0b84146149e3ea1adcb27b1482eTimo Sirainen }
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 */
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset);
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
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen if ((ret = mail_transaction_log_file_read_more(file)) <= 0)
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen if (file->log->index->nfs_flush && !nfs_flush &&
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen mail_transaction_log_file_need_nfs_flush(file)) {
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen /* we didn't read enough data. flush and try again. */
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen return mail_transaction_log_file_read(file, start_offset, TRUE);
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen }
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if ((ret = mail_transaction_log_file_sync(file)) <= 0) {
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen i_assert(ret != 0); /* happens only with mmap */
7ab64f2a89e0256693a4f0f0d6c3da6daab27cdcTimo Sirainen return -1;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
8c7000574087d5702cc3830e7f80c695ff8e9221Timo 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);
8c7000574087d5702cc3830e7f80c695ff8e9221Timo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainenstatic int
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainenlog_file_map_check_offsets(struct mail_transaction_log_file *file,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen uoff_t start_offset, uoff_t end_offset)
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen{
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (start_offset > file->sync_offset) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* broken start offset */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_index_set_error(file->log->index,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "%s: start_offset (%"PRIuUOFF_T") > "
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "current sync_offset (%"PRIuUOFF_T")",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->filepath, start_offset, file->sync_offset);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_index_set_error(file->log->index,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "%s: end_offset (%"PRIuUOFF_T") > "
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "current sync_offset (%"PRIuUOFF_T")",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->filepath, start_offset, file->sync_offset);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 1;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen}
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainenstatic int
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainenmail_transaction_log_file_mmap(struct mail_transaction_log_file *file)
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen{
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (file->buffer != NULL) {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen /* in case we just switched to mmaping */
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&file->buffer);
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
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;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_size = 0;
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->filepath, "mmap()");
c131bf703b200890867f4c3839597ffdc7eba18dTimo 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,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen MADV_SEQUENTIAL) < 0) {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->filepath, "madvise()");
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->buffer = buffer_create_const_data(default_pool,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_base,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->mmap_size);
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
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen file->filepath, "munmap()");
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen }
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,
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen uoff_t start_offset)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen{
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen struct stat st;
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
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if (fstat(file->fd, &st) < 0) {
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen file->filepath, "fstat()");
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return -1;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen }
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen file->last_size = st.st_size;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if ((uoff_t)st.st_size < file->sync_offset) {
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen mail_transaction_log_file_set_corrupted(file,
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen "file size shrank");
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 */
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if ((ret = mail_transaction_log_file_sync(file)) < 0)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return 0;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if (ret > 0)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return 1;
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,
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen FALSE);
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen }
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if (mail_transaction_log_file_mmap(file) < 0)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return -1;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if ((ret = mail_transaction_log_file_sync(file)) < 0)
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return 0;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen } while (ret == 0);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return 1;
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen}
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uoff_t start_offset, uoff_t end_offset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_index *index = file->log->index;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.indexid == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* corrupted */
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);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (index->log_locked && file == file->log->head &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen end_offset == (uoff_t)-1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we're not interested of going further than sync_offset */
6f5d19886f36fb20777618ef9362be39d3dc4182Timo Sirainen if (log_file_map_check_offsets(file, start_offset,
6f5d19886f36fb20777618ef9362be39d3dc4182Timo Sirainen end_offset) == 0)
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 */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size = buffer_get_used_size(file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer_offset + size >= end_offset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (start_offset < file->buffer_offset) {
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* we had moved the log to memory but failed to read
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen the beginning of the log file */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen mail_index_set_error(index,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "%s: Beginning of the log isn't available",
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen file->filepath);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return 0;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return log_file_map_check_offsets(file, start_offset,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen end_offset);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen if (!index->mmap_disable)
b251b66e48ed682fa511b9dabc979807fc18f71bTimo Sirainen ret = mail_transaction_log_file_map_mmap(file, start_offset);
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen else {
c131bf703b200890867f4c3839597ffdc7eba18dTimo Sirainen mail_transaction_log_file_munmap(file);
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen ret = mail_transaction_log_file_read(file, start_offset, FALSE);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen return ret <= 0 ? ret :
47571dffa47750bd6188b9a846cea8c3b066753eTimo Sirainen log_file_map_check_offsets(file, start_offset, end_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainenvoid mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen *file)
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen{
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen buffer_t *buf;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen return;
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 */
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->filepath,
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen "munmap()");
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
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. */
d7363f0716a4ca8bf8d9af1fe277113c705739b0Timo Sirainen (void)mail_transaction_log_file_read(file, 0, FALSE);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen if (close(file->fd) < 0) {
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->filepath, "close()");
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen file->fd = -1;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen}