bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "fdatasync-path.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-binary.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-dec.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "istream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "istream-crlf.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ostream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "write-full.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "index-mail.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "index-pop3-uidl.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-copy.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "dbox-save.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-map.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-file.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-sync.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_save_mail {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file_append_context *file_append;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t seq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t append_offset;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen bool written_to_disk;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mdbox_save_context {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_context ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mailbox *mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_sync_context *sync_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen struct dbox_file *cur_file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file_append_context *cur_file_append;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_append_context *append_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ARRAY_TYPE(uint32_t) copy_map_uids;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen struct mdbox_map_atomic_context *atomic;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_transaction_context *map_trans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dbox_save_mail) mails;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek#define MDBOX_SAVECTX(s) container_of(DBOX_SAVECTX(s), struct mdbox_save_context, ctx)
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic struct dbox_file *
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenmdbox_copy_file_get_file(struct mailbox_transaction_context *t,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen uint32_t seq, uoff_t *offset_r)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const struct mdbox_mail_index_record *rec;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const void *data;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen uint32_t file_id;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen mail_index_lookup_ext(t->view, seq, ctx->mbox->ext_id, &data, NULL);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen rec = data;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup(ctx->mbox->storage->map, rec->map_uid,
714c6a150480112eb1a5f309d0cc39b60613a719Timo Sirainen &file_id, offset_r) < 0)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen i_unreached();
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen return mdbox_file_init(ctx->mbox->storage, file_id);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_file *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_save_file_get_file(struct mailbox_transaction_context *t,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t seq, uoff_t *offset_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct dbox_save_mail *mails, *mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mails = array_get(&ctx->mails, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(count > 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(seq >= mails[0].seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9a02317c852face76737763fa6ec43b444688de5Timo Sirainen mail = &mails[seq - mails[0].seq];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(mail->seq == seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen if (mail->file_append == NULL) {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen /* copied mail */
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen return mdbox_copy_file_get_file(t, seq, offset_r);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen }
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen /* saved mail */
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen i_assert(mail->written_to_disk);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (dbox_file_append_flush(mail->file_append) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen mail->file_append->file->refcount++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *offset_r = mail->append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return mail->file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mail_save_context *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_save_alloc(struct mailbox_transaction_context *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_mailbox *mbox = MDBOX_MAILBOX(t->box);
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* use the existing allocated structure */
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen ctx->cur_file = NULL;
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen ctx->ctx.failed = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = FALSE;
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen ctx->ctx.dbox_output = NULL;
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen ctx->cur_file_append = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx = i_new(struct mdbox_save_context, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.ctx.transaction = t;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen ctx->ctx.trans = t->itrans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox = mbox;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->atomic = mdbox_map_atomic_begin(mbox->storage->map);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->append_ctx = mdbox_map_append_begin(ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&ctx->mails, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t->save_ctx = &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return t->save_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_mail *save_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t mail_size, append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* get the size of the mail to be saved, if possible */
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen if (i_stream_get_size(input, TRUE, &mail_size) <= 0) {
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen /* we couldn't find out the exact size. fallback to non-exact,
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen maybe it'll give something useful. the mail size is used
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen only to figure out if it's causing mdbox file to grow
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen too large. */
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen if (i_stream_get_size(input, FALSE, &mail_size) <= 0)
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen mail_size = 0;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen }
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_next(ctx->append_ctx, mail_size, 0,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->cur_file_append,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->ctx.dbox_output) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen i_assert(ctx->ctx.dbox_output->offset <= (uint32_t)-1);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen append_offset = ctx->ctx.dbox_output->offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen ctx->cur_file = ctx->cur_file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_begin(&ctx->ctx, input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail = array_append_space(&ctx->mails);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->file_append = ctx->cur_file_append;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->seq = ctx->ctx.seq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->append_offset = append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ctx->ctx.failed ? -1 : 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mdbox_save_mail_write_metadata(struct mdbox_save_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_mail *mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file *file = mail->file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_message_header dbox_msg_hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t message_size;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_t guid_128;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen message_size = ctx->ctx.dbox_output->offset -
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail->append_offset - mail->file_append->file->msg_header_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen dbox_save_write_metadata(&ctx->ctx.ctx, ctx->ctx.dbox_output,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen message_size, ctx->mbox->box.name, guid_128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* save the 128bit GUID to index so if the map index gets corrupted
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen we can still find the message */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox->guid_ext_id, guid_128, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (o_stream_pwrite(ctx->ctx.dbox_output, &dbox_msg_hdr,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(dbox_msg_hdr), mail->append_offset) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen mail->written_to_disk = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mdbox_save_finish_write(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen struct dbox_save_mail *mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = TRUE;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (ctx->ctx.dbox_output == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen dbox_save_end(&ctx->ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen mail = array_idx_modifiable(&ctx->mails, array_count(&ctx->mails) - 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.failed) T_BEGIN {
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen if (mdbox_save_mail_write_metadata(ctx, mail) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_finish(ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen if (mail->file_append->file->input != NULL) {
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen /* if we try to read the saved mail before unlocking file,
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen make sure the input stream doesn't have stale data */
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen i_stream_sync(mail->file_append->file->input);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_unref(&ctx->ctx.input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->ctx.failed) {
f776b9a125c59a96de6807e9558942cf7b7ab079Timo Sirainen index_storage_save_abort_last(&ctx->ctx.ctx, ctx->ctx.seq);
836e57b1e7817d008f8ae05cd4b506f420fed80dTimo Sirainen mdbox_map_append_abort(ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_delete(&ctx->mails, array_count(&ctx->mails) - 1, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_save_finish(struct mail_save_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = mdbox_save_finish_write(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen index_save_context_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_save_cancel(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_save_context *ctx = DBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)mdbox_save_finish(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstatic void
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenmdbox_save_set_map_uids(struct mdbox_save_context *ctx,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen uint32_t first_map_uid, uint32_t last_map_uid)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mdbox_mailbox *mbox = ctx->mbox;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mail_index_view *view = ctx->ctx.ctx.transaction->view;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const struct mdbox_mail_index_record *old_rec;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mdbox_mail_index_record rec;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const struct dbox_save_mail *mails;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen unsigned int i, count;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const void *data;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen uint32_t next_map_uid = first_map_uid;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mdbox_update_header(mbox, ctx->ctx.trans, NULL);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&rec);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen rec.save_date = ioloop_time;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mails = array_get(&ctx->mails, &count);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen for (i = 0; i < count; i++) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_index_lookup_ext(view, mails[i].seq, mbox->ext_id,
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen &data, NULL);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen old_rec = data;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (old_rec != NULL && old_rec->map_uid != 0) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen /* message was copied. keep the existing map uid */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen continue;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen }
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen rec.map_uid = next_map_uid++;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_index_update_ext(ctx->ctx.trans, mails[i].seq,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mbox->ext_id, &rec, NULL);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen }
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_assert(next_map_uid == last_map_uid + 1);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_index_header *hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t first_map_uid, last_map_uid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(ctx->ctx.finished);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen /* flush/fsync writes to m.* files before locking the map */
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen if (mdbox_map_append_flush(ctx->append_ctx) < 0) {
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen mdbox_transaction_save_rollback(_ctx);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen return -1;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen }
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen /* make sure the map gets locked */
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen if (mdbox_map_atomic_lock(ctx->atomic, "saving") < 0) {
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen mdbox_transaction_save_rollback(_ctx);
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen return -1;
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen }
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen /* lock the mailbox after map to avoid deadlocks. if we've noticed
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen any corruption, deal with it later, otherwise we won't have
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen up-to-date atomic->sync_view */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (mdbox_sync_begin(ctx->mbox, MDBOX_SYNC_FLAG_NO_PURGE |
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MDBOX_SYNC_FLAG_FORCE |
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen MDBOX_SYNC_FLAG_FSYNC |
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen MDBOX_SYNC_FLAG_NO_REBUILD, ctx->atomic,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen &ctx->sync_ctx) < 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_transaction_save_rollback(_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen /* assign map UIDs for newly saved messages after we've successfully
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen acquired all the locks. the transaction is now very unlikely to
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen fail. the UIDs are written to the transaction log immediately within
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen this function, but the map is left locked. */
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if (mdbox_map_append_assign_map_uids(ctx->append_ctx, &first_map_uid,
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen &last_map_uid) < 0) {
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen mdbox_transaction_save_rollback(_ctx);
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen return -1;
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen }
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen /* update dbox header flags */
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view,
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen ctx->mbox->hdr_ext_id, offsetof(struct mdbox_index_header, flags));
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* assign UIDs for new messages */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &_t->changes->saved_uids);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (ctx->ctx.highest_pop3_uidl_seq != 0) {
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen const struct dbox_save_mail *mails;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct seq_range_iter iter;
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen unsigned int highest_pop3_uidl_idx;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen uint32_t uid;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen mails = array_idx(&ctx->mails, 0);
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen highest_pop3_uidl_idx =
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen ctx->ctx.highest_pop3_uidl_seq - mails[0].seq;
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen i_assert(mails[highest_pop3_uidl_idx].seq == ctx->ctx.highest_pop3_uidl_seq);
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen seq_range_array_iter_init(&iter, &_t->changes->saved_uids);
3aae8844765b1d74d847e8e37daa135ac7035e6bTimo Sirainen if (!seq_range_array_iter_nth(&iter, highest_pop3_uidl_idx, &uid))
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen i_unreached();
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen index_pop3_uidl_set_max_uid(&ctx->mbox->box, ctx->ctx.trans, uid);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
fb5efc6ed69da679d9da31ef62daa7024de18212Timo Sirainen /* save map UIDs to mailbox index */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (first_map_uid != 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mdbox_save_set_map_uids(ctx, first_map_uid, last_map_uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* increase map's refcount for copied mails */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (array_is_created(&ctx->copy_map_uids)) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->map_trans = mdbox_map_transaction_begin(ctx->atomic, FALSE);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_update_refcounts(ctx->map_trans,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->copy_map_uids, 1) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen mail_index_sync_set_reason(ctx->sync_ctx->index_sync_ctx, "copying");
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen } else {
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen mail_index_sync_set_reason(ctx->sync_ctx->index_sync_ctx, "saving");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _t->changes->uid_validity = hdr->uid_validity;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid mdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen result);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* finish writing the mailbox APPENDs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mdbox_sync_finish(&ctx->sync_ctx, TRUE) == 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* commit refcount increases for copied mails */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ctx->map_trans != NULL) {
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen if (mdbox_map_transaction_commit(ctx->map_trans, "copy refcount updates") < 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* flush file append writes */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mdbox_map_append_commit(ctx->append_ctx) < 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* update the sync tail offset, everything else
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen was already written at this point. */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const char *box_path = mailbox_get_path(&ctx->mbox->box);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (fdatasync_path(box_path) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(_ctx->dest_mail,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "fdatasync_path(%s) failed: %m", box_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_transaction_save_rollback(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.finished)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_save_cancel(&ctx->ctx.ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->append_ctx != NULL)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->map_trans != NULL)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_transaction_free(&ctx->map_trans);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ctx->atomic != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (array_is_created(&ctx->copy_map_uids))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->copy_map_uids);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->sync_ctx != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)mdbox_sync_finish(&ctx->sync_ctx, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->mails);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen struct dbox_save_mail *save_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mailbox *src_mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mail_index_record rec;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen const void *guid_data;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen guid_128_t wanted_guid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen if (mail->box->storage != _ctx->transaction->box->storage ||
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen _ctx->transaction->box->disable_reflink_copy_to)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return mail_storage_copy(_ctx, mail);
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek src_mbox = MDBOX_MAILBOX(mail->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&rec);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen rec.save_date = ioloop_time;
767ff4367960efd5fa868f3b56f850fd4c205c8bTimo Sirainen if (mdbox_mail_lookup(src_mbox, mail->transaction->view, mail->seq,
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen &rec.map_uid) < 0) {
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen index_save_context_free(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen mail_index_lookup_ext(mail->transaction->view, mail->seq,
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen src_mbox->guid_ext_id, &guid_data, NULL);
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen if (guid_data == NULL || guid_128_is_empty(guid_data)) {
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen /* missing GUID, something's broken. don't copy using
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen refcounting. */
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen return mail_storage_copy(_ctx, mail);
61279c3c77aa4a6f8d1de82b468ab01b14418318Timo Sirainen } else if (_ctx->data.guid != NULL &&
61279c3c77aa4a6f8d1de82b468ab01b14418318Timo Sirainen (guid_128_from_string(_ctx->data.guid, wanted_guid) < 0 ||
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen memcmp(guid_data, wanted_guid, sizeof(wanted_guid)) != 0)) {
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen /* GUID change requested. we can't do it with refcount
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen copying */
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen return mail_storage_copy(_ctx, mail);
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen }
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* remember the map_uid so we can later increase its refcount */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!array_is_created(&ctx->copy_map_uids))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&ctx->copy_map_uids, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&ctx->copy_map_uids, &rec.map_uid, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* add message to mailbox index */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_add_to_index(&ctx->ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox->ext_id, &rec, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen ctx->mbox->guid_ext_id, guid_data, NULL);
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen index_copy_cache_fields(_ctx, mail, ctx->ctx.seq);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen save_mail = array_append_space(&ctx->mails);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen save_mail->seq = ctx->ctx.seq;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
a825281071af96cc148e49c64ac36d8c5cf26f71Timo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->ctx.seq);
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen index_save_context_free(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}