maildir-copy.c revision 1c890e28803578f778c85450172a388879bd4823
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "lib.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "array.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "ioloop.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "maildir-storage.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "index-mail.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-copy.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <stdlib.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <unistd.h>
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct maildir_copy_context {
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen struct maildir_mailbox *mbox;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int hardlink;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_t pool;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct rollback *rollbacks;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct hardlink_ctx {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *dest_path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int found;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct rollback {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct rollback *next;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const char *fname;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstatic int do_hardlink(struct maildir_mailbox *mbox, const char *path,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen void *context)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen{
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen struct hardlink_ctx *ctx = context;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (link(path, ctx->dest_path) < 0) {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (errno == ENOENT)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen return 0;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (ENOSPACE(errno)) {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen mail_storage_set_error(STORAGE(mbox->storage),
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen "Not enough disk space");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (errno == EACCES || errno == EXDEV)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen return 1;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen mail_storage_set_critical(STORAGE(mbox->storage),
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen "link(%s, %s) failed: %m",
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen path, ctx->dest_path);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen return -1;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen }
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
11352dc3e4b29f3d2763c82f8ea4f99e8daf4fa3Timo Sirainen ctx->found = TRUE;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen return 1;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen}
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenstatic int maildir_copy_hardlink(struct mail *mail,
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen struct maildir_copy_context *ctx)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct index_mail *imail = (struct index_mail *)mail;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)imail->ibox;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct hardlink_ctx do_ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct rollback *rb;
cd8507179823de33d6e8242e10dbc15d136245b5Timo Sirainen enum mail_flags flags;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *keywords;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *dest_fname;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_t ARRAY_DEFINE(keywords_arr, const char *);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen unsigned int count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen flags = mail_get_flags(mail);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen keywords = mail_get_keywords(mail);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dest_fname = maildir_generate_tmp_filename(&ioloop_timeval);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen count = strarray_length(keywords);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (count > 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ARRAY_CREATE(&keywords_arr, pool_datastack_create(),
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *, count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append(&keywords_arr, keywords, count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dest_fname = maildir_filename_set_flags(NULL, // FIXME: !!!
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dest_fname, flags, count != 0 ?
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen &keywords_arr : NULL);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memset(&do_ctx, 0, sizeof(do_ctx));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen do_ctx.dest_path =
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen t_strconcat(ctx->mbox->path, "/new/", dest_fname, NULL);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (maildir_file_do(mbox, imail->mail.mail.uid,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen do_hardlink, &do_ctx) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!do_ctx.found)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen rb = p_new(ctx->pool, struct rollback, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen rb->fname = p_strdup(ctx->pool, dest_fname);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen rb->next = ctx->rollbacks;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->rollbacks = rb;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct maildir_copy_context *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmaildir_copy_init(struct maildir_mailbox *mbox)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct maildir_copy_context *ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_t pool;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool = pool_alloconly_create("maildir_copy_context", 2048);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx = p_new(pool, struct maildir_copy_context, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->pool = pool;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen ctx->hardlink = FALSE; //FIXME:broken! getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen ctx->mbox = mbox;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen return ctx;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen}
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenint maildir_transaction_copy_commit(struct maildir_copy_context *ctx)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen{
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen pool_unref(ctx->pool);
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen return 0;
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen}
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenvoid maildir_transaction_copy_rollback(struct maildir_copy_context *ctx)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen{
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen struct rollback *rb;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen for (rb = ctx->rollbacks; rb != NULL; rb = rb->next) {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen t_push();
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen (void)unlink(t_strconcat(ctx->mbox->path,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen "/new/", rb->fname, NULL));
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen t_pop();
11352dc3e4b29f3d2763c82f8ea4f99e8daf4fa3Timo Sirainen }
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen pool_unref(ctx->pool);
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen}
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainenint maildir_copy(struct mailbox_transaction_context *_t, struct mail *mail,
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen struct mail *dest_mail)
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen{
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen struct maildir_transaction_context *t =
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen (struct maildir_transaction_context *)_t;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen struct maildir_copy_context *ctx;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen int ret;
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen if (t->copy_ctx == NULL)
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen t->copy_ctx = maildir_copy_init(mbox);
8305127d1074cf9a1e25dec9be2735276462079dTimo Sirainen ctx = t->copy_ctx;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen if (ctx->hardlink &&
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen mail->box->storage == STORAGE(ctx->mbox->storage)) {
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen // FIXME: handle dest_mail
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen t_push();
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen ret = maildir_copy_hardlink(mail, ctx);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen t_pop();
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (ret > 0)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret < 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen /* non-fatal hardlinking failure, try the slow way */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen return mail_storage_copy(_t, mail, dest_mail);
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen}
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen