mail-transaction-log-file.c revision 8cd0a1a2200e65cd134d03fe3f93ec02f1746359
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "ioloop.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "buffer.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "file-dotlock.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "nfs-workarounds.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "read-full.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#include "write-full.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#include "mmap-util.h"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#include "mail-index-private.h"
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen#include "mail-transaction-log-private.h"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen#define LOG_PREFETCH 1024
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen#define MEMORY_LOG_NAME "(in-memory transaction log file)"
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *fmt, ...)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen va_list va;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->corrupted = TRUE;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->hdr.indexid = 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* indexid=0 marks the log file as corrupted */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (pwrite_full(file->fd, &file->hdr.indexid,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen sizeof(file->hdr.indexid),
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen offsetof(struct mail_transaction_log_header,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen indexid)) < 0) {
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen file->filepath, "pwrite()");
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen va_start(va, fmt);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen t_push();
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen mail_index_set_error(file->log->index,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen "Corrupted transaction log file %s: %s",
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->filepath, t_strdup_vprintf(fmt, va));
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen t_pop();
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen va_end(va);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct mail_transaction_log_file *
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_alloc(struct mail_transaction_log *log,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen const char *path)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen struct mail_transaction_log_file *file;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen file = i_new(struct mail_transaction_log_file, 1);
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen file->log = log;
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen file->filepath = i_strdup(path);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen file->fd = -1;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen return file;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid mail_transaction_log_file_free(struct mail_transaction_log_file **_file)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_transaction_log_file *file = *_file;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct mail_transaction_log_file **p;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen int old_errno = errno;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen *_file = NULL;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_unlock(file);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen for (p = &file->log->files; *p != NULL; p = &(*p)->next) {
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (*p == file) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen *p = file->next;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (file == file->log->head)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen file->log->head = NULL;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (file->buffer != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen buffer_free(file->buffer);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen if (file->mmap_base != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (munmap(file->mmap_base, file->mmap_size) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->filepath,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen "munmap()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->fd != -1) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (close(file->fd) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen file->filepath,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "close()");
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(file->filepath);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen errno = old_errno;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic void
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenmail_transaction_log_file_add_to_list(struct mail_transaction_log_file *file)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_transaction_log *log = file->log;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_transaction_log_file **p;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_index_map *map = log->index->map;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (map != NULL && file->hdr.file_seq == map->hdr.log_file_seq &&
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen map->hdr.log_file_head_offset != 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we can get a valid log offset from index file. initialize
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen sync_offset from it so we don't have to read the whole log
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file from beginning. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (map->hdr.log_file_head_offset >= file->hdr.hdr_size)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->sync_offset = map->hdr.log_file_head_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_set_error(log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "%s: log_file_head_offset too small",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen log->index->filepath);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->sync_offset = file->hdr.hdr_size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->saved_tail_offset = map->hdr.log_file_tail_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->sync_offset = file->hdr.hdr_size;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen /* insert it to correct position */
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen for (p = &log->files; *p != NULL; p = &(*p)->next) {
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen if ((*p)->hdr.file_seq > file->hdr.file_seq)
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen break;
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen i_assert((*p)->hdr.file_seq < file->hdr.file_seq);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen file->next = *p;
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen *p = file;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_init_hdr(struct mail_transaction_log *log,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_transaction_log_header *hdr)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_index *index = log->index;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen memset(hdr, 0, sizeof(*hdr));
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->minor_version = MAIL_TRANSACTION_LOG_MINOR_VERSION;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->hdr_size = sizeof(struct mail_transaction_log_header);
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->indexid = log->index->indexid;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen hdr->create_stamp = ioloop_time;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (index->fd != -1) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* not creating index - make sure we have latest header */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (!index->mapping) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (mail_index_map(index,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if we got here from mapping, the .log file is
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen corrupted. use whatever values we got from index
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (index->map != NULL) {
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen hdr->prev_file_seq = index->map->hdr.log_file_seq;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen hdr->prev_file_offset = index->map->hdr.log_file_head_offset;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen hdr->file_seq = index->map->hdr.log_file_seq + 1;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen hdr->file_seq = 1;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen }
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* make sure the sequence grows */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen hdr->file_seq = log->head->hdr.file_seq+1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct mail_transaction_log_file *
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_alloc_in_memory(struct mail_transaction_log *log)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen struct mail_transaction_log_file *file;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file = mail_transaction_log_file_alloc(log, MEMORY_LOG_NAME);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (mail_transaction_log_init_hdr(log, &file->hdr) < 0) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen i_free(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->buffer = buffer_create_dynamic(default_pool, 4096);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen file->buffer_offset = sizeof(file->hdr);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_add_to_list(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return file;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen int ret;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (file->log->dotlock_count > 0)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen ret = 1;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen else {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen ret = file_dotlock_create(&file->log->dotlock_settings,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file->filepath, 0,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen &file->log->dotlock);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (ret > 0) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen file->log->dotlock_count++;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen file->locked = TRUE;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return 0;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (ret < 0) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen file->filepath,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "file_dotlock_create()");
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mail_index_set_error(file->log->index,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "Timeout while waiting for release of "
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "dotlock for transaction log file %s",
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen file->filepath);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen file->log->index->index_lock_timeout = TRUE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen}
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenstatic int
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenmail_transaction_log_file_undotlock(struct mail_transaction_log_file *file)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen{
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen int ret;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (--file->log->dotlock_count > 0)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return 0;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = file_dotlock_delete(&file->log->dotlock);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret < 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file->filepath, "file_dotlock_delete()");
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret == 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_set_error(file->log->index,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "Dotlock was lost for transaction log file %s",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file->filepath);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return 0;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen}
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenint mail_transaction_log_file_lock(struct mail_transaction_log_file *file)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen{
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen int ret;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (file->locked)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file->locked = TRUE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return mail_transaction_log_file_dotlock(file);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(file->file_lock == NULL);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ret = mail_index_lock_fd(file->log->index, file->filepath, file->fd,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen F_WRLCK, MAIL_INDEX_LOCK_SECS,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen &file->file_lock);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (ret > 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file->locked = TRUE;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (ret < 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file->filepath,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "mail_index_wait_lock_fd()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return -1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen mail_index_set_error(file->log->index,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "Timeout while waiting for lock for transaction log file %s",
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file->filepath);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file->log->index->index_lock_timeout = TRUE;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return -1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (!file->locked)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file->locked = FALSE;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (file->log->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen mail_transaction_log_file_undotlock(file);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen file_unlock(&file->file_lock);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainenstatic int
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen bool ignore_estale)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen struct mail_transaction_log_file *f;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen int ret;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (file->corrupted)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret < 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (errno != ESTALE || !ignore_estale) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file->filepath,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "pread_full()");
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret == 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_transaction_log_file_set_corrupted(file,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "unexpected end of file while reading header");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.major_version != MAIL_TRANSACTION_LOG_MAJOR_VERSION) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* incompatible version - fix silently */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.hdr_size < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_set_corrupted(file,
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen "Header size too small");
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen return 0;
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.hdr_size < sizeof(file->hdr)) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* @UNSAFE: smaller than we expected - zero out the fields we
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen shouldn't have filled */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen memset(PTR_OFFSET(&file->hdr, file->hdr.hdr_size), 0,
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen sizeof(file->hdr) - file->hdr.hdr_size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->hdr.indexid == 0) {
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen /* corrupted */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->corrupted = TRUE;
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen mail_index_set_error(file->log->index,
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen "Transaction log file %s: marked corrupted",
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen file->filepath);
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen if (file->hdr.indexid != file->log->index->indexid) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (file->log->index->indexid != 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* index file was probably just rebuilt and we don't
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen know about it yet */
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen mail_transaction_log_file_set_corrupted(file,
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen "indexid changed %u -> %u",
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen file->log->index->indexid, file->hdr.indexid);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen return 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* creating index file. since transaction log is created
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen first, use the indexid in it to create the main index
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen to avoid races. */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen file->log->index->indexid = file->hdr.indexid;
dc23356d79e452e70b589aae8fb78cd43002c384Timo Sirainen }
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* make sure we already don't have a file with the same sequence
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen opened. it shouldn't happen unless the old log file was
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen corrupted. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen for (f = file->log->files; f != NULL; f = f->next) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (f->hdr.file_seq == file->hdr.file_seq) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* mark the old file corrupted. we can't safely remove
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it from the list however, so return failure. */
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen mail_transaction_log_file_set_corrupted(f,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "duplicate transaction log sequence (%u)",
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen f->hdr.file_seq);
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen return 0;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return 1;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenmail_transaction_log_file_stat(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bool ignore_estale)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct stat st;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (fstat(file->fd, &st) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (errno != ESTALE || !ignore_estale) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->filepath, "fstat()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->st_dev = st.st_dev;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->st_ino = st.st_ino;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->last_mtime = st.st_mtime;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->last_size = st.st_size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenstatic bool
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenmail_transaction_log_file_is_dupe(struct mail_transaction_log_file *file)
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen{
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen struct mail_transaction_log_file *tmp;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen for (tmp = file->log->files; tmp != NULL; tmp = tmp->next) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (tmp->st_ino == file->st_ino &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen CMP_DEV_T(tmp->st_dev, file->st_dev))
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_create2(struct mail_transaction_log_file *file,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen int new_fd, bool reset,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct dotlock **dotlock)
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_index *index = file->log->index;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen struct stat st;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *path2;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen int fd, ret;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen bool rename_existing;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* log creation is locked now - see if someone already created it.
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen note that if we're rotating, we need to keep the log locked until
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen the file has been rewritten. and because fcntl() locks are stupid,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if we go and open()+close() the file and we had it already opened,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen its locks are lost. so we use stat() to check if the file has been
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen recreated, although it almost never is. */
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (reset)
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen rename_existing = FALSE;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen else if (nfs_safe_stat(file->filepath, &st) < 0) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (errno != ENOENT) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen "stat()");
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen return -1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rename_existing = FALSE;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen } else if (st.st_ino == file->st_ino &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen CMP_DEV_T(st.st_dev, file->st_dev) &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* inode/dev checks are enough when we're rotating the file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen but not when we're replacing a broken log file */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen st.st_mtime == file->last_mtime &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (uoff_t)st.st_size == file->last_size) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* no-one else recreated the file */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rename_existing = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* recreated. use the file if its header is ok */
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen fd = nfs_safe_open(file->filepath, O_RDWR);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (fd == -1) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (errno != ENOENT) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->filepath, "open()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->fd = fd;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (mail_transaction_log_file_read_hdr(file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen FALSE) > 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* yes, it was ok */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)file_dotlock_delete(dotlock);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen mail_transaction_log_file_add_to_list(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen file->fd = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (close(fd) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->filepath, "close()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen rename_existing = FALSE;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (mail_transaction_log_init_hdr(file->log, &file->hdr) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (reset) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->hdr.prev_file_seq = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->hdr.prev_file_offset = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "write_full()");
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->fd = new_fd;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = mail_transaction_log_file_stat(file, FALSE);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* if we return -1 the dotlock deletion code closes the fd */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->fd = -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (ret < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen /* keep two log files */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (rename_existing) {
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen /* rename() would be nice and easy way to do this, except then
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen there's a race condition between the rename and
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen file_dotlock_replace(). during that time the log file
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen doesn't exist, which could cause problems. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen path2 = t_strconcat(file->filepath, ".2", NULL);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (unlink(path2) < 0 && errno != ENOENT) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen mail_index_set_error(index, "unlink(%s) failed: %m",
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen path2);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* try to link() anyway */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (link(file->filepath, path2) < 0 &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen errno != ENOENT && errno != EEXIST) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_set_error(index, "link(%s, %s) failed: %m",
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->filepath, path2);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* ignore the error. we don't care that much about the
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen second log file and we're going to overwrite this
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen first one. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (file_dotlock_replace(dotlock,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* success */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->fd = new_fd;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_add_to_list(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint mail_transaction_log_file_create(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bool reset)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_index *index = file->log->index;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct dotlock *dotlock;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen mode_t old_mask;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen int fd;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* With dotlocking we might already have path.lock created, so this
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen filename has to be different. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen old_mask = umask(index->mode ^ 0666);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fd = file_dotlock_open(&file->log->new_dotlock_settings,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen file->filepath, 0, &dotlock);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen umask(old_mask);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (fd == -1) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "file_dotlock_open()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (index->gid != (gid_t)-1 &&
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen fchown(fd, (uid_t)-1, index->gid) < 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_index_file_set_syscall_error(index, file->filepath,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen "fchown()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)file_dotlock_delete(&dotlock);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen /* either fd gets used or the dotlock gets deleted and returned fd
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen is for the existing file */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (mail_transaction_log_file_create2(file, fd, reset, &dotlock) < 0) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (dotlock != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)file_dotlock_delete(&dotlock);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainenint mail_transaction_log_file_open(struct mail_transaction_log_file *file,
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen bool check_existing)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen unsigned int i;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bool ignore_estale;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0;; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->fd = nfs_safe_open(file->filepath, O_RDWR);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (file->fd == -1) {
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen if (errno == ENOENT)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen file->filepath, "open()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen ignore_estale = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (mail_transaction_log_file_stat(file, ignore_estale) < 0)
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen ret = -1;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen else if (check_existing &&
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen mail_transaction_log_file_is_dupe(file))
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen return 0;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen else {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = mail_transaction_log_file_read_hdr(file,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ignore_estale);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret > 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* success */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* corrupted */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlink(file->filepath) < 0 && errno != ENOENT) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_set_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "unlink(%s) failed: %m",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->filepath);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen return 0;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (errno != ESTALE ||
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen i == MAIL_INDEX_ESTALE_RETRY_COUNT) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* syscall error */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return -1;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen /* ESTALE - try again */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_add_to_list(file);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 1;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenlog_file_track_mailbox_sync_offset_hdr(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const void *data, unsigned int size)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen const struct mail_transaction_header_update *u = data;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const struct mail_index_header *ihdr;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen const unsigned int offset_pos =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen offsetof(struct mail_index_header, log_file_tail_offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const unsigned int offset_size = sizeof(ihdr->log_file_tail_offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint32_t sync_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen i_assert(offset_size == sizeof(sync_offset));
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (size < sizeof(*u) || size < sizeof(*u) + u->size) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen "header update extends beyond record size");
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (u->offset <= offset_pos &&
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen u->offset + u->size >= offset_pos + offset_size) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen memcpy(&sync_offset,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen CONST_PTR_OFFSET(u + 1, offset_pos - u->offset),
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen sizeof(sync_offset));
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (sync_offset < file->saved_tail_offset) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen mail_transaction_log_file_set_corrupted(file,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen "log_file_tail_offset shrinked");
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen }
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen file->saved_tail_offset = sync_offset;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen if (sync_offset > file->max_tail_offset)
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen file->max_tail_offset = sync_offset;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen return 1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen}
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenstatic int
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenlog_file_track_mailbox_sync_offset(struct mail_transaction_log_file *file,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen const struct mail_transaction_header *hdr,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen unsigned int trans_size)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen int ret;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen MAIL_TRANSACTION_HEADER_UPDATE) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* see if this updates mailbox_sync_offset */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = log_file_track_mailbox_sync_offset_hdr(file, hdr + 1,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen trans_size -
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen sizeof(*hdr));
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (ret != 0)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return ret < 0 ? -1 : 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (file->max_tail_offset == file->sync_offset) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* external transactions aren't synced to mailbox. we can
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen update mailbox sync offset to skip this transaction to
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen avoid re-reading it at the next sync. */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen file->max_tail_offset += trans_size;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenstatic int
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenmail_transaction_log_file_sync(struct mail_transaction_log_file *file)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen const struct mail_transaction_header *hdr;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen const void *data;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct stat st;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen size_t size, avail;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen uint32_t trans_size = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen data = buffer_get_data(file->buffer, &size);
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen if (file->sync_offset < file->buffer_offset)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->sync_offset = file->buffer_offset;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen hdr = CONST_PTR_OFFSET(data, file->sync_offset -
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen file->buffer_offset);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen trans_size = mail_index_offset_to_uint32(hdr->size);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (trans_size == 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* unfinished */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return 1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (trans_size < sizeof(*hdr)) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_transaction_log_file_set_corrupted(file,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "hdr.size too small (%u)", trans_size);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (file->sync_offset - file->buffer_offset + trans_size > size)
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen break;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* transaction has been fully written */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (log_file_track_mailbox_sync_offset(file, hdr,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen trans_size) < 0)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->sync_offset += trans_size;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen trans_size = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (file->mmap_base != NULL && !file->locked) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* Now that all the mmaped pages have page faulted, check if
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen the file had changed while doing that. Only after the last
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen page has faulted, the size returned by fstat() can be
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen trusted. Otherwise it might point to a page boundary while
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen the next page is still being written.
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen Without this check we might see partial transactions,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen sometimes causing "Extension record updated without intro
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen prefix" errors. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (fstat(file->fd, &st) < 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->filepath,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "fstat()");
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if ((uoff_t)st.st_size != file->last_size) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->last_size = st.st_size;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen avail = file->sync_offset - file->buffer_offset;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (avail != size) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* There's more data than we could sync at the moment. If the
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen last record's size wasn't valid, we can't know if it will
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen be updated unless we've locked the log.
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen If the record size was valid, this is an error because the
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen pread()s or the above fstat() check for mmaps should have
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen guaranteed that this doesn't happen. */
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen if (file->locked || trans_size != 0) {
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen if (trans_size != 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_transaction_log_file_set_corrupted(file,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "hdr.size too large (%u)", trans_size);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen } else {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen mail_transaction_log_file_set_corrupted(file,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen "Unexpected garbage at EOF");
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen // FIXME: here we probably want to flush NFS data cache
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (file->next != NULL &&
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->hdr.file_seq == file->next->hdr.prev_file_seq &&
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen file->next->hdr.prev_file_offset != file->sync_offset) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_index_set_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "Invalid transaction log size "
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen "(%"PRIuUOFF_T" vs %u): %s", file->sync_offset,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen file->log->head->hdr.prev_file_offset, file->filepath);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return -1;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return 1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainenmail_transaction_log_file_insert_read(struct mail_transaction_log_file *file,
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen uoff_t offset)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen void *data;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen size_t size;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen ssize_t ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen size = file->buffer_offset - offset;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_copy(file->buffer, size, file->buffer, 0, (size_t)-1);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen data = buffer_get_space_unsafe(file->buffer, 0, size);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = pread_full(file->fd, data, size, offset);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (ret > 0) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* success */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen file->buffer_offset -= size;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return 1;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen }
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* failure. don't leave ourself to inconsistent state */
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_copy(file->buffer, 0, file->buffer, size, (size_t)-1);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen buffer_set_used_size(file->buffer, file->buffer->used - size);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_transaction_log_file_set_corrupted(file, "file shrinked");
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (errno == ESTALE) {
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen /* log file was deleted in NFS server, fail silently */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->filepath, "pread()");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenmail_transaction_log_file_read(struct mail_transaction_log_file *file,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uoff_t start_offset)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen void *data;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen size_t size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint32_t read_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(file->mmap_base == NULL);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (file->buffer != NULL && file->buffer_offset > start_offset) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we have to insert missing data to beginning of buffer */
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen ret = mail_transaction_log_file_insert_read(file, start_offset);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (ret <= 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (file->buffer == NULL) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen file->buffer =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen buffer_create_dynamic(default_pool, LOG_PREFETCH);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen file->buffer_offset = start_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen /* read all records */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen read_offset = file->buffer_offset + buffer_get_used_size(file->buffer);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen do {
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (ret > 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen read_offset += ret;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen size = read_offset - file->buffer_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen buffer_set_used_size(file->buffer, size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } while (ret > 0 || (ret < 0 && errno == EINTR));
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen file->last_size = read_offset;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret < 0) {
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (errno == ESTALE) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* log file was deleted in NFS server, fail silently */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return 0;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_index_file_set_syscall_error(file->log->index,
file->filepath, "pread()");
return -1;
}
if ((ret = mail_transaction_log_file_sync(file)) <= 0) {
i_assert(ret != 0);
return 0;
}
i_assert(file->sync_offset >= file->buffer_offset);
buffer_set_used_size(file->buffer,
file->sync_offset - file->buffer_offset);
return 1;
}
static int
log_file_map_check_offsets(struct mail_transaction_log_file *file,
uoff_t start_offset, uoff_t end_offset)
{
if (start_offset > file->sync_offset) {
/* broken start offset */
mail_index_set_error(file->log->index,
"%s: start_offset (%"PRIuUOFF_T") > "
"current sync_offset (%"PRIuUOFF_T")",
file->filepath, start_offset, file->sync_offset);
return 0;
}
if (end_offset != (uoff_t)-1 && end_offset > file->sync_offset) {
mail_index_set_error(file->log->index,
"%s: end_offset (%"PRIuUOFF_T") > "
"current sync_offset (%"PRIuUOFF_T")",
file->filepath, start_offset, file->sync_offset);
return 0;
}
return 1;
}
static int
mail_transaction_log_file_mmap(struct mail_transaction_log_file *file)
{
if (file->buffer != NULL) {
/* in case we just switched to mmaping */
buffer_free(file->buffer);
}
file->mmap_size = file->last_size;
file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ, MAP_SHARED,
file->fd, 0);
if (file->mmap_base == MAP_FAILED) {
file->mmap_base = NULL;
file->mmap_size = 0;
mail_index_file_set_syscall_error(file->log->index,
file->filepath, "mmap()");
return -1;
}
if (file->mmap_size > mmap_get_page_size()) {
if (madvise(file->mmap_base, file->mmap_size,
MADV_SEQUENTIAL) < 0) {
mail_index_file_set_syscall_error(file->log->index,
file->filepath, "madvise()");
}
}
file->buffer = buffer_create_const_data(default_pool,
file->mmap_base,
file->mmap_size);
file->buffer_offset = 0;
return 0;
}
static void
mail_transaction_log_file_munmap(struct mail_transaction_log_file *file)
{
if (file->mmap_base == NULL)
return;
if (munmap(file->mmap_base, file->mmap_size) < 0) {
mail_index_file_set_syscall_error(file->log->index,
file->filepath, "munmap()");
}
file->mmap_base = NULL;
file->mmap_size = 0;
buffer_free(file->buffer);
}
int mail_transaction_log_file_map(struct mail_transaction_log_file *file,
uoff_t start_offset, uoff_t end_offset)
{
struct mail_index *index = file->log->index;
size_t size;
struct stat st;
int ret;
if (file->hdr.indexid == 0) {
/* corrupted */
return 0;
}
i_assert(start_offset >= file->hdr.hdr_size);
i_assert(start_offset <= end_offset);
if (index->log_locked && file == file->log->head &&
end_offset == (uoff_t)-1) {
/* we're not interested of going further than sync_offset */
if (log_file_map_check_offsets(file, start_offset,
end_offset) == 0)
return 0;
i_assert(start_offset <= file->sync_offset);
end_offset = file->sync_offset;
}
if (file->buffer != NULL && file->buffer_offset <= start_offset) {
/* see if we already have it */
size = buffer_get_used_size(file->buffer);
if (file->buffer_offset + size >= end_offset)
return 1;
}
if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
if (start_offset < file->buffer_offset) {
/* we had moved the log to memory but failed to read
the beginning of the log file */
mail_index_set_error(index,
"%s: Beginning of the log isn't available",
file->filepath);
return 0;
}
return log_file_map_check_offsets(file, start_offset,
end_offset);
}
if (!index->mmap_disable) {
/* we are going to mmap() this file, but it's not necessarily
mmaped currently. */
i_assert(file->buffer_offset == 0 || file->mmap_base == NULL);
i_assert(file->mmap_size == 0 || file->mmap_base != NULL);
if (fstat(file->fd, &st) < 0) {
mail_index_file_set_syscall_error(index, file->filepath,
"fstat()");
return -1;
}
file->last_size = st.st_size;
if ((uoff_t)st.st_size < file->sync_offset) {
mail_transaction_log_file_set_corrupted(file,
"file size shrinked");
return 0;
}
if ((uoff_t)st.st_size == file->mmap_size) {
/* we already have the whole file mmaped */
if ((ret = mail_transaction_log_file_sync(file)) < 0)
return 0;
if (ret > 0) {
return log_file_map_check_offsets(file,
start_offset,
end_offset);
}
/* size changed, re-mmap */
}
}
if (index->mmap_disable) {
mail_transaction_log_file_munmap(file);
ret = mail_transaction_log_file_read(file, start_offset);
if (ret <= 0)
return ret;
} else {
do {
mail_transaction_log_file_munmap(file);
if (mail_transaction_log_file_mmap(file) < 0)
return -1;
if ((ret = mail_transaction_log_file_sync(file)) < 0)
return 0;
} while (ret == 0);
}
return log_file_map_check_offsets(file, start_offset, end_offset);
}
void mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file
*file)
{
buffer_t *buf;
if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file))
return;
if (file->mmap_base != NULL) {
/* just copy to memory */
i_assert(file->buffer_offset == 0);
buf = buffer_create_dynamic(default_pool, file->mmap_size);
buffer_append(buf, file->mmap_base, file->mmap_size);
buffer_free(file->buffer);
file->buffer = buf;
/* and lose the mmap */
if (munmap(file->mmap_base, file->mmap_size) < 0) {
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;
}