mail-index-sync-update.c revision 2ebfb5c0608e2323b73271208f4036a7ea7d7f3a
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2004 Timo Sirainen */
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#include "lib.h"
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#include "ioloop.h"
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen#include "array.h"
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen#include "mmap-util.h"
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen#include "mail-index-view-private.h"
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#include "mail-index-sync-private.h"
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#include "mail-transaction-log.h"
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#include "mail-transaction-log-private.h"
7ed711d973b319320da100d3e905ef7b99ed69d6Timo Sirainen
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen/* If we have less than this many bytes to sync from log file, don't bother
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen reading the main index */
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen#define MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE 2048
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenstatic void
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainenmail_index_sync_update_log_offset(struct mail_index_sync_map_ctx *ctx,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_map *map, bool eol)
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen{
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen uint32_t prev_seq;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen uoff_t prev_offset;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen &prev_seq, &prev_offset);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (!eol) {
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen if (prev_offset == ctx->ext_intro_end_offset &&
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen prev_seq == ctx->ext_intro_seq) {
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen /* previous transaction was an extension introduction.
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen we probably came here from
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen mail_index_sync_ext_reset(). if there are any more
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen views which want to continue syncing it needs the
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen intro. so back up a bit more.
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen don't do this in case the last transaction in the
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen log is the extension intro, so we don't keep trying
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen to sync it over and over again. */
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen prev_offset = ctx->ext_intro_offset;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen }
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen } else {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen i_assert(ctx->view->index->log->head->hdr.file_seq == prev_seq);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen map->hdr.log_file_seq = prev_seq;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen map->hdr.log_file_head_offset = prev_offset;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen}
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainenstatic void mail_index_sync_replace_map(struct mail_index_sync_map_ctx *ctx,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_map *map)
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_view *view = ctx->view;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(view->map != map);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi mail_index_sync_update_log_offset(ctx, view->map, FALSE);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi mail_index_unmap(&view->map);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi view->map = map;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (ctx->type != MAIL_INDEX_SYNC_HANDLER_VIEW)
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen view->index->map = map;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen}
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainenstatic void
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainenmail_index_sync_move_to_private_memory(struct mail_index_sync_map_ctx *ctx)
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen{
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen struct mail_index_map *map = ctx->view->map;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map) ||
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->rec_map->lock_id != 0);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if (map->refcount > 1) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen map = mail_index_map_clone(map);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen mail_index_sync_replace_map(ctx, map);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen }
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(ctx->view->map))
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen mail_index_map_move_to_memory(ctx->view->map);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen}
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainenstruct mail_index_map *
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainenmail_index_sync_get_atomic_map(struct mail_index_sync_map_ctx *ctx)
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen{
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen mail_index_sync_move_to_private_memory(ctx);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen mail_index_record_map_move_to_private(ctx->view->map);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen ctx->view->map->write_atomic = TRUE;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen return ctx->view->map;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen}
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainenstatic int
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen uint8_t old_flags, uint8_t new_flags,
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen const char **error_r)
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen{
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen /* different seen-flag */
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if ((old_flags & MAIL_SEEN) != 0) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if (hdr->seen_messages_count == 0) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen *error_r = "Seen counter wrong";
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen return -1;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen }
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen hdr->seen_messages_count--;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen } else {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if (hdr->seen_messages_count >= hdr->messages_count) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen *error_r = "Seen counter wrong";
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen return -1;
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen }
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen if (++hdr->seen_messages_count == hdr->messages_count)
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen }
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen }
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen /* different deleted-flag */
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen if ((old_flags & MAIL_DELETED) == 0) {
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen hdr->deleted_messages_count++;
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen if (hdr->deleted_messages_count > hdr->messages_count) {
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen *error_r = "Deleted counter wrong";
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen return -1;
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen }
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen } else {
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen if (hdr->deleted_messages_count == 0 ||
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen hdr->deleted_messages_count > hdr->messages_count) {
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen *error_r = "Deleted counter wrong";
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen return -1;
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen }
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen if (--hdr->deleted_messages_count == 0)
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen }
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen return 0;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen}
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenstatic void
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainenmail_index_sync_header_update_counts_all(struct mail_index_sync_map_ctx *ctx,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen uint32_t uid,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen uint8_t old_flags, uint8_t new_flags)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen{
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen struct mail_index_map *const *maps;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen const char *error;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen unsigned int i, count;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen maps = array_get(&ctx->view->map->rec_map->maps, &count);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen for (i = 0; i < count; i++) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if (uid >= maps[i]->hdr.next_uid)
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen continue;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen if (mail_index_header_update_counts(&maps[i]->hdr,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen old_flags, new_flags,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen &error) < 0)
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
7ed711d973b319320da100d3e905ef7b99ed69d6Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenstatic void
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainenmail_index_sync_header_update_counts(struct mail_index_sync_map_ctx *ctx,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen uint32_t uid, uint8_t old_flags,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen uint8_t new_flags, bool all)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen const char *error;
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen if (all) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen mail_index_sync_header_update_counts_all(ctx, uid, old_flags,
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen new_flags);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen } else {
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainen i_assert(uid < ctx->view->map->hdr.next_uid);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (mail_index_header_update_counts(&ctx->view->map->hdr,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen old_flags, new_flags,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen &error) < 0)
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainen}
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainen
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainenstatic void
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainenmail_index_header_update_lowwaters(struct mail_index_sync_map_ctx *ctx,
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainen uint32_t uid, enum mail_flags flags)
b1e46e840dae172f61140dc260eede4f124ebb31Timo Sirainen{
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen struct mail_index_map *const *maps;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen unsigned int i, count;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen maps = array_get(&ctx->view->map->rec_map->maps, &count);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen for (i = 0; i < count; i++) {
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen if ((flags & MAIL_SEEN) == 0 &&
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen uid < maps[i]->hdr.first_unseen_uid_lowwater)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen maps[i]->hdr.first_unseen_uid_lowwater = uid;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if ((flags & MAIL_DELETED) != 0 &&
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen uid < maps[i]->hdr.first_deleted_uid_lowwater)
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen maps[i]->hdr.first_deleted_uid_lowwater = uid;
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen }
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen}
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainenstatic int
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainensync_expunge_call_handlers(struct mail_index_sync_map_ctx *ctx,
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen uint32_t seq1, uint32_t seq2)
7ed711d973b319320da100d3e905ef7b99ed69d6Timo Sirainen{
7ed711d973b319320da100d3e905ef7b99ed69d6Timo Sirainen const struct mail_index_expunge_handler *eh;
b8b085f7bc6f1c0367802a9f00062bbbd981690dTimo Sirainen struct mail_index_record *rec;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen unsigned int i, count;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen /* call expunge handlers only when syncing index file */
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen if (ctx->type != MAIL_INDEX_SYNC_HANDLER_FILE)
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen return 0;
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen
98e8f95ffee4eacca72b1bcf082f2c735592301bTimo Sirainen if (!ctx->expunge_handlers_set)
98e8f95ffee4eacca72b1bcf082f2c735592301bTimo Sirainen mail_index_sync_init_expunge_handlers(ctx);
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen if (!array_is_created(&ctx->expunge_handlers))
23878bd03d1de531e3261a25598beec621351910Timo Sirainen return 0;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainen eh = array_get(&ctx->expunge_handlers, &count);
23878bd03d1de531e3261a25598beec621351910Timo Sirainen for (i = 0; i < count; i++, eh++) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen for (; seq1 <= seq2; seq1++) {
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen rec = MAIL_INDEX_MAP_IDX(ctx->view->map, seq1-1);
57434d8add2f13b6d6dbd39b941e9e80c64be74eTimo Sirainen if (eh->handler(ctx, seq1,
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen PTR_OFFSET(rec, eh->record_offset),
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen eh->sync_context, eh->context) < 0)
4ca6f6e2ae7be7c5f04ea5ef176a7c4a47ea3d33Timo Sirainen return -1;
7ed711d973b319320da100d3e905ef7b99ed69d6Timo Sirainen }
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen return 0;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen}
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenstatic int
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainensync_expunge(const struct mail_transaction_expunge *e, unsigned int count,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_sync_map_ctx *ctx)
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_map *map = ctx->view->map;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_record *rec;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen uint32_t seq_count, seq, seq1, seq2;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen unsigned int i;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen for (i = 0; i < count; i++, e++) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_index_lookup_uid_range(ctx->view, e->uid1, e->uid2,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen &seq1, &seq2);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (seq1 == 0) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen /* everything expunged already */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen continue;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen for (seq = seq1; seq <= seq2; seq++) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq-1);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen mail_index_sync_header_update_counts(ctx, rec->uid,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen rec->flags, 0,
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen FALSE);
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi if (sync_expunge_call_handlers(ctx, seq1, seq2) < 0)
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen return -1;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen /* @UNSAFE */
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen memmove(MAIL_INDEX_MAP_IDX(map, seq1-1),
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MAIL_INDEX_MAP_IDX(map, seq2),
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (map->rec_map->records_count - seq2) *
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi map->hdr.record_size);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen seq_count = seq2 - seq1 + 1;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen map->rec_map->records_count -= seq_count;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen map->hdr.messages_count -= seq_count;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen return 1;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen}
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenvoid mail_index_sync_write_seq_update(struct mail_index_sync_map_ctx *ctx,
23878bd03d1de531e3261a25598beec621351910Timo Sirainen uint32_t seq1, uint32_t seq2)
23878bd03d1de531e3261a25598beec621351910Timo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_map *map = ctx->view->map;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (map->rec_map->write_seq_first == 0 ||
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen map->rec_map->write_seq_first > seq1)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen map->rec_map->write_seq_first = seq1;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (map->rec_map->write_seq_last < seq2)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen map->rec_map->write_seq_last = seq2;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen}
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainenstatic int sync_append(const struct mail_index_record *rec,
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen struct mail_index_sync_map_ctx *ctx)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_view *view = ctx->view;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen struct mail_index_map *map = view->map;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen enum mail_flags new_flags;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen void *dest;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen size_t append_pos;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen if (rec->uid < map->hdr.next_uid) {
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen mail_index_sync_set_corrupted(ctx,
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen "Append with UID %u, but next_uid = %u",
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen rec->uid, map->hdr.next_uid);
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen return -1;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen }
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen
2df92c5bbd42ff42a1a38d688a6b11f1d326cb78Timo Sirainen /* move to memory. the mapping is written when unlocking so we don't
2df92c5bbd42ff42a1a38d688a6b11f1d326cb78Timo Sirainen waste time re-mmap()ing multiple times or waste space growing index
2df92c5bbd42ff42a1a38d688a6b11f1d326cb78Timo Sirainen file too large */
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen mail_index_sync_move_to_private_memory(ctx);
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen map = view->map;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen if (rec->uid <= map->rec_map->last_appended_uid) {
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen i_assert(map->hdr.messages_count < map->rec_map->records_count);
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen /* the flags may have changed since it was added to map.
23878bd03d1de531e3261a25598beec621351910Timo Sirainen use the updated flags already, so flag counters won't get
23878bd03d1de531e3261a25598beec621351910Timo Sirainen broken. */
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen new_flags =
23878bd03d1de531e3261a25598beec621351910Timo Sirainen MAIL_INDEX_MAP_IDX(map, map->hdr.messages_count)->flags;
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen } else {
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen /* don't rely on buffer->used being at the correct position.
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen at least expunges can move it */
bada94029be451d716948d6e03a4fc329447486aTimo Sirainen append_pos = map->rec_map->records_count * map->hdr.record_size;
2df92c5bbd42ff42a1a38d688a6b11f1d326cb78Timo Sirainen dest = buffer_get_space_unsafe(map->rec_map->buffer, append_pos,
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen map->hdr.record_size);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen map->rec_map->records =
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen buffer_get_modifiable_data(map->rec_map->buffer, NULL);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen memcpy(dest, rec, sizeof(*rec));
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen memset(PTR_OFFSET(dest, sizeof(*rec)), 0,
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->hdr.record_size - sizeof(*rec));
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->rec_map->records_count++;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->rec_map->last_appended_uid = rec->uid;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen new_flags = rec->flags;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen mail_index_sync_write_seq_update(ctx,
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->rec_map->records_count,
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->rec_map->records_count);
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen }
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->hdr.messages_count++;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen map->hdr.next_uid = rec->uid+1;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
28c669e01da03d36cef8f64a0eddc000c47befd8Timo Sirainen if ((new_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
28c669e01da03d36cef8f64a0eddc000c47befd8Timo Sirainen map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen mail_index_header_update_lowwaters(ctx, rec->uid, new_flags);
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen mail_index_sync_header_update_counts(ctx, rec->uid,
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen 0, new_flags, FALSE);
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen return 1;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen}
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen struct mail_index_sync_map_ctx *ctx)
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen{
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_view *view = ctx->view;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen struct mail_index_record *rec;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen uint8_t flag_mask, old_flags;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen uint32_t idx, seq1, seq2;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen mail_index_lookup_uid_range(view, u->uid1, u->uid2, &seq1, &seq2);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (seq1 == 0)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen return 1;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen view->map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen flag_mask = ~u->remove_flags;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen if (((u->add_flags | u->remove_flags) &
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen (MAIL_SEEN | MAIL_DELETED)) == 0) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen /* we're not modifying any counted/lowwatered flags */
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen for (idx = seq1-1; idx < seq2; idx++) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, idx);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
28c669e01da03d36cef8f64a0eddc000c47befd8Timo Sirainen } else {
28c669e01da03d36cef8f64a0eddc000c47befd8Timo Sirainen for (idx = seq1-1; idx < seq2; idx++) {
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, idx);
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen old_flags = rec->flags;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen mail_index_header_update_lowwaters(ctx, rec->uid,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen rec->flags);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen mail_index_sync_header_update_counts(ctx, rec->uid,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen old_flags,
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen rec->flags, TRUE);
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen return 1;
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen}
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi struct mail_index_sync_map_ctx *ctx)
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen{
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen struct mail_index_map *map = ctx->view->map;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen uint32_t orig_log_file_tail_offset = map->hdr.log_file_tail_offset;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (u->offset >= map->hdr.base_header_size ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen u->offset + u->size > map->hdr.base_header_size) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mail_index_sync_set_corrupted(ctx,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen "Header update outside range: %u + %u > %u",
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen u->offset, u->size, map->hdr.base_header_size);
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen return -1;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen buffer_write(map->hdr_copy_buf, u->offset, u + 1, u->size);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen map->hdr_base = map->hdr_copy_buf->data;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen map->write_base_header = TRUE;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainen /* @UNSAFE */
23878bd03d1de531e3261a25598beec621351910Timo Sirainen if ((uint32_t)(u->offset + u->size) <= sizeof(map->hdr)) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen memcpy(PTR_OFFSET(&map->hdr, u->offset),
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen u + 1, u->size);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen } else if (u->offset < sizeof(map->hdr)) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen memcpy(PTR_OFFSET(&map->hdr, u->offset),
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen u + 1, sizeof(map->hdr) - u->offset);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* the tail offset updates are intended for internal transaction
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen log handling. we'll update the offset in the header only when
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen the sync is finished. */
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen map->hdr.log_file_tail_offset = orig_log_file_tail_offset;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen return 1;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen}
c439de14aff3e8b1d6adf30fa5215f5dff642a04Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainenint mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
23878bd03d1de531e3261a25598beec621351910Timo Sirainen const struct mail_transaction_header *hdr,
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen const void *data)
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen{
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen int ret = 0;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen t_push();
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen case MAIL_TRANSACTION_APPEND: {
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen const struct mail_index_record *rec, *end;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
c43bfb802ccb82e3855253bd8cb2233e3b061dd7Timo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
c43bfb802ccb82e3855253bd8cb2233e3b061dd7Timo Sirainen for (rec = data; rec < end; rec++) {
c43bfb802ccb82e3855253bd8cb2233e3b061dd7Timo Sirainen ret = sync_append(rec, ctx);
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen if (ret <= 0)
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen break;
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen }
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen break;
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen }
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen case MAIL_TRANSACTION_EXPUNGE:
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: {
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen const struct mail_transaction_expunge *rec = data, *end;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen /* this is simply a request for expunge */
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen break;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen }
23878bd03d1de531e3261a25598beec621351910Timo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen ret = sync_expunge(rec, end - rec, ctx);
23878bd03d1de531e3261a25598beec621351910Timo Sirainen break;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen }
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE: {
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen const struct mail_transaction_flag_update *rec, *end;
3e1cc04de22e3c564644562897b0a5212bd6ee46Timo Sirainen
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen end = CONST_PTR_OFFSET(data, hdr->size);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen for (rec = data; rec < end; rec++) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen ret = sync_flag_update(rec, ctx);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (ret <= 0)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen break;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen break;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen case MAIL_TRANSACTION_HEADER_UPDATE: {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen const struct mail_transaction_header_update *rec;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen unsigned int i;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen for (i = 0; i < hdr->size; ) {
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen ret = sync_header_update(rec, ctx);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (ret <= 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen i += sizeof(*rec) + rec->size;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if ((i % 4) != 0)
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen i += 4 - (i % 4);
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen }
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainen break;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi case MAIL_TRANSACTION_EXT_INTRO: {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen const struct mail_transaction_ext_intro *rec = data;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen unsigned int i;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen uint32_t prev_seq;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen uoff_t prev_offset;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi &prev_seq, &prev_offset);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen ctx->ext_intro_seq = prev_seq;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen ctx->ext_intro_offset = prev_offset;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen ctx->ext_intro_end_offset =
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen prev_offset + hdr->size + sizeof(*hdr);
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi for (i = 0; i < hdr->size; ) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if (i + sizeof(*rec) > hdr->size) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen /* should be just extra padding */
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen break;
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen }
05093f69a5ac540a569c4e675686ed96e61667c6Timo Sirainen
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (i + sizeof(*rec) + rec->name_size > hdr->size) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen mail_index_sync_set_corrupted(ctx,
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen "ext intro: name_size too large");
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen ret = -1;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen break;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen }
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ret = mail_index_sync_ext_intro(ctx, rec);
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if (ret <= 0)
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen break;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i += sizeof(*rec) + rec->name_size;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen if ((i % 4) != 0)
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen i += 4 - (i % 4);
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen }
23878bd03d1de531e3261a25598beec621351910Timo Sirainen break;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen }
23878bd03d1de531e3261a25598beec621351910Timo Sirainen case MAIL_TRANSACTION_EXT_RESET: {
23878bd03d1de531e3261a25598beec621351910Timo Sirainen const struct mail_transaction_ext_reset *rec = data;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainen if (hdr->size != sizeof(*rec)) {
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen mail_index_sync_set_corrupted(ctx,
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen "ext reset: invalid record size");
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen ret = -1;
e09c7dc961cb9cab04ec7cc79215c2f6318fbde0Timo Sirainen break;
9cf4bb70f014849735aab4226691edcdf56b3271Timo Sirainen }
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ret = mail_index_sync_ext_reset(ctx, rec);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen case MAIL_TRANSACTION_EXT_HDR_UPDATE: {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen const struct mail_transaction_ext_hdr_update *rec = data;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen unsigned int i;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen for (i = 0; i < hdr->size; ) {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (i + sizeof(*rec) > hdr->size ||
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen i + sizeof(*rec) + rec->size > hdr->size) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen mail_index_sync_set_corrupted(ctx,
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen "ext hdr update: invalid record size");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen break;
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = mail_index_sync_ext_hdr_update(ctx, rec);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (ret <= 0)
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen i += sizeof(*rec) + rec->size;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if ((i % 4) != 0)
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen i += 4 - (i % 4);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen case MAIL_TRANSACTION_EXT_REC_UPDATE: {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen const struct mail_transaction_ext_rec_update *rec;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen const struct mail_index_ext *ext;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen unsigned int i, record_size;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (ctx->cur_ext_map_idx == (uint32_t)-1) {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen mail_index_sync_set_corrupted(ctx,
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen "Extension record updated "
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen "without intro prefix");
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ret = -1;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (ctx->cur_ext_ignore) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ret = 1;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ext = array_idx(&ctx->view->map->extensions,
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ctx->cur_ext_map_idx);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen /* the record is padded to 32bits in the transaction log */
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen record_size = (sizeof(*rec) + ext->record_size + 3) & ~3;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen for (i = 0; i < hdr->size; i += record_size) {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen rec = CONST_PTR_OFFSET(data, i);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (i + record_size > hdr->size) {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen mail_index_sync_set_corrupted(ctx,
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen "ext rec update: invalid record size");
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ret = -1;
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen break;
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen }
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ret = mail_index_sync_ext_rec_update(ctx, rec);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen if (ret <= 0)
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE: {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen const struct mail_transaction_keyword_update *rec = data;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen ret = mail_index_sync_keywords(ctx, hdr, rec);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen break;
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen }
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET: {
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen const struct mail_transaction_keyword_reset *rec = data;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi break;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi default:
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_unreached();
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi t_pop();
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi return ret;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi}
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomivoid mail_index_sync_map_init(struct mail_index_sync_map_ctx *sync_map_ctx,
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi struct mail_index_view *view,
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi enum mail_index_sync_handler_type type)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi{
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi memset(sync_map_ctx, 0, sizeof(*sync_map_ctx));
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi sync_map_ctx->view = view;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi sync_map_ctx->cur_ext_map_idx = (uint32_t)-1;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi sync_map_ctx->type = type;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi mail_index_sync_init_handlers(sync_map_ctx);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi}
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomivoid mail_index_sync_map_deinit(struct mail_index_sync_map_ctx *sync_map_ctx)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi{
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if (sync_map_ctx->unknown_extensions != NULL)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi buffer_free(sync_map_ctx->unknown_extensions);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if (sync_map_ctx->expunge_handlers_used)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi mail_index_sync_deinit_expunge_handlers(sync_map_ctx);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi mail_index_sync_deinit_handlers(sync_map_ctx);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi}
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomistatic void mail_index_sync_update_hdr_dirty_flag(struct mail_index_map *map)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi{
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi const struct mail_index_record *rec;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi unsigned int i;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi return;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi /* do we have dirty flags anymore? */
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi for (i = 0; i < map->rec_map->records_count; i++) {
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi rec = MAIL_INDEX_MAP_IDX(map, i);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi break;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi}
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi#ifdef DEBUG
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomivoid mail_index_map_check(struct mail_index_map *map)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi{
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi const struct mail_index_header *hdr = &map->hdr;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi unsigned int i, del = 0, seen = 0;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(hdr->messages_count <= map->rec_map->records_count);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi for (i = 0; i < hdr->messages_count; i++) {
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi const struct mail_index_record *rec;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi rec = MAIL_INDEX_MAP_IDX(map, i);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if (rec->flags & MAIL_DELETED) {
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(rec->uid >= hdr->first_deleted_uid_lowwater);
59849b39adb9ee2a6155bc77078503e60d4ea56bTimo Sirainen del++;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if (rec->flags & MAIL_SEEN)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi seen++;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi else
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen i_assert(rec->uid >= hdr->first_unseen_uid_lowwater);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi }
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(del == hdr->deleted_messages_count);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(seen == hdr->seen_messages_count);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi}
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi#endif
59849b39adb9ee2a6155bc77078503e60d4ea56bTimo Sirainen
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomiint mail_index_sync_map(struct mail_index_map **_map,
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi enum mail_index_sync_handler_type type, bool force)
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi{
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi struct mail_index_map *map = *_map;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi struct mail_index *index = map->index;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi struct mail_index_view *view;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi struct mail_index_sync_map_ctx sync_map_ctx;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi const struct mail_transaction_header *thdr;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi const void *tdata;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi uint32_t prev_seq;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi uoff_t start_offset, prev_offset;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi int ret;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi bool had_dirty, reset;
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi if (!force) {
c220c8cd341ee9ba78979397c5d33ccd98b5d19fAki Tuomi /* see if we'd prefer to reopen the index file instead of
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen syncing the current map from the transaction log */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen uoff_t log_size, index_size;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (index->log->head == NULL)
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen return 0;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (index->fd == -1 &&
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen index->log->head->hdr.prev_file_seq != 0) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* we don't know the index's size, so use the
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen smallest index size we're willing to read */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen index_size = MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen } else {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen index_size = map->hdr.header_size +
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->rec_map->records_count *
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.record_size;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* this isn't necessary correct currently, but it should be
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen close enough */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen log_size = index->log->head->last_size;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (log_size > map->hdr.log_file_tail_offset &&
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen log_size - map->hdr.log_file_tail_offset > index_size)
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen return 0;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen start_offset = type == MAIL_INDEX_SYNC_HANDLER_FILE ?
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.log_file_tail_offset : map->hdr.log_file_head_offset;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen view = mail_index_view_open_with_map(index, map);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen ret = mail_transaction_log_view_set(view->log_view,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.log_file_seq, start_offset,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen (uint32_t)-1, (uoff_t)-1, &reset);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (ret <= 0) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (force && ret == 0) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* the seq/offset is probably broken */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen (void)mail_index_fsck(index);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* can't use it. sync by re-reading index. */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen mail_index_view_close(&view);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen return 0;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* view referenced the map. avoid unnecessary map cloning by
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen unreferencing the map while view exists. */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->refcount--;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen had_dirty = (map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (had_dirty) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->write_base_header = TRUE;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (map->hdr_base != map->hdr_copy_buf->data) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* if syncing updates the header, it updates hdr_copy_buf
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen and updates hdr_base to hdr_copy_buf. so the buffer must
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen initially contain a valid header or we'll break it when
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen writing it. */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen buffer_reset(map->hdr_copy_buf);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen buffer_append(map->hdr_copy_buf, map->hdr_base,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.header_size);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
d4847b921058734e0668bc7690465c91523d9ec0Martti Rannanjärvi mail_index_sync_map_init(&sync_map_ctx, view, type);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen if (reset) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* Reset the entire index. Leave only indexid and
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen log_file_seq. */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen &prev_seq, &prev_offset);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map = mail_index_map_alloc(index);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map->hdr.log_file_seq = prev_seq;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen mail_index_sync_replace_map(&sync_map_ctx, map);
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen }
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen map = NULL;
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen /* FIXME: when transaction sync lock is removed, we'll need to handle
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen the case when a transaction is committed while mailbox is being
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen synced ([synced transactions][new transaction][ext transaction]).
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen this means int_offset contains [synced] and ext_offset contains
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen all */
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view, &thdr,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen &tdata)) > 0) {
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
209d29ccf7550b0731147c53a0419749270fc501Timo Sirainen &prev_seq, &prev_offset);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi if (LOG_IS_BEFORE(prev_seq, prev_offset,
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi view->map->hdr.log_file_seq,
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen view->map->hdr.log_file_head_offset)) {
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi /* this has been synced already. we're here only to call
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi expunge handlers and extension update handlers. */
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen i_assert(type == MAIL_INDEX_SYNC_HANDLER_FILE);
a18da4410dcd47ab8d9b40c09a76a54fa55b9c86Timo Sirainen
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
a18da4410dcd47ab8d9b40c09a76a54fa55b9c86Timo Sirainen continue;
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi if ((thdr->type & MAIL_TRANSACTION_EXT_MASK) == 0)
23878bd03d1de531e3261a25598beec621351910Timo Sirainen continue;
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi }
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi /* we'll just skip over broken entries */
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi (void)mail_index_sync_record(&sync_map_ctx, thdr, tdata);
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen }
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi map = view->map;
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen if (had_dirty)
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen mail_index_sync_update_hdr_dirty_flag(map);
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi mail_index_sync_update_log_offset(&sync_map_ctx, view->map, TRUE);
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi#ifdef DEBUG
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi mail_index_map_check(map);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi#endif
5f7f5baf6ce0b9428793b590ca286cdb24f67a11Aki Tuomi i_assert(map->hdr.indexid == index->indexid || map->hdr.indexid == 0);
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi /* transaction log tracks internally the current tail offset.
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi besides using header updates, it also updates the offset to skip
2a9af9ae38a33b93e10ee01b42f5612b175418baTimo Sirainen over following external transactions to avoid extra unneeded log
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen reading. */
4b5a2e923b61c3512dec0fcb32653fbd652bdc32Aki Tuomi map->hdr.log_file_tail_offset = index->log->head->max_tail_offset;
4673195d0f741536cd4e1d2b8c1708a7d4ced2baTimo Sirainen
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen buffer_write(map->hdr_copy_buf, 0, &map->hdr, sizeof(map->hdr));
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
23878bd03d1de531e3261a25598beec621351910Timo Sirainen memcpy(map->rec_map->mmap_base, map->hdr_copy_buf->data,
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi map->hdr_copy_buf->used);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi }
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi if (sync_map_ctx.errors) {
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen /* avoid the same syncing errors the next time */
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi mail_index_write(index, FALSE);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi }
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen
a18da4410dcd47ab8d9b40c09a76a54fa55b9c86Timo Sirainen /* restore refcount before closing the view. this is necessary also
a18da4410dcd47ab8d9b40c09a76a54fa55b9c86Timo Sirainen if map got cloned, because view closing would otherwise destroy it */
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi map->refcount++;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen mail_index_sync_map_deinit(&sync_map_ctx);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi mail_index_view_close(&view);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen if (mail_index_map_check_header(map) <= 0) {
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi mail_index_set_error(index,
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi "Synchronization corrupted index header: %s",
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen index->filepath);
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi (void)mail_index_fsck(index);
ecbbdf594f9329fc15a182bd6c7c4a7fb144ed74Timo Sirainen map = index->map;
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi }
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi *_map = map;
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi return ret < 0 ? -1 : 1;
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen}
0368f3b0ae3fc1ea892da5c5ec02c05c0c3989afAki Tuomi