bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenint mail_index_map_parse_extensions(struct mail_index_map *map)
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 mail_index_map_init_extbufs(map, old_count + 5);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; i < old_count; i++)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen for (i = 0; offset < map->hdr.header_size; i++) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Header extension #%d (%s) goes outside header",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Broken extension #%d (%s): %s",
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",
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)mail_index_map_register_ext(map, name, ext_offset, ext_hdr);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenint mail_index_map_parse_keywords(struct mail_index_map *map)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen unsigned int i, name_area_end_offset, old_count;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS, &idx)) {
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 i_assert(ext->hdr_offset < map->hdr.header_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Keywords can only be added into same mapping. Removing requires a
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen new mapping (recreating the index file) */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* nothing changed */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* make sure the header is valid */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keywords removed unexpectedly",
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 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 mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keyword header doesn't end with NUL",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* create file -> index mapping */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
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 old_idx = array_idx(&map->keyword_idx_map, i);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (!mail_index_keyword_lookup(index, keyword, &kw_idx) ||
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Keywords changed unexpectedly",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* Register the newly seen keywords */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const char *keyword = name + kw_rec[i].name_offset;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Empty keyword name in header",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_keyword_lookup_or_create(index, keyword, &kw_idx);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen array_append(&map->keyword_idx_map, &kw_idx, 1);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenbool mail_index_check_header_compat(struct mail_index *index,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen enum mail_index_header_compat_flags compat_flags = 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
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 if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* we've already complained about it */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* architecture change */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "Corrupted header sizes (base %u, full %u)",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "Header size is larger than file (%u > %"PRIuUOFF_T")",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "indexid changed: %u -> %u",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_transaction_log_indexid_changed(index->log);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic void mail_index_map_clear_recent_flags(struct mail_index_map *map)
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmody for (seq = 1; seq <= map->hdr.messages_count; seq++) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainenint mail_index_map_check_header(struct mail_index_map *map,
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen const char **error_r)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen const struct mail_index_header *hdr = &map->hdr;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1, error_r))
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 hdr->record_size, sizeof(struct mail_index_record));
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "uidvalidity=0, but next_uid=%u", hdr->next_uid);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->messages_count > map->rec_map->records_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "messages_count is higher in header than record map (%u > %u)",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->messages_count, map->rec_map->records_count);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->seen_messages_count > hdr->messages_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "seen_messages_count %u > messages_count %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->seen_messages_count, hdr->messages_count);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->deleted_messages_count > hdr->messages_count) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "deleted_messages_count %u > messages_count %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->deleted_messages_count, hdr->messages_count);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* upgrade silently from v1.0 */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen map->hdr.unused_old_recent_messages_count = 0;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* fall through */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* pre-v1.1.rc6: make sure the \Recent flags are gone */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen map->hdr.minor_version = MAIL_INDEX_MINOR_VERSION;
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen /* fall through */
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen /* pre-v2.2 (although should have been done in v2.1 already):
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen make sure the old unused fields are cleared */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_recent_uid %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_unseen_uid_lowwater > hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_unseen_uid_lowwater %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->first_unseen_uid_lowwater, hdr->next_uid);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->first_deleted_uid_lowwater > hdr->next_uid) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "first_deleted_uid_lowwater %u > next_uid %u",
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen hdr->first_deleted_uid_lowwater, hdr->next_uid);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* last message's UID must be smaller than next_uid.
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen also make sure it's not zero. */
1df526903ed039e8ff966a223c43b8d04eddf3c7Phil Carmody rec = MAIL_INDEX_REC_AT_SEQ(map, hdr->messages_count);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen "last message uid %u >= next_uid %u",