mdbox-save.c revision 767ff4367960efd5fa868f3b56f850fd4c205c8b
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "fdatasync-path.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "hex-binary.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "hex-dec.h"
daf029d2a627daa39d05507140f385162828172eTimo Sirainen#include "str.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-crlf.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "ostream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "write-full.h"
daf029d2a627daa39d05507140f385162828172eTimo Sirainen#include "index-mail.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-copy.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "dbox-save.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mdbox-storage.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mdbox-map.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mdbox-file.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mdbox-sync.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stdlib.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct dbox_save_mail {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_file_append_context *file_append;
daf029d2a627daa39d05507140f385162828172eTimo Sirainen uint32_t seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t append_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct mdbox_save_context {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_save_context ctx;
daf029d2a627daa39d05507140f385162828172eTimo Sirainen
daf029d2a627daa39d05507140f385162828172eTimo Sirainen struct mdbox_mailbox *mbox;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mdbox_sync_context *sync_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct dbox_file_append_context *cur_file_append;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_map_append_context *append_ctx;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ARRAY_TYPE(uint32_t) copy_map_uids;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_map_transaction_context *map_trans;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ARRAY_DEFINE(mails, struct dbox_save_mail);
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct dbox_file *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmdbox_copy_file_get_file(struct mailbox_transaction_context *t,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen uint32_t seq, uoff_t *offset_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mdbox_save_context *ctx =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (struct mdbox_save_context *)t->save_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct mdbox_mail_index_record *rec;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen const void *data;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen bool expunged;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen uint32_t file_id;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_lookup_ext(t->view, seq, ctx->mbox->ext_id,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &data, &expunged);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rec = data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (dbox_map_lookup(ctx->mbox->storage->map, rec->map_uid,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &file_id, offset_r) <= 0)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen i_unreached();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return mdbox_file_init(ctx->mbox->storage, file_id);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstruct dbox_file *
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenmdbox_save_file_get_file(struct mailbox_transaction_context *t,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t seq, uoff_t *offset_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mdbox_save_context *ctx =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (struct mdbox_save_context *)t->save_ctx;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const struct dbox_save_mail *mails, *mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int count;
35df1dd606c5ef21068ab4fe4be305859d4fad4bTimo Sirainen
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen mails = array_get(&ctx->mails, &count);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_assert(count > 0);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_assert(seq >= mails[0].seq);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail = &mails[seq - mails[0].seq];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(mail->seq == seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen if (mail->file_append == NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* copied mail */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return mdbox_copy_file_get_file(t, seq, offset_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* saved mail */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (dbox_file_append_flush(mail->file_append) < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->ctx.failed = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail->file_append->file->refcount++;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen *offset_r = mail->append_offset;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return mail->file_append->file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_save_context *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmdbox_save_alloc(struct mailbox_transaction_context *t)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)t->box;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mdbox_save_context *ctx =
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen (struct mdbox_save_context *)t->save_ctx;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ctx != NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* use the existing allocated structure */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.finished = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &ctx->ctx.ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen ctx = i_new(struct mdbox_save_context, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.ctx.transaction = t;
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen ctx->ctx.trans = t->itrans;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->mbox = mbox;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->append_ctx = dbox_map_append_begin(mbox->storage->map, 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_array_init(&ctx->mails, 32);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen t->save_ctx = &ctx->ctx.ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return t->save_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint mdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_save_mail *save_mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t mail_size, append_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* get the size of the mail to be saved, if possible */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (i_stream_get_size(input, TRUE, &mail_size) <= 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct stat *st;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we couldn't find out the exact size. fallback to non-exact,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen maybe it'll give something useful. the mail size is used
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen only to figure out if it's causing mdbox file to grow
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen too large. */
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen st = i_stream_stat(input, FALSE);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen mail_size = st->st_size > 0 ? st->st_size : 0;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (dbox_map_append_next(ctx->append_ctx, mail_size,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen &ctx->cur_file_append,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen &ctx->ctx.dbox_output) < 0) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen ctx->ctx.failed = TRUE;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return -1;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen i_assert(ctx->ctx.dbox_output->offset <= (uint32_t)-1);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen append_offset = ctx->ctx.dbox_output->offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ctx->ctx.cur_file = ctx->cur_file_append->file;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_save_begin(&ctx->ctx, input);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen save_mail = array_append_space(&ctx->mails);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen save_mail->file_append = ctx->cur_file_append;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen save_mail->seq = ctx->ctx.seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen save_mail->append_offset = append_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ctx->ctx.failed ? -1 : 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int mdbox_save_mail_write_metadata(struct mdbox_save_context *ctx,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct dbox_save_mail *mail)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_file *file = mail->file_append->file;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct dbox_message_header dbox_msg_hdr;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t message_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint8_t guid_128[MAIL_GUID_128_SIZE];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen message_size = ctx->ctx.dbox_output->offset -
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail->append_offset - mail->file_append->file->msg_header_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_save_write_metadata(&ctx->ctx.ctx, ctx->ctx.dbox_output,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->mbox->box.name, guid_128);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* save the 128bit GUID to index so if the map index gets corrupted
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen we can still find the message */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->mbox->guid_ext_id, guid_128, NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen if (o_stream_pwrite(ctx->ctx.dbox_output, &dbox_msg_hdr,
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen sizeof(dbox_msg_hdr), mail->append_offset) < 0) {
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen return 0;
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e743c8779135b67056f8211cad867f79d3d4065eTimo Sirainenstatic int mdbox_save_finish_write(struct mail_save_context *_ctx)
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct dbox_save_mail *mails;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ctx->ctx.finished = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ctx->ctx.dbox_output == NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen dbox_save_end(&ctx->ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index_mail_cache_parse_deinit(_ctx->dest_mail,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _ctx->received_date, !ctx->ctx.failed);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mails = array_idx_modifiable(&ctx->mails, array_count(&ctx->mails) - 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!ctx->ctx.failed) T_BEGIN {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mdbox_save_mail_write_metadata(ctx, mails) < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->ctx.failed = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen else
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen dbox_map_append_finish(ctx->append_ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen } T_END;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_unref(&ctx->ctx.input);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ctx->ctx.failed) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen array_delete(&ctx->mails, array_count(&ctx->mails) - 1, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint mdbox_save_finish(struct mail_save_context *ctx)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ret = mdbox_save_finish_write(ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index_save_context_free(ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid mdbox_save_cancel(struct mail_save_context *_ctx)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->failed = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)mdbox_save_finish(_ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint mdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mdbox_mailbox *mbox = ctx->mbox;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const struct mail_index_header *hdr;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen uint32_t first_map_uid, last_map_uid;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(ctx->ctx.finished);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* lock the mailbox before map to avoid deadlocks */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mdbox_sync_begin(mbox, MDBOX_SYNC_FLAG_NO_PURGE |
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen MDBOX_SYNC_FLAG_FORCE |
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen MDBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mdbox_transaction_save_rollback(_ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* get map UIDs for messages saved to multi-files. they're written
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen to transaction log immediately within this function, but the map
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen is left locked. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (dbox_map_append_assign_map_uids(ctx->append_ctx, &first_map_uid,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen &last_map_uid) < 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mdbox_transaction_save_rollback(_ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* assign UIDs for new messages */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen &_t->changes->saved_uids);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* add map_uids for all messages saved to multi-files */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (first_map_uid != 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mdbox_mail_index_record rec;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const struct dbox_save_mail *mails;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned int i, count;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen uint32_t next_map_uid = first_map_uid;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mdbox_update_header(mbox, ctx->ctx.trans, NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen memset(&rec, 0, sizeof(rec));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen rec.save_date = ioloop_time;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mails = array_get(&ctx->mails, &count);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < count; i++) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen rec.map_uid = next_map_uid++;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_update_ext(ctx->ctx.trans, mails[i].seq,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mbox->ext_id, &rec, NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(next_map_uid == last_map_uid + 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* increase map's refcount for copied mails */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (array_is_created(&ctx->copy_map_uids)) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->map_trans =
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen dbox_map_transaction_begin(mbox->storage->map, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (dbox_map_update_refcounts(ctx->map_trans,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen &ctx->copy_map_uids, 1) < 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mdbox_transaction_save_rollback(_ctx);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ctx->ctx.mail != NULL)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_free(&ctx->ctx.mail);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen _t->changes->uid_validity = hdr->uid_validity;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid mdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mail_index_transaction_commit_result *result)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen result);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* finish writing the mailbox APPENDs */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mdbox_sync_finish(&ctx->sync_ctx, TRUE) == 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ctx->map_trans != NULL)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)dbox_map_transaction_commit(ctx->map_trans);
/* commit only updates the sync tail offset, everything else
was already written at this point. */
(void)dbox_map_append_commit(ctx->append_ctx);
}
dbox_map_append_free(&ctx->append_ctx);
if (!ctx->mbox->storage->storage.storage.set->fsync_disable) {
if (fdatasync_path(ctx->mbox->box.path) < 0) {
i_error("fdatasync_path(%s) failed: %m",
ctx->mbox->box.path);
}
}
mdbox_transaction_save_rollback(_ctx);
}
void mdbox_transaction_save_rollback(struct mail_save_context *_ctx)
{
struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
if (!ctx->ctx.finished)
mdbox_save_cancel(&ctx->ctx.ctx);
if (ctx->append_ctx != NULL)
dbox_map_append_free(&ctx->append_ctx);
if (ctx->map_trans != NULL)
dbox_map_transaction_free(&ctx->map_trans);
if (array_is_created(&ctx->copy_map_uids))
array_free(&ctx->copy_map_uids);
if (ctx->sync_ctx != NULL)
(void)mdbox_sync_finish(&ctx->sync_ctx, FALSE);
if (ctx->ctx.mail != NULL)
mail_free(&ctx->ctx.mail);
array_free(&ctx->mails);
i_free(ctx);
}
int mdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
{
struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
struct dbox_save_mail *save_mail;
struct mdbox_mailbox *src_mbox;
struct mdbox_mail_index_record rec;
const void *data;
bool expunged;
ctx->ctx.finished = TRUE;
if (mail->box->storage != _ctx->transaction->box->storage)
return mail_storage_copy(_ctx, mail);
src_mbox = (struct mdbox_mailbox *)mail->box;
memset(&rec, 0, sizeof(rec));
rec.save_date = ioloop_time;
if (mdbox_mail_lookup(src_mbox, mail->transaction->view, mail->seq,
&rec.map_uid) < 0)
return -1;
/* remember the map_uid so we can later increase its refcount */
if (!array_is_created(&ctx->copy_map_uids))
i_array_init(&ctx->copy_map_uids, 32);
array_append(&ctx->copy_map_uids, &rec.map_uid, 1);
/* add message to mailbox index */
dbox_save_add_to_index(&ctx->ctx);
mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
ctx->mbox->ext_id, &rec, NULL);
mail_index_lookup_ext(mail->transaction->view, mail->seq,
src_mbox->guid_ext_id, &data, &expunged);
if (data != NULL) {
mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
ctx->mbox->guid_ext_id, data, NULL);
}
save_mail = array_append_space(&ctx->mails);
save_mail->seq = ctx->ctx.seq;
if (_ctx->dest_mail != NULL)
mail_set_seq(_ctx->dest_mail, ctx->ctx.seq);
return 0;
}