mail-transaction-log.c revision f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-lock.h"
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen#include "file-dotlock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-view-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-transaction-private.h"
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#include <sys/stat.h>
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen/* this lock should never exist for a long time.. */
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#define LOG_DOTLOCK_TIMEOUT 30
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#define LOG_DOTLOCK_STALE_TIMEOUT 0
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 120
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_transaction_add_ctx {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log *log;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_view *view;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen buffer_t *appends, *expunges;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen buffer_t *flag_updates, *cache_updates;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen};
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic struct mail_transaction_log_file *
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen const char *path);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic int
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen int lock_type);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen const char *fmt, ...)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen va_list va;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen file->hdr.indexid = 0;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen sizeof(file->hdr.indexid), 0) < 0) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen file->filepath, "pwrite()");
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen va_start(va, fmt);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen t_push();
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen mail_index_set_error(file->log->index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Corrupted transaction log file %s: %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen va_end(va);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen struct mail_index *index = log->index;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct mail_transaction_log_file *file;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen unsigned int lock_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_lock_head(log) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file = log->head;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = mail_index_lock_shared(index, TRUE, &lock_id);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (ret == 0) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen ret = mail_index_map(index, FALSE);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (ret <= 0)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen ret = -1;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen else if (file->hdr.file_seq != index->hdr->log_file_seq) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen /* broken - fix it by creating a new log file */
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen ret = mail_transaction_log_rotate(log);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen return ret;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_transaction_log *
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenmail_transaction_log_open_or_create(struct mail_index *index)
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen{
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen struct mail_transaction_log *log;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen const char *path;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen log = i_new(struct mail_transaction_log, 1);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen log->index = index;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen path = t_strconcat(log->index->filepath,
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen MAIL_TRANSACTION_LOG_PREFIX, NULL);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen log->head = mail_transaction_log_file_open_or_create(log, path);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen if (log->head == NULL) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen i_free(log);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen return NULL;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (index->fd != -1 &&
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen log->head->hdr.file_seq != index->hdr->log_file_seq) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* head log file isn't same as head index file -
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen shouldn't happen except in race conditions. lock them and
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen check again - FIXME: missing error handling.
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen FIXME: index->hdr check crashes if we created the log */
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen (void)mail_transaction_log_check_file_seq(log);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen return log;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen}
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainenvoid mail_transaction_log_close(struct mail_transaction_log *log)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen i_assert(log->views == NULL);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen i_free(log);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen}
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainenstatic int
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file,
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen int lock_type)
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen{
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen int ret;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen if (lock_type == F_UNLCK) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = file_unlock_dotlock(file->filepath, &file->dotlock);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret < 0) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen file->filepath, "file_unlock_dotlock()");
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return -1;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen }
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen file->lock_type = F_UNLCK;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen if (ret == 0) {
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen mail_index_set_error(file->log->index,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen "Dotlock was lost for transaction log file %s",
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen file->filepath);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return -1;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return 0;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen ret = file_lock_dotlock(file->filepath, NULL, FALSE,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen LOG_DOTLOCK_TIMEOUT,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen LOG_DOTLOCK_STALE_TIMEOUT,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen NULL, NULL, &file->dotlock);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (ret > 0) {
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen file->lock_type = F_WRLCK;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (ret < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->filepath,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "file_lock_dotlock()");
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_set_error(file->log->index,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "Timeout while waiting for release of "
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "dotlock for transaction log file %s",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->filepath);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->log->index->index_lock_timeout = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int lock_type)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int ret;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (lock_type == F_UNLCK) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(file->lock_type != F_UNLCK);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_assert(file->lock_type == F_UNLCK);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen if (file->log->index->fcntl_locks_disable)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return mail_transaction_log_file_dotlock(file, lock_type);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = file_wait_lock_full(file->fd, lock_type, DEFAULT_LOCK_TIMEOUT,
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen NULL, NULL);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret > 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->lock_type = lock_type;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen file->filepath,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "file_wait_lock()");
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return -1;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mail_index_set_error(file->log->index,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen "Timeout while waiting for release of "
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen "%s fcntl() lock for transaction log file %s",
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen lock_type == F_WRLCK ? "exclusive" : "shared",
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen file->filepath);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen file->log->index->index_lock_timeout = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return -1;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic void
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenmail_transaction_log_file_close(struct mail_transaction_log_file *file)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (close(file->fd) < 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen file->filepath, "close()");
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_free(file->filepath);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_free(file);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenstatic int
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct stat *st)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t old_size = file->hdr.used_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (file->lock_type != F_UNLCK)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (mail_transaction_log_file_lock(file, F_RDLCK) < 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)mail_transaction_log_file_lock(file, F_UNLCK);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen // FIXME: handle ESTALE
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen file->filepath,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "pread_full()");
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "unexpected end of file while reading header");
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen return 0;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen }
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen if (file->hdr.indexid == 0) {
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen /* corrupted */
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen mail_index_set_error(file->log->index,
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen "Transaction log file %s: marked corrupted",
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen file->filepath);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen return 0;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen }
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen if (file->hdr.indexid != file->log->index->indexid &&
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen file->log->index->indexid != 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* either index was just recreated, or transaction has wrong
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen indexid. we don't know here which one is the case, so we'll
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen just fail. If index->indexid == 0, we're rebuilding it and
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen we just want to lock the transaction log. */
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen mail_index_set_error(file->log->index,
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen "Transaction log file %s: invalid indexid",
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen file->filepath);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen return 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file->hdr.used_size > st->st_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "used_size (%u) > file size (%"PRIuUOFF_T")",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->hdr.used_size, (uoff_t)st->st_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->hdr.used_size < old_size) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen mail_transaction_log_file_set_corrupted(file,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "used_size (%u) < old_size (%u)",
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->hdr.used_size, old_size);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenstatic int mail_transaction_log_file_create(struct mail_transaction_log *log,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const char *path,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen dev_t dev, ino_t ino)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen struct mail_index *index = log->index;
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen struct mail_transaction_log_header hdr;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct stat st;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen unsigned int lock_id;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen int fd, fd2, ret;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen fd = file_dotlock_open(path, NULL, LOG_DOTLOCK_TIMEOUT,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen LOG_DOTLOCK_STALE_TIMEOUT,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (fd == -1) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen mail_index_file_set_syscall_error(index, path,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen "file_dotlock_open()");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return -1;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* log creation is locked now - see if someone already created it */
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen fd2 = open(path, O_RDWR);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (fd2 != -1) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if ((ret = fstat(fd2, &st)) < 0) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen mail_index_file_set_syscall_error(index, path,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen "fstat()");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen } else if (st.st_dev == dev && st.st_ino == ino) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* same file, still broken */
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen } else {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen (void)file_dotlock_delete(path, fd2);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return fd2;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen (void)close(fd2);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen fd2 = -1;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (ret < 0)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return -1;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen } else if (errno != ENOENT) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen mail_index_file_set_syscall_error(index, path, "open()");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return -1;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen memset(&hdr, 0, sizeof(hdr));
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen hdr.indexid = index->indexid;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen hdr.used_size = sizeof(hdr);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (index->fd != -1) {
c680a6b35b459045e92814778908da5a93922107Timo Sirainen index->log_locked = TRUE; /* kludging around assert.. */
c680a6b35b459045e92814778908da5a93922107Timo Sirainen if (mail_index_lock_exclusive(index, &lock_id) < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)file_dotlock_delete(path, fd);
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen index->log_locked = FALSE;
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen return -1;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen }
096953143c4032bad154637f687551856f7946cbTimo Sirainen
096953143c4032bad154637f687551856f7946cbTimo Sirainen ret = mail_index_map(index, FALSE);
096953143c4032bad154637f687551856f7946cbTimo Sirainen if (ret > 0) {
096953143c4032bad154637f687551856f7946cbTimo Sirainen /* update log_file_* fields in header */
c680a6b35b459045e92814778908da5a93922107Timo Sirainen struct mail_index_header idx_hdr;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen idx_hdr = *index->hdr;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen idx_hdr.log_file_seq++;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen idx_hdr.log_file_offset = sizeof(hdr);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_index_write_header(index, &idx_hdr) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen hdr.file_seq = index->hdr->log_file_seq;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_unlock(index, lock_id);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen index->log_locked = FALSE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret <= 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)file_dotlock_delete(path, fd);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* creating new index file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr.file_seq = index->hdr->log_file_seq+1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(index, path, "write_full()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)file_dotlock_delete(path, fd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen fd2 = dup(fd);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (fd2 < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_index_file_set_syscall_error(index, path, "dup()");
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (void)file_dotlock_delete(path, fd);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (file_dotlock_replace(path, fd, FALSE) <= 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* success */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return fd2;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic struct mail_transaction_log_file *
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenmail_transaction_log_file_fd_open(struct mail_transaction_log *log,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const char *path, int fd)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file **p;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file *file;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct stat st;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen int ret;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (fstat(fd, &st) < 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail_index_file_set_syscall_error(log->index, path, "stat()");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->refcount = 1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->log = log;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->filepath = i_strdup(path);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->fd = fd;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->lock_type = F_UNLCK;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->st_dev = st.st_dev;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->st_ino = st.st_ino;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (ret == 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* corrupted header */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen fd = mail_transaction_log_file_create(log, path,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen st.st_dev, st.st_ino);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (fstat(fd, &st) < 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen "stat()");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen (void)close(fd);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen fd = -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (fd != -1) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen (void)close(file->fd);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->fd = fd;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen file->st_dev = st.st_dev;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->st_ino = st.st_ino;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(&file->hdr, 0, sizeof(file->hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_file_read_hdr(file, &st);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret <= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_close(file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen for (p = &log->tail; *p != NULL; p = &(*p)->next)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen ;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *p = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return file;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct mail_transaction_log_file *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen int fd;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen fd = open(path, O_RDWR);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (fd == -1) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (errno != ENOENT) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen mail_index_file_set_syscall_error(log->index, path,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen "open()");
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return NULL;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen fd = mail_transaction_log_file_create(log, path, 0, 0);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (fd == -1)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return NULL;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return mail_transaction_log_file_fd_open(log, path, fd);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct mail_transaction_log_file **p;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen for (p = &log->tail; *p != NULL; ) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if ((*p)->refcount != 0)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen p = &(*p)->next;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen else {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen mail_transaction_log_file_close(*p);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen *p = (*p)->next;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic int mail_transaction_log_rotate(struct mail_transaction_log *log)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct mail_transaction_log_file *file;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct stat st;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen int fd;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen if (fstat(log->head->fd, &st) < 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_index_file_set_syscall_error(log->index,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen log->head->filepath,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "fstat()");
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return -1;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen fd = mail_transaction_log_file_create(log, log->head->filepath,
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen st.st_dev, st.st_ino);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (fd == -1)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen file = mail_transaction_log_file_fd_open(log, log->head->filepath, fd);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (file == NULL)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (log->head != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (--log->head->refcount == 0)
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen mail_transaction_logs_clean(log);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen log->head = file;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic int mail_transaction_log_refresh(struct mail_transaction_log *log)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen{
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct mail_transaction_log_file *file;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct stat st;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char *path;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen int ret;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen path = t_strconcat(log->index->filepath,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen MAIL_TRANSACTION_LOG_PREFIX, NULL);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (stat(path, &st) < 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen mail_index_file_set_syscall_error(log->index, path, "stat()");
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (log->head != NULL &&
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen log->head->st_ino == st.st_ino &&
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen log->head->st_dev == st.st_dev) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* same file */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen ret = mail_transaction_log_file_read_hdr(log->head, &st);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return ret <= 0 ? -1 : 0;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen file = mail_transaction_log_file_open_or_create(log, path);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (file == NULL)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return -1;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (log->head != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (--log->head->refcount == 0)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen mail_transaction_logs_clean(log);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen }
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen log->head = file;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen return 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenint mail_transaction_log_file_find(struct mail_transaction_log *log,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen uint32_t file_seq,
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen struct mail_transaction_log_file **file_r)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen{
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen struct mail_transaction_log_file *file;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (file_seq > log->head->hdr.file_seq) {
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (mail_transaction_log_refresh(log) < 0)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen return -1;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen for (file = log->tail; file != NULL; file = file->next) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (file->hdr.file_seq == file_seq) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen *file_r = file;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return 1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic int
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uoff_t offset)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen void *data;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen size_t size;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen int ret;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen i_assert(file->mmap_base == NULL);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen i_assert(offset <= file->hdr.used_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (file->buffer != NULL && file->buffer_offset > offset) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* we have to insert missing data to beginning of buffer */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen size = file->buffer_offset - offset;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen file->buffer_offset = offset;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen ret = pread_full(file->fd, data, size, offset);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (ret < 0 && errno == ESTALE) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* log file was deleted in NFS server, fail silently */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = 0;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (ret <= 0)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return ret;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (file->buffer == NULL) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size = file->hdr.used_size - offset;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen file->buffer = buffer_create_dynamic(default_pool,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size, (size_t)-1);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen file->buffer_offset = offset;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size = 0;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen } else {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size = buffer_get_used_size(file->buffer);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (file->buffer_offset + size >= file->hdr.used_size) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen /* caller should have checked this.. */
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen return 1;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen }
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen }
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen offset = file->buffer_offset + size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size = file->hdr.used_size - file->buffer_offset - size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (size == 0)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen return 1;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen data = buffer_append_space_unsafe(file->buffer, size);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = pread_full(file->fd, data, size, offset);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (ret < 0 && errno == ESTALE) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* log file was deleted in NFS server, fail silently */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return ret;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uoff_t start_offset, uoff_t end_offset)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen struct mail_index *index = file->log->index;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen size_t size;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen struct stat st;
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen int ret, use_mmap;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(start_offset <= end_offset);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->hdr.indexid == 0) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen /* corrupted */
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen return 0;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* with mmap_no_write we could alternatively just write to log with
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen msync() rather than pwrite(). that'd cause slightly more disk I/O,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen so rather use more memory. */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen use_mmap = !index->mmap_disable && !index->mmap_no_write;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* see if we already have it */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen size = buffer_get_used_size(file->buffer);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (file->buffer_offset + size >= end_offset)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (fstat(file->fd, &st) < 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen "fstat()");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (st.st_size == file->hdr.used_size &&
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen file->buffer_offset <= start_offset && end_offset == (uoff_t)-1) {
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen /* we've seen the whole file.. do we have all of it mapped? */
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen size = buffer_get_used_size(file->buffer);
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen if (file->buffer_offset + size == file->hdr.used_size)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen return 1;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen }
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->buffer != NULL &&
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen (file->mmap_base != NULL || use_mmap)) {
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen buffer_free(file->buffer);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file->buffer = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->mmap_base != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen "munmap()");
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->mmap_base = NULL;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (mail_transaction_log_file_read_hdr(file, &st) <= 0)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen return -1;
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen if (end_offset == (uoff_t)-1)
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen end_offset = file->hdr.used_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (start_offset < sizeof(file->hdr)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen "offset (%"PRIuUOFF_T"u) < header size (%"PRIuSIZE_T")",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen start_offset, sizeof(file->hdr));
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen return -1;
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (end_offset > file->hdr.used_size) {
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen mail_transaction_log_file_set_corrupted(file,
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen "offset (%"PRIuUOFF_T"u) > used_size (%u)",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen end_offset, file->hdr.used_size);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (!use_mmap) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret <= 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret < 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_index_file_set_syscall_error(index,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen file->filepath, "pread_full()");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Unexpected EOF");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen /* make sure we don't leave ourself in
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen inconsistent state */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file->buffer != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(file->buffer);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->buffer = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen file->mmap_size = file->hdr.used_size;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen MAP_SHARED, file->fd, 0);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if (file->mmap_base == MAP_FAILED) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file->mmap_base = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen "mmap()");
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen file->buffer = buffer_create_const_data(default_pool, file->mmap_base,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen file->mmap_size);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen file->buffer_offset = 0;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen return 1;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainenstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen{
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen struct mail_transaction_log_file *file;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen /* we want to get the head file locked. this is a bit racy,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen since by the time we have it locked a new log file may have been
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen created.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen creating new log file requires locking the head file, so if we
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen can lock it and don't see another file, we can be sure no-one is
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen creating a new log at the moment */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen for (;;) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file = log->head;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_file_lock(file, F_WRLCK) < 0)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file->refcount++;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen ret = mail_transaction_log_refresh(log);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (--file->refcount == 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_transaction_logs_clean(log);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen file = NULL;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ret == 0 && log->head == file) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* success */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen break;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
if (file != NULL) {
if (mail_transaction_log_file_lock(file, F_UNLCK) < 0)
return -1;
}
if (ret < 0)
break;
/* try again */
}
return ret;
}
static int get_expunge_buf(struct mail_transaction_log *log,
struct mail_index_view *view, buffer_t *expunges)
{
struct mail_transaction_log_view *sync_view;
const struct mail_transaction_header *hdr;
const void *data;
int ret;
sync_view = mail_transaction_log_view_open(log);
ret = mail_transaction_log_view_set(sync_view, view->log_file_seq,
view->log_file_offset,
log->head->hdr.file_seq,
log->head->hdr.used_size,
MAIL_TRANSACTION_TYPE_MASK);
while ((ret = mail_transaction_log_view_next(sync_view,
&hdr, &data, NULL)) == 1) {
if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
MAIL_TRANSACTION_EXPUNGE) {
mail_transaction_log_sort_expunges(expunges,
data, hdr->size);
}
}
mail_transaction_log_view_close(sync_view);
return ret;
}
static void
log_view_fix_sequences(struct mail_index_view *view, buffer_t *view_expunges,
buffer_t *buf, size_t record_size, int two, int uids)
{
// FIXME: make sure this function works correctly
const struct mail_transaction_expunge *exp, *exp_end, *exp2;
unsigned char *data;
uint32_t *seq, expunges_before, count;
size_t src_idx, dest_idx, size;
if (buf == NULL)
return;
exp = buffer_get_data(view_expunges, &size);
exp_end = exp + (size / sizeof(*exp));
if (exp == exp_end)
return;
data = buffer_get_modifyable_data(buf, &size);
expunges_before = 0;
for (src_idx = dest_idx = 0; src_idx < size; src_idx += record_size) {
seq = (uint32_t *)&data[src_idx];
while (exp != exp_end && exp->seq1 < seq[0]) {
expunges_before += exp->seq2 - exp->seq1 + 1;
exp++;
}
if (exp != exp_end && exp->seq1 == seq[0]) {
/* this sequence was expunged */
if (!two)
continue;
/* we point to next non-expunged message */
}
if (expunges_before != 0) {
if (uids) {
(void)mail_index_lookup_uid(view, seq[0],
&seq[2]);
}
seq[0] -= expunges_before;
}
if (two) {
exp2 = exp;
count = expunges_before;
while (exp2 != exp_end && exp2->seq1 <= seq[1]) {
count += exp->seq2 - exp->seq1 + 1;
exp2++;
}
if (seq[1] < count || seq[1]-count < seq[0]) {
/* whole range is expunged */
continue;
}
if (count != 0) {
if (uids) {
(void)mail_index_lookup_uid(view,
seq[1],
&seq[3]);
}
seq[1] -= count;
}
}
if (src_idx != dest_idx)
memcpy(&data[dest_idx], &data[src_idx], record_size);
dest_idx += record_size;
}
buffer_set_used_size(buf, dest_idx);
}
static int
mail_transaction_log_fix_sequences(struct mail_transaction_log *log,
struct mail_index_transaction *t)
{
buffer_t *view_expunges;
if (t->updates == NULL && t->cache_updates == NULL &&
t->expunges == NULL)
return 0;
/* all sequences are currently relative to given view. we have to
find out all the expunges since then, even the ones that aren't
yet synchronized to index file. */
view_expunges = buffer_create_dynamic(default_pool, 1024, (size_t)-1);
if (get_expunge_buf(log, t->view, view_expunges) < 0) {
buffer_free(view_expunges);
return -1;
}
log_view_fix_sequences(t->view, view_expunges, t->updates,
sizeof(struct mail_transaction_flag_update),
TRUE, FALSE);
log_view_fix_sequences(t->view, view_expunges, t->cache_updates,
sizeof(struct mail_transaction_cache_update),
FALSE, FALSE);
log_view_fix_sequences(t->view, view_expunges, t->expunges,
sizeof(struct mail_transaction_expunge),
TRUE, TRUE);
buffer_free(view_expunges);
return 0;
}
static int
log_append_buffer(struct mail_transaction_log_file *file, const buffer_t *buf,
enum mail_transaction_type type, int external)
{
struct mail_transaction_header hdr;
const void *data;
size_t size;
i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
if (buf != NULL) {
data = buffer_get_data(buf, &size);
if (size == 0)
return 0;
} else {
/* write only the header */
data = NULL;
size = 0;
}
hdr.type = type;
if (type == MAIL_TRANSACTION_EXPUNGE)
hdr.type |= MAIL_TRANSACTION_EXPUNGE_PROT;
if (external)
hdr.type |= MAIL_TRANSACTION_EXTERNAL;
hdr.size = size;
if (pwrite_full(file->fd, &hdr, sizeof(hdr), file->hdr.used_size) < 0)
return -1;
file->hdr.used_size += sizeof(hdr);
if (size != 0) {
if (pwrite_full(file->fd, data, size, file->hdr.used_size) < 0)
return -1;
file->hdr.used_size += size;
}
return 0;
}
int mail_transaction_log_append(struct mail_index_transaction *t,
uint32_t *log_file_seq_r,
uoff_t *log_file_offset_r)
{
struct mail_index_view *view = t->view;
struct mail_transaction_log *log;
struct mail_transaction_log_file *file;
size_t offset;
uoff_t append_offset;
int ret;
if (t->updates == NULL && t->cache_updates == NULL &&
t->expunges == NULL && t->appends == NULL) {
/* nothing to append */
return 0;
}
log = mail_index_view_get_index(view)->log;
if (log->index->log_locked) {
i_assert(view->external);
} else {
if (mail_transaction_log_lock_head(log) < 0)
return -1;
}
file = log->head;
append_offset = file->hdr.used_size;
if (mail_transaction_log_fix_sequences(log, t) < 0) {
if (!log->index->log_locked)
(void)mail_transaction_log_file_lock(file, F_UNLCK);
return -1;
}
ret = 0;
if (t->appends != NULL) {
ret = log_append_buffer(file, t->appends,
MAIL_TRANSACTION_APPEND,
view->external);
}
if (t->updates != NULL && ret == 0) {
ret = log_append_buffer(file, t->updates,
MAIL_TRANSACTION_FLAG_UPDATE,
view->external);
}
if (t->cache_updates != NULL && ret == 0) {
ret = log_append_buffer(file, t->cache_updates,
MAIL_TRANSACTION_CACHE_UPDATE,
view->external);
}
if (t->expunges != NULL && ret == 0) {
ret = log_append_buffer(file, t->expunges,
MAIL_TRANSACTION_EXPUNGE,
view->external);
}
if (ret == 0) {
/* rewrite used_size */
offset = offsetof(struct mail_transaction_log_header,
used_size);
ret = pwrite_full(file->fd, &file->hdr.used_size,
sizeof(file->hdr.used_size), offset);
}
if (ret == 0 && (t->updates != NULL || t->appends != NULL) &&
t->hide_transaction) {
mail_index_view_add_synced_transaction(view, file->hdr.file_seq,
append_offset);
}
if (ret < 0) {
file->hdr.used_size = append_offset;
mail_index_file_set_syscall_error(log->index, file->filepath,
"pwrite()");
} else if (fsync(file->fd) < 0) {
/* we don't know how much of it got written,
it may be corrupted now.. */
mail_index_file_set_syscall_error(log->index, file->filepath,
"fsync()");
ret = -1;
}
*log_file_seq_r = file->hdr.file_seq;
*log_file_offset_r = file->hdr.used_size;
if (!log->index->log_locked)
(void)mail_transaction_log_file_lock(file, F_UNLCK);
return ret;
}
int mail_transaction_log_sync_lock(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(!log->index->log_locked);
if (mail_transaction_log_lock_head(log) < 0)
return -1;
log->index->log_locked = TRUE;
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->hdr.used_size;
return 0;
}
void mail_transaction_log_sync_unlock(struct mail_transaction_log *log)
{
i_assert(log->index->log_locked);
log->index->log_locked = FALSE;
(void)mail_transaction_log_file_lock(log->head, F_UNLCK);
}
void mail_transaction_log_get_head(struct mail_transaction_log *log,
uint32_t *file_seq_r, uoff_t *file_offset_r)
{
i_assert(log->index->log_locked);
*file_seq_r = log->head->hdr.file_seq;
*file_offset_r = log->head->hdr.used_size;
}