maildir-sync-index.c revision 3759cb2dfce3b479a59e2f62ee0cc9ddd4a85924
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen struct maildir_sync_context *maildir_sync_ctx;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen struct index_sync_changes_context *sync_changes;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenmaildir_sync_get_keywords_sync_ctx(struct maildir_index_sync_context *ctx)
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenstatic int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenstatic int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen /* get the current flags and keywords */
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx,
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen /* apply changes */
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen index_sync_changes_apply(ctx->sync_changes, NULL,
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen /* and try renaming with the new name */
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen newfname = maildir_filename_set_flags(ctx->keywords_sync_ctx, fname,
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvistatic void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* partial syncing */
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen /* most likely a race condition: we read the maildir, then someone else
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen expunged messages and committed changes to index. so, this message
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen shouldn't actually exist. */
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RACING) == 0) {
d4488f314d0c799c5f5b8a7890e17eef868f7a2cMartti Rannanjärvi /* mark it racy and check in next sync */
498eecf19b1b408d5321cb048697744d7cee90b2Timo Sirainen maildir_uidlist_add_flags(ctx->mbox->uidlist, filename,
11d72d764c104b4f1a8c44ec8a5fee420517645bTimo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* give the new UID to it immediately */
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen i_warning("Maildir %s: Expunged message reappeared, giving a new UID "
11d72d764c104b4f1a8c44ec8a5fee420517645bTimo Sirainen "(old uid=%u, file=%s)", ctx->mbox->path, uid, filename);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenint maildir_sync_index_begin(struct maildir_mailbox *mbox,
5f237cf1915127fe143ac4c1d3cb4d1139f3b97dTimo Sirainen struct maildir_sync_context *maildir_sync_ctx,
5f237cf1915127fe143ac4c1d3cb4d1139f3b97dTimo Sirainen /* don't drop recent messages if we're saving messages */
11d72d764c104b4f1a8c44ec8a5fee420517645bTimo Sirainen if (!mbox->ibox.keep_recent && maildir_sync_ctx != NULL)
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
11d72d764c104b4f1a8c44ec8a5fee420517645bTimo Sirainen if (mail_index_sync_begin(mbox->ibox.index, &sync_ctx, &view, &trans,
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen ctx = i_new(struct maildir_index_sync_context, 1);
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen maildir_keywords_sync_init(mbox->keywords, mbox->ibox.index);
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen ctx->sync_changes = index_sync_changes_init(&mbox->ibox, ctx->sync_ctx,
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainenint maildir_sync_index_finish(struct maildir_index_sync_context **_ctx,
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen struct maildir_index_sync_context *ctx = *_ctx;
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi mail_index_sync_rollback(&ctx->sync_ctx);
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen /* Set syncing_commit=TRUE so that if any sync callbacks try
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen to access mails which got lost (eg. expunge callback trying
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen to open the file which was just unlinked) we don't try to
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen start a second index sync and crash. */
f148466c7b648669b99bf20c651ae7fc81d28659Timo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen maildir_keywords_sync_deinit(&ctx->keywords_sync_ctx);
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen index_sync_changes_deinit(&ctx->sync_changes);
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainenmaildir_index_header_has_changed(const struct maildir_index_header *old_hdr,
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen if (old_hdr->new_mtime != new_hdr->new_mtime ||
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen old_hdr->new_mtime_nsecs != new_hdr->new_mtime_nsecs ||
7d800c558b4a40f11748d4ebfc2bf89eb743f03cTimo Sirainen old_hdr->cur_mtime_nsecs != new_hdr->cur_mtime_nsecs)
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainenmaildir_index_update_ext_header(struct maildir_mailbox *mbox,
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen mail_index_get_header_ext(mbox->ibox.view, mbox->maildir_ext_id,
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen maildir_index_header_has_changed(data, &mbox->maildir_hdr)) {
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen mail_index_update_header_ext(trans, mbox->maildir_ext_id, 0,
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainenint maildir_sync_index(struct maildir_index_sync_context *ctx,
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi struct maildir_mailbox *mbox = ctx->mbox;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen struct mail_index_transaction *trans = ctx->trans;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen uint32_t uid_validity, next_uid, hdr_next_uid, first_recent_uid;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen unsigned int changes = 0;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen i_assert(maildir_uidlist_is_locked(mbox->uidlist));
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen uid_validity != 0 && hdr->uid_validity != 0) {
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen /* uidvalidity changed and index isn't being synced for the
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen first time, reset the index so we can add all messages as
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen maildir_uidlist_set_next_uid(mbox->uidlist, 1, TRUE);
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen seq = prev_uid = 0; first_recent_uid = hdr->first_recent_uid;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen t_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen t_array_init(&idx_keywords, MAILDIR_MAX_KEYWORDS);
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen iter = maildir_uidlist_iter_init(mbox->uidlist);
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx, filename,
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen /* the private flags are kept only in indexes. don't use them
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen at all even for newly seen mails */
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen ctx->flags &= ~mbox->ibox.box.private_flags_mask;
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen /* Trust uidlist recent flags only for newly added
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen messages. When saving/copying messages with flags
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen they're stored to cur/ and uidlist treats them
6df4a174b4cbdc439ed435a0cdc71d4a0126d54aTimo Sirainen as non-recent. */
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0) {
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen /* expunged */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen index_sync_changes_read(ctx->sync_changes, rec->uid, &expunged);
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* successful expunge */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* the private flags are stored only in indexes, keep them */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen ctx->flags |= rec->flags & mbox->ibox.box.private_flags_mask;
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if (index_sync_changes_have(ctx->sync_changes)) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* apply flag changes to maildir */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* partial syncing */
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* we last saw this mail in new/, but it's
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen not there anymore. possibly expunged,
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen make sure. */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* we haven't been able to update maildir with this
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen record's flag changes. don't sync them. */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* update keywords if they have changed */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen mail_index_lookup_keywords(view, seq, &idx_keywords);
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if (!index_keyword_array_cmp(&ctx->keywords, &idx_keywords)) {
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen /* expunge the rest */
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen for (seq++; seq <= hdr->messages_count; seq++)
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen /* add \Recent flags. use updated view so it contains newly
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen appended messages. */
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen view2 = mail_index_transaction_open_updated_view(trans);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen if (mail_index_lookup_seq_range(view2, first_recent_uid, (uint32_t)-1,
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen index_mailbox_set_recent_seq(&mbox->ibox, view2, seq, seq2);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx) < 0)
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen mbox->ibox.box.v.sync_notify(&mbox->ibox.box, 0, 0);
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi mbox->maildir_hdr.cur_mtime = time(NULL);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen maildir_uidlist_set_uid_validity(mbox->uidlist, uid_validity);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen maildir_uidlist_set_next_uid(mbox->uidlist, hdr_next_uid, FALSE);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen offsetof(struct mail_index_header, uid_validity),
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen next_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen i_assert(hdr->first_recent_uid <= first_recent_uid);
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen if (hdr->first_recent_uid < first_recent_uid) {
aeaf818613081b9a9ff8c9fd4306e8dbfab4fd86Timo Sirainen offsetof(struct mail_index_header, first_recent_uid),
7195d775e5e943af90d24a615847c733a104e3d4Timo Sirainen &first_recent_uid, sizeof(first_recent_uid), FALSE);
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainenstatic unsigned int maildir_list_get_ext_id(struct maildir_storage *storage,
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen if (storage->maildir_list_ext_id == (uint32_t)-1) {
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen mail_index_ext_register(mail_index_view_get_index(view),
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen "maildir", 0,
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainenint maildir_list_index_has_changed(struct mailbox *box,
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen ext_id = maildir_list_get_ext_id(mbox->storage, list_view);
12e5ac049bd74f8b98d9dc62adcb0bf3217beef6Martti Rannanjärvi mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* doesn't exist, not synced or dirty-synced */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen root_dir = mailbox_list_get_path(mail_storage_get_list(box->storage),
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* check if new/ changed */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen new_dir = t_strconcat(root_dir, "/new", NULL);
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen /* check if cur/ changed */
7a12331c6360968b141a0888e0bf04dd24145f23Timo Sirainen cur_dir = t_strconcat(root_dir, "/cur", NULL);
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainenint maildir_list_index_update_sync(struct mailbox *box,
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen const struct maildir_index_header *mhdr = &mbox->maildir_hdr;
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen const struct maildir_list_index_record *old_rec;
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen /* get the current record */
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen list_view = mail_index_transaction_get_view(trans);
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen ext_id = maildir_list_get_ext_id(mbox->storage, list_view);
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen if (mhdr->new_check_time <= mhdr->new_mtime + MAILDIR_SYNC_SECS ||
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen mhdr->cur_check_time <= mhdr->cur_mtime + MAILDIR_SYNC_SECS) {
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen /* dirty, we need a refresh next time */
12fd7a30563f3256642070ef9528dda0d089cb41Timo Sirainen memcmp(old_rec, &new_rec, sizeof(old_rec)) != 0) {