mail-index-fsck.c revision a553ee9b9c50d7cd317825ccb8150331560a9dd9
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "lib.h"
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen#include "ioloop.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "array.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "mail-index-private.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "mail-transaction-log-private.h"
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void mail_index_fsck_error(struct mail_index *index,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *fmt, ...) ATTR_FORMAT(2, 3);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void mail_index_fsck_error(struct mail_index *index,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *fmt, ...)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen va_list va;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
22627da0fb77c1d0d9a8e8bc485ef5540b6f2e69Timo Sirainen va_start(va, fmt);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen mail_index_set_error(index, "Fixed index file %s: %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen index->filepath, t_strdup_vprintf(fmt, va));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen va_end(va);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#define CHECK(field, oper) \
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (hdr->field oper map->hdr.field) { \
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_fsck_error(index, #field" %u -> %u", \
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen map->hdr.field, hdr->field); \
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenmail_index_fsck_log_pos(struct mail_index *index, struct mail_index_map *map,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mail_index_header *hdr)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen uint32_t file_seq;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen uoff_t file_offset;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen mail_transaction_log_get_head(index->log, &file_seq, &file_offset);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (hdr->log_file_seq < file_seq) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen hdr->log_file_head_offset = hdr->log_file_tail_offset =
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen sizeof(struct mail_transaction_log_header);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (hdr->log_file_head_offset > file_offset)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->log_file_head_offset = file_offset;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (hdr->log_file_tail_offset > hdr->log_file_head_offset)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->log_file_tail_offset = hdr->log_file_head_offset;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->log_file_seq = file_seq;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(log_file_seq, !=);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen if (hdr->log_file_seq == map->hdr.log_file_seq) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen /* don't bother complaining about these if file changed too */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(log_file_head_offset, !=);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(log_file_tail_offset, !=);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenmail_index_fsck_header(struct mail_index *index, struct mail_index_map *map,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct mail_index_header *hdr)
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* mail_index_map_check_header() has already checked that the index
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen isn't completely broken. */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen hdr->uid_validity = ioloop_time;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (index->log->head != NULL)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mail_index_fsck_log_pos(index, map, hdr);
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen}
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic bool
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenarray_has_name(const ARRAY_TYPE(const_string) *names, const char *name)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen const char *const *str;
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen unsigned int i, count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen str = array_get(names, &count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen for (i = 0; i < count; i++) {
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen if (strcmp(str[i], name) == 0)
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen return TRUE;
554c1c792dc6fce1e25c74555c2da786bffde75fTimo Sirainen }
554c1c792dc6fce1e25c74555c2da786bffde75fTimo Sirainen return FALSE;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen}
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainenstatic unsigned int
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainenmail_index_fsck_find_keyword_count(struct mail_index_map *map,
6df2db16b3920346ed07cefb86e8bdcb7e1faec5Timo Sirainen const struct mail_index_ext_header *ext_hdr)
6df2db16b3920346ed07cefb86e8bdcb7e1faec5Timo Sirainen{
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen const struct mail_index_record *rec;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen const uint8_t *kw;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen unsigned int r, i, j, cur, max = 0, kw_pos, kw_size;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen kw_pos = ext_hdr->record_offset;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen kw_size = ext_hdr->record_size;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen rec = map->rec_map->records;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen for (r = 0; r < map->rec_map->records_count; r++) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen kw = CONST_PTR_OFFSET(rec, kw_pos);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen for (i = cur = 0; i < kw_size; i++) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen if (kw[i] != 0) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen for (j = 0; j < 8; j++) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen if ((kw[i] & (1 << j)) != 0)
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen cur = i * 8 + j + 1;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen }
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (cur > max) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen max = cur;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (max == kw_size*8)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return max;
407caeb5d0c8a6b158e2caef48dd909011d40340Timo Sirainen }
407caeb5d0c8a6b158e2caef48dd909011d40340Timo Sirainen rec = CONST_PTR_OFFSET(rec, map->hdr.record_size);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return max;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic bool
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenkeyword_name_is_valid(const char *buffer, unsigned int pos, unsigned int size)
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen{
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen for (; pos < size; pos++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (buffer[pos] == '\0')
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (((unsigned char)buffer[pos] & 0x7f) < 32) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* control characters aren't valid */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenmail_index_fsck_keywords(struct mail_index *index, struct mail_index_map *map,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_header *hdr,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const struct mail_index_ext_header *ext_hdr,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int ext_offset, unsigned int *offset_p)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const struct mail_index_keyword_header *kw_hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_keyword_header *new_kw_hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_keyword_header_rec new_kw_rec;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *name, *name_buffer, **name_array;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen unsigned int i, j, name_pos, name_size, rec_pos, hdr_offset, diff;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int changed_count, keywords_count, name_base_pos;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ARRAY_TYPE(const_string) names;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_t *dest;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen bool changed = FALSE;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen hdr_offset = ext_offset +
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_map_ext_hdr_offset(sizeof("keywords")-1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, hdr_offset);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen keywords_count = kw_hdr->keywords_count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_rec = (const void *)(kw_hdr + 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_buffer = (const char *)(kw_rec + keywords_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_pos = (size_t)(name_buffer - (const char *)kw_hdr);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (name_pos > ext_hdr->hdr_size) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* the header is completely broken */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen keywords_count =
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_fsck_find_keyword_count(map, ext_hdr);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_fsck_error(index, "Assuming keywords_count = %u",
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen keywords_count);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen kw_rec = NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_size = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen changed = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_size = ext_hdr->hdr_size - name_pos;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen }
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* create keyword name array. invalid keywords are added as
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen empty strings */
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen t_array_init(&names, keywords_count);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < keywords_count; i++) {
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen if (name_size == 0 ||
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen !keyword_name_is_valid(name_buffer, kw_rec[i].name_offset,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name_size))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name = "";
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen else
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name = name_buffer + kw_rec[i].name_offset;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (*name != '\0' && array_has_name(&names, name)) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* duplicate */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name = "";
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_append(&names, &name, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* give new names to invalid keywords */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen changed_count = 0;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name_array = array_idx_modifiable(&names, 0);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen for (i = j = 0; i < keywords_count; i++) {
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen while (name_array[i][0] == '\0') {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name = t_strdup_printf("unknown-%d", j++);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!array_has_name(&names, name)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_array[i] = name;
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen changed = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen changed_count++;
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!changed) {
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen /* nothing was broken */
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen return;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen }
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_fsck_error(index, "Renamed %u keywords to unknown-*",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen changed_count);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen dest = buffer_create_dynamic(default_pool,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen I_MAX(ext_hdr->hdr_size, 128));
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen new_kw_hdr = buffer_append_space_unsafe(dest, sizeof(*new_kw_hdr));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen new_kw_hdr->keywords_count = keywords_count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* add keyword records so we can start appending names directly */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen rec_pos = dest->used;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen memset(&new_kw_rec, 0, sizeof(new_kw_rec));
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen buffer_append_space_unsafe(dest, keywords_count * sizeof(*kw_rec));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* write the actual records and names */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen name_base_pos = dest->used;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < keywords_count; i++) {
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen new_kw_rec.name_offset = dest->used - name_base_pos;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen buffer_write(dest, rec_pos, &new_kw_rec, sizeof(new_kw_rec));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen rec_pos += sizeof(*kw_rec);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen buffer_append(dest, name_array[i], strlen(name_array[i]) + 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* keep the header size at least the same size as before */
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen if (dest->used < ext_hdr->hdr_size)
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen buffer_append_zero(dest, ext_hdr->hdr_size - dest->used);
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen
4c9c55e15f35474f53f11659e796c63b1c34e884Timo Sirainen if (dest->used > ext_hdr->hdr_size) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* need to resize the header */
4c9c55e15f35474f53f11659e796c63b1c34e884Timo Sirainen struct mail_index_ext_header new_ext_hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen diff = dest->used - ext_hdr->hdr_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen buffer_copy(map->hdr_copy_buf, hdr_offset + diff,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->hdr_copy_buf, hdr_offset, (size_t)-1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->header_size += diff;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *offset_p += diff;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen new_ext_hdr = *ext_hdr;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen new_ext_hdr.hdr_size += diff;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen buffer_write(map->hdr_copy_buf, ext_offset,
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen &new_ext_hdr, sizeof(new_ext_hdr));
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen }
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen i_assert(hdr_offset + dest->used <= map->hdr_copy_buf->used);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen buffer_write(map->hdr_copy_buf, hdr_offset, dest->data, dest->used);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen /* keywords changed unexpectedly, so all views are broken now */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen index->inconsistency_id++;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_free(&dest);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenmail_index_fsck_extensions(struct mail_index *index, struct mail_index_map *map,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mail_index_header *hdr)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen const struct mail_index_ext_header *ext_hdr;
4c9c55e15f35474f53f11659e796c63b1c34e884Timo Sirainen ARRAY_TYPE(const_string) names;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *name, *error;
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen unsigned int offset, next_offset, i;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
22627da0fb77c1d0d9a8e8bc485ef5540b6f2e69Timo Sirainen t_array_init(&names, 64);
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(hdr->base_header_size);
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen for (i = 0; offset < hdr->header_size; i++) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* mail_index_map_ext_get_next() uses map->hdr, so make sure
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen it's up-to-date */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen map->hdr = *hdr;
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen next_offset = offset;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (mail_index_map_ext_get_next(map, &next_offset,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen &ext_hdr, &name) < 0) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* the extension continued outside header, drop it */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_fsck_error(index,
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen "Dropped extension #%d (%s) "
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen "with invalid header size",
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen i, name);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen hdr->header_size = offset;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen break;
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (mail_index_map_ext_hdr_check(hdr, ext_hdr, name,
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen &error) < 0) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen mail_index_fsck_error(index,
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen "Dropped broken extension #%d (%s)", i, name);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen } else if (array_has_name(&names, name)) {
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen mail_index_fsck_error(index,
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen "Dropped duplicate extension %s", name);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* name may change if header buffer is changed */
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen name = t_strdup(name);
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen if (strcmp(name, "keywords") == 0) {
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen mail_index_fsck_keywords(index, map, hdr,
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen ext_hdr, offset,
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen &next_offset);
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen array_append(&names, &name, 1);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen offset = next_offset;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen continue;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* drop the field */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->header_size -= next_offset - offset;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen buffer_copy(map->hdr_copy_buf, offset,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->hdr_copy_buf, next_offset, (size_t)-1);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen buffer_set_used_size(map->hdr_copy_buf, hdr->header_size);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenmail_index_fsck_records(struct mail_index *index, struct mail_index_map *map,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mail_index_header *hdr)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mail_index_record *rec, *next_rec;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen uint32_t i, last_uid;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen bool logged_unordered_uids = FALSE, logged_zero_uids = FALSE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen bool records_dropped = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen hdr->messages_count = 0;
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen hdr->seen_messages_count = 0;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->deleted_messages_count = 0;
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->first_unseen_uid_lowwater = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->first_deleted_uid_lowwater = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
c44f402f17f9a58ead24ac0083945cae86fb172bTimo Sirainen rec = map->rec_map->records; last_uid = 0;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < map->rec_map->records_count; ) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen next_rec = PTR_OFFSET(rec, hdr->record_size);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (rec->uid <= last_uid) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* log an error once, and skip this record */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (rec->uid == 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!logged_zero_uids) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_fsck_error(index,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen "Record UIDs have zeroes");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen logged_zero_uids = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen } else {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (!logged_unordered_uids) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen mail_index_fsck_error(index,
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen "Record UIDs unordered");
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen logged_unordered_uids = TRUE;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen /* not the fastest way when we're skipping lots of
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen records, but this should happen rarely so don't
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen bother optimizing. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen memmove(rec, next_rec, hdr->record_size *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen (map->rec_map->records_count - i - 1));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->rec_map->records_count--;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen records_dropped = TRUE;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen continue;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->messages_count++;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen if ((rec->flags & MAIL_SEEN) != 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->seen_messages_count++;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if ((rec->flags & MAIL_DELETED) != 0)
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen hdr->deleted_messages_count++;
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen if ((rec->flags & MAIL_SEEN) == 0 &&
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->first_unseen_uid_lowwater == 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->first_unseen_uid_lowwater = rec->uid;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if ((rec->flags & MAIL_DELETED) != 0 &&
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->first_deleted_uid_lowwater == 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hdr->first_deleted_uid_lowwater = rec->uid;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen last_uid = rec->uid;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen rec = next_rec;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (records_dropped) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* all existing views are broken now */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen index->inconsistency_id++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (hdr->next_uid <= last_uid) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_fsck_error(index, "next_uid %u -> %u",
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen hdr->next_uid, last_uid+1);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen hdr->next_uid = last_uid+1;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (hdr->first_unseen_uid_lowwater == 0)
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (hdr->first_deleted_uid_lowwater == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (hdr->first_recent_uid > hdr->next_uid)
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen hdr->first_recent_uid = hdr->next_uid;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen if (hdr->first_recent_uid == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen hdr->first_recent_uid = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(uid_validity, !=);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(messages_count, !=);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(seen_messages_count, !=);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(deleted_messages_count, !=);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen CHECK(first_unseen_uid_lowwater, <);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen CHECK(first_deleted_uid_lowwater, <);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen CHECK(first_recent_uid, !=);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenmail_index_fsck_map(struct mail_index *index, struct mail_index_map *map)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_header hdr;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (index->log->head != NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* Remember the log head position. If we go back in the index's
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen head offset, ignore errors in the log up to this offset. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_transaction_log_get_head(index->log,
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen &index->fsck_log_head_file_seq,
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen &index->fsck_log_head_file_offset);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen hdr = map->hdr;
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen mail_index_fsck_header(index, map, &hdr);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen mail_index_fsck_extensions(index, map, &hdr);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_fsck_records(index, map, &hdr);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->hdr = hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenint mail_index_fsck(struct mail_index *index)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen bool orig_locked = index->log_locked;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_map *map;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen uint32_t file_seq;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen uoff_t file_offset;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_warning("fscking index file %s", index->filepath);
f119596e34bc4a7ce374f4aa5f4f1eb12061a372Timo Sirainen
f119596e34bc4a7ce374f4aa5f4f1eb12061a372Timo Sirainen if (index->log->head == NULL) {
f119596e34bc4a7ce374f4aa5f4f1eb12061a372Timo Sirainen /* we're trying to open the index files, but there wasn't
f119596e34bc4a7ce374f4aa5f4f1eb12061a372Timo Sirainen any .log file. this should be rare, so just fsck it without
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen locking. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen orig_locked = TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (!orig_locked) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (mail_transaction_log_sync_lock(index->log, &file_seq,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen &file_offset) < 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen map = mail_index_map_clone(index->map);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_unmap(&index->map);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen index->map = map;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
294c71436de227178c709e4d498e7be9b5d8d7feTimo Sirainen T_BEGIN {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_fsck_map(index, map);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } T_END;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->write_base_header = TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen map->write_atomic = TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mail_index_write(index, FALSE);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!orig_locked)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_transaction_log_sync_unlock(index->log);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenvoid mail_index_fsck_locked(struct mail_index *index)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int ret;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(index->log_locked);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = mail_index_fsck(index);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(ret == 0);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen