maildir-save.c revision a6562b39f4121b976ffe242ad538a22527fce586
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "ioloop.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "istream-crlf.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "ostream.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "fdatasync-path.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "str.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "index-mail.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-storage.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-uidlist.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "maildir-keywords.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-filename.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-sync.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <stdio.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <stdlib.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <unistd.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <fcntl.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <utime.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <sys/stat.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct maildir_filename {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_filename *next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *basename;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t size, vsize;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum mail_flags flags;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int keywords_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* unsigned int keywords[]; */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct maildir_save_context {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_save_context ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool_t pool;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_mailbox *mbox;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_index_transaction *trans;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_index_sync_context *sync_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail *mail, *cur_dest_mail;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *tmpdir, *newdir, *curdir;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_filename *files, **files_tail, *file_last;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int files_count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_t *keywords_buffer;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ARRAY_TYPE(keyword_indexes) keywords_array;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct ostream *output;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int fd;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t first_seq, seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int want_mails:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int have_keywords:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int locked:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int failed:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int moving:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int finished:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int maildir_file_move(struct maildir_save_context *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *tmpname, const char *destname,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool newdir)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *tmp_path, *new_path;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
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 new_path = newdir ?
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen t_strconcat(ctx->newdir, "/", destname, NULL) :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen t_strconcat(ctx->curdir, "/", destname, NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
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
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 if (rename(tmp_path, new_path) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ENOSPACE(errno)) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_error(storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "rename(%s, %s) failed: %m",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen tmp_path, new_path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct maildir_save_context *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmaildir_save_transaction_init(struct maildir_transaction_context *t)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_save_context *ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool_t pool;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen pool = pool_alloconly_create("maildir_save_context", 4096);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx = p_new(pool, struct maildir_save_context, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->ctx.transaction = &t->ictx.mailbox_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->pool = pool;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->mbox = mbox;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->trans = t->ictx.trans;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->files_tail = &ctx->files;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->fd = -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
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
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 Sirainen ctx->finished = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenuint32_t maildir_save_add(struct maildir_transaction_context *t,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *base_fname, enum mail_flags flags,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_keywords *keywords,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail *dest_mail)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_save_context *ctx = t->save_ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_filename *mf;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
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 mf = p_malloc(ctx->pool, sizeof(*mf) +
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen sizeof(unsigned int) * (keywords == NULL ? 0 :
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen keywords->count));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->basename = p_strdup(ctx->pool, base_fname);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->flags = flags;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->size = (uoff_t)-1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->vsize = (uoff_t)-1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->file_last = mf;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(*ctx->files_tail == NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *ctx->files_tail = mf;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->files_tail = &mf->next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->files_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (keywords != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(sizeof(keywords->idx[0]) == sizeof(unsigned int));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* @UNSAFE */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mf->keywords_count = keywords->count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memcpy(mf + 1, keywords->idx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen sizeof(unsigned int) * keywords->count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->have_keywords = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* insert into index */
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen mail_index_append(ctx->trans, 0, &ctx->seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (keywords != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MODIFY_REPLACE, keywords);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->first_seq == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->first_seq = ctx->seq;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(ctx->files->next == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (dest_mail == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->mail == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mailbox_transaction_context *_t =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &t->ictx.mailbox_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->mail = mail_alloc(_t, 0, NULL);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen dest_mail = ctx->mail;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen mail_set_seq(dest_mail, ctx->seq);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (ctx->input == NULL) {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen /* FIXME: copying with hardlinking. we could copy the
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen cached data directly */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cur_dest_mail = NULL;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input = index_mail_cache_parse_init(dest_mail, ctx->input);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_stream_unref(&ctx->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->input = input;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen ctx->cur_dest_mail = dest_mail;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx->seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic bool
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainenmaildir_get_updated_filename(struct maildir_save_context *ctx,
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen struct maildir_filename *mf,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **fname_r)
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen{
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen const char *basename = mf->basename;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen if (ctx->mbox->storage->save_size_in_filename &&
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen mf->size != (uoff_t)-1) {
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen MAILDIR_EXTRA_FILE_SIZE, mf->size);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen }
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen if (mf->vsize != (uoff_t)-1) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen MAILDIR_EXTRA_VIRTUAL_SIZE,
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen mf->vsize);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen }
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mf->keywords_count == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = basename;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = maildir_filename_set_flags(NULL, basename,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mf->flags & MAIL_FLAGS_MASK, NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
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 mf->keywords_count * sizeof(unsigned int));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = maildir_filename_set_flags(ctx->keywords_sync_ctx, basename,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mf->flags & MAIL_FLAGS_MASK,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &ctx->keywords_array);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic const char *maildir_mf_get_path(struct maildir_save_context *ctx,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_filename *mf)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char *fname;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
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 }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
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);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen else
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen return t_strdup_printf("%s/%s", ctx->curdir, fname);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenconst char *maildir_save_file_get_path(struct mailbox_transaction_context *_t,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uint32_t seq)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen struct maildir_transaction_context *t =
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen (struct maildir_transaction_context *)_t;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = t->save_ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_filename *mf;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(seq >= ctx->first_seq);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen seq -= ctx->first_seq;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mf = ctx->files;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while (seq > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mf = mf->next;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(mf != NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen seq--;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return maildir_mf_get_path(ctx, mf);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **fname_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct mailbox *box = &mbox->ibox.box;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct stat st;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen unsigned int prefix_len;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char *tmp_fname = NULL;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen string_t *path;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int fd;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen path = t_str_new(256);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen str_append(path, dir);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen str_append_c(path, '/');
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen prefix_len = str_len(path);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (;;) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen tmp_fname = maildir_filename_generate();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen str_truncate(path, prefix_len);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen str_append(path, tmp_fname);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
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 if (stat(str_c(path), &st) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* try another file name */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (errno != ENOENT) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_storage_set_critical(box->storage,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "stat(%s) failed: %m", str_c(path));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* doesn't exist */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mode_t old_mask = umask(0777 & ~box->file_create_mode);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen fd = open(str_c(path),
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0777);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen umask(old_mask);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (fd != -1 || errno != EEXIST)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen break;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* race condition between stat() and open().
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen highly unlikely. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *fname_r = tmp_fname;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (fd == -1) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ENOSPACE(errno)) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_storage_set_error(box->storage,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_storage_set_critical(box->storage,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "open(%s) failed: %m", str_c(path));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
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 Sirainen mail_storage_set_critical(box->storage,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "fchown(%s) failed: %m", str_c(path));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return fd;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstruct mail_save_context *
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenmaildir_save_alloc(struct mailbox_transaction_context *_t)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_transaction_context *t =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (struct maildir_transaction_context *)_t;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (t->save_ctx == NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen t->save_ctx = maildir_save_transaction_init(t);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return &t->save_ctx->ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainenint maildir_save_begin(struct mail_save_context *_ctx, struct istream *input)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_transaction_context *t =
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (struct maildir_transaction_context *)_ctx->transaction;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen _ctx->flags &= ~MAIL_RECENT;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ctx->mbox->ibox.keep_recent)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen _ctx->flags |= MAIL_RECENT;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen T_BEGIN {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* create a new file in tmp/ directory */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char *fname;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->fd = maildir_create_tmp(ctx->mbox, ctx->tmpdir, &fname);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ctx->fd == -1)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->failed = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->input = (ctx->mbox->storage->storage.flags &
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_stream_create_crlf(input) :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_create_lf(input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen maildir_save_add(t, fname, _ctx->flags, _ctx->keywords,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen _ctx->dest_mail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ctx->failed) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->output = o_stream_create_fd_file(ctx->fd, 0, FALSE);
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen o_stream_cork(ctx->output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx->failed ? -1 : 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint maildir_save_continue(struct mail_save_context *_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->failed)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen do {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen mail_storage_set_critical(storage,
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen "o_stream_send_istream(%s/%s) "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "failed: %m",
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen ctx->tmpdir, ctx->file_last->basename);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->failed = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ctx->cur_dest_mail != NULL)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_cache_parse_continue(ctx->cur_dest_mail);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
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 Sirainen } while (i_stream_read(ctx->input) > 0);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int maildir_save_finish_real(struct mail_save_context *_ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct utimbuf buf;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct stat st;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen const char *path;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen int output_errno;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->finished = TRUE;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen if (ctx->failed && ctx->fd == -1) {
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen /* tmp file creation failed */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen }
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->basename, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_flush(ctx->output) < 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "o_stream_flush(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->failed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen if (ctx->ctx.received_date != (time_t)-1) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* set the received_date by modifying mtime */
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen buf.actime = ioloop_time;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen buf.modtime = ctx->ctx.received_date;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen if (utime(path, &buf) < 0) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ctx->failed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "utime(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (ctx->fd != -1) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (fstat(ctx->fd, &st) == 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->ctx.received_date = st.st_mtime;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->failed = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "fstat(%s) failed: %m", path);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen } else {
659fe5d24825b160cae512538088020d97a60239Timo Sirainen /* hardlinked */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (stat(path, &st) == 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->ctx.received_date = st.st_mtime;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen else {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->failed = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "stat(%s) failed: %m", path);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ctx->cur_dest_mail != NULL) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_cache_parse_deinit(ctx->cur_dest_mail,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->ctx.received_date,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen !ctx->failed);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_stream_unref(&ctx->input);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* remember the size in case we want to add it to filename */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->file_last->size = ctx->output->offset;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ctx->cur_dest_mail == NULL ||
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_get_virtual_size(ctx->cur_dest_mail,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen &ctx->file_last->vsize) < 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->file_last->vsize = (uoff_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen output_errno = ctx->output->stream_errno;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen o_stream_destroy(&ctx->output);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (!ctx->mbox->ibox.fsync_disable && !ctx->failed) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (fsync(ctx->fd) < 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "fsync(%s) failed: %m", path);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->failed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (close(ctx->fd) < 0) {
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen mail_storage_set_critical(storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "close(%s) failed: %m", path);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->failed = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->fd = -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ctx->failed) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_filename **fm;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* delete the tmp file */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (unlink(path) < 0 && errno != ENOENT) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "unlink(%s) failed: %m", path);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen errno = output_errno;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ENOSPACE(errno)) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_error(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else if (errno != 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(storage,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "write(%s) failed: %m", ctx->mbox->path);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen /* remove from the linked list */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen for (fm = &ctx->files; (*fm)->next != NULL; fm = &(*fm)->next) ;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_assert(*fm == ctx->file_last);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen *fm = NULL;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->files_tail = fm;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->file_last = NULL;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->files_count--;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->file_last = NULL;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenint maildir_save_finish(struct mail_save_context *ctx)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen int ret;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen T_BEGIN {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ret = maildir_save_finish_real(ctx);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } T_END;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_save_context_free(ctx);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenvoid maildir_save_cancel(struct mail_save_context *_ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->failed = TRUE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen (void)maildir_save_finish(_ctx);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic void
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenmaildir_transaction_unlink_copied_files(struct maildir_save_context *ctx,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_filename *pos)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_filename *mf;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen T_BEGIN {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)unlink(maildir_mf_get_path(ctx, mf));
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } T_END;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ctx->files = pos;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int maildir_transaction_fsync_dirs(struct maildir_save_context *ctx,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen bool new_changed, bool cur_changed)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ctx->mbox->ibox.fsync_disable)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (new_changed) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (fdatasync_path(ctx->newdir) < 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_error("fdatasync_path(%s) failed: %m", ctx->newdir);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (cur_changed) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (fdatasync_path(ctx->curdir) < 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_error("fdatasync_path(%s) failed: %m", ctx->curdir);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaildir_transaction_save_commit_pre_sync(struct maildir_save_context *ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct maildir_transaction_context *t =
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (struct maildir_transaction_context *)ctx->ctx.transaction;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t uid, first_uid, next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll need to keep the lock past the sync deinit */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = maildir_uidlist_lock(mbox->uidlist);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen i_assert(ret > 0);
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (maildir_sync_index_begin(mbox, NULL, &ctx->sync_ctx) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->keywords_sync_ctx =
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_sync_header_refresh(mbox) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_uidlist_refresh_fast_init(mbox->uidlist) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* if messages were added to index, assign them UIDs */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen i_assert(first_uid != 0);
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
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* these mails are all recent in our session */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (uid = first_uid; uid < next_uid; uid++)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_mailbox_set_recent_uid(&mbox->ibox, uid);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mbox->ibox.keep_recent) {
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. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_header(ctx->trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offsetof(struct mail_index_header,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first_recent_uid),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &next_uid, sizeof(next_uid), FALSE);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* this will work even if index isn't updated */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen *t->ictx.first_saved_uid = first_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *t->ictx.last_saved_uid = next_uid - 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_transaction_context *t =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct maildir_transaction_context *)ctx->ctx.transaction;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_filename *mf;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen uint32_t seq;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen enum maildir_uidlist_rec_flag flags;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen enum maildir_uidlist_sync_flags sync_flags;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen bool newdir, new_changed, cur_changed;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen int ret;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->output == NULL);
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen i_assert(ctx->finished);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sync_flags = MAILDIR_UIDLIST_SYNC_PARTIAL |
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen MAILDIR_UIDLIST_SYNC_NOREFRESH;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
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 &&
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen !ctx->have_keywords) {
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen /* assign the UIDs if we happen to get a lock */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_flags |= MAILDIR_UIDLIST_SYNC_TRYLOCK;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen &ctx->uidlist_sync_ctx);
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen if (ret <= 0 &&
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (ret < 0 || (sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) == 0)) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen maildir_transaction_save_rollback(ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return -1;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->locked = ret > 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->locked) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_transaction_save_commit_pre_sync(ctx) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_transaction_save_rollback(ctx);
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen return -1;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen }
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen } else {
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--)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen mail_index_expunge(ctx->trans, seq);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen mail_cache_transaction_rollback(&t->ictx.cache_trans);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen t->ictx.cache_trans =
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen mail_cache_get_transaction(t->ictx.cache_view,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen t->ictx.trans);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen }
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen /* move them into new/ and/or cur/ */
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen ret = 0;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen ctx->moving = TRUE;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen new_changed = cur_changed = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen T_BEGIN {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen const char *dest;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen newdir = maildir_get_updated_filename(ctx, mf, &dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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 = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (newdir)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_changed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur_changed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = maildir_file_move(ctx, mf->basename,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest, newdir);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = maildir_transaction_fsync_dirs(ctx, new_changed,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur_changed);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0 && ctx->uidlist_sync_ctx != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* everything was moved successfully. update our internal
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen state. */
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) T_BEGIN {
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen const char *dest;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen newdir = maildir_get_updated_filename(ctx, mf, &dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen flags = MAILDIR_UIDLIST_REC_FLAG_RECENT;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (newdir)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen dest, flags);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen i_assert(ret > 0);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen } T_END;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen }
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ctx->uidlist_sync_ctx != NULL) {
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen /* update dovecot-uidlist file. */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx) < 0)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ret = -1;
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen }
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen *t->ictx.saved_uid_validity =
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_uidlist_get_uid_validity(ctx->mbox->uidlist);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->mail != NULL) {
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. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_free(&ctx->mail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ctx->locked) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen /* It doesn't matter if index syncing fails */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ctx->keywords_sync_ctx = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)maildir_sync_index_finish(&ctx->sync_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret < 0, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ret < 0) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ctx->keywords_sync_ctx = !ctx->have_keywords ? NULL :
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_keywords_sync_init(ctx->mbox->keywords,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->mbox->ibox.index);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen if (ctx->keywords_sync_ctx != NULL)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_keywords_sync_deinit(&ctx->keywords_sync_ctx);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen /* returning failure finishes the save_context */
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen maildir_transaction_save_rollback(ctx);
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen return -1;
abbe0657a4d6271740d41cf1de55e8686f5769fcTimo Sirainen }
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen return ret;
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen}
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainen
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainenvoid maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
bde6382cf65fba6165dc3603f5419e194d87f404Timo Sirainen{
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen ctx->ctx.transaction = NULL; /* transaction is already freed */
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen if (ctx->locked)
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen maildir_uidlist_unlock(ctx->mbox->uidlist);
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen pool_unref(&ctx->pool);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainen
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainenstatic void
ad8b3389ab62c5facb3d49037963076e3d32c147Timo Sirainenmaildir_transaction_save_rollback_real(struct maildir_save_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct maildir_filename *mf;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen string_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t dir_len;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen bool hardlinks = FALSE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(ctx->output == NULL);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ctx->finished)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_save_cancel(&ctx->ctx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen str = t_str_new(1024);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen str_append(str, ctx->tmpdir);
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen str_append_c(str, '/');
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen dir_len = str_len(str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mf->flags |= MAILDIR_SAVE_FLAG_DELETED;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen str_truncate(str, dir_len);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen str_append(str, mf->basename);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)unlink(str_c(str));
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen } else {
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen hardlinks = TRUE;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen }
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen }
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (hardlinks)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen maildir_transaction_unlink_copied_files(ctx, NULL);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (ctx->uidlist_sync_ctx != NULL)
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen (void)maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ctx->locked)
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen maildir_uidlist_unlock(ctx->mbox->uidlist);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (ctx->sync_ctx != NULL)
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen (void)maildir_sync_index_finish(&ctx->sync_ctx, TRUE, FALSE);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen if (ctx->mail != NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_free(&ctx->mail);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen pool_unref(&ctx->pool);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen}
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainenvoid maildir_transaction_save_rollback(struct maildir_save_context *ctx)
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen{
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen T_BEGIN {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen maildir_transaction_save_rollback_real(ctx);
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen } T_END;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen}
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen