mail-transaction-log-file.c revision 8c7000574087d5702cc3830e7f80c695ff8e9221
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "buffer.h"
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen#include "file-dotlock.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "nfs-workarounds.h"
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen#include "read-full.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "write-full.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mmap-util.h"
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include "mail-index-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-transaction-log-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#define LOG_PREFETCH 1024
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainenvoid
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *fmt, ...)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen va_list va;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->hdr.indexid = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* indexid=0 marks the log file as corrupted */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sizeof(file->hdr.indexid),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen offsetof(struct mail_transaction_log_header,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen indexid)) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->filepath, "pwrite()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen va_start(va, fmt);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen t_push();
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_index_set_error(file->log->index,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Corrupted transaction log file %s: %s",
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen t_pop();
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen va_end(va);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainenstruct mail_transaction_log_file *
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *path)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file *file;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->log = log;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->filepath = i_strdup(path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->fd = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return file;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file *file = *_file;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file **p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int old_errno = errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *_file = NULL;
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen mail_transaction_log_file_unlock(file);
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen if (*p == file) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen *p = file->next;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen break;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen }
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen }
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (file == file->log->head)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen file->log->head = NULL;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (file->buffer != NULL)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen buffer_free(file->buffer);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (file->mmap_base != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen file->filepath,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "munmap()");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (file->fd != -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (close(file->fd) < 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen file->filepath,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "close()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(file->filepath);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(file);
7fe37c2b0e4cd2a39896ab16e47eb418a59e3934Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen errno = old_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log *log = file->log;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file **p;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen struct mail_index_map *map = log->index->map;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (map != NULL && file->hdr.file_seq == map->hdr.log_file_seq &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen map->hdr.log_file_head_offset != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we can get a valid log offset from index file. initialize
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen sync_offset from it so we don't have to read the whole log
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen file from beginning. */
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen if (map->hdr.log_file_head_offset >= file->hdr.hdr_size)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen file->sync_offset = map->hdr.log_file_head_offset;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen else {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen mail_index_set_error(log->index,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "%s: log_file_head_offset too small",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen log->index->filepath);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen file->sync_offset = file->hdr.hdr_size;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen file->saved_tail_offset = map->hdr.log_file_tail_offset;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen } else {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen file->sync_offset = file->hdr.hdr_size;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* insert it to correct position */
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen for (p = &log->files; *p != NULL; p = &(*p)->next) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if ((*p)->hdr.file_seq > file->hdr.file_seq)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->next = *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *p = file;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainenstatic int
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen struct mail_transaction_log_header *hdr)
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index *index = log->index;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int lock_id = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen if (log->index->indexid == 0)
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen log->index->indexid = ioloop_time;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen memset(hdr, 0, sizeof(*hdr));
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen hdr->indexid = log->index->indexid;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen hdr->create_stamp = ioloop_time;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (index->fd != -1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not creating index - make sure we have latest header */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen &lock_id) <= 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen }
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen if (index->map != NULL) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen hdr->prev_file_seq = index->map->hdr.log_file_seq;
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen hdr->prev_file_offset = index->map->hdr.log_file_head_offset;
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen hdr->file_seq = index->map->hdr.log_file_seq + 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr->file_seq = 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (index->fd != -1)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_unlock(index, lock_id);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* make sure the sequence grows */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen hdr->file_seq = log->head->hdr.file_seq+1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainenstruct mail_transaction_log_file *
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log)
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen{
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen struct mail_transaction_log_file *file;
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen file = mail_transaction_log_file_alloc(log, MEMORY_LOG_NAME);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen if (mail_transaction_log_init_hdr(log, &file->hdr) < 0) {
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen i_free(file);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->buffer_offset = sizeof(file->hdr);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen mail_transaction_log_file_add_to_list(file);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen return file;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenstatic int
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen{
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen int ret;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (file->log->dotlock_count > 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = 1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen else {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen file->filepath, 0,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen &file->log->dotlock);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (ret > 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen file->log->dotlock_count++;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen file->locked = TRUE;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (ret < 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen file->filepath,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "file_dotlock_create()");
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return -1;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen mail_index_set_error(file->log->index,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen "Timeout while waiting for release of "
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen "dotlock for transaction log file %s",
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen file->filepath);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen file->log->index->index_lock_timeout = TRUE;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen return -1;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenstatic int
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen{
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen int ret;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (--file->log->dotlock_count > 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (ret < 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen file->filepath, "file_dotlock_delete()");
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return -1;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (ret == 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_index_set_error(file->log->index,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen "Dotlock was lost for transaction log file %s",
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen file->filepath);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return -1;
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen }
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mail_transaction_log_file_lock(struct mail_transaction_log_file *file)
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen{
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen int ret;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen if (file->locked)
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen return 0;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->locked = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return mail_transaction_log_file_dotlock(file);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(file->file_lock == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen F_WRLCK, MAIL_INDEX_LOCK_SECS,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &file->file_lock);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (ret > 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen file->locked = TRUE;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return 0;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (ret < 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen file->filepath,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen "mail_index_wait_lock_fd()");
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return -1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_error(file->log->index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Timeout while waiting for lock for transaction log file %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->filepath);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->log->index->index_lock_timeout = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen}
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (!file->locked)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->locked = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_transaction_log_file_undotlock(file);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return;
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen file_unlock(&file->file_lock);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen}
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenstatic int
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool ignore_estale)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_transaction_log_file *f;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen int ret;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen i_assert(!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen if (ret < 0) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (errno != ESTALE || !ignore_estale) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen file->filepath,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen "pread_full()");
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen }
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return -1;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (ret == 0) {
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen mail_transaction_log_file_set_corrupted(file,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen "unexpected end of file while reading header");
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen return 0;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* incompatible version - fix silently */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen return 0;
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen mail_transaction_log_file_set_corrupted(file,
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen "Header size too small");
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen return 0;
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen }
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen if (file->hdr.hdr_size < sizeof(file->hdr)) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen shouldn't have filled */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen sizeof(file->hdr) - file->hdr.hdr_size);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.indexid == 0) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* corrupted */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen mail_index_set_error(file->log->index,
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen "Transaction log file %s: marked corrupted",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->filepath);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen if (file->log->index->fd != -1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* index file was probably just rebuilt and we don't
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen know about it yet */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen mail_transaction_log_file_set_corrupted(file,
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen "invalid indexid (%u != %u)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->hdr.indexid, file->log->index->indexid);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen return 0;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen }
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* creating index file. since transaction log is created
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen first, use the indexid in it to create the main index
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen to avoid races. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file->log->index->indexid = file->hdr.indexid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen /* make sure we already don't have a file with the same sequence
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen opened. it shouldn't happen unless the old log file was
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen corrupted. */
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen if (f->hdr.file_seq == file->hdr.file_seq) {
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen /* mark the old file corrupted. we can't safely remove
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen it from the list however, so return failure. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_transaction_log_file_set_corrupted(f,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "duplicate transaction log sequence (%u)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen f->hdr.file_seq);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenstatic int
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenmail_transaction_log_file_stat(struct mail_transaction_log_file *file,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen bool ignore_estale)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen{
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen struct stat st;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (fstat(file->fd, &st) < 0) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (errno != ESTALE || !ignore_estale) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen file->filepath, "fstat()");
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen }
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return -1;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen }
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen file->st_dev = st.st_dev;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen file->st_ino = st.st_ino;
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen file->last_mtime = st.st_mtime;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->last_size = st.st_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_transaction_log_file_is_dupe(struct mail_transaction_log_file *file)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_transaction_log_file *tmp;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (tmp = file->log->files; tmp != NULL; tmp = tmp->next) {
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen if (tmp->st_ino == file->st_ino &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen CMP_DEV_T(tmp->st_dev, file->st_dev))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log_file *file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int new_fd, struct dotlock **dotlock)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen{
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen struct mail_index *index = file->log->index;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen struct stat st;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen const char *path2;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int fd, ret;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen bool rename_existing;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* log creation is locked now - see if someone already created it.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen note that if we're rotating, we need to keep the log locked until
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen the file has been rewritten. and because fcntl() locks are stupid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if we go and open()+close() the file and we had it already opened,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen its locks are lost. so we use stat() to check if the file has been
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen recreated, although it almost never is. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (nfs_safe_stat(file->filepath, &st) < 0) {
cbcba924a745c938260fd39cb284175b75f8eaf2Timo Sirainen if (errno != ENOENT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "stat()");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rename_existing = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (st.st_ino == file->st_ino &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen CMP_DEV_T(st.st_dev, file->st_dev) &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* inode/dev checks are enough when we're rotating the file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen but not when we're replacing a broken log file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen st.st_mtime == file->last_mtime &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (uoff_t)st.st_size == file->last_size) {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* no-one else recreated the file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen rename_existing = TRUE;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen } else {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* recreated. use the file if its header is ok */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen fd = nfs_safe_open(file->filepath, O_RDWR);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (fd == -1) {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (errno != ENOENT) {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen mail_index_file_set_syscall_error(index,
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen file->filepath, "open()");
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->fd = fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_transaction_log_file_read_hdr(file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen FALSE) == 0) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen /* yes, it was ok */
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen (void)file_dotlock_delete(dotlock);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->fd = -1;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen if (close(fd) < 0) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen mail_index_file_set_syscall_error(index,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen file->filepath, "close()");
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen rename_existing = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen "write_full()");
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen return -1;
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen }
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen file->fd = new_fd;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen /* if we return -1 the dotlock deletion code closes the fd */
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen file->fd = -1;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (ret < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* keep two log files */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (rename_existing) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* rename() would be nice and easy way to do this, except then
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen there's a race condition between the rename and
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file_dotlock_replace(). during that time the log file
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doesn't exist, which could cause problems. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path2 = t_strconcat(file->filepath, ".2", NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlink(path2) < 0 && errno != ENOENT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path2);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* try to link() anyway */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (link(file->filepath, path2) < 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen errno != ENOENT && errno != EEXIST) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->filepath, path2);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* ignore the error. we don't care that much about the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen second log file and we're going to overwrite this
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first one. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (file_dotlock_replace(dotlock,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* success */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen file->fd = new_fd;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen mail_transaction_log_file_add_to_list(file);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index *index = file->log->index;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct dotlock *dotlock;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mode_t old_mask;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int fd;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen /* With dotlocking we might already have path.lock created, so this
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen filename has to be different. */
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen old_mask = umask(index->mode ^ 0666);
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen fd = file_dotlock_open(&file->log->new_dotlock_settings,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->filepath, 0, &dotlock);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen umask(old_mask);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd == -1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "file_dotlock_open()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (index->gid != (gid_t)-1 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fchown(fd, (uid_t)-1, index->gid) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "fchown()");
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen (void)file_dotlock_delete(&dotlock);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return -1;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen }
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen is for the existing file */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (mail_transaction_log_file_create2(file, fd, &dotlock) < 0) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (dotlock != NULL)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen (void)file_dotlock_delete(&dotlock);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen return -1;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen }
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return 0;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen}
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen bool check_existing)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen{
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen unsigned int i;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen bool ignore_estale;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen int ret;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen for (i = 0;; i++) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDWR);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (file->fd == -1) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (errno == ENOENT)
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen return 0;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen file->filepath, "open()");
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen return -1;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen }
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen ignore_estale = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (mail_transaction_log_file_stat(file, ignore_estale) < 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = -1;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen else if (check_existing &&
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_transaction_log_file_is_dupe(file))
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = mail_transaction_log_file_read_hdr(file,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ignore_estale);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (ret > 0) {
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* success */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen break;
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen }
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (ret == 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* corrupted */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (unlink(file->filepath) < 0 && errno != ENOENT) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_index_set_error(file->log->index,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen "unlink(%s) failed: %m",
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen file->filepath);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen if (errno != ESTALE ||
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* syscall error */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen return -1;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen }
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* ESTALE - try again */
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen }
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen mail_transaction_log_file_add_to_list(file);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen return 1;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenlog_file_track_mailbox_sync_offset_hdr(struct mail_transaction_log_file *file,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen const void *data, unsigned int size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_transaction_header_update *u = data;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen const struct mail_index_header *ihdr;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen const unsigned int offset_pos =
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen offsetof(struct mail_index_header, log_file_tail_offset);
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_tail_offset);
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen uint32_t sync_offset;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen i_assert(offset_size == sizeof(sync_offset));
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen mail_transaction_log_file_set_corrupted(file,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen "header update extends beyond record size");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (u->offset <= offset_pos &&
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen u->offset + u->size >= offset_pos + offset_size) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen memcpy(&sync_offset,
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen sizeof(sync_offset));
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (sync_offset < file->saved_tail_offset) {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen "log_file_tail_offset shrinked");
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen return -1;
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->saved_tail_offset = sync_offset;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (sync_offset > file->max_tail_offset)
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen file->max_tail_offset = sync_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenlog_file_track_mailbox_sync_offset(struct mail_transaction_log_file *file,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct mail_transaction_header *hdr,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int trans_size)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int ret;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MAIL_TRANSACTION_HEADER_UPDATE) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* see if this updates mailbox_sync_offset */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, hdr + 1,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen trans_size -
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen sizeof(*hdr));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret != 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return ret < 0 ? -1 : 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (file->max_tail_offset == file->sync_offset) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* external transactions aren't synced to mailbox. we can
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen update mailbox sync offset to skip this transaction to
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen avoid re-reading it at the next sync. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen file->max_tail_offset += trans_size;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct mail_transaction_header *hdr;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const void *data;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen size_t size, avail;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen uint32_t trans_size = 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen data = buffer_get_data(file->buffer, &size);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (file->sync_offset < file->buffer_offset)
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen file->sync_offset = file->buffer_offset;
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen hdr = CONST_PTR_OFFSET(data, file->sync_offset -
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen file->buffer_offset);
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen if (trans_size == 0) {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen /* unfinished */
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (trans_size < sizeof(*hdr)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_transaction_log_file_set_corrupted(file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "hdr.size too small (%u)", trans_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (file->sync_offset - file->buffer_offset + trans_size > size)
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen break;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen /* transaction has been fully written */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (log_file_track_mailbox_sync_offset(file, hdr,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen trans_size) < 0)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->sync_offset += trans_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen trans_size = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen avail = file->sync_offset - file->buffer_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (avail != size) {
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen /* There's more data than we could sync at the moment. If the
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen last record's size wasn't valid, we can't know if it will
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen be updated unless we've locked the log.
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen Without locking we can be sure only if we're not using
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mmaping, because with mmaping the data and the file size
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen can get updated at any time. */
0c96e2994ab4e25c9042ce21e9d39ca5054df3b6Timo Sirainen if (file->locked ||
0c96e2994ab4e25c9042ce21e9d39ca5054df3b6Timo Sirainen (trans_size != 0 && file->mmap_base == NULL)) {
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen if (trans_size != 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_transaction_log_file_set_corrupted(file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "hdr.size too large (%u)", trans_size);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_transaction_log_file_set_corrupted(file,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Unexpected garbage at EOF");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen // FIXME: here we probably want to flush NFS data cache
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic int
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenmail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen uoff_t offset)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen void *data;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen size_t size;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen ssize_t ret;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen size = file->buffer_offset - offset;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = pread_full(file->fd, data, size, offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* success */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer_offset -= size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen }
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* failure. don't leave ourself to inconsistent state */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_set_used_size(file->buffer, file->buffer->used - size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen if (ret == 0) {
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen mail_transaction_log_file_set_corrupted(file, "file shrinked");
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen return 0;
56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54Timo Sirainen } else if (errno == ESTALE) {
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* log file was deleted in NFS server, fail silently */
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen return 0;
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen file->filepath, "pread()");
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen return -1;
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainenstatic int
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen uoff_t start_offset)
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen{
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen void *data;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen size_t size;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen uint32_t read_offset;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen i_assert(file->mmap_base == NULL);
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen if (file->buffer != NULL && file->buffer_offset > start_offset) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we have to insert missing data to beginning of buffer */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset);
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen if (ret <= 0)
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen return ret;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen }
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen if (file->buffer == NULL) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen file->buffer =
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen file->buffer_offset = start_offset;
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen }
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen /* read all records */
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
93aa246b98205afab357471ecaaf51291a35bfa0Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen do {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen read_offset += ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size = read_offset - file->buffer_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_set_used_size(file->buffer, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } while (ret > 0 || (ret < 0 && errno == EINTR));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->last_size = read_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno == ESTALE) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* log file was deleted in NFS server, fail silently */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen file->filepath, "pread()");
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen return -1;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_transaction_log_file_sync(file) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_assert(file->sync_offset >= file->buffer_offset);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen buffer_set_used_size(file->buffer,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen file->sync_offset - file->buffer_offset);
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen return 1;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen}
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenstatic int
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenlog_file_map_check_offsets(struct mail_transaction_log_file *file,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen uoff_t start_offset, uoff_t end_offset)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen{
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (start_offset > file->sync_offset) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* broken start offset */
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen mail_index_set_error(file->log->index,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen "%s: start_offset (%"PRIuUOFF_T") > "
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen "current sync_offset (%"PRIuUOFF_T")",
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen file->filepath, start_offset, file->sync_offset);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return 0;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen mail_index_set_error(file->log->index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "%s: end_offset (%"PRIuUOFF_T") > "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "current sync_offset (%"PRIuUOFF_T")",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->filepath, start_offset, file->sync_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mail_transaction_log_file_map(struct mail_transaction_log_file *file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uoff_t start_offset, uoff_t end_offset)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen{
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen struct mail_index *index = file->log->index;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen size_t size;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen struct stat st;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen int ret;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen if (file->hdr.indexid == 0) {
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen /* corrupted */
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen return 0;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen }
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen i_assert(start_offset >= file->hdr.hdr_size);
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen i_assert(start_offset <= end_offset);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (index->log_locked && file == file->log->head &&
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen end_offset == (uoff_t)-1) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* we're not interested of going further than sync_offset */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (log_file_map_check_offsets(file, start_offset,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen end_offset) == 0)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen return 0;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen i_assert(start_offset <= file->sync_offset);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen end_offset = file->sync_offset;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen }
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (file->buffer != NULL && file->buffer_offset <= start_offset) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* see if we already have it */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen size = buffer_get_used_size(file->buffer);
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (file->buffer_offset + size >= end_offset)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen return 1;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen }
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen if (start_offset < file->buffer_offset) {
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* we had moved the log to memory but failed to read
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen the beginning of the log file */
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen mail_index_set_error(index,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen "%s: Beginning of the log isn't available",
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen file->filepath);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return log_file_map_check_offsets(file, start_offset,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen end_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!index->mmap_disable) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we are going to mmap() this file, but it's not necessarily
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mmaped currently. */
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen i_assert(file->buffer_offset == 0 || file->mmap_base == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(file->mmap_size == 0 || file->mmap_base != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (fstat(file->fd, &st) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen "fstat()");
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen return -1;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen }
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen file->last_size = st.st_size;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen if ((uoff_t)st.st_size < file->sync_offset) {
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen mail_transaction_log_file_set_corrupted(file,
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen "file size shrinked");
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen return 0;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen }
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if ((uoff_t)st.st_size == file->mmap_size) {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* we already have the whole file mmaped */
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (mail_transaction_log_file_sync(file) < 0)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return 0;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return log_file_map_check_offsets(file, start_offset,
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen end_offset);
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen }
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen }
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (file->mmap_base != NULL) {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen "munmap()");
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen }
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen file->mmap_base = NULL;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen file->mmap_size = 0;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen buffer_free(file->buffer);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen }
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen if (index->mmap_disable) {
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen ret = mail_transaction_log_file_read(file, start_offset);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (ret <= 0)
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return ret;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen } else {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (file->buffer != NULL) {
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* in case we just switched to mmaping */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_free(file->buffer);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->mmap_size = st.st_size;
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAP_SHARED, file->fd, 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (file->mmap_base == MAP_FAILED) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->mmap_base = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->mmap_size = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen "mmap()");
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen return -1;
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen if (file->mmap_size > mmap_get_page_size()) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (madvise(file->mmap_base, file->mmap_size,
a7bf18c0a462e4069675dec5038c474f8eb0a60dTimo Sirainen MADV_SEQUENTIAL) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_file_set_syscall_error(index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->filepath, "madvise()");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer = buffer_create_const_data(default_pool,
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen file->mmap_base,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->mmap_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen file->buffer_offset = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_transaction_log_file_sync(file) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return log_file_map_check_offsets(file, start_offset, end_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenvoid mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen *file)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen{
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buffer_t *buf;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen return;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (file->mmap_base != NULL) {
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* just copy to memory */
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen i_assert(file->buffer_offset == 0);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buf = buffer_create_dynamic(default_pool, file->mmap_size);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buffer_append(buf, file->mmap_base, file->mmap_size);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buffer_free(file->buffer);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen file->buffer = buf;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* and lose the mmap */
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
file->filepath,
"munmap()");
}
file->mmap_base = NULL;
} else if (file->buffer_offset != 0) {
/* we don't have the full log in the memory. read it. */
(void)mail_transaction_log_file_read(file, 0);
}
if (close(file->fd) < 0) {
mail_index_file_set_syscall_error(file->log->index,
file->filepath, "close()");
}
file->fd = -1;
}