sdbox-save.c revision cc0a651962a3e54d5a62231ac5847ae7f9f7de7f
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2007-2015 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "array.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "fdatasync-path.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "hex-binary.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "hex-dec.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "str.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream-crlf.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "ostream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "write-full.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "index-mail.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-copy.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "dbox-attachment.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "dbox-save.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "sdbox-storage.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "sdbox-file.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "sdbox-sync.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstruct sdbox_save_context {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct dbox_save_context ctx;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct sdbox_mailbox *mbox;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct sdbox_sync_context *sync_ctx;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct dbox_file *cur_file;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct dbox_file_append_context *append_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen uint32_t first_saved_seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ARRAY(struct dbox_file *) files;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct dbox_file *
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainensdbox_save_file_get_file(struct mailbox_transaction_context *t, uint32_t seq)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct sdbox_save_context *ctx =
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen (struct sdbox_save_context *)t->save_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct dbox_file *const *files, *file;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen unsigned int count;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_assert(seq >= ctx->first_saved_seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen files = array_get(&ctx->files, &count);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen i_assert(count > 0);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen i_assert(seq - ctx->first_saved_seq < count);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen file = files[seq - ctx->first_saved_seq];
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen i_assert(((struct sdbox_file *)file)->written_to_disk);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen return file;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstruct mail_save_context *
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainensdbox_save_alloc(struct mailbox_transaction_context *t)
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen{
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)t->box;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen struct sdbox_save_context *ctx =
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen (struct sdbox_save_context *)t->save_ctx;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen if (ctx != NULL) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* use the existing allocated structure */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->cur_file = NULL;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen ctx->ctx.failed = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.finished = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.dbox_output = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &ctx->ctx.ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx = i_new(struct sdbox_save_context, 1);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen ctx->ctx.ctx.transaction = t;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.trans = t->itrans;
7db932bd4934cd967eeae643300aef5b91caeaeaTimo Sirainen ctx->mbox = mbox;
7db932bd4934cd967eeae643300aef5b91caeaeaTimo Sirainen i_array_init(&ctx->files, 32);
74066569545099304b20e790df7c261883d1746bTimo Sirainen t->save_ctx = &ctx->ctx.ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return t->save_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenvoid sdbox_save_add_file(struct mail_save_context *_ctx, struct dbox_file *file)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen struct dbox_file *const *files;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen unsigned int count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (ctx->first_saved_seq == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->first_saved_seq = ctx->ctx.seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen files = array_get(&ctx->files, &count);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen if (count > 0) {
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen /* a plugin may leave a previously saved file open.
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen we'll close it here to avoid eating too many fds. */
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen dbox_file_close(files[count-1]);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen array_append(&ctx->files, &file, 1);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenint sdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct dbox_file *file;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int ret;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen file = sdbox_file_create(ctx->mbox);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen ctx->append_ctx = dbox_file_append_init(file);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen ret = dbox_file_get_append_stream(ctx->append_ctx,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen &ctx->ctx.dbox_output);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (ret <= 0) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_assert(ret != 0);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen dbox_file_append_rollback(&ctx->append_ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_file_unref(&file);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen ctx->ctx.failed = TRUE;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen return -1;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->cur_file = file;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen dbox_save_begin(&ctx->ctx, input);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sdbox_save_add_file(_ctx, file);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return ctx->ctx.failed ? -1 : 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenstatic int dbox_save_mail_write_metadata(struct dbox_save_context *ctx,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct dbox_file *file)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)file;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs_arr;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen const struct mail_attachment_extref *extrefs;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct dbox_message_header dbox_msg_hdr;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen uoff_t message_size;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen guid_128_t guid_128;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen unsigned int i, count;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen message_size = ctx->dbox_output->offset -
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen file->msg_header_size - file->file_header_size;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen dbox_save_write_metadata(&ctx->ctx, ctx->dbox_output,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen message_size, NULL, guid_128);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (o_stream_pwrite(ctx->dbox_output, &dbox_msg_hdr,
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen sizeof(dbox_msg_hdr),
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen file->file_header_size) < 0) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return -1;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen }
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen sfile->written_to_disk = TRUE;
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen /* remember the attachment paths until commit time */
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen extrefs_arr = index_attachment_save_get_extrefs(&ctx->ctx);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (extrefs_arr != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen extrefs = array_get(extrefs_arr, &count);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen extrefs = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen count = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (count > 0) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen sfile->attachment_pool =
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen pool_alloconly_create("sdbox attachment paths", 512);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen p_array_init(&sfile->attachment_paths,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen sfile->attachment_pool, count);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen for (i = 0; i < count; i++) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen const char *path = p_strdup(sfile->attachment_pool,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen extrefs[i].path);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen array_append(&sfile->attachment_paths, &path, 1);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return 0;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic int dbox_save_finish_write(struct mail_save_context *_ctx)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct dbox_file **files;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ctx->ctx.finished = TRUE;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (ctx->ctx.dbox_output == NULL)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -1;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (_ctx->data.save_date != (time_t)-1) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* we can't change ctime, but we can add the date to cache */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct index_mail *mail = (struct index_mail *)_ctx->dest_mail;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen uint32_t t = _ctx->data.save_date;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t));
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen dbox_save_end(&ctx->ctx);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen files = array_idx_modifiable(&ctx->files, array_count(&ctx->files) - 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!ctx->ctx.failed) T_BEGIN {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (dbox_save_mail_write_metadata(&ctx->ctx, *files) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx->ctx.failed = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } T_END;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (ctx->ctx.failed) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_expunge(ctx->ctx.trans, ctx->ctx.seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_file_append_rollback(&ctx->append_ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_file_unlink(*files);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_file_unref(files);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_delete(&ctx->files, array_count(&ctx->files) - 1, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen dbox_file_append_checkpoint(ctx->append_ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (dbox_file_append_commit(&ctx->append_ctx) < 0)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen ctx->ctx.failed = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dbox_file_close(*files);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_unref(&ctx->ctx.input);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->ctx.dbox_output = NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return ctx->ctx.failed ? -1 : 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenint sdbox_save_finish(struct mail_save_context *ctx)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int ret;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen ret = dbox_save_finish_write(ctx);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen index_save_context_free(ctx);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return ret;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenvoid sdbox_save_cancel(struct mail_save_context *_ctx)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ctx->failed = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (void)sdbox_save_finish(_ctx);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenstatic int dbox_save_assign_uids(struct sdbox_save_context *ctx,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen const ARRAY_TYPE(seq_range) *uids)
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct dbox_file *const *files;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct seq_range_iter iter;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen unsigned int i, count, n = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t uid;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen bool ret;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen seq_range_array_iter_init(&iter, uids);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen files = array_get(&ctx->files, &count);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen for (i = 0; i < count; i++) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)files[i];
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen ret = seq_range_array_iter_nth(&iter, n++, &uid);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen i_assert(ret);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (sdbox_file_assign_uid(sfile, uid) < 0)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen return -1;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return 0;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void dbox_save_unref_files(struct sdbox_save_context *ctx)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct dbox_file **files;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned int i, count;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen files = array_get_modifiable(&ctx->files, &count);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen for (i = 0; i < count; i++) {
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (ctx->ctx.failed) {
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen struct sdbox_file *sfile =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen (struct sdbox_file *)files[i];
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen (void)sdbox_file_unlink_aborted_save(sfile);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen dbox_file_unref(&files[i]);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen array_free(&ctx->files);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenint sdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen{
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen const struct mail_index_header *hdr;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(ctx->ctx.finished);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (array_count(&ctx->files) == 0) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* the mail must be freed in the commit_pre() */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (ctx->ctx.mail != NULL)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen mail_free(&ctx->ctx.mail);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (sdbox_sync_begin(ctx->mbox, SDBOX_SYNC_FLAG_FORCE |
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen SDBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen sdbox_transaction_save_rollback(_ctx);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return -1;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen }
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen /* update dbox header flags */
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view,
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen ctx->mbox->hdr_ext_id, offsetof(struct sdbox_index_header, flags));
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen /* assign UIDs for new messages */
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen &_t->changes->saved_uids);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (dbox_save_assign_uids(ctx, &_t->changes->saved_uids) < 0) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen sdbox_transaction_save_rollback(_ctx);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen return -1;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen }
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen if (ctx->ctx.mail != NULL)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen mail_free(&ctx->ctx.mail);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen _t->changes->uid_validity = hdr->uid_validity;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return 0;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid sdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct mail_index_transaction_commit_result *result)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (array_count(&ctx->files) == 0) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen sdbox_transaction_save_rollback(_ctx);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen result);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (sdbox_sync_finish(&ctx->sync_ctx, TRUE) < 0)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ctx->ctx.failed = TRUE;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen const char *box_path = mailbox_get_path(&ctx->mbox->box);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (fdatasync_path(box_path) < 0) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_storage_set_critical(storage,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen "fdatasync_path(%s) failed: %m", box_path);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen sdbox_transaction_save_rollback(_ctx);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid sdbox_transaction_save_rollback(struct mail_save_context *_ctx)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (!ctx->ctx.finished)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen sdbox_save_cancel(_ctx);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen dbox_save_unref_files(ctx);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (ctx->sync_ctx != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (void)sdbox_sync_finish(&ctx->sync_ctx, FALSE);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (ctx->ctx.mail != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_free(&ctx->ctx.mail);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen i_free(ctx);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen