bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen#include "ioloop.h"
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-private.h"
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen#include "mail-transaction-log-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_index_fsck_error(struct mail_index *index,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const char *fmt, ...) ATTR_FORMAT(2, 3);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mail_index_fsck_error(struct mail_index *index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *fmt, ...)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_list va;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_start(va, fmt);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(index, "Fixed index file %s: %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->filepath, t_strdup_vprintf(fmt, va));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_end(va);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define CHECK(field, oper) \
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->field oper map->hdr.field) { \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_fsck_error(index, #field" %u -> %u", \
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen map->hdr.field, hdr->field); \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainenstatic void
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainenmail_index_fsck_log_pos(struct mail_index *index, struct mail_index_map *map,
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen struct mail_index_header *hdr)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen uint32_t file_seq;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen uoff_t file_offset;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen mail_transaction_log_get_head(index->log, &file_seq, &file_offset);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->log_file_seq < file_seq) {
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen /* index's log_file_seq is too old. move it to log head. */
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->log_file_head_offset = hdr->log_file_tail_offset =
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen sizeof(struct mail_transaction_log_header);
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen } else if (hdr->log_file_seq == file_seq) {
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen /* index's log_file_seq matches the current log. make sure the
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen offsets are valid. */
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->log_file_head_offset > file_offset)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->log_file_head_offset = file_offset;
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen else if (hdr->log_file_head_offset < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE)
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen hdr->log_file_head_offset = MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE;
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->log_file_tail_offset > hdr->log_file_head_offset)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->log_file_tail_offset = hdr->log_file_head_offset;
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen else if (hdr->log_file_tail_offset < MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE)
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen hdr->log_file_tail_offset = MAIL_TRANSACTION_LOG_HEADER_MIN_SIZE;
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen } else {
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen /* index's log_file_seq is newer than exists. move it to
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen end of the current log head. */
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen hdr->log_file_head_offset = hdr->log_file_tail_offset =
826f767b6017e4572dcc1dcd4f7573a5df6cd767Timo Sirainen file_offset;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen }
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->log_file_seq = file_seq;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen CHECK(log_file_seq, !=);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->log_file_seq == map->hdr.log_file_seq) {
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen /* don't bother complaining about these if file changed too */
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen CHECK(log_file_head_offset, !=);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen CHECK(log_file_tail_offset, !=);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen }
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen}
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainenstatic void
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainenmail_index_fsck_header(struct mail_index *index, struct mail_index_map *map,
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen struct mail_index_header *hdr)
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen{
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen /* mail_index_map_check_header() has already checked that the index
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen isn't completely broken. */
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1)
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen hdr->uid_validity = ioloop_time;
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen if (index->log->head != NULL)
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen mail_index_fsck_log_pos(index, map, hdr);
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen}
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenstatic bool
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenarray_has_name(const ARRAY_TYPE(const_string) *names, const char *name)
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen const char *const *namep;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach(names, namep) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (strcmp(*namep, name) == 0)
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen return TRUE;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen }
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen return FALSE;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen}
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenstatic unsigned int
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenmail_index_fsck_find_keyword_count(struct mail_index_map *map,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const struct mail_index_ext_header *ext_hdr)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen{
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const struct mail_index_record *rec;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const uint8_t *kw;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen unsigned int r, i, j, cur, max = 0, kw_pos, kw_size;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw_pos = ext_hdr->record_offset;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw_size = ext_hdr->record_size;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen rec = map->rec_map->records;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (r = 0; r < map->rec_map->records_count; r++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw = CONST_PTR_OFFSET(rec, kw_pos);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (i = cur = 0; i < kw_size; i++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (kw[i] != 0) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (j = 0; j < 8; j++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if ((kw[i] & (1 << j)) != 0)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen cur = i * 8 + j + 1;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (cur > max) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen max = cur;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (max == kw_size*8)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return max;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen rec = CONST_PTR_OFFSET(rec, map->hdr.record_size);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return max;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen}
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenstatic bool
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenkeyword_name_is_valid(const char *buffer, unsigned int pos, unsigned int size)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen{
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (; pos < size; pos++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (buffer[pos] == '\0')
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return TRUE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (((unsigned char)buffer[pos] & 0x7f) < 32) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* control characters aren't valid */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return FALSE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return FALSE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen}
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenstatic void
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenmail_index_fsck_keywords(struct mail_index *index, struct mail_index_map *map,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen struct mail_index_header *hdr,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const struct mail_index_ext_header *ext_hdr,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen unsigned int ext_offset, unsigned int *offset_p)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen{
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen struct mail_index_keyword_header *new_kw_hdr;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen struct mail_index_keyword_header_rec new_kw_rec;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen const char *name, *name_buffer, **name_array;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen unsigned int i, j, name_pos, name_size, rec_pos, hdr_offset, diff;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen unsigned int changed_count, keywords_count, name_base_pos;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen ARRAY_TYPE(const_string) names;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_t *dest;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen bool changed = FALSE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen hdr_offset = ext_offset +
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen mail_index_map_ext_hdr_offset(sizeof(MAIL_INDEX_EXT_KEYWORDS)-1);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, hdr_offset);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen keywords_count = kw_hdr->keywords_count;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw_rec = (const void *)(kw_hdr + 1);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_buffer = (const char *)(kw_rec + keywords_count);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_pos = (size_t)(name_buffer - (const char *)kw_hdr);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (name_pos > ext_hdr->hdr_size) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* the header is completely broken */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen keywords_count =
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen mail_index_fsck_find_keyword_count(map, ext_hdr);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen mail_index_fsck_error(index, "Assuming keywords_count = %u",
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen keywords_count);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen kw_rec = NULL;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_size = 0;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen changed = TRUE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen } else {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_size = ext_hdr->hdr_size - name_pos;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* create keyword name array. invalid keywords are added as
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen empty strings */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen t_array_init(&names, keywords_count);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (i = 0; i < keywords_count; i++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (name_size == 0 ||
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen !keyword_name_is_valid(name_buffer, kw_rec[i].name_offset,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_size))
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name = "";
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen else
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name = name_buffer + kw_rec[i].name_offset;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (*name != '\0' && array_has_name(&names, name)) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* duplicate */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name = "";
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen array_append(&names, &name, 1);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* give new names to invalid keywords */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen changed_count = 0;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_array = array_idx_modifiable(&names, 0);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (i = j = 0; i < keywords_count; i++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen while (name_array[i][0] == '\0') {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name = t_strdup_printf("unknown-%d", j++);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (!array_has_name(&names, name)) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_array[i] = name;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen changed = TRUE;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen changed_count++;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (!changed) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* nothing was broken */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen return;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen mail_index_fsck_error(index, "Renamed %u keywords to unknown-*",
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen changed_count);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen dest = buffer_create_dynamic(default_pool,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen I_MAX(ext_hdr->hdr_size, 128));
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen new_kw_hdr = buffer_append_space_unsafe(dest, sizeof(*new_kw_hdr));
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen new_kw_hdr->keywords_count = keywords_count;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* add keyword records so we can start appending names directly */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen rec_pos = dest->used;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&new_kw_rec);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)buffer_append_space_unsafe(dest, keywords_count * sizeof(*kw_rec));
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* write the actual records and names */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name_base_pos = dest->used;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen for (i = 0; i < keywords_count; i++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen new_kw_rec.name_offset = dest->used - name_base_pos;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_write(dest, rec_pos, &new_kw_rec, sizeof(new_kw_rec));
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen rec_pos += sizeof(*kw_rec);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_append(dest, name_array[i], strlen(name_array[i]) + 1);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* keep the header size at least the same size as before */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (dest->used < ext_hdr->hdr_size)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_append_zero(dest, ext_hdr->hdr_size - dest->used);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen if (dest->used > ext_hdr->hdr_size) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* need to resize the header */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen struct mail_index_ext_header new_ext_hdr;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen diff = dest->used - ext_hdr->hdr_size;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_copy(map->hdr_copy_buf, hdr_offset + diff,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen map->hdr_copy_buf, hdr_offset, (size_t)-1);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen map->hdr_base = map->hdr_copy_buf->data;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen hdr->header_size += diff;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen *offset_p += diff;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen new_ext_hdr = *ext_hdr;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen new_ext_hdr.hdr_size += diff;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_write(map->hdr_copy_buf, ext_offset,
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen &new_ext_hdr, sizeof(new_ext_hdr));
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen i_assert(hdr_offset + dest->used <= map->hdr_copy_buf->used);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen buffer_write(map->hdr_copy_buf, hdr_offset, dest->data, dest->used);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* keywords changed unexpectedly, so all views are broken now */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen index->inconsistency_id++;
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&dest);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen}
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenstatic void
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenmail_index_fsck_extensions(struct mail_index *index, struct mail_index_map *map,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen struct mail_index_header *hdr)
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen{
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen const struct mail_index_ext_header *ext_hdr;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen ARRAY_TYPE(const_string) names;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen const char *name, *error;
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen unsigned int offset, next_offset, i;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen t_array_init(&names, 64);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(hdr->base_header_size);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen for (i = 0; offset < hdr->header_size; i++) {
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen /* mail_index_map_ext_get_next() uses map->hdr, so make sure
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen it's up-to-date */
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen map->hdr = *hdr;
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen next_offset = offset;
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen if (mail_index_map_ext_get_next(map, &next_offset,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen &ext_hdr, &name) < 0) {
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen /* the extension continued outside header, drop it */
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen mail_index_fsck_error(index,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen "Dropped extension #%d (%s) "
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen "with invalid header size",
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen i, name);
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen hdr->header_size = offset;
909a45f03f34dcdf9495b037ab87520152a4bc6bTimo Sirainen buffer_set_used_size(map->hdr_copy_buf, hdr->header_size);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen break;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen }
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen if (mail_index_map_ext_hdr_check(hdr, ext_hdr, name,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen &error) < 0) {
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen mail_index_fsck_error(index,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen "Dropped broken extension #%d (%s)", i, name);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen } else if (array_has_name(&names, name)) {
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen mail_index_fsck_error(index,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen "Dropped duplicate extension %s", name);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen } else {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen /* name may change if header buffer is changed */
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen name = t_strdup(name);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (strcmp(name, MAIL_INDEX_EXT_KEYWORDS) == 0) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen mail_index_fsck_keywords(index, map, hdr,
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen ext_hdr, offset,
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen &next_offset);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen }
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen array_append(&names, &name, 1);
a553ee9b9c50d7cd317825ccb8150331560a9dd9Timo Sirainen offset = next_offset;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen continue;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen }
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen /* drop the field */
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen hdr->header_size -= next_offset - offset;
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen buffer_copy(map->hdr_copy_buf, offset,
1944ee7729e2fabd85773a81ca408acd3e36ab1cTimo Sirainen map->hdr_copy_buf, next_offset, (size_t)-1);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen buffer_set_used_size(map->hdr_copy_buf, hdr->header_size);
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen map->hdr_base = map->hdr_copy_buf->data;
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen }
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen}
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainenstatic void
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainenmail_index_fsck_records(struct mail_index *index, struct mail_index_map *map,
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen struct mail_index_header *hdr)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen{
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen struct mail_index_record *rec, *next_rec;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen uint32_t i, last_uid;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen bool logged_unordered_uids = FALSE, logged_zero_uids = FALSE;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen bool records_dropped = FALSE;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->messages_count = 0;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->seen_messages_count = 0;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->deleted_messages_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_unseen_uid_lowwater = 0;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_deleted_uid_lowwater = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen rec = map->rec_map->records; last_uid = 0;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen for (i = 0; i < map->rec_map->records_count; ) {
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen next_rec = PTR_OFFSET(rec, hdr->record_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rec->uid <= last_uid) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen /* log an error once, and skip this record */
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (rec->uid == 0) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (!logged_zero_uids) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen mail_index_fsck_error(index,
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen "Record UIDs have zeroes");
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen logged_zero_uids = TRUE;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen }
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen } else {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (!logged_unordered_uids) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen mail_index_fsck_error(index,
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen "Record UIDs unordered");
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen logged_unordered_uids = TRUE;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen }
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen }
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen /* not the fastest way when we're skipping lots of
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen records, but this should happen rarely so don't
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen bother optimizing. */
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen memmove(rec, next_rec, hdr->record_size *
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen (map->rec_map->records_count - i - 1));
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen map->rec_map->records_count--;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen records_dropped = TRUE;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->messages_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_SEEN) != 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->seen_messages_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_DELETED) != 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->deleted_messages_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_SEEN) == 0 &&
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_unseen_uid_lowwater == 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_unseen_uid_lowwater = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_DELETED) != 0 &&
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_deleted_uid_lowwater == 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_deleted_uid_lowwater = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last_uid = rec->uid;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen rec = next_rec;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen i++;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen }
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (records_dropped) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen /* all existing views are broken now */
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen index->inconsistency_id++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->next_uid <= last_uid) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_fsck_error(index, "next_uid %u -> %u",
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->next_uid, last_uid+1);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->next_uid = last_uid+1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->first_unseen_uid_lowwater == 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->first_deleted_uid_lowwater == 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->first_recent_uid > hdr->next_uid)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_recent_uid = hdr->next_uid;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen if (hdr->first_recent_uid == 0)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr->first_recent_uid = 1;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen CHECK(uid_validity, !=);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CHECK(messages_count, !=);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CHECK(seen_messages_count, !=);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CHECK(deleted_messages_count, !=);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CHECK(first_unseen_uid_lowwater, <);
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen CHECK(first_deleted_uid_lowwater, <);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen CHECK(first_recent_uid, !=);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen}
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainenstatic void
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainenmail_index_fsck_map(struct mail_index *index, struct mail_index_map *map)
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen{
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen struct mail_index_header hdr;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen if (index->log->head != NULL) {
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen /* Remember the log head position. If we go back in the index's
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen head offset, ignore errors in the log up to this offset. */
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen mail_transaction_log_get_head(index->log,
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen &index->fsck_log_head_file_seq,
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen &index->fsck_log_head_file_offset);
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen }
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen hdr = map->hdr;
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen mail_index_fsck_header(index, map, &hdr);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen mail_index_fsck_extensions(index, map, &hdr);
9f57ffa4d421951bbfc7f2de2abcbd8033e6a8c3Timo Sirainen mail_index_fsck_records(index, map, &hdr);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainen hdr.flags |= MAIL_INDEX_HDR_FLAG_FSCKD;
633e6afa5de9ad8108ff8dbdee889ecf6170026eTimo Sirainen map->hdr = hdr;
909a45f03f34dcdf9495b037ab87520152a4bc6bTimo Sirainen i_assert(map->hdr_copy_buf->used == map->hdr.header_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_fsck(struct mail_index *index)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen bool orig_locked = index->log_sync_locked;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen struct mail_index_map *map;
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen uint32_t file_seq;
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen uoff_t file_offset;
b9ce555e8624a5593b3bfd81b572b7d2e1e1fca5Timo Sirainen
77f386273491b3a20b49b2a5a9db4b6e360615f9Timo Sirainen i_warning("fscking index file %s", index->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen index->fscked = TRUE;
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen if (index->log->head == NULL) {
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen /* we're trying to open the index files, but there wasn't
3e42e3748e489b62554ae0562b5537c20defc1eeTimo Sirainen any .log file. */
3e42e3748e489b62554ae0562b5537c20defc1eeTimo Sirainen if (mail_transaction_log_create(index->log, FALSE) < 0)
3e42e3748e489b62554ae0562b5537c20defc1eeTimo Sirainen return -1;
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen }
d67f6ca7e313e9192268f6bf9952594524655dcdTimo Sirainen
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen if (!orig_locked) {
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen if (mail_transaction_log_sync_lock(index->log, "fscking",
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen &file_seq, &file_offset) < 0)
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen return -1;
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen }
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen map = mail_index_map_clone(index->map);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen mail_index_unmap(&index->map);
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen index->map = map;
b00eab39755656ee5bac297f5f6ae959da5acef1Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_index_fsck_map(index, map);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen mail_index_write(index, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen if (!orig_locked)
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen mail_transaction_log_sync_unlock(index->log, "fscking");
eb9f7005390bf7d5771d2faedb771ce41103b93aTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainenvoid mail_index_fsck_locked(struct mail_index *index)
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen{
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen int ret;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen i_assert(index->log_sync_locked);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen ret = mail_index_fsck(index);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen i_assert(ret == 0);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen}
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainenbool mail_index_reset_fscked(struct mail_index *index)
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen{
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen bool ret = index->fscked;
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen index->fscked = FALSE;
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen return ret;
8a3f549a3cb1d6dd980a4fa3db284653e256dae7Timo Sirainen}