mail-index-sync-update.c revision 945631faab2bf1aed8d95a1fd0c317a9ce153725
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "buffer.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "file-set-size.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mmap-util.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-index-view-private.h"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen#include "mail-index-sync-private.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-transaction-log.h"
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen#include "mail-transaction-log-private.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-transaction-util.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenmail_index_sync_update_log_offset(struct mail_index_sync_map_ctx *ctx,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_index_map *map)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t prev_seq;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uoff_t prev_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen &prev_seq, &prev_offset);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!ctx->sync_only_external)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.log_file_int_offset = prev_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else if (map->hdr.log_file_seq != prev_seq && map == ctx->view->map) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* log sequence changed. update internal offset to
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen beginning of the new file. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(map->hdr.log_file_int_offset ==
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->view->index->log->head->hdr.prev_file_offset);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.log_file_int_offset =
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->view->index->log->head->hdr.hdr_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.log_file_seq = prev_seq;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.log_file_ext_offset = prev_offset;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenmail_index_map_msync(struct mail_index *index, struct mail_index_map *map)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int base_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen base_size = I_MIN(map->hdr.base_header_size, sizeof(map->hdr));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->mmap_used_size = index->hdr->header_size +
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen map->records_count * map->hdr.record_size;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memcpy(map->mmap_base, &map->hdr, base_size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memcpy(PTR_OFFSET(map->mmap_base, base_size),
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen CONST_PTR_OFFSET(map->hdr_base, base_size),
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen map->hdr.header_size - base_size);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (msync(map->mmap_base, map->mmap_used_size, MS_SYNC) < 0) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen mail_index_set_syscall_error(index, "msync()");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainenvoid mail_index_sync_replace_map(struct mail_index_sync_map_ctx *ctx,
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct mail_index_map *map)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen{
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct mail_index_view *view = ctx->view;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct mail_index_map *old_map = view->map;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen i_assert(view->map != map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen old_map->refcount++;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* if map still exists after this, it's only in views. */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->map->write_to_disk = FALSE;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* keywords aren't parsed for the new map yet */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->map->keywords_read = FALSE;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_unmap(view->index, &view->map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->map = map;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if ((ctx->type & (MAIL_INDEX_SYNC_HANDLER_FILE |
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen MAIL_INDEX_SYNC_HANDLER_HEAD)) != 0 &&
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->index->map != map) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_unmap(view->index, &view->index->map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->index->map = map;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen view->index->hdr = &map->hdr;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen map->refcount++;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ctx->type == MAIL_INDEX_SYNC_HANDLER_FILE) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen map->write_to_disk = TRUE;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen map->write_atomic = TRUE;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(old_map)) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* other processes may still have the same file mapped,
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen and since we could have already updated the records, make
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen sure we leave the header in a valid state as well */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_sync_update_log_offset(ctx, old_map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen (void)mail_index_map_msync(view->index, old_map);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_index_unmap(view->index, &old_map);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen i_assert(view->hdr.messages_count == map->hdr.messages_count);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenstatic int
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen uint8_t old_flags, uint8_t new_flags,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen const char **error_r)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* different recent-flag */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if ((old_flags & MAIL_RECENT) == 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen hdr->recent_messages_count++;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (hdr->recent_messages_count > hdr->messages_count) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen *error_r = "Recent counter wrong";
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen } else {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (hdr->recent_messages_count == 0 ||
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen hdr->recent_messages_count > hdr->messages_count) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen *error_r = "Recent counter wrong";
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (--hdr->recent_messages_count == 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen hdr->first_recent_uid_lowwater = hdr->next_uid;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* different seen-flag */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if ((old_flags & MAIL_SEEN) != 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (hdr->seen_messages_count == 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen *error_r = "Seen counter wrong";
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen hdr->seen_messages_count--;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen } else {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (hdr->seen_messages_count >= hdr->messages_count) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen *error_r = "Seen counter wrong";
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (++hdr->seen_messages_count == hdr->messages_count)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* different deleted-flag */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if ((old_flags & MAIL_DELETED) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hdr->deleted_messages_count++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (hdr->deleted_messages_count > hdr->messages_count) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen *error_r = "Deleted counter wrong";
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen } else {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (hdr->deleted_messages_count == 0 ||
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen hdr->deleted_messages_count > hdr->messages_count) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen *error_r = "Deleted counter wrong";
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return -1;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (--hdr->deleted_messages_count == 0)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return 0;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid mail_index_view_recalc_counters(struct mail_index_view *view)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen{
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen struct mail_index_map *map = view->map;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen const struct mail_index_record *rec;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen const char *error;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen unsigned int i;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen map->hdr.recent_messages_count = 0;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen map->hdr.seen_messages_count = 0;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen map->hdr.deleted_messages_count = 0;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen for (i = 0; i < view->hdr.messages_count; i++) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, i);
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (mail_index_header_update_counts(&map->hdr, 0, rec->flags,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen &error) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen i_panic("mail_index_view_recalc_counters(): %s", error);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen view->hdr.recent_messages_count = map->hdr.recent_messages_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->hdr.seen_messages_count = map->hdr.seen_messages_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->hdr.deleted_messages_count = map->hdr.deleted_messages_count;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->broken_counters = FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstatic void
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenmail_index_header_update_lowwaters(struct mail_index_header *hdr,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const struct mail_index_record *rec)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if ((rec->flags & MAIL_RECENT) != 0 &&
009217abb57a24a4076092e8e4e165545747839eStephan Bosch rec->uid < hdr->first_recent_uid_lowwater)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hdr->first_recent_uid_lowwater = rec->uid;
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen if ((rec->flags & MAIL_SEEN) == 0 &&
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen rec->uid < hdr->first_unseen_uid_lowwater)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hdr->first_unseen_uid_lowwater = rec->uid;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if ((rec->flags & MAIL_DELETED) != 0 &&
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen rec->uid < hdr->first_deleted_uid_lowwater)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen hdr->first_deleted_uid_lowwater = rec->uid;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstatic int sync_expunge(const struct mail_transaction_expunge *e,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct mail_index_sync_map_ctx *ctx)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct mail_index_view *view = ctx->view;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mail_index_map *map = view->map;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen struct mail_index_record *rec;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *error;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen uint32_t count, seq, seq1, seq2;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen const struct mail_index_expunge_handler *expunge_handlers, *eh;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int i, expunge_handlers_count;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (e->uid1 > e->uid2 || e->uid1 == 0) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen mail_index_sync_set_corrupted(ctx,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen "Invalid UID range in expunge (%u .. %u)",
009217abb57a24a4076092e8e4e165545747839eStephan Bosch e->uid1, e->uid2);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!view->map->write_to_disk || view->map->refcount != 1) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* expunges have to be atomic. so we'll have to copy
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen the mapping, do the changes there and then finally
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen replace the whole index file. to avoid extra disk
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen I/O we copy the index into memory rather than to
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen temporary file */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen map = mail_index_map_clone(map, map->hdr.record_size);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen mail_index_sync_replace_map(ctx, map);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* we want atomic rename()ing */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen map->write_atomic = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (mail_index_lookup_uid_range(view, e->uid1, e->uid2,
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen &seq1, &seq2) < 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (seq1 == 0)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return 1;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* call expunge handlers only when syncing index file */
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen if (ctx->type == MAIL_INDEX_SYNC_HANDLER_FILE &&
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen !ctx->expunge_handlers_set)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_sync_init_expunge_handlers(ctx);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ctx->type == MAIL_INDEX_SYNC_HANDLER_FILE &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_is_created(&ctx->expunge_handlers)) {
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen expunge_handlers = array_get(&ctx->expunge_handlers,
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen &expunge_handlers_count);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen } else {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen expunge_handlers = NULL;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen expunge_handlers_count = 0;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen if (ctx->unreliable_flags || view->broken_counters)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen view->broken_counters = TRUE;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen else {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen for (seq = seq1; seq <= seq2; seq++) {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq-1);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if (mail_index_header_update_counts(&map->hdr,
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen rec->flags, 0,
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen &error) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen for (i = 0; i < expunge_handlers_count; i++) {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen eh = &expunge_handlers[i];
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen for (seq = seq1; seq <= seq2; seq++) {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq-1);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen if (eh->handler(ctx, seq,
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen PTR_OFFSET(rec, eh->record_offset),
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen eh->sync_context, eh->context) < 0)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen return -1;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen }
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen }
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen /* @UNSAFE */
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen count = seq2 - seq1 + 1;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen memmove(MAIL_INDEX_MAP_IDX(map, seq1-1), MAIL_INDEX_MAP_IDX(map, seq2),
87842f621233257b7a7945d994ba931508b34877Timo Sirainen (map->records_count - seq2) * map->hdr.record_size);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen map->records_count -= count;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen map->hdr.messages_count -= count;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen view->hdr.messages_count -= count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (map->buffer != NULL) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen buffer_set_used_size(map->buffer, map->records_count *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.record_size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->records = buffer_get_modifiable_data(map->buffer, NULL);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return 1;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen}
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainenstatic void write_seq_update(struct mail_index_map *map,
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen uint32_t seq1, uint32_t seq2)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen{
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if (map->write_seq_first == 0 ||
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen map->write_seq_first > seq1)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen map->write_seq_first = seq1;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if (map->write_seq_last < seq2)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen map->write_seq_last = seq2;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen}
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainenstatic int sync_append(const struct mail_index_record *rec,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen struct mail_index_sync_map_ctx *ctx)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen{
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen struct mail_index_view *view = ctx->view;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen struct mail_index_map *map = view->map;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen const char *error;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen void *dest;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (rec->uid < map->hdr.next_uid) {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen mail_index_sync_set_corrupted(ctx,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen "Append with UID %u, but next_uid = %u",
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen rec->uid, map->hdr.next_uid);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen return -1;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen i_assert(map->records_count * map->hdr.record_size ==
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen buffer_get_used_size(map->buffer));
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen dest = buffer_append_space_unsafe(map->buffer,
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen map->hdr.record_size);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen map->records = buffer_get_modifiable_data(map->buffer, NULL);
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen } else {
87842f621233257b7a7945d994ba931508b34877Timo Sirainen i_assert((map->records_count+1) * map->hdr.record_size <=
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen map->mmap_size);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen dest = MAIL_INDEX_MAP_IDX(map, map->records_count);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen memcpy(dest, rec, sizeof(*rec));
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen memset(PTR_OFFSET(dest, sizeof(*rec)), 0,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen map->hdr.record_size - sizeof(*rec));
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen map->hdr.messages_count++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.next_uid = rec->uid+1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->records_count++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->hdr.messages_count++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->hdr.next_uid = rec->uid+1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen write_seq_update(map, map->hdr.messages_count, map->hdr.messages_count);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_header_update_lowwaters(&map->hdr, rec);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!view->broken_counters) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (mail_index_header_update_counts(&map->hdr, 0, rec->flags,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen &error) < 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_index_sync_map_ctx *ctx)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen struct mail_index_view *view = ctx->view;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_index_header *hdr;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct mail_index_record *rec;
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen const char *error;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen uint8_t flag_mask, old_flags;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen uint32_t idx, seq1, seq2;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen if (u->uid1 > u->uid2 || u->uid1 == 0) {
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen mail_index_sync_set_corrupted(ctx,
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen "Invalid UID range in flag update (%u .. %u)",
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen u->uid1, u->uid2);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return -1;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (mail_index_lookup_uid_range(view, u->uid1, u->uid2,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen &seq1, &seq2) < 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return -1;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (seq1 == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return 1;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen write_seq_update(view->map, seq1, seq2);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen hdr = &view->map->hdr;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen hdr->flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen flag_mask = ~u->remove_flags;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (((u->add_flags | u->remove_flags) &
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen (MAIL_SEEN | MAIL_DELETED | MAIL_RECENT)) == 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen /* we're not modifying any counted/lowwatered flags */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else if (view->broken_counters || ctx->unreliable_flags) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen view->broken_counters = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (idx = seq1-1; idx < seq2; idx++) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, idx);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen mail_index_header_update_lowwaters(hdr, rec);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen } else {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen for (idx = seq1-1; idx < seq2; idx++) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, idx);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen old_flags = rec->flags;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen mail_index_header_update_lowwaters(hdr, rec);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (mail_index_header_update_counts(hdr, old_flags,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen rec->flags,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen &error) < 0) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return -1;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen }
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen return 1;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen}
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen struct mail_index_sync_map_ctx *ctx)
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen{
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen struct mail_index_map *map = ctx->view->map;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (u->offset >= map->hdr.base_header_size ||
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen u->offset + u->size > map->hdr.base_header_size) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen mail_index_sync_set_corrupted(ctx,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen "Header update outside range: %u + %u > %u",
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen u->offset, u->size, map->hdr.base_header_size);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return -1;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen buffer_write(map->hdr_copy_buf, u->offset, u + 1, u->size);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen /* @UNSAFE */
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if ((uint32_t)(u->offset + u->size) <= sizeof(map->hdr)) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen memcpy(PTR_OFFSET(&map->hdr, u->offset),
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen u + 1, u->size);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen } else if (u->offset < sizeof(map->hdr)) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen memcpy(PTR_OFFSET(&map->hdr, u->offset),
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen u + 1, sizeof(map->hdr) - u->offset);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return 1;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen}
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainenstatic int mail_index_grow(struct mail_index *index, struct mail_index_map *map,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen unsigned int count)
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen{
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen void *hdr_copy;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen size_t size, hdr_copy_size;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return 0;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen i_assert(map == index->map);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen i_assert(!index->mapping); /* mail_index_sync_from_transactions() */
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen size = map->hdr.header_size +
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen (map->records_count + count) * map->hdr.record_size;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (size <= map->mmap_size)
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return 0;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen /* when we grow fast, do it exponentially */
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen if (count < index->last_grow_count)
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen count = index->last_grow_count;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen if (count < MAIL_INDEX_MAX_POWER_GROW)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen count = nearest_power(count);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen index->last_grow_count = count;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen size = map->hdr.header_size +
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen (map->records_count + count) * map->hdr.record_size;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen if (file_set_size(index->fd, (off_t)size) < 0)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen return mail_index_set_syscall_error(index, "file_set_size()");
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen /* we only wish to grow the file, but mail_index_map() updates the
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen headers as well and may break our modified hdr_copy. so, take
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen a backup of it and put it back afterwards */
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen t_push();
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_assert(map->hdr_copy_buf->used == map->hdr.header_size);
a56fcfa52e89601d96376a29cd392a671fe25713Timo Sirainen hdr_copy_size = map->hdr_copy_buf->used;
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen hdr_copy = t_malloc(hdr_copy_size);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen memcpy(hdr_copy, map->hdr_copy_buf->data, hdr_copy_size);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen memcpy(hdr_copy, &map->hdr, sizeof(map->hdr));
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen if (mail_index_map(index, TRUE) <= 0) {
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen t_pop();
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen return -1;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen }
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen map = index->map;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen buffer_reset(map->hdr_copy_buf);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen buffer_append(map->hdr_copy_buf, hdr_copy, hdr_copy_size);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen memcpy(&map->hdr, hdr_copy, sizeof(map->hdr));
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen map->records_count = map->hdr.messages_count;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen i_assert(map->mmap_size >= size);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen t_pop();
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen return 0;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen}
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
a99dcacb7cb6e0288f8642483f395f8e4a7aa79cTimo Sirainenstatic void
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainenmail_index_update_day_headers(struct mail_index_header *hdr, uint32_t uid)
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const int max_days =
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen sizeof(hdr->day_first_uid) / sizeof(hdr->day_first_uid[0]);
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen struct tm tm;
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen time_t stamp;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen int i, days;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen /* get beginning of today */
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen tm = *localtime(&ioloop_time);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen tm.tm_hour = 0;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen tm.tm_min = 0;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen tm.tm_sec = 0;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen stamp = mktime(&tm);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if (stamp == (time_t)-1)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen i_panic("mktime(today) failed");
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if ((time_t)hdr->day_stamp >= stamp)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen return;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen /* get number of days since last message */
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen days = (stamp - hdr->day_stamp) / (3600*24);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if (days > max_days)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen days = max_days;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen /* @UNSAFE: move days forward and fill the missing days with old
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen day_first_uid[0]. */
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen memcpy(hdr->day_first_uid + days,
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen hdr->day_first_uid, max_days - days);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (i = 1; i < days; i++)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen hdr->day_first_uid[i] = hdr->day_first_uid[0];
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen hdr->day_stamp = stamp;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen hdr->day_first_uid[0] = uid;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen}
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenint mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen const struct mail_transaction_header *hdr,
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen const void *data)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen{
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen int ret = 0;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen t_push();
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case MAIL_TRANSACTION_APPEND: {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const struct mail_index_record *rec, *end;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen for (rec = data; rec < end; rec++) {
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen ret = sync_append(rec, ctx);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (ret <= 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case MAIL_TRANSACTION_EXPUNGE:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const struct mail_transaction_expunge *rec, *end;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen for (rec = data; rec < end; rec++) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ret = sync_expunge(rec, ctx);
5733207dc3ec10e6e5a6e0a8b30fbd1b061062b9Timo Sirainen if (ret <= 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE: {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const struct mail_transaction_flag_update *rec, *end;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen for (rec = data; rec < end; rec++) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen ret = sync_flag_update(rec, ctx);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (ret <= 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen }
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen break;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen }
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen case MAIL_TRANSACTION_HEADER_UPDATE: {
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen const struct mail_transaction_header_update *rec;
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen unsigned int i;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen for (i = 0; i < hdr->size; ) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen rec = CONST_PTR_OFFSET(data, i);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen ret = sync_header_update(rec, ctx);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if (ret <= 0)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen break;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen i += sizeof(*rec) + rec->size;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if ((i % 4) != 0)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen i += 4 - (i % 4);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen case MAIL_TRANSACTION_EXT_INTRO: {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen const struct mail_transaction_ext_intro *rec = data;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen unsigned int i;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen for (i = 0; i < hdr->size; ) {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if (i + sizeof(*rec) > hdr->size) {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen /* should be just extra padding */
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen ret = mail_index_sync_ext_intro(ctx, rec);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if (ret <= 0)
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen i += sizeof(*rec) + rec->name_size;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if ((i % 4) != 0)
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen i += 4 - (i % 4);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen case MAIL_TRANSACTION_EXT_RESET: {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen const struct mail_transaction_ext_reset *rec = data;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen ret = mail_index_sync_ext_reset(ctx, rec);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen case MAIL_TRANSACTION_EXT_HDR_UPDATE: {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen const struct mail_transaction_ext_hdr_update *rec = data;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen unsigned int i;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen for (i = 0; i < hdr->size; ) {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen ret = mail_index_sync_ext_hdr_update(ctx, rec);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if (ret <= 0)
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen i += sizeof(*rec) + rec->size;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if ((i % 4) != 0)
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen i += 4 - (i % 4);
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen case MAIL_TRANSACTION_EXT_REC_UPDATE: {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen const struct mail_transaction_ext_rec_update *rec, *end;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen const struct mail_index_ext *ext;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen unsigned int record_size;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen if (ctx->cur_ext_id == (uint32_t)-1) {
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen mail_index_sync_set_corrupted(ctx,
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen "Extension record updated "
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen "without intro prefix");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ctx->cur_ext_ignore) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = 1;
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen break;
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen }
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ext = array_idx(&ctx->view->map->extensions, ctx->cur_ext_id);
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen /* the record is padded to 32bits in the transaction log */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen record_size = (sizeof(*rec) + ext->record_size + 3) & ~3;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen rec = data;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while (rec < end) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = mail_index_sync_ext_rec_update(ctx, rec);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret <= 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen rec = CONST_PTR_OFFSET(rec, record_size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen break;
9ba1a38e2fa5ffe9d0db83c4a14a6552bcff3181Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE: {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen const struct mail_transaction_keyword_update *rec = data;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = mail_index_sync_keywords(ctx, hdr, rec);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET: {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct mail_transaction_keyword_reset *rec = data;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen default:
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi i_unreached();
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen t_pop();
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(ctx->view->map->records_count ==
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->view->map->hdr.messages_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(ctx->view->hdr.messages_count ==
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->view->map->hdr.messages_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_index_sync_map_init(struct mail_index_sync_map_ctx *sync_map_ctx,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_index_view *view,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen enum mail_index_sync_handler_type type)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memset(sync_map_ctx, 0, sizeof(*sync_map_ctx));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sync_map_ctx->view = view;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sync_map_ctx->cur_ext_id = (uint32_t)-1;
bcbca4b66800f0fbfe2643a86d5a6b63d752454dTimo Sirainen sync_map_ctx->type = type;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* make sure we re-read it in case it has changed */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sync_map_ctx->view->map->keywords_read = FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen mail_index_sync_init_handlers(sync_map_ctx);
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_index_sync_map_deinit(struct mail_index_sync_map_ctx *sync_map_ctx)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (sync_map_ctx->expunge_handlers_used)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_sync_deinit_expunge_handlers(sync_map_ctx);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_sync_deinit_handlers(sync_map_ctx);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void mail_index_sync_remove_recent(struct mail_index_sync_ctx *sync_ctx)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
struct mail_index_map *map = sync_ctx->view->map;
struct mail_index_record *rec;
unsigned int i;
for (i = 0; i < map->records_count; i++) {
rec = MAIL_INDEX_MAP_IDX(map, i);
if ((rec->flags & MAIL_RECENT) != 0) {
rec->flags &= ~MAIL_RECENT;
write_seq_update(map, i + 1, i + 1);
}
}
map->hdr.recent_messages_count = 0;
map->hdr.first_recent_uid_lowwater = map->hdr.next_uid;
}
int mail_index_sync_update_index(struct mail_index_sync_ctx *sync_ctx,
bool sync_only_external)
{
struct mail_index *index = sync_ctx->index;
struct mail_index_view *view = sync_ctx->view;
struct mail_index_map *map;
struct mail_index_sync_map_ctx sync_map_ctx;
const struct mail_transaction_header *thdr;
const void *data;
unsigned int count, old_lock_id;
uint32_t i, first_append_uid;
int ret;
bool had_dirty, skipped, check_ext_offsets;
mail_index_sync_map_init(&sync_map_ctx, view,
MAIL_INDEX_SYNC_HANDLER_FILE);
/* we'll have to update view->lock_id to avoid mail_index_view_lock()
trying to update the file later. */
old_lock_id = view->lock_id;
if (mail_index_lock_exclusive(index, &view->lock_id) < 0)
return -1;
mail_index_unlock(index, old_lock_id);
/* NOTE: locking may change index->map so make sure the assignment is
after locking */
map = index->map;
if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
map->write_to_disk = TRUE;
if (map->hdr_base != map->hdr_copy_buf->data) {
buffer_reset(map->hdr_copy_buf);
buffer_append(map->hdr_copy_buf, map->hdr_base,
map->hdr.header_size);
map->hdr_base = map->hdr_copy_buf->data;
}
i_assert(map->hdr.base_header_size >= sizeof(map->hdr));
mail_index_unmap(index, &view->map);
view->map = map;
view->map->refcount++;
i_assert(view->hdr.messages_count == map->hdr.messages_count);
had_dirty = (map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
if (had_dirty)
map->hdr.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
if (sync_ctx->sync_recent) {
/* mark all messages non-recent */
mail_index_sync_remove_recent(sync_ctx);
}
/* make sure we don't go doing fsck while modifying the index */
index->sync_update = TRUE;
first_append_uid = 0;
check_ext_offsets = TRUE;
while ((ret = mail_transaction_log_view_next(view->log_view, &thdr,
&data, &skipped)) > 0) {
if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
if (sync_only_external) {
/* we're syncing only external changes. */
continue;
}
} else if (check_ext_offsets) {
if (mail_index_is_ext_synced(view->log_view, view->map))
continue;
check_ext_offsets = FALSE;
}
if ((thdr->type & MAIL_TRANSACTION_APPEND) != 0) {
const struct mail_index_record *rec = data;
if (first_append_uid == 0)
first_append_uid = rec->uid;
map = view->map;
count = thdr->size / sizeof(*rec);
if (mail_index_grow(index, map, count) < 0) {
ret = -1;
break;
}
if (map != index->map) {
index->map->refcount++;
mail_index_sync_replace_map(&sync_map_ctx,
index->map);
}
}
if (mail_index_sync_record(&sync_map_ctx, thdr, data) < 0) {
ret = -1;
break;
}
/* mail_index_sync_record() might have changed map to anything.
make sure we don't accidentally try to use it. */
map = NULL;
}
if (ret == 0)
mail_index_sync_update_log_offset(&sync_map_ctx, view->map);
mail_index_sync_map_deinit(&sync_map_ctx);
index->sync_update = FALSE;
if (ret < 0) {
mail_index_view_unlock(view);
return -1;
}
map = view->map;
i_assert(map->records_count == map->hdr.messages_count);
i_assert(map->hdr_copy_buf->used <= map->hdr.header_size);
if (first_append_uid != 0)
mail_index_update_day_headers(&map->hdr, first_append_uid);
if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) == 0 &&
had_dirty) {
/* do we have dirty flags anymore? */
const struct mail_index_record *rec;
for (i = 0; i < map->records_count; i++) {
rec = MAIL_INDEX_MAP_IDX(map, i);
if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
map->hdr.flags |=
MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
break;
}
}
}
if (mail_index_map_msync(index, map) < 0)
ret = -1;
i_assert(view->map == index->map);
view->hdr = map->hdr;
mail_index_view_unlock(view);
return ret;
}