maildir-save.c revision fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic int maildir_file_move(struct maildir_save_context *ctx,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen /* if we have flags, we'll move it to cur/ directly, because files in
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen new/ directory can't have flags. alternative would be to write it
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen in new/ and set the flags dirty in index file, but in that case
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen external MUAs would see wrong flags. */
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen tmp_path = t_strconcat(ctx->tmpdir, "/", basename, NULL);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen t_strconcat(ctx->newdir, "/", basename, NULL) :
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen mail_storage_set_error(ctx->ibox->box.storage,
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen "Not enough disk space");
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen "link(%s, %s) failed: %m", tmp_path, new_path);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen if (unlink(tmp_path) < 0 && errno != ENOENT) {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenmaildir_save_transaction_init(struct maildir_transaction_context *t)
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen pool = pool_alloconly_create("maildir_save_context", 4096);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx = p_new(pool, struct maildir_save_context, 1);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->tmpdir = p_strconcat(pool, ibox->path, "/tmp", NULL);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->newdir = p_strconcat(pool, ibox->path, "/new", NULL);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen ctx->curdir = p_strconcat(pool, ibox->path, "/cur", NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->save_crlf = getenv("MAIL_SAVE_CRLF") != NULL;
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainenmaildir_save_init(struct mailbox_transaction_context *_t,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen time_t received_date, int timezone_offset __attr_unused__,
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct istream *input, int want_mail __attr_unused__)
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen t->save_ctx = maildir_save_transaction_init(t);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* create a new file in tmp/ directory */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen ctx->fd = maildir_create_tmp(ibox, ctx->tmpdir, ibox->mail_create_mode,
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen output = o_stream_create_file(ctx->fd, system_pool, 0, FALSE);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* now, we want to be able to rollback the whole append session,
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen so we'll just store the name of this temp file and move it later
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen into new/ or cur/. if dest_fname is NULL, it's moved to new/,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen otherwise to cur/. */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen maildir_filename_set_flags(fname, flags, NULL); // FIXME
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mf = p_new(ctx->pool, struct maildir_filename, 1);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* insert into index */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, flags);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainenint maildir_save_continue(struct mail_save_context *_ctx)
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainenint maildir_save_finish(struct mail_save_context *_ctx, struct mail *dest_mail)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
1618629fd55e914c8d2e28fc01b8264613f00a99Timo Sirainen /* tmp file creation failed */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen path = t_strconcat(ctx->tmpdir, "/", ctx->files->basename, NULL);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* set the received_date by modifying mtime */
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen /* FIXME: when saving multiple messages, we could get better
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen performance if we left the fd open and fsync()ed it later */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen /* delete the tmp file */
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_error(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen "Not enough disk space");
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen } else if (errno != 0) {
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainenvoid maildir_save_cancel(struct mail_save_context *_ctx)
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainenstatic void maildir_save_commit_abort(struct maildir_save_context *ctx,
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen /* try to unlink the mails already moved */
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen for (mf = ctx->files; mf != pos; mf = mf->next) {
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen str_printfa(str, "%s/%s", ctx->newdir, mf->basename);
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen str_printfa(str, "%s/%s", ctx->curdir, mf->dest);
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainenint maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen sync_ctx = maildir_sync_index_begin(ctx->ibox);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen ret = maildir_uidlist_lock(ctx->ibox->uidlist);
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen /* error or timeout - our transaction is broken */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (maildir_sync_index_finish(sync_ctx, TRUE) < 0) {
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen first_uid = maildir_uidlist_get_next_uid(ctx->ibox->uidlist);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen mail_index_append_assign_uids(ctx->trans, first_uid, &last_uid);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* move them into new/ */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen ctx->sync_ctx = maildir_uidlist_sync_init(ctx->ibox->uidlist, TRUE);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen fname = mf->dest != NULL ? mf->dest : mf->basename;
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen if (maildir_file_move(ctx, mf->basename, mf->dest) < 0 ||
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen (void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainenvoid maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen /* can't do anything anymore if we fail */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen (void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainenvoid maildir_transaction_save_rollback(struct maildir_save_context *ctx)
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen /* clean up the temp files */
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {