maildir-save.c revision a6562b39f4121b976ffe242ad538a22527fce586
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* unsigned int keywords[]; */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_filename *files, **files_tail, *file_last;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int maildir_file_move(struct maildir_save_context *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* if we have flags, we'll move it to cur/ directly, because files in
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen new/ directory can't have flags. alternative would be to write it
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen in new/ and set the flags dirty in index file, but in that case
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen external MUAs would see wrong flags. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen tmp_path = t_strconcat(ctx->tmpdir, "/", tmpname, NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen t_strconcat(ctx->newdir, "/", destname, NULL) :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen t_strconcat(ctx->curdir, "/", destname, NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* maildir spec says we should use link() + unlink() here. however
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen since our filename is guaranteed to be unique, rename() works just
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen as well, except faster. even if the filename wasn't unique, the
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen problem could still happen if the file was already moved from
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen new/ to cur/, so link() doesn't really provide any safety anyway.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen Besides the small temporary performance benefits, this rename() is
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen almost required with OSX's HFS+ filesystem, since it implements
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen hard links in a pretty ugly way, which makes the performance crawl
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen when a lot of hard links are used. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "rename(%s, %s) failed: %m",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmaildir_save_transaction_init(struct maildir_transaction_context *t)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool = pool_alloconly_create("maildir_save_context", 4096);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx = p_new(pool, struct maildir_save_context, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->tmpdir = p_strconcat(pool, mbox->path, "/tmp", NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->newdir = p_strconcat(pool, mbox->path, "/new", NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->curdir = p_strconcat(pool, mbox->path, "/cur", NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->keywords_buffer = buffer_create_const_data(pool, NULL, 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_create_from_buffer(&ctx->keywords_array, ctx->keywords_buffer,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen sizeof(unsigned int));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenuint32_t maildir_save_add(struct maildir_transaction_context *t,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *base_fname, enum mail_flags flags,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_save_context *ctx = t->save_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* now, we want to be able to rollback the whole append session,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen so we'll just store the name of this temp file and move it later
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen into new/ or cur/. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* @UNSAFE */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen sizeof(unsigned int) * (keywords == NULL ? 0 :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->basename = p_strdup(ctx->pool, base_fname);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(sizeof(keywords->idx[0]) == sizeof(unsigned int));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* insert into index */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen /* FIXME: copying with hardlinking. we could copy the
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen cached data directly */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input = index_mail_cache_parse_init(dest_mail, ctx->input);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainenmaildir_get_updated_filename(struct maildir_save_context *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **fname_r)
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen if (ctx->mbox->storage->save_size_in_filename &&
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = maildir_filename_set_flags(NULL, basename,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(ctx->keywords_sync_ctx != NULL || mf->keywords_count == 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen buffer_update_const_data(ctx->keywords_buffer, mf + 1,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = maildir_filename_set_flags(ctx->keywords_sync_ctx, basename,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic const char *maildir_mf_get_path(struct maildir_save_context *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!ctx->moving && (mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* file is still in tmp/ */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return t_strdup_printf("%s/%s", ctx->tmpdir, mf->basename);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* already moved to new/ or cur/ */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (maildir_get_updated_filename(ctx, mf, &fname))
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return t_strdup_printf("%s/%s", ctx->newdir, mf->basename);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen return t_strdup_printf("%s/%s", ctx->curdir, fname);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenconst char *maildir_save_file_get_path(struct mailbox_transaction_context *_t,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = t->save_ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while (seq > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **fname_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* stat() first to see if it exists. pretty much the only
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen possibility of that happening is if time had moved
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen backwards, but even then it's highly unlikely. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* try another file name */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* doesn't exist */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mode_t old_mask = umask(0777 & ~box->file_create_mode);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* race condition between stat() and open().
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen highly unlikely. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (box->file_create_gid != (gid_t)-1) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenmaildir_save_alloc(struct mailbox_transaction_context *_t)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen t->save_ctx = maildir_save_transaction_init(t);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainenint maildir_save_begin(struct mail_save_context *_ctx, struct istream *input)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (struct maildir_transaction_context *)_ctx->transaction;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* create a new file in tmp/ directory */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->fd = maildir_create_tmp(ctx->mbox, ctx->tmpdir, &fname);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->input = (ctx->mbox->storage->storage.flags &
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen maildir_save_add(t, fname, _ctx->flags, _ctx->keywords,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->output = o_stream_create_fd_file(ctx->fd, 0, FALSE);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint maildir_save_continue(struct mail_save_context *_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen "o_stream_send_istream(%s/%s) "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "failed: %m",
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_cache_parse_continue(ctx->cur_dest_mail);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* both tee input readers may consume data from our primary
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen input stream. we'll have to make sure we don't return with
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen one of the streams still having data in them. */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int maildir_save_finish_real(struct mail_save_context *_ctx)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen /* tmp file creation failed */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->basename, NULL);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* set the received_date by modifying mtime */
659fe5d24825b160cae512538088020d97a60239Timo Sirainen /* hardlinked */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_cache_parse_deinit(ctx->cur_dest_mail,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* remember the size in case we want to add it to filename */
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (!ctx->mbox->ibox.fsync_disable && !ctx->failed) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* delete the tmp file */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else if (errno != 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* remove from the linked list */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen for (fm = &ctx->files; (*fm)->next != NULL; fm = &(*fm)->next) ;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenint maildir_save_finish(struct mail_save_context *ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenvoid maildir_save_cancel(struct mail_save_context *_ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenmaildir_transaction_unlink_copied_files(struct maildir_save_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* try to unlink the mails already moved */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen for (mf = ctx->files; mf != pos; mf = mf->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mf->flags & MAILDIR_SAVE_FLAG_DELETED) == 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int maildir_transaction_fsync_dirs(struct maildir_save_context *ctx,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_error("fdatasync_path(%s) failed: %m", ctx->newdir);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_error("fdatasync_path(%s) failed: %m", ctx->curdir);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaildir_transaction_save_commit_pre_sync(struct maildir_save_context *ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (struct maildir_transaction_context *)ctx->ctx.transaction;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll need to keep the lock past the sync deinit */
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (maildir_sync_index_begin(mbox, NULL, &ctx->sync_ctx) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_uidlist_refresh_fast_init(mbox->uidlist) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* now that uidlist is locked, make sure all the existing mails
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen have been added to index. we don't really look into the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir, just add all the new mails listed in
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen dovecot-uidlist to index. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_sync_index(ctx->sync_ctx, TRUE) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* if messages were added to index, assign them UIDs */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_append_assign_uids(ctx->trans, first_uid, &next_uid);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(next_uid = first_uid + ctx->files_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* these mails are all recent in our session */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_mailbox_set_recent_uid(&mbox->ibox, uid);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* maildir_sync_index() dropped recent flags from
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen existing messages. we'll still need to drop recent
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen flags from these newly added messages. */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* this will work even if index isn't updated */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct maildir_transaction_context *)ctx->ctx.transaction;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen /* if we want to assign UIDs or keywords, we require uidlist lock */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if ((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) == 0 &&
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen /* assign the UIDs if we happen to get a lock */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (ret < 0 || (sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) == 0)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_transaction_save_commit_pre_sync(ctx) < 0) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen /* since we couldn't lock uidlist, we'll have to drop the
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen appends to index. */
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen for (seq = ctx->seq; seq >= ctx->first_seq; seq--)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen mail_cache_transaction_rollback(&t->ictx.cache_trans);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen mail_cache_get_transaction(t->ictx.cache_view,
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen /* move them into new/ and/or cur/ */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen newdir = maildir_get_updated_filename(ctx, mf, &dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if hardlink-flag is set, the file is already in
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen destination. if the hardlinked mail contained
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen keywords, it was linked into tmp/ and it doesn't
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen have the hardlink-flag set, so it's treated as any
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen other saved mail. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = maildir_transaction_fsync_dirs(ctx, new_changed,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0 && ctx->uidlist_sync_ctx != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* everything was moved successfully. update our internal
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) T_BEGIN {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen newdir = maildir_get_updated_filename(ctx, mf, &dest);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen /* update dovecot-uidlist file. */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx) < 0)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_uidlist_get_uid_validity(ctx->mbox->uidlist);
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen /* Mail freeing may trigger cache updates and a call to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_save_file_get_path(). Do this before finishing index
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sync so we still have keywords_sync_ctx. */
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen /* It doesn't matter if index syncing fails */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)maildir_sync_index_finish(&ctx->sync_ctx,
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ctx->keywords_sync_ctx = !ctx->have_keywords ? NULL :
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_keywords_sync_init(ctx->mbox->keywords,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* unlink the files we just moved in an attempt to rollback
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the transaction. uidlist is still locked, so at least other
abbe0657a4d6271740d41cf1de55e8686f5769fcTimo Sirainen Dovecot instances haven't yet seen the files. */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_transaction_unlink_copied_files(ctx, mf);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_keywords_sync_deinit(&ctx->keywords_sync_ctx);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen /* returning failure finishes the save_context */
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainenvoid maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ctx->ctx.transaction = NULL; /* transaction is already freed */
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainenmaildir_transaction_save_rollback_real(struct maildir_save_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* clean up the temp files */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) == 0) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen maildir_transaction_unlink_copied_files(ctx, NULL);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen (void)maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen (void)maildir_sync_index_finish(&ctx->sync_ctx, TRUE, FALSE);