mdbox-save.c revision b67974c4b89ab6950c2694cce8dfb1b6561cc084
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2007-2017 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fdatasync-path.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "hex-binary.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hex-dec.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "str.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-crlf.h"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen#include "index-mail.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-pop3-uidl.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-copy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "dbox-save.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mdbox-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mdbox-map.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mdbox-file.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mdbox-sync.h"
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainenstruct dbox_save_mail {
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen struct dbox_file_append_context *file_append;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t append_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool written_to_disk;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen};
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstruct mdbox_save_context {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct dbox_save_context ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mdbox_mailbox *mbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mdbox_sync_context *sync_ctx;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen struct dbox_file *cur_file;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen struct dbox_file_append_context *cur_file_append;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_map_append_context *append_ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ARRAY_TYPE(uint32_t) copy_map_uids;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mdbox_map_atomic_context *atomic;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_map_transaction_context *map_trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ARRAY(struct dbox_save_mail) mails;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MDBOX_SAVECTX(s) container_of(DBOX_SAVECTX(s), struct mdbox_save_context, ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct dbox_file *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmdbox_copy_file_get_file(struct mailbox_transaction_context *t,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen uint32_t seq, uoff_t *offset_r)
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen{
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen const struct mdbox_mail_index_record *rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const void *data;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen uint32_t file_id;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_lookup_ext(t->view, seq, ctx->mbox->ext_id, &data, NULL);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen rec = data;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_map_lookup(ctx->mbox->storage->map, rec->map_uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &file_id, offset_r) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen return mdbox_file_init(ctx->mbox->storage, file_id);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstruct dbox_file *
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenmdbox_save_file_get_file(struct mailbox_transaction_context *t,
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen uint32_t seq, uoff_t *offset_r)
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen const struct dbox_save_mail *mails, *mail;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen unsigned int count;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen mails = array_get(&ctx->mails, &count);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen i_assert(count > 0);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen i_assert(seq >= mails[0].seq);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen mail = &mails[seq - mails[0].seq];
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen i_assert(mail->seq == seq);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail->file_append == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* copied mail */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return mdbox_copy_file_get_file(t, seq, offset_r);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen /* saved mail */
50c4a9739b55370b1d3950d7b3ec2f7cd2ed5f49Timo Sirainen i_assert(mail->written_to_disk);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen if (dbox_file_append_flush(mail->file_append) < 0)
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen ctx->ctx.failed = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail->file_append->file->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *offset_r = mail->append_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return mail->file_append->file;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen}
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstruct mail_save_context *
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenmdbox_save_alloc(struct mailbox_transaction_context *t)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen{
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen struct mdbox_mailbox *mbox = MDBOX_MAILBOX(t->box);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(t->save_ctx);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (ctx != NULL) {
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen /* use the existing allocated structure */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cur_file = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->ctx.failed = FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->ctx.finished = FALSE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->ctx.dbox_output = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->cur_file_append = NULL;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return &ctx->ctx.ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx = i_new(struct mdbox_save_context, 1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->ctx.ctx.transaction = t;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->ctx.trans = t->itrans;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->mbox = mbox;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->atomic = mdbox_map_atomic_begin(mbox->storage->map);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->append_ctx = mdbox_map_append_begin(ctx->atomic);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&ctx->mails, 32);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen t->save_ctx = &ctx->ctx.ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return t->save_ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct dbox_save_mail *save_mail;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uoff_t mail_size, append_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* get the size of the mail to be saved, if possible */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (i_stream_get_size(input, TRUE, &mail_size) <= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we couldn't find out the exact size. fallback to non-exact,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maybe it'll give something useful. the mail size is used
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen only to figure out if it's causing mdbox file to grow
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen too large. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (i_stream_get_size(input, FALSE, &mail_size) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_size = 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_map_append_next(ctx->append_ctx, mail_size, 0,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &ctx->cur_file_append,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &ctx->ctx.dbox_output) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->ctx.failed = TRUE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(ctx->ctx.dbox_output->offset <= (uint32_t)-1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen append_offset = ctx->ctx.dbox_output->offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->cur_file = ctx->cur_file_append->file;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen dbox_save_begin(&ctx->ctx, input);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen save_mail = array_append_space(&ctx->mails);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen save_mail->file_append = ctx->cur_file_append;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen save_mail->seq = ctx->ctx.seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen save_mail->append_offset = append_offset;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return ctx->ctx.failed ? -1 : 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainenstatic int mdbox_save_mail_write_metadata(struct mdbox_save_context *ctx,
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen struct dbox_save_mail *mail)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dbox_file *file = mail->file_append->file;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct dbox_message_header dbox_msg_hdr;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uoff_t message_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen guid_128_t guid_128;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen message_size = ctx->ctx.dbox_output->offset -
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen mail->append_offset - mail->file_append->file->msg_header_size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen dbox_save_write_metadata(&ctx->ctx.ctx, ctx->ctx.dbox_output,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen message_size, ctx->mbox->box.name, guid_128);
faef57a36800fe952a5794328467f846d5480ae6Timo Sirainen /* save the 128bit GUID to index so if the map index gets corrupted
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen we can still find the message */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->mbox->guid_ext_id, guid_128, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_pwrite(ctx->ctx.dbox_output, &dbox_msg_hdr,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sizeof(dbox_msg_hdr), mail->append_offset) < 0) {
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen mail->written_to_disk = TRUE;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return 0;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen}
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainenstatic int mdbox_save_finish_write(struct mail_save_context *_ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct dbox_save_mail *mail;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->ctx.finished = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->ctx.dbox_output == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen dbox_save_end(&ctx->ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen mail = array_idx_modifiable(&ctx->mails, array_count(&ctx->mails) - 1);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (!ctx->ctx.failed) T_BEGIN {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_save_mail_write_metadata(ctx, mail) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->ctx.failed = TRUE;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen else
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_map_append_finish(ctx->append_ctx);
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen } T_END;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail->file_append->file->input != NULL) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* if we try to read the saved mail before unlocking file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen make sure the input stream doesn't have stale data */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_stream_sync(mail->file_append->file->input);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_unref(&ctx->ctx.input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->ctx.failed) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen index_storage_save_abort_last(&ctx->ctx.ctx, ctx->ctx.seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_map_append_abort(ctx->append_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen array_delete(&ctx->mails, array_count(&ctx->mails) - 1, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen}
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainenint mdbox_save_finish(struct mail_save_context *ctx)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen{
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen int ret;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ret = mdbox_save_finish_write(ctx);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen index_save_context_free(ctx);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen return ret;
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mdbox_save_cancel(struct mail_save_context *_ctx)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dbox_save_context *ctx = DBOX_SAVECTX(_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->failed = TRUE;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen (void)mdbox_save_finish(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmdbox_save_set_map_uids(struct mdbox_save_context *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t first_map_uid, uint32_t last_map_uid)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_mailbox *mbox = ctx->mbox;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_index_view *view = ctx->ctx.ctx.transaction->view;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mdbox_mail_index_record *old_rec;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen struct mdbox_mail_index_record rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct dbox_save_mail *mails;
bb1e9bd834c04f272b6e3f4d4a7686c26d6e5c2aTimo Sirainen unsigned int i, count;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen const void *data;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen uint32_t next_map_uid = first_map_uid;
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_update_header(mbox, ctx->ctx.trans, NULL);
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen i_zero(&rec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec.save_date = ioloop_time;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mails = array_get(&ctx->mails, &count);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (i = 0; i < count; i++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_lookup_ext(view, mails[i].seq, mbox->ext_id,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &data, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_rec = data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (old_rec != NULL && old_rec->map_uid != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* message was copied. keep the existing map uid */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec.map_uid = next_map_uid++;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_ext(ctx->ctx.trans, mails[i].seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mbox->ext_id, &rec, NULL);
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen }
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen i_assert(next_map_uid == last_map_uid + 1);
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_index_header *hdr;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t first_map_uid, last_map_uid;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_assert(ctx->ctx.finished);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen /* flush/fsync writes to m.* files before locking the map */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_map_append_flush(ctx->append_ctx) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mdbox_transaction_save_rollback(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure the map gets locked */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_map_atomic_lock(ctx->atomic, "saving") < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mdbox_transaction_save_rollback(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* lock the mailbox after map to avoid deadlocks. if we've noticed
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen any corruption, deal with it later, otherwise we won't have
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen up-to-date atomic->sync_view */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_sync_begin(ctx->mbox, MDBOX_SYNC_FLAG_NO_PURGE |
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen MDBOX_SYNC_FLAG_FORCE |
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MDBOX_SYNC_FLAG_FSYNC |
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen MDBOX_SYNC_FLAG_NO_REBUILD, ctx->atomic,
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen &ctx->sync_ctx) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_transaction_save_rollback(_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen /* assign map UIDs for newly saved messages after we've successfully
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen acquired all the locks. the transaction is now very unlikely to
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen fail. the UIDs are written to the transaction log immediately within
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen this function, but the map is left locked. */
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen if (mdbox_map_append_assign_map_uids(ctx->append_ctx, &first_map_uid,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen &last_map_uid) < 0) {
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen mdbox_transaction_save_rollback(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* update dbox header flags */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->mbox->hdr_ext_id, offsetof(struct mdbox_index_header, flags));
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* assign UIDs for new messages */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &_t->changes->saved_uids);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (ctx->ctx.highest_pop3_uidl_seq != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct dbox_save_mail *mails;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct seq_range_iter iter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int highest_pop3_uidl_idx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t uid;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mails = array_idx(&ctx->mails, 0);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen highest_pop3_uidl_idx =
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->ctx.highest_pop3_uidl_seq - mails[0].seq;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen i_assert(mails[highest_pop3_uidl_idx].seq == ctx->ctx.highest_pop3_uidl_seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen seq_range_array_iter_init(&iter, &_t->changes->saved_uids);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (!seq_range_array_iter_nth(&iter, highest_pop3_uidl_idx, &uid))
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_unreached();
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen index_pop3_uidl_set_max_uid(&ctx->mbox->box, ctx->ctx.trans, uid);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* save map UIDs to mailbox index */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (first_map_uid != 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_save_set_map_uids(ctx, first_map_uid, last_map_uid);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* increase map's refcount for copied mails */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (array_is_created(&ctx->copy_map_uids)) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ctx->map_trans = mdbox_map_transaction_begin(ctx->atomic, FALSE);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_map_update_refcounts(ctx->map_trans,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen &ctx->copy_map_uids, 1) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mdbox_transaction_save_rollback(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_sync_set_reason(ctx->sync_ctx->index_sync_ctx, "copying");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_sync_set_reason(ctx->sync_ctx->index_sync_ctx, "saving");
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen _t->changes->uid_validity = hdr->uid_validity;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_index_transaction_commit_result *result)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* finish writing the mailbox APPENDs */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (mdbox_sync_finish(&ctx->sync_ctx, TRUE) == 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* commit refcount increases for copied mails */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->map_trans != NULL) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mdbox_map_transaction_commit(ctx->map_trans, "copy refcount updates") < 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* flush file append writes */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (mdbox_map_append_commit(ctx->append_ctx) < 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* update the sync tail offset, everything else
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen was already written at this point. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const char *box_path = mailbox_get_path(&ctx->mbox->box);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (fdatasync_path(box_path) < 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_storage_set_critical(storage,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen "fdatasync_path(%s) failed: %m", box_path);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenvoid mdbox_transaction_save_rollback(struct mail_save_context *_ctx)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (!ctx->ctx.finished)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_save_cancel(&ctx->ctx.ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->append_ctx != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->map_trans != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mdbox_map_transaction_free(&ctx->map_trans);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->atomic != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (array_is_created(&ctx->copy_map_uids))
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen array_free(&ctx->copy_map_uids);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ctx->sync_ctx != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen (void)mdbox_sync_finish(&ctx->sync_ctx, FALSE);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen array_free(&ctx->mails);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_free(ctx);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen}
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenint mdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mdbox_save_context *ctx = MDBOX_SAVECTX(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct dbox_save_mail *save_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mdbox_mailbox *src_mbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mdbox_mail_index_record rec;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const void *guid_data;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen guid_128_t wanted_guid;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen ctx->ctx.finished = TRUE;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail->box->storage != _ctx->transaction->box->storage ||
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen _ctx->transaction->box->disable_reflink_copy_to)
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen return mail_storage_copy(_ctx, mail);
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen src_mbox = MDBOX_MAILBOX(mail->box);
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen i_zero(&rec);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec.save_date = ioloop_time;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mdbox_mail_lookup(src_mbox, mail->transaction->view, mail->seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen &rec.map_uid) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen index_save_context_free(_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen }
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen mail_index_lookup_ext(mail->transaction->view, mail->seq,
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen src_mbox->guid_ext_id, &guid_data, NULL);
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen if (guid_data == NULL || guid_128_is_empty(guid_data)) {
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen /* missing GUID, something's broken. don't copy using
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen refcounting. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return mail_storage_copy(_ctx, mail);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else if (_ctx->data.guid != NULL &&
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen (guid_128_from_string(_ctx->data.guid, wanted_guid) < 0 ||
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen memcmp(guid_data, wanted_guid, sizeof(wanted_guid)) != 0)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* GUID change requested. we can't do it with refcount
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen copying */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return mail_storage_copy(_ctx, mail);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen }
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* remember the map_uid so we can later increase its refcount */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (!array_is_created(&ctx->copy_map_uids))
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen i_array_init(&ctx->copy_map_uids, 32);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen array_append(&ctx->copy_map_uids, &rec.map_uid, 1);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* add message to mailbox index */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dbox_save_add_to_index(&ctx->ctx);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->mbox->ext_id, &rec, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ctx->mbox->guid_ext_id, guid_data, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen index_copy_cache_fields(_ctx, mail, ctx->ctx.seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen save_mail = array_append_space(&ctx->mails);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen save_mail->seq = ctx->ctx.seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->ctx.seq);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen index_save_context_free(_ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen