mail-transaction-log-file.c revision 902222fb0928d1701f20a384b73f327b1d9a15dd
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->hdr.indexid = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /*FIXME: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()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }*/
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_start(va, fmt);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen t_push();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Corrupted transaction log file %s: %s",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen t_pop();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_end(va);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->log != NULL && file->log->index->map != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* this may have happened because of broken index.
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen make sure it's ok. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_index_fsck(file->log->index);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
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)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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 &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr.log_file_index_int_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. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->sync_offset = map->hdr.log_file_index_int_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->mailbox_sync_saved_offset =
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr.log_file_mailbox_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 unsigned int lock_id = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (log->index->indexid == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen log->index->indexid = ioloop_time;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen &lock_id) <= 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (index->hdr != NULL) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->prev_file_seq = index->hdr->log_file_seq;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->prev_file_offset = index->hdr->log_file_index_int_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->file_seq = index->hdr->log_file_seq + 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->file_seq = 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (index->fd != -1)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_unlock(index, lock_id);
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,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Timeout while waiting for release of "
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,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen F_WRLCK, MAIL_INDEX_LOCK_SECS,
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
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 */
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) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->fd != -1) {
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,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "invalid indexid (%u != %u)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->hdr.indexid, file->log->index->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) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "old transaction log already opened (%u == %u)",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen f->hdr.file_seq, file->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,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int new_fd, 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
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. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen 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,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen FALSE) == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* yes, it was ok */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)file_dotlock_delete(dotlock);
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
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
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->fd = new_fd;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo 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 }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (link(file->filepath, path2) < 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
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file)
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 */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_file_create2(file, fd, &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 =
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen offsetof(struct mail_index_header, log_file_mailbox_offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_mailbox_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
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (sync_offset < file->mailbox_sync_saved_offset) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "mailbox_sync_offset shrinked");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->mailbox_sync_saved_offset = sync_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (sync_offset > file->mailbox_sync_max_offset)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->mailbox_sync_max_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
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_HEADER_UPDATE) != 0) {
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
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->mailbox_sync_max_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. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->mailbox_sync_max_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;
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 */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
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;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen avail = file->sync_offset - file->buffer_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (avail != size && avail >= sizeof(*hdr)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* record goes outside the file we've seen. or if
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen we're accessing the log file via unlocked mmaped
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen memory, it may be just that the memory was updated
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen after we checked the file size. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->locked || file->mmap_base == NULL) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (trans_size != 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "hdr.size too large (%u)", trans_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Unexpected garbage at EOF");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen // FIXME: here we probably want to flush NFS data cache
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainenstatic int
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen uoff_t offset)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen void *data;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uint32_t read_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->mmap_base == NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL && file->buffer_offset > offset) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we have to insert missing data to beginning of buffer */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size = file->buffer_offset - offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset -= size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = pread_full(file->fd, data, size, offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Unexpected end of file");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (errno == ESTALE) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log file was deleted in NFS server,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fail silently */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "pread()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer == NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer =
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset = offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* read all records */
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_sync(file) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* EOF */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_set_used_size(file->buffer,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->sync_offset - file->buffer_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (errno == ESTALE) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log file was deleted in NFS server, fail silently */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "pread()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo 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 struct stat st;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(start_offset <= end_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.indexid == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* corrupted */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (start_offset < file->hdr.hdr_size) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "offset (%"PRIuUOFF_T") < header size (%u)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen start_offset, file->hdr.hdr_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
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 */
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
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!index->mmap_disable) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fstat(file->fd, &st) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "fstat()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->last_size = st.st_size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (start_offset > (uoff_t)st.st_size) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "start_offset (%"PRIuUOFF_T") > file size "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "(%"PRIuUOFF_T")", start_offset,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (uoff_t)st.st_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_base != NULL &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (uoff_t)st.st_size == file->mmap_size &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset <= start_offset &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen end_offset == (uoff_t)-1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* it's all mmaped already */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_sync(file) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (file->mmap_base != NULL || !index->mmap_disable)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_free(file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = NULL;
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(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "munmap()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_base = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (index->mmap_disable) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret <= 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure we don't leave ourself in
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen inconsistent state */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_free(file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_size = st.st_size;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen MAP_SHARED, file->fd, 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_base == MAP_FAILED) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_base = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "mmap()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_size > mmap_get_page_size()) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (madvise(file->mmap_base, file->mmap_size,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen MADV_SEQUENTIAL) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, "madvise()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = buffer_create_const_data(default_pool,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_base,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->mmap_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_sync(file) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (start_offset > file->sync_offset) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "start_offset (%"PRIuUOFF_T") > current sync_offset "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "(%"PRIuUOFF_T")", start_offset, file->sync_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "end_offset (%"PRIuUOFF_T") > current sync_offset "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "(%"PRIuUOFF_T")", end_offset, file->sync_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
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);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo 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. */
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen (void)mail_transaction_log_file_read(file, 0);
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}