From: Timo Sirainen Date: Mon, 10 Aug 2020 16:59:36 +0000 (+0300) Subject: lib-index: mail_index_write() - Make sure index is rewritten after log rotation X-Git-Tag: 2.3.14.rc1~320 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f388a47038ab1ee164c3d5dc234536d8a8cd4adb;p=thirdparty%2Fdovecot%2Fcore.git lib-index: mail_index_write() - Make sure index is rewritten after log rotation Otherwise the index will point to .log.2 file, which could become deleted before the index is rewritten again. --- diff --git a/src/lib-index/Makefile.am b/src/lib-index/Makefile.am index e1c5dbdc45..b9d197c28b 100644 --- a/src/lib-index/Makefile.am +++ b/src/lib-index/Makefile.am @@ -69,6 +69,7 @@ test_programs = \ test-mail-index-sync-ext \ test-mail-index-transaction-finish \ test-mail-index-transaction-update \ + test-mail-index-write \ test-mail-transaction-log-append \ test-mail-transaction-log-file \ test-mail-transaction-log-view @@ -114,6 +115,10 @@ test_mail_index_transaction_update_SOURCES = test-mail-index-transaction-update. test_mail_index_transaction_update_LDADD = mail-index-transaction-update.lo $(test_libs) test_mail_index_transaction_update_DEPENDENCIES = $(test_deps) +test_mail_index_write_SOURCES = test-mail-index-write.c +test_mail_index_write_LDADD = mail-index-write.lo $(test_libs) +test_mail_index_write_DEPENDENCIES = $(test_deps) + test_mail_transaction_log_append_SOURCES = test-mail-transaction-log-append.c test_mail_transaction_log_append_LDADD = mail-transaction-log-append.lo $(test_libs) test_mail_transaction_log_append_DEPENDENCIES = $(test_deps) diff --git a/src/lib-index/mail-index-write.c b/src/lib-index/mail-index-write.c index 12bbb3904c..6d2054b06d 100644 --- a/src/lib-index/mail-index-write.c +++ b/src/lib-index/mail-index-write.c @@ -155,6 +155,7 @@ void mail_index_write(struct mail_index *index, bool want_rotate, const char *reason) { struct mail_index_header *hdr = &index->map->hdr; + bool rotated = FALSE; i_assert(index->log_sync_locked); @@ -184,12 +185,13 @@ void mail_index_write(struct mail_index *index, bool want_rotate, wasn't, it just causes an extra stat() and gets fixed later on. */ hdr->log2_rotate_time = ioloop_time; + rotated = TRUE; } } if (MAIL_INDEX_IS_IN_MEMORY(index)) ; - else if (!mail_index_should_recreate(index)) { + else if (!rotated && !mail_index_should_recreate(index)) { /* make sure we don't keep getting back in here */ index->reopen_main_index = TRUE; } else { diff --git a/src/lib-index/test-mail-index-write.c b/src/lib-index/test-mail-index-write.c new file mode 100644 index 0000000000..1559ab38ec --- /dev/null +++ b/src/lib-index/test-mail-index-write.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "test-common.h" +#include "mail-index-private.h" +#include "mail-transaction-log-private.h" + +#define TEST_INDEX_FNAME ".test.index.write" +#define TEST_INDEXID 123456 +#define LOG_FILE1_HEAD_OFFSET 200 + +static bool expect_index_rewrite; +static bool rotate_fail; + +static struct mail_transaction_log_file log_file = { + .hdr = { + .indexid = TEST_INDEXID, + .file_seq = 1, + }, +}; +static struct mail_transaction_log_file log_file2 = { + .hdr = { + .indexid = TEST_INDEXID, + .file_seq = 2, + .prev_file_seq = 1, + .prev_file_offset = LOG_FILE1_HEAD_OFFSET, + }, +}; + +void mail_index_set_error(struct mail_index *index ATTR_UNUSED, + const char *fmt ATTR_UNUSED, ...) +{ +} + +void mail_index_set_syscall_error(struct mail_index *index ATTR_UNUSED, + const char *function) +{ + i_error("%s() failed: %m", function); +} + +void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED, + const char *filepath, + const char *function) +{ + i_error("%s(%s) failed: %m", function, filepath); +} + +int mail_index_create_tmp_file(struct mail_index *index ATTR_UNUSED, + const char *path_prefix, const char **path_r) +{ + const char *path; + int fd; + + test_assert(expect_index_rewrite); + + path = *path_r = t_strconcat(path_prefix, ".tmp", NULL); + fd = open(path, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + i_error("creat() failed: %m"); + return -1; + } + return fd; +} + +int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED) +{ + return -1; +} + +int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset) +{ + i_assert(!reset); + + if (rotate_fail) + return -1; + + log_file.next = &log_file2; + log->head = &log_file2; + return 0; +} + +static void test_mail_index_write(void) +{ + struct mail_transaction_log log = { + .head = &log_file, + .files = &log_file, + }; + struct mail_index_record_map rec_map = { + .records_count = 0, + }; + struct mail_index_map map = { + .hdr = { + .indexid = TEST_INDEXID, + .log_file_seq = 1, + .log_file_tail_offset = 100, + .log_file_head_offset = LOG_FILE1_HEAD_OFFSET, + }, + .rec_map = &rec_map, + }; + struct mail_index index = { + .event = event_create(NULL), + .log = &log, + .map = &map, + .dir = ".", + .fd = -1, + .indexid = TEST_INDEXID, + .filepath = TEST_INDEX_FNAME, + .log_sync_locked = TRUE, + }; + + test_begin("test_mail_index_write()"); + + /* test failed rotation, no index rewrite */ + rotate_fail = TRUE; + expect_index_rewrite = FALSE; + test_assert(!index.reopen_main_index); + index.fd = 1; /* anything but -1 */ + mail_index_write(&index, TRUE, "testing"); + test_assert(log.head == log.files); + test_assert(index.reopen_main_index); + + /* test failed rotation, with index rewrite */ + expect_index_rewrite = TRUE; + index.reopen_main_index = FALSE; + index.fd = -1; + mail_index_write(&index, TRUE, "testing"); + test_assert(log.head == log.files); + test_assert(!index.reopen_main_index); + + /* test successful rotation, with index rewrite */ + rotate_fail = FALSE; + mail_index_write(&index, TRUE, "testing"); + test_assert(log.head != log.files && log.head == &log_file2); + test_assert(!index.reopen_main_index); + + event_unref(&index.event); + i_unlink(TEST_INDEX_FNAME); + test_end(); +} + +int main(void) +{ + static void (*const test_functions[])(void) = { + test_mail_index_write, + NULL + }; + return test_run(test_functions); +}