mail-index-sync-update.c revision 1b317fe22572738681d34d80da8012638e1e1281
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek/* Copyright (C) 2004 Timo Sirainen */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "lib.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "ioloop.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "array.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mmap-util.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mail-index-view-private.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mail-index-sync-private.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mail-transaction-log.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mail-transaction-log-private.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_sync_update_log_offset(struct mail_index_sync_map_ctx *ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_map *map, bool eol)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t prev_seq;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uoff_t prev_offset;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek &prev_seq, &prev_offset);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (!eol) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (prev_offset == ctx->ext_intro_end_offset &&
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek prev_seq == ctx->ext_intro_seq) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* previous transaction was an extension introduction.
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek we probably came here from
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_ext_reset(). if there are any more
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek views which want to continue syncing it needs the
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek intro. so back up a bit more.
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek don't do this in case the last transaction in the
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek log is the extension intro, so we don't keep trying
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek to sync it over and over again. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek prev_offset = ctx->ext_intro_offset;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_assert(ctx->view->index->log->head->hdr.file_seq == prev_seq);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.log_file_seq = prev_seq;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.log_file_head_offset = prev_offset;
a95c006f748fa9df0dd81509b51974133d2786afLukas Slebodnik}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek#if 0 // FIXME: can we / do we want to support this?
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_map_msync(struct mail_index *index, struct mail_index_map *map)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek buffer_write(map->hdr_copy_buf, 0, &map->hdr, sizeof(map->hdr));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->mmap_used_size = map->hdr.header_size +
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->records_count * map->hdr.record_size;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek memcpy(map->mmap_base, &map->hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek I_MIN(map->hdr.base_header_size, sizeof(map->hdr)));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek memcpy(PTR_OFFSET(map->mmap_base, map->hdr.base_header_size),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek CONST_PTR_OFFSET(map->hdr_base, map->hdr.base_header_size),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->hdr.header_size - map->hdr.base_header_size);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (msync(map->mmap_base, map->mmap_used_size, MS_SYNC) < 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_set_syscall_error(index, "msync()");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#endif
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void mail_index_sync_replace_map(struct mail_index_sync_map_ctx *ctx,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov struct mail_index_map *map)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_view *view = ctx->view;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_assert(view->map != map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_update_log_offset(ctx, view->map, FALSE);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#if 0 // FIXME
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* we could have already updated some of the records, so make sure
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek that other views (in possibly other processes) will see this map's
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek header in a valid state. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (void)mail_index_map_msync(view->index, view->map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#endif
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_unmap(view->index, &view->map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek view->map = map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (ctx->type != MAIL_INDEX_SYNC_HANDLER_VIEW)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov view->index->map = map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekvoid mail_index_sync_move_to_private(struct mail_index_sync_map_ctx *ctx)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_map *map = ctx->view->map;
04868f1573f4b26ef34610b6d7069172f93bd8abJakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (map->refcount == 1) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map))
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_map_move_to_memory(map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek map = mail_index_map_clone(map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_replace_map(ctx, map);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstruct mail_index_map *
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_sync_get_atomic_map(struct mail_index_sync_map_ctx *ctx)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_move_to_private(ctx);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ctx->view->map->write_atomic = TRUE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return ctx->view->map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_header_update_counts(struct mail_index_header *hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint8_t old_flags, uint8_t new_flags,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char **error_r)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* different recent-flag */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((old_flags & MAIL_RECENT) == 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->recent_messages_count++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (hdr->recent_messages_count > hdr->messages_count) {
828cc04cd1ed9076faa6e1545055ae69a04f0f0fLukas Slebodnik *error_r = "Recent counter wrong";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (hdr->recent_messages_count == 0 ||
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek hdr->recent_messages_count > hdr->messages_count) {
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek *error_r = "Recent counter wrong";
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek return -1;
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (--hdr->recent_messages_count == 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_recent_uid_lowwater = hdr->next_uid;
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* different seen-flag */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((old_flags & MAIL_SEEN) != 0) {
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek if (hdr->seen_messages_count == 0) {
4cae8609b513c267af11c0409bfe1d17d3a5da2fMichal Zidek *error_r = "Seen counter wrong";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->seen_messages_count--;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (hdr->seen_messages_count >= hdr->messages_count) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek *error_r = "Seen counter wrong";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (++hdr->seen_messages_count == hdr->messages_count)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_unseen_uid_lowwater = hdr->next_uid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* different deleted-flag */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((old_flags & MAIL_DELETED) == 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->deleted_messages_count++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (hdr->deleted_messages_count > hdr->messages_count) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek *error_r = "Deleted counter wrong";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (hdr->deleted_messages_count == 0 ||
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->deleted_messages_count > hdr->messages_count) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek *error_r = "Deleted counter wrong";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (--hdr->deleted_messages_count == 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_deleted_uid_lowwater = hdr->next_uid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_sync_header_update_counts(struct mail_index_sync_map_ctx *ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint8_t old_flags, uint8_t new_flags)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *error;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (mail_index_header_update_counts(&ctx->view->map->hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek old_flags, new_flags, &error) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_set_corrupted(ctx, "%s", error);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmail_index_header_update_lowwaters(struct mail_index_header *hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct mail_index_record *rec)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((rec->flags & MAIL_RECENT) != 0 &&
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->uid < hdr->first_recent_uid_lowwater)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_recent_uid_lowwater = rec->uid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((rec->flags & MAIL_SEEN) == 0 &&
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->uid < hdr->first_unseen_uid_lowwater)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_unseen_uid_lowwater = rec->uid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if ((rec->flags & MAIL_DELETED) != 0 &&
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->uid < hdr->first_deleted_uid_lowwater)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->first_deleted_uid_lowwater = rec->uid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozeksync_expunge_call_handlers(struct mail_index_sync_map_ctx *ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t seq1, uint32_t seq2)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct mail_index_expunge_handler *eh;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_record *rec;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek unsigned int i, count;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* call expunge handlers only when syncing index file */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (ctx->type != MAIL_INDEX_SYNC_HANDLER_FILE)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (!ctx->expunge_handlers_set)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_init_expunge_handlers(ctx);
e15a9f81eb33066937710d7dee6976a3646d119cJakub Hrozek
e45b81abe0aafa8a04bd64ac31a2fac63ce675b7Jakub Hrozek if (!array_is_created(&ctx->expunge_handlers))
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek eh = array_get(&ctx->expunge_handlers, &count);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (i = 0; i < count; i++, eh++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (; seq1 <= seq2; seq1++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec = MAIL_INDEX_MAP_IDX(ctx->view->map, seq1-1);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (eh->handler(ctx, seq1,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek PTR_OFFSET(rec, eh->record_offset),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek eh->sync_context, eh->context) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozeksync_expunge(const struct mail_transaction_expunge *e, unsigned int count,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_sync_map_ctx *ctx)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_map *map = ctx->view->map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_record *rec;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t seq_count, seq, seq1, seq2;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek unsigned int i;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* we don't ever want to move around data inside a memory mapped file.
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek it gets corrupted too easily if we crash in the middle. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek // FIXME: it's necessary for current view code that we get atomic
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek // map even if these messages are already expunged, because the
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek // view code doesn't check that and our index_int_offset goes wrong
e15a9f81eb33066937710d7dee6976a3646d119cJakub Hrozek map = mail_index_sync_get_atomic_map(ctx);
e45b81abe0aafa8a04bd64ac31a2fac63ce675b7Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (i = 0; i < count; i++, e++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (mail_index_lookup_uid_range(ctx->view, e->uid1, e->uid2,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek &seq1, &seq2) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (seq1 == 0) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* everything expunged already */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov continue;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (seq = seq1; seq <= seq2; seq++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec = MAIL_INDEX_MAP_IDX(map, seq-1);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_header_update_counts(ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->flags, 0);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (sync_expunge_call_handlers(ctx, seq1, seq2) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* @UNSAFE */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek memmove(MAIL_INDEX_MAP_IDX(map, seq1-1),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek MAIL_INDEX_MAP_IDX(map, seq2),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (map->records_count - seq2) * map->hdr.record_size);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek seq_count = seq2 - seq1 + 1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->records_count -= seq_count;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->hdr.messages_count -= seq_count;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* lookup_uid_range() relies on this */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ctx->view->hdr.messages_count -= seq_count;
e15a9f81eb33066937710d7dee6976a3646d119cJakub Hrozek }
e45b81abe0aafa8a04bd64ac31a2fac63ce675b7Jakub Hrozek return 1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekvoid mail_index_sync_write_seq_update(struct mail_index_sync_map_ctx *ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t seq1, uint32_t seq2)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina struct mail_index_map *map = ctx->view->map;
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map));
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina if (map->write_seq_first == 0 ||
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina map->write_seq_first > seq1)
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina map->write_seq_first = seq1;
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina if (map->write_seq_last < seq2)
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina map->write_seq_last = seq2;
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina}
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březina
a7401bf72db3a6eb62b1628f9dd141f7118e3510Pavel Březinastatic int sync_append(const struct mail_index_record *rec,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_sync_map_ctx *ctx)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_view *view = ctx->view;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_map *map = view->map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek void *dest;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek size_t append_pos;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (rec->uid < map->hdr.next_uid) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mail_index_sync_set_corrupted(ctx,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek "Append with UID %u, but next_uid = %u",
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek rec->uid, map->hdr.next_uid);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return -1;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* move to memory. the mapping is written when unlocking so we don't
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek waste time re-mmap()ing multiple times or waste space growing index
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek file too large */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mail_index_sync_move_to_private(ctx);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map = view->map;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* don't rely on buffer->used being at the correct position.
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek at least expunges can move it */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek append_pos = map->records_count * map->hdr.record_size;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek dest = buffer_get_space_unsafe(map->buffer, append_pos,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.record_size);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->records = buffer_get_modifiable_data(map->buffer, NULL);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek memcpy(dest, rec, sizeof(*rec));
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek memset(PTR_OFFSET(dest, sizeof(*rec)), 0,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.record_size - sizeof(*rec));
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.messages_count++;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->hdr.next_uid = rec->uid+1;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek map->records_count++;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
3bd78eb2faf09635b8d307e4440ccb1420f80716Jakub Hrozek mail_index_sync_write_seq_update(ctx, map->hdr.messages_count,
3bd78eb2faf09635b8d307e4440ccb1420f80716Jakub Hrozek map->hdr.messages_count);
3bd78eb2faf09635b8d307e4440ccb1420f80716Jakub Hrozek
3bd78eb2faf09635b8d307e4440ccb1420f80716Jakub Hrozek if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
3bd78eb2faf09635b8d307e4440ccb1420f80716Jakub Hrozek map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mail_index_header_update_lowwaters(&map->hdr, rec);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mail_index_sync_header_update_counts(ctx, 0, rec->flags);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return 1;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail_index_sync_map_ctx *ctx)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail_index_view *view = ctx->view;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail_index_header *hdr;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_record *rec;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint8_t flag_mask, old_flags;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t idx, seq1, seq2;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (mail_index_lookup_uid_range(view, u->uid1, u->uid2,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek &seq1, &seq2) < 0)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return -1;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (seq1 == 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_move_to_private(ctx);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_write_seq_update(ctx, seq1, seq2);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
a95c006f748fa9df0dd81509b51974133d2786afLukas Slebodnik hdr = &view->map->hdr;
a95c006f748fa9df0dd81509b51974133d2786afLukas Slebodnik if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek hdr->flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek flag_mask = ~u->remove_flags;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (((u->add_flags | u->remove_flags) &
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek (MAIL_SEEN | MAIL_DELETED | MAIL_RECENT)) == 0) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* we're not modifying any counted/lowwatered flags */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek for (idx = seq1-1; idx < seq2; idx++) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek rec = MAIL_INDEX_MAP_IDX(view->map, idx);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek rec->flags = (rec->flags & flag_mask) | u->add_flags;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (idx = seq1-1; idx < seq2; idx++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec = MAIL_INDEX_MAP_IDX(view->map, idx);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek old_flags = rec->flags;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->flags = (rec->flags & flag_mask) | u->add_flags;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_header_update_lowwaters(hdr, rec);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_header_update_counts(ctx, old_flags,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek rec->flags);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int sync_header_update(const struct mail_transaction_header_update *u,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_index_sync_map_ctx *ctx)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail_index_map *map = ctx->view->map;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek uint32_t orig_log_file_tail_offset = map->hdr.log_file_tail_offset;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (u->offset >= map->hdr.base_header_size ||
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek u->offset + u->size > map->hdr.base_header_size) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mail_index_sync_set_corrupted(ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek "Header update outside range: %u + %u > %u",
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek u->offset, u->size, map->hdr.base_header_size);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek buffer_write(map->hdr_copy_buf, u->offset, u + 1, u->size);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->hdr_base = map->hdr_copy_buf->data;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->write_base_header = TRUE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* @UNSAFE */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if ((uint32_t)(u->offset + u->size) <= sizeof(map->hdr)) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek memcpy(PTR_OFFSET(&map->hdr, u->offset),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek u + 1, u->size);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else if (u->offset < sizeof(map->hdr)) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek memcpy(PTR_OFFSET(&map->hdr, u->offset),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek u + 1, sizeof(map->hdr) - u->offset);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* the tail offset updates are intended for internal transaction
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek log handling. we'll update the offset in the header only when
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek the sync is finished. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek map->hdr.log_file_tail_offset = orig_log_file_tail_offset;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return 1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekint mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct mail_transaction_header *hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const void *data)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek int ret = 0;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek t_push();
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek case MAIL_TRANSACTION_APPEND: {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const struct mail_index_record *rec, *end;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek end = CONST_PTR_OFFSET(data, hdr->size);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek for (rec = data; rec < end; rec++) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek ret = sync_append(rec, ctx);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (ret <= 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek break;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
break;
}
case MAIL_TRANSACTION_EXPUNGE:
case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: {
const struct mail_transaction_expunge *rec = data, *end;
if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
/* this is simply a request for expunge */
break;
}
end = CONST_PTR_OFFSET(data, hdr->size);
ret = sync_expunge(rec, end - rec, ctx);
break;
}
case MAIL_TRANSACTION_FLAG_UPDATE: {
const struct mail_transaction_flag_update *rec, *end;
end = CONST_PTR_OFFSET(data, hdr->size);
for (rec = data; rec < end; rec++) {
ret = sync_flag_update(rec, ctx);
if (ret <= 0)
break;
}
break;
}
case MAIL_TRANSACTION_HEADER_UPDATE: {
const struct mail_transaction_header_update *rec;
unsigned int i;
for (i = 0; i < hdr->size; ) {
rec = CONST_PTR_OFFSET(data, i);
ret = sync_header_update(rec, ctx);
if (ret <= 0)
break;
i += sizeof(*rec) + rec->size;
if ((i % 4) != 0)
i += 4 - (i % 4);
}
break;
}
case MAIL_TRANSACTION_EXT_INTRO: {
const struct mail_transaction_ext_intro *rec = data;
unsigned int i;
uint32_t prev_seq;
uoff_t prev_offset;
mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
&prev_seq, &prev_offset);
ctx->ext_intro_seq = prev_seq;
ctx->ext_intro_offset = prev_offset;
ctx->ext_intro_end_offset =
prev_offset + hdr->size + sizeof(*hdr);
for (i = 0; i < hdr->size; ) {
if (i + sizeof(*rec) > hdr->size) {
/* should be just extra padding */
break;
}
rec = CONST_PTR_OFFSET(data, i);
if (i + sizeof(*rec) + rec->name_size > hdr->size) {
mail_index_sync_set_corrupted(ctx,
"ext intro: name_size too large");
ret = -1;
break;
}
ret = mail_index_sync_ext_intro(ctx, rec);
if (ret <= 0)
break;
i += sizeof(*rec) + rec->name_size;
if ((i % 4) != 0)
i += 4 - (i % 4);
}
break;
}
case MAIL_TRANSACTION_EXT_RESET: {
const struct mail_transaction_ext_reset *rec = data;
if (hdr->size != sizeof(*rec)) {
mail_index_sync_set_corrupted(ctx,
"ext reset: invalid record size");
ret = -1;
break;
}
ret = mail_index_sync_ext_reset(ctx, rec);
break;
}
case MAIL_TRANSACTION_EXT_HDR_UPDATE: {
const struct mail_transaction_ext_hdr_update *rec = data;
unsigned int i;
for (i = 0; i < hdr->size; ) {
rec = CONST_PTR_OFFSET(data, i);
if (i + sizeof(*rec) > hdr->size ||
i + sizeof(*rec) + rec->size > hdr->size) {
mail_index_sync_set_corrupted(ctx,
"ext hdr update: invalid record size");
ret = -1;
break;
}
ret = mail_index_sync_ext_hdr_update(ctx, rec);
if (ret <= 0)
break;
i += sizeof(*rec) + rec->size;
if ((i % 4) != 0)
i += 4 - (i % 4);
}
break;
}
case MAIL_TRANSACTION_EXT_REC_UPDATE: {
const struct mail_transaction_ext_rec_update *rec;
const struct mail_index_ext *ext;
unsigned int i, record_size;
if (ctx->cur_ext_id == (uint32_t)-1) {
mail_index_sync_set_corrupted(ctx,
"Extension record updated "
"without intro prefix");
ret = -1;
break;
}
if (ctx->cur_ext_ignore) {
ret = 1;
break;
}
ext = array_idx(&ctx->view->map->extensions, ctx->cur_ext_id);
/* the record is padded to 32bits in the transaction log */
record_size = (sizeof(*rec) + ext->record_size + 3) & ~3;
for (i = 0; i < hdr->size; i += record_size) {
rec = CONST_PTR_OFFSET(data, i);
if (i + record_size > hdr->size) {
mail_index_sync_set_corrupted(ctx,
"ext rec update: invalid record size");
ret = -1;
break;
}
ret = mail_index_sync_ext_rec_update(ctx, rec);
if (ret <= 0)
break;
}
break;
}
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
const struct mail_transaction_keyword_update *rec = data;
ret = mail_index_sync_keywords(ctx, hdr, rec);
break;
}
case MAIL_TRANSACTION_KEYWORD_RESET: {
const struct mail_transaction_keyword_reset *rec = data;
ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
break;
}
default:
i_unreached();
}
t_pop();
i_assert(ctx->view->map->records_count ==
ctx->view->map->hdr.messages_count);
ctx->view->hdr = ctx->view->map->hdr;
return ret;
}
void mail_index_sync_map_init(struct mail_index_sync_map_ctx *sync_map_ctx,
struct mail_index_view *view,
enum mail_index_sync_handler_type type)
{
memset(sync_map_ctx, 0, sizeof(*sync_map_ctx));
sync_map_ctx->view = view;
sync_map_ctx->cur_ext_id = (uint32_t)-1;
sync_map_ctx->type = type;
/* make sure we re-read it in case it has changed */
sync_map_ctx->view->map->keywords_read = FALSE;
mail_index_sync_init_handlers(sync_map_ctx);
}
void mail_index_sync_map_deinit(struct mail_index_sync_map_ctx *sync_map_ctx)
{
if (sync_map_ctx->expunge_handlers_used)
mail_index_sync_deinit_expunge_handlers(sync_map_ctx);
mail_index_sync_deinit_handlers(sync_map_ctx);
}
static void mail_index_sync_update_hdr_dirty_flag(struct mail_index_map *map)
{
const struct mail_index_record *rec;
unsigned int i;
if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0)
return;
/* do we have dirty flags anymore? */
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;
}
}
}
#ifdef DEBUG
void mail_index_map_check(struct mail_index_map *map)
{
const struct mail_index_header *hdr = &map->hdr;
unsigned int i, del = 0, recent = 0, seen = 0;
i_assert(hdr->messages_count == map->records_count);
for (i = 0; i < map->records_count; i++) {
const struct mail_index_record *rec;
rec = MAIL_INDEX_MAP_IDX(map, i);
if (rec->flags & MAIL_DELETED) {
i_assert(rec->uid >= hdr->first_deleted_uid_lowwater);
del++;
}
if (rec->flags & MAIL_RECENT) {
i_assert(rec->uid >= hdr->first_recent_uid_lowwater);
recent++;
}
if (rec->flags & MAIL_SEEN)
seen++;
else
i_assert(rec->uid >= hdr->first_unseen_uid_lowwater);
}
i_assert(del == hdr->deleted_messages_count);
i_assert(recent == hdr->recent_messages_count);
i_assert(seen == hdr->seen_messages_count);
}
#endif
int mail_index_sync_map(struct mail_index *index, struct mail_index_map **_map,
enum mail_index_sync_handler_type type, bool force)
{
struct mail_index_map *map = *_map;
struct mail_index_view *view;
struct mail_index_sync_map_ctx sync_map_ctx;
const struct mail_transaction_header *thdr;
const void *tdata;
uint32_t prev_seq, mailbox_sync_seq;
uoff_t start_offset, prev_offset, mailbox_sync_offset;
int ret;
bool had_dirty;
i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
if (!force) {
/* see if we'd prefer to reopen the index file instead of
syncing the current map from the transaction log */
uoff_t log_size, index_size;
if (index->log->head == NULL || index->fd == -1)
return 0;
index_size = map->hdr.header_size +
map->records_count * map->hdr.record_size;
/* this isn't necessary correct currently, but it should be
close enough */
log_size = index->log->head->last_size;
if (log_size > map->hdr.log_file_tail_offset &&
log_size - map->hdr.log_file_tail_offset > index_size)
return 0;
}
start_offset = type == MAIL_INDEX_SYNC_HANDLER_FILE ?
map->hdr.log_file_tail_offset : map->hdr.log_file_head_offset;
view = mail_index_view_open_with_map(index, map);
ret = mail_transaction_log_view_set(view->log_view,
map->hdr.log_file_seq, start_offset,
(uint32_t)-1, (uoff_t)-1);
if (ret <= 0) {
if (force && ret == 0) {
/* the seq/offset is probably broken */
(void)mail_index_fsck(index);
}
/* can't use it. sync by re-reading index. */
mail_index_view_close(&view);
return 0;
}
mail_transaction_log_get_mailbox_sync_pos(index->log, &mailbox_sync_seq,
&mailbox_sync_offset);
/* view referenced the map. avoid unnecessary map cloning by
unreferencing the map while view exists. */
map->refcount--;
had_dirty = (map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
if (had_dirty) {
map->hdr.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
map->write_base_header = TRUE;
}
if (map->hdr_base != map->hdr_copy_buf->data) {
/* if syncing updates the header, it updates hdr_copy_buf
and updates hdr_base to hdr_copy_buf. so the buffer must
initially contain a valid header or we'll break it when
writing it. */
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;
}
mail_index_sync_map_init(&sync_map_ctx, view, type);
map = NULL;
/* FIXME: when transaction sync lock is removed, we'll need to handle
the case when a transaction is committed while mailbox is being
synced ([synced transactions][new transaction][ext transaction]).
this means int_offset contains [synced] and ext_offset contains
all */
while ((ret = mail_transaction_log_view_next(view->log_view, &thdr,
&tdata)) > 0) {
mail_transaction_log_view_get_prev_pos(view->log_view,
&prev_seq, &prev_offset);
if (LOG_IS_BEFORE(prev_seq, prev_offset,
view->map->hdr.log_file_seq,
view->map->hdr.log_file_head_offset)) {
/* this has been synced already. we're here only to call
expunge handlers and extension update handlers. */
i_assert(type == MAIL_INDEX_SYNC_HANDLER_FILE);
if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
continue;
if ((thdr->type & MAIL_TRANSACTION_EXT_MASK) == 0)
continue;
}
/* we'll just skip over broken entries */
(void)mail_index_sync_record(&sync_map_ctx, thdr, tdata);
}
map = view->map;
if (had_dirty)
mail_index_sync_update_hdr_dirty_flag(map);
mail_index_sync_update_log_offset(&sync_map_ctx, view->map, TRUE);
#ifdef DEBUG
mail_index_map_check(map);
#endif
i_assert(map->hdr.indexid == index->indexid);
/* transaction log tracks internally the current tail offset.
besides using header updates, it also updates the offset to skip
over following external transactions to avoid extra unneeded log
reading. */
map->hdr.log_file_tail_offset = index->log->head->max_tail_offset;
if (map->write_base_header) {
i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map));
buffer_write(map->hdr_copy_buf, 0, &map->hdr, sizeof(map->hdr));
}
/*FIXME:if (mail_index_map_msync(index, map) < 0)
ret = -1;*/
if (sync_map_ctx.errors) {
/* avoid the same syncing errors the next time */
mail_index_write(index, FALSE);
}
/* restore refcount before closing the view. this is necessary also
if map got cloned, because view closing would otherwise destroy it */
map->refcount++;
mail_index_sync_map_deinit(&sync_map_ctx);
mail_index_view_close(&view);
i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
*_map = map;
return ret < 0 ? -1 : 1;
}