bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "lib.h"
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen#include "array.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "hostpid.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "istream.h"
5ef7efd45b1adf3a09cf9c229cf0a3d3d54405a2Timo Sirainen#include "istream-crlf.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "ostream.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "str.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "index-mail.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "cydir-storage.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "cydir-sync.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include <stdio.h>
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen#include <utime.h>
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstruct cydir_save_context {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct mail_save_context ctx;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct cydir_mailbox *mbox;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct mail_index_transaction *trans;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen char *tmp_basename;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen unsigned int mail_count;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct cydir_sync_context *sync_ctx;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* updated for each appended mail: */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen uint32_t seq;
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen struct istream *input;
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen int fd;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool failed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool finished:1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen};
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek#define CYDIR_SAVECTX(s) container_of(s, struct cydir_save_context, ctx)
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic char *cydir_generate_tmp_filename(void)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
d97860e16db095a14038d50efda1e4bb64375128Timo Sirainen static unsigned int create_count = 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
d97860e16db095a14038d50efda1e4bb64375128Timo Sirainen return i_strdup_printf("temp.%s.P%sQ%uM%s.%s",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dec2str(ioloop_timeval.tv_sec), my_pid,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen create_count++,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dec2str(ioloop_timeval.tv_usec), my_hostname);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic const char *
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_get_save_path(struct cydir_save_context *ctx, unsigned int num)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *dir;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen dir = mailbox_get_path(&ctx->mbox->box);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return t_strdup_printf("%s/%s.%u", dir, ctx->tmp_basename, num);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstruct mail_save_context *
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainencydir_save_alloc(struct mailbox_transaction_context *t)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_mailbox *mbox = CYDIR_MAILBOX(t->box);
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen struct cydir_save_context *ctx;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen if (t->save_ctx == NULL) {
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen ctx = i_new(struct cydir_save_context, 1);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen ctx->ctx.transaction = t;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen ctx->mbox = mbox;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen ctx->trans = t->itrans;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen ctx->tmp_basename = cydir_generate_tmp_filename();
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ctx->fd = -1;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen t->save_ctx = &ctx->ctx;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen }
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen return t->save_ctx;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen}
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenint cydir_save_begin(struct mail_save_context *_ctx, struct istream *input)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
9287cdd3d77d361ef75a987da24a97a5f43b4954Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct mailbox_transaction_context *trans = _ctx->transaction;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen enum mail_flags save_flags;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct istream *crlf_input;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen ctx->failed = FALSE;
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *path;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen path = cydir_get_save_path(ctx, ctx->mail_count);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0660);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ctx->fd != -1) {
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen _ctx->data.output =
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen o_stream_create_fd_file(ctx->fd, 0, FALSE);
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen o_stream_set_name(_ctx->data.output, path);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen o_stream_cork(_ctx->data.output);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(trans->box, "open(%s) failed: %m",
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi path);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->failed = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ctx->failed)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* add to index */
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen save_flags = _ctx->data.flags & ~MAIL_RECENT;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_index_append(ctx->trans, 0, &ctx->seq);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen save_flags);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (_ctx->data.keywords != NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen MODIFY_REPLACE, _ctx->data.keywords);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (_ctx->data.min_modseq != 0) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen mail_index_update_modseq(ctx->trans, ctx->seq,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen _ctx->data.min_modseq);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->seq);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
5ef7efd45b1adf3a09cf9c229cf0a3d3d54405a2Timo Sirainen crlf_input = i_stream_create_crlf(input);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen ctx->input = index_mail_cache_parse_init(_ctx->dest_mail, crlf_input);
5ef7efd45b1adf3a09cf9c229cf0a3d3d54405a2Timo Sirainen i_stream_unref(&crlf_input);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return ctx->failed ? -1 : 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenint cydir_save_continue(struct mail_save_context *_ctx)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (ctx->failed)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen if (index_storage_save_continue(_ctx, ctx->input,
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen _ctx->dest_mail) < 0) {
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen ctx->failed = TRUE;
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen return -1;
c68f28e2cf5f9621511bece0414335e551dc82c6Timo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainenstatic int cydir_save_flush(struct cydir_save_context *ctx, const char *path)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen struct mail_storage *storage = &ctx->mbox->storage->storage;
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi struct mailbox *box = &ctx->mbox->box;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen struct stat st;
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen int ret = 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen if (o_stream_finish(ctx->ctx.data.output) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "write(%s) failed: %s", path,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen o_stream_get_error(ctx->ctx.data.output));
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ret = -1;
d97860e16db095a14038d50efda1e4bb64375128Timo Sirainen }
d97860e16db095a14038d50efda1e4bb64375128Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen if (fsync(ctx->fd) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "fsync(%s) failed: %m", path);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ret = -1;
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen }
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen }
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (ctx->ctx.data.received_date == (time_t)-1) {
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen if (fstat(ctx->fd, &st) == 0)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen ctx->ctx.data.received_date = st.st_mtime;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "fstat(%s) failed: %m", path);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ret = -1;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen }
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen } else {
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen struct utimbuf ut;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen ut.actime = ioloop_time;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen ut.modtime = ctx->ctx.data.received_date;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen if (utime(path, &ut) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "utime(%s) failed: %m", path);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ret = -1;
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen }
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen }
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen o_stream_destroy(&ctx->ctx.data.output);
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen if (close(ctx->fd) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "close(%s) failed: %m", path);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ret = -1;
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen }
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen ctx->fd = -1;
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen return ret;
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen}
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainenint cydir_save_finish(struct mail_save_context *_ctx)
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen const char *path = cydir_get_save_path(ctx, ctx->mail_count);
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ctx->finished = TRUE;
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen if (ctx->fd != -1) {
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen if (cydir_save_flush(ctx, path) < 0)
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen ctx->failed = TRUE;
1e73a28edcf5ec105d238a7d7c95c390e8c84c8fTimo Sirainen }
b66484774d4059fa10671cbc50b6489fa40b117fTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (!ctx->failed)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ctx->mail_count++;
275cc4c040899c132b2acbe2fcac48ba4c1abbcfTimo Sirainen else
275cc4c040899c132b2acbe2fcac48ba4c1abbcfTimo Sirainen i_unlink(path);
7e06256923a3fc199687c5ac38818b7adb5e126dTimo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen index_mail_cache_parse_deinit(_ctx->dest_mail,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen _ctx->data.received_date, !ctx->failed);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&ctx->input);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen index_save_context_free(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return ctx->failed ? -1 : 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenvoid cydir_save_cancel(struct mail_save_context *_ctx)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ctx->failed = TRUE;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (void)cydir_save_finish(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainenint cydir_transaction_save_commit_pre(struct mail_save_context *_ctx)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const struct mail_index_header *hdr;
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen struct seq_range_iter iter;
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen uint32_t uid;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *dir;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen string_t *src_path, *dest_path;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int n;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t src_prefixlen, dest_prefixlen;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_assert(ctx->finished);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen if (cydir_sync_begin(ctx->mbox, &ctx->sync_ctx, TRUE) < 0) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ctx->failed = TRUE;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen cydir_transaction_save_rollback(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen mail_index_append_finish_uids(ctx->trans, hdr->next_uid,
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen &_t->changes->saved_uids);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen _t->changes->uid_validity = ctx->sync_ctx->uid_validity;
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen dir = mailbox_get_path(&ctx->mbox->box);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen src_path = t_str_new(256);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_printfa(src_path, "%s/%s.", dir, ctx->tmp_basename);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen src_prefixlen = str_len(src_path);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dest_path = t_str_new(256);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_append(dest_path, dir);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_append_c(dest_path, '/');
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dest_prefixlen = str_len(dest_path);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen seq_range_array_iter_init(&iter, &_t->changes->saved_uids); n = 0;
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen while (seq_range_array_iter_nth(&iter, n++, &uid)) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_truncate(src_path, src_prefixlen);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_truncate(dest_path, dest_prefixlen);
8cf32443413f811d514123c5c74c95c87594b0e3Timo Sirainen str_printfa(src_path, "%u", n-1);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_printfa(dest_path, "%u.", uid);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (rename(str_c(src_path), str_c(dest_path)) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&ctx->mbox->box,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "rename(%s, %s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen str_c(src_path), str_c(dest_path));
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ctx->failed = TRUE;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen cydir_transaction_save_rollback(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid cydir_transaction_save_commit_post(struct mail_save_context *_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
ee794ada9a89699f7ee06e3b0fd2da88670165d2Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen result);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (void)cydir_sync_finish(&ctx->sync_ctx, TRUE);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen cydir_transaction_save_rollback(_ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainenvoid cydir_transaction_save_rollback(struct mail_save_context *_ctx)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
a97fdf205b182250b0fe56c0f6f418bc22fb09a3Josef 'Jeff' Sipek struct cydir_save_context *ctx = CYDIR_SAVECTX(_ctx);
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (!ctx->finished)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen cydir_save_cancel(&ctx->ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (ctx->sync_ctx != NULL)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (void)cydir_sync_finish(&ctx->sync_ctx, FALSE);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_free(ctx->tmp_basename);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_free(ctx);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}