bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#include "lib.h"
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#include "array.h"
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#include "mail-index-private.h"
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenint mail_index_map_parse_extensions(struct mail_index_map *map)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen{
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen struct mail_index *index = map->index;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_ext_header *ext_hdr;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen unsigned int i, old_count, offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const char *name, *error;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen uint32_t ext_id, ext_map_idx, ext_offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* extension headers always start from 64bit offsets, so if base header
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen doesn't happen to be 64bit aligned we'll skip some bytes */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi /* nothing to do, skip allocations and all */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen old_count = array_count(&index->extensions);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen ext_id = (uint32_t)-1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; i < old_count; i++)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen array_append(&map->ext_id_map, &ext_id, 1);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; offset < map->hdr.header_size; i++) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen ext_offset = offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (mail_index_map_ext_get_next(map, &offset,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen &ext_hdr, &name) < 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Header extension #%d (%s) goes outside header",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath, i, name);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen name, &error) < 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Broken extension #%d (%s): %s",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath, i, name, error);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (mail_index_map_lookup_ext(map, name, &ext_map_idx)) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Duplicate header extension %s",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath, name);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)mail_index_map_register_ext(map, name, ext_offset, ext_hdr);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen}
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenint mail_index_map_parse_keywords(struct mail_index_map *map)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen{
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen struct mail_index *index = map->index;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_ext *ext;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const char *name;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen unsigned int i, name_area_end_offset, old_count;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen uint32_t idx;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS, &idx)) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (array_is_created(&map->keyword_idx_map))
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen array_clear(&map->keyword_idx_map);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen ext = array_idx(&map->extensions, idx);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Extension header contains:
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen - struct mail_index_keyword_header
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen - struct mail_index_keyword_header_rec * keywords_count
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen - const char names[] * keywords_count
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen i_assert(ext->hdr_offset < map->hdr.header_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen kw_rec = (const void *)(kw_hdr + 1);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen array_count(&map->keyword_idx_map);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Keywords can only be added into same mapping. Removing requires a
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen new mapping (recreating the index file) */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (kw_hdr->keywords_count == old_count) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* nothing changed */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* make sure the header is valid */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (kw_hdr->keywords_count < old_count) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keywords removed unexpectedly",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "keywords_count larger than header size",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; i < kw_hdr->keywords_count; i++) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (kw_rec[i].name_offset > name_area_end_offset) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "name_offset points outside allocated header",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (name[name_area_end_offset-1] != '\0') {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keyword header doesn't end with NUL",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* create file -> index mapping */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (!array_is_created(&map->keyword_idx_map))
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#ifdef DEBUG
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Check that existing headers are still the same. It's behind DEBUG
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen since it's pretty useless waste of CPU normally. */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const char *keyword = name + kw_rec[i].name_offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const unsigned int *old_idx;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen unsigned int kw_idx;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen old_idx = array_idx(&map->keyword_idx_map, i);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (!mail_index_keyword_lookup(index, keyword, &kw_idx) ||
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen kw_idx != *old_idx) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keywords changed unexpectedly",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#endif
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Register the newly seen keywords */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen i = array_count(&map->keyword_idx_map);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (; i < kw_hdr->keywords_count; i++) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const char *keyword = name + kw_rec[i].name_offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen unsigned int kw_idx;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (*keyword == '\0') {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Empty keyword name in header",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_keyword_lookup_or_create(index, keyword, &kw_idx);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen array_append(&map->keyword_idx_map, &kw_idx, 1);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen}
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenbool mail_index_check_header_compat(struct mail_index *index,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_header *hdr,
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen uoff_t file_size, const char **error_r)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen{
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen enum mail_index_header_compat_flags compat_flags = 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
debc93e622751c6c09e8105e504c5833f1ca0d6dMartti Rannanjärvi#ifndef WORDS_BIGENDIAN
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen#endif
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen /* major version change */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf("Major version changed (%u != %u)",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->major_version, MAIL_INDEX_MAJOR_VERSION);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return FALSE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* we've already complained about it */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = "Header's corrupted flag is set";
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return FALSE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->compat_flags != compat_flags) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* architecture change */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = "CPU architecture changed";
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return FALSE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen hdr->header_size < hdr->base_header_size) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "Corrupted header sizes (base %u, full %u)",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->base_header_size, hdr->header_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return FALSE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->header_size > file_size) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "Header size is larger than file (%u > %"PRIuUOFF_T")",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->header_size, file_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return FALSE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->indexid != index->indexid) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (index->indexid != 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "indexid changed: %u -> %u",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->filepath, index->indexid,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen hdr->indexid);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->indexid = hdr->indexid;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_transaction_log_indexid_changed(index->log);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return TRUE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen}
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic void mail_index_map_clear_recent_flags(struct mail_index_map *map)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen{
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen struct mail_index_record *rec;
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmody uint32_t seq;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmody for (seq = 1; seq <= map->hdr.messages_count; seq++) {
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmody rec = MAIL_INDEX_REC_AT_SEQ(map, seq);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen rec->flags &= ~MAIL_RECENT;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen}
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainenint mail_index_map_check_header(struct mail_index_map *map,
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen const char **error_r)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen{
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen struct mail_index *index = map->index;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_header *hdr = &map->hdr;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1, error_r))
9644b7914445f0fb1098038218bfcb7d135a8698Timo Sirainen return 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* following some extra checks that only take a bit of CPU */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "record_size too small (%u < %"PRIuSIZE_T")",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->record_size, sizeof(struct mail_index_record));
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return -1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "uidvalidity=0, but next_uid=%u", hdr->next_uid);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->next_uid == 0) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = "next_uid=0";
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->messages_count > map->rec_map->records_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "messages_count is higher in header than record map (%u > %u)",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->messages_count, map->rec_map->records_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->seen_messages_count > hdr->messages_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "seen_messages_count %u > messages_count %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->seen_messages_count, hdr->messages_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->deleted_messages_count > hdr->messages_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "deleted_messages_count %u > messages_count %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->deleted_messages_count, hdr->messages_count);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen switch (hdr->minor_version) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen case 0:
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* upgrade silently from v1.0 */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen map->hdr.unused_old_recent_messages_count = 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->first_recent_uid == 0)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen map->hdr.first_recent_uid = 1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen index->need_recreate = TRUE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* fall through */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen case 1:
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* pre-v1.1.rc6: make sure the \Recent flags are gone */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_map_clear_recent_flags(map);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen map->hdr.minor_version = MAIL_INDEX_MINOR_VERSION;
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen /* fall through */
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen case 2:
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen /* pre-v2.2 (although should have been done in v2.1 already):
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen make sure the old unused fields are cleared */
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen map->hdr.unused_old_sync_size_part1 = 0;
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen map->hdr.log2_rotate_time = 0;
2ecee6ed2bfd5c9bc5c6cc8a675b9db4cbbcd81fTimo Sirainen map->hdr.last_temp_file_scan = 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_recent_uid == 0) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = "first_recent_uid=0";
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_recent_uid > hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_recent_uid %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->first_recent_uid, hdr->next_uid);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_unseen_uid_lowwater > hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_unseen_uid_lowwater %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->first_unseen_uid_lowwater, hdr->next_uid);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_deleted_uid_lowwater > hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_deleted_uid_lowwater %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->first_deleted_uid_lowwater, hdr->next_uid);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->messages_count > 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* last message's UID must be smaller than next_uid.
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen also make sure it's not zero. */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_record *rec;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen
1df526903ed039e8ff966a223c43b8d04eddf3c7Phil Carmody rec = MAIL_INDEX_REC_AT_SEQ(map, hdr->messages_count);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (rec->uid == 0) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = "last message has uid=0";
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return -1;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (rec->uid >= hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *error_r = t_strdup_printf(
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "last message uid %u >= next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen rec->uid, hdr->next_uid);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 0;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen }
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return 1;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen}