mail-transaction-log.c revision 97d1089f42026a767dc24a5eed1d34fceb1f71a1
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "lib.h"
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen#include "ioloop.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "buffer.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "file-lock.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "file-dotlock.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "read-full.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "write-full.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mmap-util.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-index-private.h"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen#include "mail-index-view-private.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-transaction-log-private.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "mail-transaction-util.h"
1d738cce754bc64bbc66d3355ebdaf3f6eac55f1Timo Sirainen#include "mail-index-transaction-private.h"
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen#include <stddef.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <sys/stat.h>
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen/* this lock should never exist for a long time.. */
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen#define LOG_DOTLOCK_TIMEOUT 30
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen#define LOG_DOTLOCK_STALE_TIMEOUT 0
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 300
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainenstruct mail_transaction_add_ctx {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct mail_transaction_log *log;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct mail_index_view *view;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen buffer_t *appends, *expunges;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen buffer_t *flag_updates, *cache_updates;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen};
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic struct mail_transaction_log_file *
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen const char *path);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen int lock_type);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic int
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen int lock_type);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainenvoid
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen const char *fmt, ...)
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen{
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen va_list va;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen file->hdr.indexid = 0;
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen sizeof(file->hdr.indexid), 0) < 0) {
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
e925f007930955f10fa8728509a44f7a53d2b13eTimo Sirainen file->filepath, "pwrite()");
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen }
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen va_start(va, fmt);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen t_push();
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen mail_index_set_error(file->log->index,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen "Corrupted transaction log file %s: %s",
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen t_pop();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen va_end(va);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#define INDEX_HAS_MISSING_LOGS(index, file) \
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen (index)->hdr->log_file_offset >= \
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sizeof(struct mail_transaction_log_header)) || \
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (file)->hdr.prev_file_offset == (index)->hdr->log_file_offset))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen struct mail_index *index = log->index;
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen struct mail_transaction_log_file *file;
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen unsigned int lock_id;
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen int ret;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_lock_head(log) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file = log->head;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->refcount++;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_lock_shared(index, TRUE, &lock_id);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_map(index, FALSE);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret <= 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else if (INDEX_HAS_MISSING_LOGS(index, file)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* broken - fix it by creating a new log file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_rotate(log, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (--file->refcount == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_logs_clean(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct mail_transaction_log *
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_open_or_create(struct mail_index *index)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log *log;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *path;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log = i_new(struct mail_transaction_log, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->index = index;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen path = t_strconcat(log->index->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen MAIL_TRANSACTION_LOG_PREFIX, NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->head = mail_transaction_log_file_open_or_create(log, path);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (log->head == NULL) {
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen i_free(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (index->fd != -1 &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen INDEX_HAS_MISSING_LOGS(index, log->head)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* head log file isn't same as head index file -
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen shouldn't happen except in race conditions. lock them and
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen check again - FIXME: missing error handling. */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen (void)mail_transaction_log_check_file_seq(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return log;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_views_close(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen log->head->refcount--;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_transaction_logs_clean(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->index->log = NULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_free(log);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen int lock_type)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen int ret;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (lock_type == F_UNLCK) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->lock_type = F_UNLCK;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (--file->log->dotlock_count > 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return 0;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = file_unlock_dotlock(file->filepath, &file->log->dotlock);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (ret < 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->filepath, "file_unlock_dotlock()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (ret == 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_set_error(file->log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "Dotlock was lost for transaction log file %s",
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen file->filepath);
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen return -1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return 0;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (file->log->dotlock_count > 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = 1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen else {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = file_lock_dotlock(file->filepath, NULL, FALSE,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen LOG_DOTLOCK_TIMEOUT,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen LOG_DOTLOCK_STALE_TIMEOUT,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen NULL, NULL, &file->log->dotlock);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0) {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->log->dotlock_count++;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->lock_type = F_WRLCK;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen return 0;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen }
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (ret < 0) {
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen file->filepath,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "file_lock_dotlock()");
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return -1;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen mail_index_set_error(file->log->index,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "Timeout while waiting for release of "
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen "dotlock for transaction log file %s",
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->filepath);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen file->log->index->index_lock_timeout = TRUE;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int lock_type)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (lock_type == F_UNLCK) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->lock_type != F_UNLCK);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen } else {
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen i_assert(file->lock_type == F_UNLCK);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen }
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen if (file->log->index->fcntl_locks_disable)
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen return mail_transaction_log_file_dotlock(file, lock_type);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen ret = file_wait_lock_full(file->fd, lock_type, DEFAULT_LOCK_TIMEOUT,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen NULL, NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret > 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->lock_type = lock_type;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen file->filepath,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "file_wait_lock()");
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 "%s fcntl() lock for transaction log file %s",
40ad2c4902e9d83557f2e8a4bff3d98fea2c8aa1Timo Sirainen lock_type == F_WRLCK ? "exclusive" : "shared",
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen file->filepath);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen file->log->index->index_lock_timeout = TRUE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainenstatic void
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenmail_transaction_log_file_close(struct mail_transaction_log_file *file)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen{
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (file->lock_type != F_UNLCK)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (file->buffer != NULL)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen buffer_free(file->buffer);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->mmap_base != NULL) {
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen file->filepath,
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen "munmap()");
b6612c334604eeb27e1ca2bd804ac66dcbc2eaadTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (close(file->fd) < 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, "close()");
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen }
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen i_free(file->filepath);
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen i_free(file);
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen}
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainenstatic int
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen struct stat *st)
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen{
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen int ret;
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen uint32_t old_size = file->hdr.used_size;
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (file->lock_type != F_UNLCK)
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen else {
e64d7b6f388fecd0c83a4f2acb54e30d5ac98c6cTimo Sirainen if (mail_transaction_log_file_lock(file, F_RDLCK) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we have to fstat() again since it may have changed after
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen locking. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fstat(file->fd, st) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "fstat()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = pread_full(file->fd, &file->hdr,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen sizeof(file->hdr), 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->last_mtime = st->st_mtime;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen // FIXME: handle ESTALE
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "pread_full()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
bdd7a96c363346f7c38f389791be1487ca08775bTimo 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 }
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen if (file->hdr.indexid == 0) {
bdd7a96c363346f7c38f389791be1487ca08775bTimo 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 }
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->log->index->fd == -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* creating index file, silently rebuild
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen transaction log as well */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* index file was probably just rebuilt and we don't know
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen about it yet */
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen mail_index_set_error(file->log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Transaction log file %s: invalid indexid (%u != %u)",
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen file->filepath, file->hdr.indexid,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->log->index->indexid);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.used_size > st->st_size) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "used_size (%u) > file size (%"PRIuUOFF_T")",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->hdr.used_size, (uoff_t)st->st_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->hdr.used_size < old_size) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "used_size (%u) < old_size (%u)",
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen file->hdr.used_size, old_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_create(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *path, dev_t dev, ino_t ino)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#define LOG_NEW_DOTLOCK_SUFFIX ".newlock"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_index *index = log->index;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_header hdr;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct stat st;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen unsigned int lock_id;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int fd, fd2, ret;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* With dotlocking we might already have path.lock created, so this
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen filename has to be different. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = file_dotlock_open(path, NULL, LOG_NEW_DOTLOCK_SUFFIX,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen LOG_DOTLOCK_TIMEOUT,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen LOG_DOTLOCK_STALE_TIMEOUT,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fd == -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, path,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "file_dotlock_open()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log creation is locked now - see if someone already created it */
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen fd2 = open(path, O_RDWR);
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen if (fd2 != -1) {
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen if ((ret = fstat(fd2, &st)) < 0) {
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen mail_index_file_set_syscall_error(index, path,
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen "fstat()");
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen } else if (st.st_dev == dev && st.st_ino == ino) {
1deffbbcd7affd2ec89284f3c644cc73db0a2b90Timo Sirainen /* same file, still broken */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return fd2;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)close(fd2);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd2 = -1;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else if (errno != ENOENT) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen mail_index_file_set_syscall_error(index, path, "open()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen memset(&hdr, 0, sizeof(hdr));
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen hdr.indexid = index->indexid;
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen hdr.used_size = sizeof(hdr);
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen
94cb0544ba0b6e249f20b76ad481bad27a633632Timo Sirainen if (index->fd != -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_lock_shared(index, TRUE, &lock_id) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr.prev_file_seq = index->hdr->log_file_seq;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr.prev_file_offset = index->hdr->log_file_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr.file_seq = index->hdr->log_file_seq+1;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo 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 */
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen hdr.file_seq = log->head->hdr.file_seq+1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index, path,
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen "write_full()");
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen return -1;
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen }
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen fd2 = dup(fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fd2 < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen mail_index_file_set_syscall_error(index, path, "dup()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* success */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return fd2;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen}
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainenstatic struct mail_transaction_log_file *
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainenmail_transaction_log_file_fd_open(struct mail_transaction_log *log,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen const char *path, int fd)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen{
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen struct mail_transaction_log_file **p;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen struct mail_transaction_log_file *file;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen struct stat st;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen int ret;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen if (fstat(fd, &st) < 0) {
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen mail_index_file_set_syscall_error(log->index, path, "fstat()");
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen return NULL;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen }
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->refcount = 1;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->log = log;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->filepath = i_strdup(path);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen file->fd = fd;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->lock_type = F_UNLCK;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen file->st_dev = st.st_dev;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen file->st_ino = st.st_ino;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen if (ret == 0) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen /* corrupted header */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen fd = mail_transaction_log_file_create(log, path,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen st.st_dev, st.st_ino);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen if (fd == -1)
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ret = -1;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen else if (fstat(fd, &st) < 0) {
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen "fstat()");
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen (void)close(fd);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen fd = -1;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen ret = -1;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (fd != -1) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen (void)close(file->fd);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->fd = fd;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->st_dev = st.st_dev;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen file->st_ino = st.st_ino;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen memset(&file->hdr, 0, sizeof(file->hdr));
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (ret <= 0) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen mail_transaction_log_file_close(file);
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen return NULL;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen for (p = &log->tail; *p != NULL; p = &(*p)->next) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if ((*p)->hdr.file_seq >= file->hdr.file_seq) {
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen /* log replaced with file having same sequence as
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen previous one. shouldn't happen unless previous
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen log file was corrupted.. */
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen break;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen }
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen *p = file;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic struct mail_transaction_log_file *
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *path)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int fd;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen fd = open(path, O_RDWR);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (fd == -1) {
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (errno != ENOENT) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "open()");
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen return NULL;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = mail_transaction_log_file_create(log, path, 0, 0);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (fd == -1)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return NULL;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return mail_transaction_log_file_fd_open(log, path, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file **p, *next;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen for (p = &log->tail; *p != NULL; ) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if ((*p)->refcount != 0)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen p = &(*p)->next;
40ad2c4902e9d83557f2e8a4bff3d98fea2c8aa1Timo Sirainen else {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen next = (*p)->next;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen mail_transaction_log_file_close(*p);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen *p = next;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen }
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (log->tail == NULL)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen log->head = NULL;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen}
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int lock_type)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file *file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct stat st;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int fd;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fstat(log->head->fd, &st) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(log->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->head->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "fstat()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fd = mail_transaction_log_file_create(log, log->head->filepath,
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen st.st_dev, st.st_ino);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (fd == -1)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file = mail_transaction_log_file_fd_open(log, log->head->filepath, fd);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file == NULL)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen if (lock_type != F_UNLCK) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_lock(file, lock_type) < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->refcount--;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_logs_clean(log);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return -1;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(file->lock_type == lock_type);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (--log->head->refcount == 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_logs_clean(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_transaction_log_file_lock(log->head, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(log->head != file);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->head = file;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainenstatic int mail_transaction_log_recreate(struct mail_transaction_log *log)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen{
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen unsigned int lock_id;
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen int ret;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen if (mail_index_lock_shared(log->index, TRUE, &lock_id) < 0)
4fcee755029b42c1f31227211290fa5047c00075Timo Sirainen return -1;
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_rotate(log, F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_unlock(log->index, lock_id);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int mail_transaction_log_refresh(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_transaction_log_file *file;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct stat st;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const char *path;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen path = t_strconcat(log->index->filepath,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen MAIL_TRANSACTION_LOG_PREFIX, NULL);
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen if (stat(path, &st) < 0) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen mail_index_file_set_syscall_error(log->index, path, "stat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (errno == ENOENT && log->head->lock_type == F_WRLCK) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* lost? */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return mail_transaction_log_recreate(log);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (log->head != NULL &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen log->head->st_ino == st.st_ino &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen log->head->st_dev == st.st_dev) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* same file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_file_read_hdr(log->head, &st);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret == 0 && log->head->lock_type == F_WRLCK) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* corrupted, recreate */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return mail_transaction_log_recreate(log);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret <= 0 ? -1 : 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file = mail_transaction_log_file_open_or_create(log, path);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file == NULL)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen i_assert(file->lock_type == F_UNLCK);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (log->head != NULL) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (--log->head->refcount == 0)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen mail_transaction_logs_clean(log);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen log->head = file;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return 0;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenint mail_transaction_log_file_find(struct mail_transaction_log *log,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen uint32_t file_seq,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_transaction_log_file **file_r)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_transaction_log_file *file;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (mail_transaction_log_refresh(log) < 0)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return -1;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
5921647936e3d9a2dc60c0e49c66dd33efca234dTimo Sirainen for (file = log->tail; file != NULL; file = file->next) {
5921647936e3d9a2dc60c0e49c66dd33efca234dTimo Sirainen if (file->hdr.file_seq == file_seq) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen *file_r = file;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return 1;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return 0;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenstatic int
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen uoff_t offset)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen void *data;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen size_t size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen int ret;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen i_assert(file->mmap_base == NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(offset <= file->hdr.used_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file->buffer != NULL && file->buffer_offset > offset) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo 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 = offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = pread_full(file->fd, data, size, offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0 && errno == ESTALE) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* log file was deleted in NFS server, fail silently */
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen ret = 0;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen }
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen if (ret <= 0)
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen return ret;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen }
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen if (file->buffer == NULL) {
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen size = file->hdr.used_size - offset;
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen file->buffer = buffer_create_dynamic(default_pool,
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen size, (size_t)-1);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen file->buffer_offset = offset;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen size = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen size = buffer_get_used_size(file->buffer);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->buffer_offset + size >= file->hdr.used_size) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* caller should have checked this.. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen offset = file->buffer_offset + size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen size = file->hdr.used_size - file->buffer_offset - size;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (size == 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return 1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = buffer_append_space_unsafe(file->buffer, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = pread_full(file->fd, data, size, offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret < 0 && errno == ESTALE) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* log file was deleted in NFS server, fail silently */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen uoff_t start_offset, uoff_t end_offset)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index *index = file->log->index;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen size_t size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct stat st;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret, use_mmap;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(start_offset <= end_offset);
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file->hdr.indexid == 0) {
347acd14d8da653ce3757b3e29981326502bed6bTimo Sirainen /* corrupted */
347acd14d8da653ce3757b3e29981326502bed6bTimo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen
8cd0a1a2200e65cd134d03fe3f93ec02f1746359Timo Sirainen /* with mmap_no_write we could alternatively just write to log with
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen msync() rather than pwrite(). that'd cause slightly more disk I/O,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen so rather use more memory. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen use_mmap = !index->mmap_disable && !index->mmap_no_write;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo 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;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (fstat(file->fd, &st) < 0) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (st.st_size == file->hdr.used_size &&
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen file->buffer_offset <= start_offset && end_offset == (uoff_t)-1) {
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen /* we've seen the whole file.. do we have all of it mapped? */
bf8f4f90cb5e5f32c2611ba3425557964b9c47fcTimo Sirainen size = file->buffer == NULL ? 0 :
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen buffer_get_used_size(file->buffer);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file->buffer_offset + size == file->hdr.used_size)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (file->buffer != NULL &&
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen (file->mmap_base != NULL || use_mmap)) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen buffer_free(file->buffer);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen file->buffer = NULL;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (file->mmap_base != NULL) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "munmap()");
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen file->mmap_base = NULL;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mail_transaction_log_file_read_hdr(file, &st) <= 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return -1;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (end_offset == (uoff_t)-1)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen end_offset = file->hdr.used_size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (start_offset < sizeof(file->hdr)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen "offset (%"PRIuUOFF_T") < header size (%"PRIuSIZE_T")",
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen start_offset, sizeof(file->hdr));
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen return -1;
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen }
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen if (end_offset > file->hdr.used_size) {
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen mail_transaction_log_file_set_corrupted(file,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "offset (%"PRIuUOFF_T") > used_size (%u)",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen end_offset, file->hdr.used_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!use_mmap) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret <= 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_file_set_syscall_error(index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->filepath, "pread_full()");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Unexpected EOF");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* make sure we don't leave ourself in
9716b2665ee3938d3dfe64bda44d7c3ae3b55d30Timo Sirainen inconsistent state */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file->buffer != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_free(file->buffer);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen file->mmap_size = file->hdr.used_size;
b222354c9553cd60b7dd418885e10c0473f73985Timo 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 file->buffer = buffer_create_const_data(default_pool, file->mmap_base,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen file->mmap_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->buffer_offset = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_file *file;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen int ret = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we want to get the head file locked. this is a bit racy,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen since by the time we have it locked a new log file may have been
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen created.
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen creating new log file requires locking the head file, so if we
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen can lock it and don't see another file, we can be sure no-one is
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen creating a new log at the moment */
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen for (;;) {
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen file = log->head;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen if (mail_transaction_log_file_lock(file, F_WRLCK) < 0)
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen return -1;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen file->refcount++;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen ret = mail_transaction_log_refresh(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (--file->refcount == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_logs_clean(log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file = NULL;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret == 0 && log->head == file) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen /* success */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen break;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen i_assert(log->head->lock_type == F_UNLCK);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (file != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_transaction_log_file_lock(file, F_UNLCK) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen if (ret < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* try again */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int mail_transaction_log_fix_appends(struct mail_transaction_log *log,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index_transaction *t)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct mail_transaction_log_view *sync_view;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_index_record *old, *old_end;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen struct mail_index_record *appends, *end, *rec, *dest;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen const struct mail_transaction_header *hdr;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen const void *data;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen size_t size;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen int ret, deleted = FALSE;
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen if (t->appends == NULL)
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen return 0;
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen appends = buffer_get_modifyable_data(t->appends, &size);
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen end = PTR_OFFSET(appends, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (appends == end)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen /* we'll just check that none of the appends are already in
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen transaction log. this could happen if we crashed before we had
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen a chance to update index file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sync_view = mail_transaction_log_view_open(log);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_view_set(sync_view, t->view->log_file_seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen t->view->log_file_offset,
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen log->head->hdr.file_seq,
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen log->head->hdr.used_size,
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen MAIL_TRANSACTION_TYPE_MASK);
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen while ((ret = mail_transaction_log_view_next(sync_view,
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen &hdr, &data, NULL)) == 1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) !=
b222354c9553cd60b7dd418885e10c0473f73985Timo Sirainen MAIL_TRANSACTION_APPEND)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen continue;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen old = data;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen old_end = CONST_PTR_OFFSET(old, hdr->size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (; old != old_end; old++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* appends are sorted */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (rec = appends; rec != end; rec++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (rec->uid >= old->uid) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (rec->uid == old->uid) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen rec->uid = 0;
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen deleted = TRUE;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen break;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
94d5a3fe15ff7096f3a2c7edcf790b5d3b8d1acbTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (deleted) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* compress deleted appends away */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (rec = dest = appends; rec != end; rec++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (rec->uid != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else if (rec != dest)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *rec = *dest;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen buffer_set_used_size(t->appends,
e3f89f85e4e2d67d287b7fcd856f241713ba8311Timo Sirainen (char *)dest - (char *)appends);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_view_close(sync_view);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenlog_append_buffer(struct mail_transaction_log_file *file, const buffer_t *buf,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen enum mail_transaction_type type, int external)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_transaction_header hdr;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const void *data;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen size_t size;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (buf != NULL) {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen data = buffer_get_data(buf, &size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (size == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* write only the header */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = NULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen size = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr.type = type;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (type == MAIL_TRANSACTION_EXPUNGE)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr.type |= MAIL_TRANSACTION_EXPUNGE_PROT;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (external)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen hdr.type |= MAIL_TRANSACTION_EXTERNAL;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen hdr.size = size;
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen if (pwrite_full(file->fd, &hdr, sizeof(hdr), file->hdr.used_size) < 0)
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen return -1;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen file->hdr.used_size += sizeof(hdr);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (size != 0) {
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (pwrite_full(file->fd, data, size, file->hdr.used_size) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen file->hdr.used_size += size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenstatic const buffer_t *
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenlog_get_hdr_update_buffer(struct mail_index_transaction *t)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen{
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen buffer_t *buf;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen struct mail_transaction_header_update u;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen uint16_t offset;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen int state = 0;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen memset(&u, 0, sizeof(u));
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256, (size_t)-1);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen for (offset = 0; offset <= sizeof(t->hdr_change); offset++) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (offset < sizeof(t->hdr_change) && t->hdr_mask[offset]) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (state == 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen u.offset = offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen state++;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } else {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (state > 0) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen u.size = offset - u.offset;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen buffer_append(buf, &u, sizeof(uint16_t)*2);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen buffer_append(buf, t->hdr_change + u.offset,
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen u.size);
eea8f295efb50d5ae6cfe056b20faa65b542a823Timo Sirainen state = 0;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return buf;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_append(struct mail_index_transaction *t,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen uint32_t *log_file_seq_r,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uoff_t *log_file_offset_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_index_view *view = t->view;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_index *index;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_transaction_log *log;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mail_transaction_log_file *file;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen size_t offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uoff_t append_offset;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen int ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen index = mail_index_view_get_index(view);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen log = index->log;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (t->updates == NULL && t->cache_updates == NULL &&
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen t->expunges == NULL && t->appends == NULL && !t->hdr_changed) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen /* nothing to append */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen *log_file_seq_r = 0;
76959d3d6fed45d5f5e1397fcdcf09a5adb87f24Timo Sirainen *log_file_offset_r = 0;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen return 0;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (log->index->log_locked) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen i_assert(view->external);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_lock_head(log) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (log->head->hdr.used_size > MAIL_TRANSACTION_LOG_ROTATE_SIZE &&
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen log->head->last_mtime <
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ioloop_time - MAIL_TRANSACTION_LOG_ROTATE_MIN_TIME) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* we might want to rotate, but check first that head file
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sequence matches the one in index header, ie. we have
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen everything synced in index. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen unsigned int lock_id;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint32_t seq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_index_lock_shared(log->index, TRUE, &lock_id) == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen seq = index->hdr->log_file_seq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_unlock(log->index, lock_id);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen seq = 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (log->head->hdr.file_seq == seq) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_rotate(log, F_WRLCK) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* that didn't work. well, try to continue
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen anyway */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file = log->head;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen append_offset = file->hdr.used_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_fix_appends(log, t) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (!log->index->log_locked)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (t->appends != NULL) {
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ret = log_append_buffer(file, t->appends,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAIL_TRANSACTION_APPEND,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen view->external);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (t->updates != NULL && ret == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, t->updates,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAIL_TRANSACTION_FLAG_UPDATE,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen view->external);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (t->cache_updates != NULL && ret == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, t->cache_updates,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAIL_TRANSACTION_CACHE_UPDATE,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen view->external);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (t->expunges != NULL && ret == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, t->expunges,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAIL_TRANSACTION_EXPUNGE,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen view->external);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (t->hdr_changed && ret == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = log_append_buffer(file, log_get_hdr_update_buffer(t),
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAIL_TRANSACTION_HEADER_UPDATE,
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen view->external);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* rewrite used_size */
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen offset = offsetof(struct mail_transaction_log_header,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen used_size);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = pwrite_full(file->fd, &file->hdr.used_size,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sizeof(file->hdr.used_size), offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret == 0 && (t->updates != NULL || t->appends != NULL) &&
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen t->hide_transaction) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_view_add_synced_transaction(view, file->hdr.file_seq,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen append_offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->hdr.used_size = append_offset;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_file_set_syscall_error(log->index, file->filepath,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "pwrite()");
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else if (fsync(file->fd) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* we don't know how much of it got written,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen it may be corrupted now.. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_file_set_syscall_error(log->index, file->filepath,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "fsync()");
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen ret = -1;
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen }
c15f15f71b885415fdaf2395ce52805770148917Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *log_file_seq_r = file->hdr.file_seq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *log_file_offset_r = file->hdr.used_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (!log->index->log_locked)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenint mail_transaction_log_sync_lock(struct mail_transaction_log *log,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(!log->index->log_locked);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_lock_head(log) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen log->index->log_locked = TRUE;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *file_offset_r = log->head->hdr.used_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(log->index->log_locked);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen log->index->log_locked = FALSE;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)mail_transaction_log_file_lock(log->head, F_UNLCK);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid mail_transaction_log_get_head(struct mail_transaction_log *log,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uint32_t *file_seq_r, uoff_t *file_offset_r)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(log->index->log_locked);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *file_seq_r = log->head->hdr.file_seq;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *file_offset_r = log->head->hdr.used_size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen