Mercurial > dovecot > core-2.2
changeset 18627:69630e6048fd
lib-index: If header is corrupted after syncing, log the reason why.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 10 May 2015 12:28:09 +0300 |
parents | fddd3dbdf987 |
children | 413962f2b7e7 |
files | src/lib-index/mail-index-map-hdr.c src/lib-index/mail-index-map-read.c src/lib-index/mail-index-private.h src/lib-index/mail-index-sync-update.c |
diffstat | 4 files changed, 101 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-index-map-hdr.c Sun May 10 12:05:06 2015 +0300 +++ b/src/lib-index/mail-index-map-hdr.c Sun May 10 12:28:09 2015 +0300 @@ -167,7 +167,7 @@ bool mail_index_check_header_compat(struct mail_index *index, const struct mail_index_header *hdr, - uoff_t file_size) + uoff_t file_size, const char **error_r) { enum mail_index_header_compat_flags compat_flags = 0; @@ -176,35 +176,34 @@ #endif if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) { - /* major version change - handle silently(?) */ + /* major version change */ + *error_r = t_strdup_printf("Major version changed (%u != %u)", + hdr->major_version, MAIL_INDEX_MAJOR_VERSION); return FALSE; } if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) { /* we've already complained about it */ + *error_r = "Header's corrupted flag is set"; return FALSE; } if (hdr->compat_flags != compat_flags) { /* architecture change */ - mail_index_set_error(index, "Rebuilding index file %s: " - "CPU architecture changed", - index->filepath); + *error_r = "CPU architecture changed"; return FALSE; } if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE || hdr->header_size < hdr->base_header_size) { - mail_index_set_error(index, "Corrupted index file %s: " - "Corrupted header sizes (base %u, full %u)", - index->filepath, hdr->base_header_size, - hdr->header_size); + *error_r = t_strdup_printf( + "Corrupted header sizes (base %u, full %u)", + hdr->base_header_size, hdr->header_size); return FALSE; } if (hdr->header_size > file_size) { - mail_index_set_error(index, "Corrupted index file %s: " - "Corrupted header size (%u > %"PRIuUOFF_T")", - index->filepath, hdr->header_size, - file_size); + *error_r = t_strdup_printf( + "Header size is larger than file (%u > %"PRIuUOFF_T")", + hdr->header_size, file_size); return FALSE; } @@ -218,7 +217,6 @@ index->indexid = hdr->indexid; mail_transaction_log_indexid_changed(index->log); } - return TRUE; } @@ -233,33 +231,51 @@ } } -int mail_index_map_check_header(struct mail_index_map *map) +int mail_index_map_check_header(struct mail_index_map *map, + const char **error_r) { struct mail_index *index = map->index; const struct mail_index_header *hdr = &map->hdr; - if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1)) + if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1, error_r)) return -1; /* following some extra checks that only take a bit of CPU */ if (hdr->record_size < sizeof(struct mail_index_record)) { - mail_index_set_error(index, "Corrupted index file %s: " - "record_size too small: %u < %"PRIuSIZE_T, - index->filepath, hdr->record_size, - sizeof(struct mail_index_record)); + *error_r = t_strdup_printf( + "record_size too small (%u < %"PRIuSIZE_T")", + hdr->record_size, sizeof(struct mail_index_record)); return -1; } - if (hdr->uid_validity == 0 && hdr->next_uid != 1) + if (hdr->uid_validity == 0 && hdr->next_uid != 1) { + *error_r = t_strdup_printf( + "uidvalidity=0, but next_uid=%u", hdr->next_uid); return 0; - if (hdr->next_uid == 0) + } + if (hdr->next_uid == 0) { + *error_r = "next_uid=0"; + return 0; + } + if (hdr->messages_count > map->rec_map->records_count) { + *error_r = t_strdup_printf( + "messages_count is higher in header than record map (%u > %u)", + hdr->messages_count, map->rec_map->records_count); return 0; - if (hdr->messages_count > map->rec_map->records_count) - return 0; + } - if (hdr->seen_messages_count > hdr->messages_count || - hdr->deleted_messages_count > hdr->messages_count) + if (hdr->seen_messages_count > hdr->messages_count) { + *error_r = t_strdup_printf( + "seen_messages_count %u > messages_count %u", + hdr->seen_messages_count, hdr->messages_count); return 0; + } + if (hdr->deleted_messages_count > hdr->messages_count) { + *error_r = t_strdup_printf( + "deleted_messages_count %u > messages_count %u", + hdr->deleted_messages_count, hdr->messages_count); + return 0; + } switch (hdr->minor_version) { case 0: /* upgrade silently from v1.0 */ @@ -279,11 +295,28 @@ map->hdr.unused_old_sync_size = 0; map->hdr.unused_old_sync_stamp = 0; } - if (hdr->first_recent_uid == 0 || - hdr->first_recent_uid > hdr->next_uid || - hdr->first_unseen_uid_lowwater > hdr->next_uid || - hdr->first_deleted_uid_lowwater > hdr->next_uid) + if (hdr->first_recent_uid == 0) { + *error_r = "first_recent_uid=0"; + return 0; + } + if (hdr->first_recent_uid > hdr->next_uid) { + *error_r = t_strdup_printf( + "first_recent_uid %u > next_uid %u", + hdr->first_recent_uid, hdr->next_uid); return 0; + } + if (hdr->first_unseen_uid_lowwater > hdr->next_uid) { + *error_r = t_strdup_printf( + "first_unseen_uid_lowwater %u > next_uid %u", + hdr->first_unseen_uid_lowwater, hdr->next_uid); + return 0; + } + if (hdr->first_deleted_uid_lowwater > hdr->next_uid) { + *error_r = t_strdup_printf( + "first_deleted_uid_lowwater %u > next_uid %u", + hdr->first_deleted_uid_lowwater, hdr->next_uid); + return 0; + } if (hdr->messages_count > 0) { /* last message's UID must be smaller than next_uid. @@ -291,9 +324,16 @@ const struct mail_index_record *rec; rec = MAIL_INDEX_REC_AT_SEQ(map, hdr->messages_count); - if (rec->uid == 0 || rec->uid >= hdr->next_uid) + if (rec->uid == 0) { + *error_r = "last message has uid=0"; + return -1; + } + if (rec->uid >= hdr->next_uid) { + *error_r = t_strdup_printf( + "last message uid %u >= next_uid %u", + rec->uid, hdr->next_uid); return 0; + } } - return 1; }
--- a/src/lib-index/mail-index-map-read.c Sun May 10 12:05:06 2015 +0300 +++ b/src/lib-index/mail-index-map-read.c Sun May 10 12:28:09 2015 +0300 @@ -31,6 +31,7 @@ struct mail_index *index = map->index; struct mail_index_record_map *rec_map = map->rec_map; const struct mail_index_header *hdr; + const char *error; i_assert(rec_map->mmap_base == NULL); @@ -66,9 +67,11 @@ return 0; } - if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) { + if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size, &error)) { /* Can't use this file */ - return 0; + mail_index_set_error(index, "Corrupted index file %s: %s", + index->filepath, error); + return -1; } rec_map->mmap_used_size = hdr->header_size + @@ -126,6 +129,7 @@ struct mail_index *index = map->index; const struct mail_index_header *hdr; unsigned char read_buf[IO_BLOCK_SIZE]; + const char *error; const void *buf; void *data = NULL; ssize_t ret; @@ -146,9 +150,11 @@ if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE && (ret > 0 || pos >= hdr->base_header_size)) { - if (!mail_index_check_header_compat(index, hdr, file_size)) { + if (!mail_index_check_header_compat(index, hdr, file_size, &error)) { /* Can't use this file */ - return 0; + mail_index_set_error(index, "Corrupted index file %s: %s", + index->filepath, error); + return -1; } initial_buf_pos = pos; @@ -295,6 +301,7 @@ struct stat st; uoff_t file_size; bool use_mmap, unusable = FALSE; + const char *error; int ret, try; ret = mail_index_reopen_if_changed(index); @@ -339,7 +346,12 @@ for (try = 0; ret > 0; try++) { /* make sure the header is ok before using this mapping */ - ret = mail_index_map_check_header(new_map); + ret = mail_index_map_check_header(new_map, &error); + if (ret < 0) { + mail_index_set_error(index, + "Corrupted index file %s: %s", + index->filepath, error); + } if (ret > 0) T_BEGIN { if (mail_index_map_parse_extensions(new_map) < 0) ret = 0;
--- a/src/lib-index/mail-index-private.h Sun May 10 12:05:06 2015 +0300 +++ b/src/lib-index/mail-index-private.h Sun May 10 12:28:09 2015 +0300 @@ -307,10 +307,16 @@ uint32_t *first_seq_r, uint32_t *last_seq_r); -int mail_index_map_check_header(struct mail_index_map *map); +/* Returns 1 on success, 0 on non-critical errors we want to silently fix, + -1 if map isn't usable. The caller is responsible for logging the errors + if -1 is returned. */ +int mail_index_map_check_header(struct mail_index_map *map, + const char **error_r); +/* Returns 1 if header is usable, 0 or -1 if not. The caller should log an + error if -1 is returned, but not if 0 is returned. */ bool mail_index_check_header_compat(struct mail_index *index, const struct mail_index_header *hdr, - uoff_t file_size); + uoff_t file_size, const char **error_r); int mail_index_map_parse_extensions(struct mail_index_map *map); int mail_index_map_parse_keywords(struct mail_index_map *map);
--- a/src/lib-index/mail-index-sync-update.c Sun May 10 12:05:06 2015 +0300 +++ b/src/lib-index/mail-index-sync-update.c Sun May 10 12:28:09 2015 +0300 @@ -911,7 +911,7 @@ const void *tdata; uint32_t prev_seq; uoff_t start_offset, prev_offset; - const char *reason; + const char *reason, *error; int ret; bool had_dirty, reset; @@ -1075,10 +1075,10 @@ i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW); - if (mail_index_map_check_header(map) <= 0) { + if (mail_index_map_check_header(map, &error) <= 0) { mail_index_set_error(index, - "Synchronization corrupted index header: %s", - index->filepath); + "Synchronization corrupted index header %s: %s", + index->filepath, error); (void)mail_index_fsck(index); map = index->map; } else if (sync_map_ctx.errors) {