]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
sdbox: Copying is now done with hard links.
authorTimo Sirainen <tss@iki.fi>
Sun, 21 Mar 2010 16:12:24 +0000 (18:12 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 21 Mar 2010 16:12:24 +0000 (18:12 +0200)
--HG--
branch : HEAD

src/lib-storage/index/dbox-common/dbox-save.h
src/lib-storage/index/dbox-single/Makefile.am
src/lib-storage/index/dbox-single/sdbox-copy.c [new file with mode: 0644]
src/lib-storage/index/dbox-single/sdbox-file.c
src/lib-storage/index/dbox-single/sdbox-file.h
src/lib-storage/index/dbox-single/sdbox-save.c
src/lib-storage/index/dbox-single/sdbox-storage.h

index ac7712a2385b395eb998cda92f59c4b54d80250d..cc61dd0879a27c66b453a9f889fec5976573e7be 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef DBOX_SAVE_H
 #define DBOX_SAVE_H
 
+#include "dbox-storage.h"
+
 struct dbox_save_context {
        struct mail_save_context ctx;
        struct mail_index_transaction *trans;
index 3dcceaaba87e74f0612667a306bab63fc418c4a3..7b97a28f569db612bb6c7b98770af41c787748a8 100644 (file)
@@ -11,6 +11,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-storage/index/dbox-common
 
 libstorage_dbox_single_la_SOURCES = \
+       sdbox-copy.c \
        sdbox-file.c \
        sdbox-mail.c \
        sdbox-save.c \
diff --git a/src/lib-storage/index/dbox-single/sdbox-copy.c b/src/lib-storage/index/dbox-single/sdbox-copy.c
new file mode 100644 (file)
index 0000000..8b9f6b8
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "nfs-workarounds.h"
+#include "dbox-save.h"
+#include "sdbox-storage.h"
+#include "sdbox-file.h"
+#include "mail-copy.h"
+
+static int
+sdbox_copy_hardlink(struct mail_save_context *_ctx, struct mail *mail)
+{
+       struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
+       struct sdbox_mailbox *dest_mbox =
+               (struct sdbox_mailbox *)_ctx->transaction->box;
+       struct sdbox_mailbox *src_mbox;
+       struct dbox_file *src_file, *dest_file;
+       const char *src_path;
+       int ret;
+
+       if (strcmp(mail->box->storage->name, SDBOX_STORAGE_NAME) == 0)
+               src_mbox = (struct sdbox_mailbox *)mail->box;
+       else {
+               /* Source storage isn't sdbox, can't hard link */
+               return 0;
+       }
+
+       src_file = sdbox_file_init(src_mbox, mail->uid);
+       dest_file = sdbox_file_init(dest_mbox, 0);
+
+       src_path = src_file->primary_path;
+       ret = nfs_safe_link(src_path, dest_file->cur_path, FALSE);
+       if (ret < 0 && errno == ENOENT && src_file->alt_path != NULL) {
+               src_path = src_file->alt_path;
+               ret = nfs_safe_link(src_path, dest_file->cur_path, FALSE);
+       }
+       if (ret < 0) {
+               if (ECANTLINK(errno))
+                       return 0;
+
+               if (errno == ENOENT)
+                       mail_set_expunged(mail);
+               else {
+                       mail_storage_set_critical(
+                               _ctx->transaction->box->storage,
+                               "link(%s, %s) failed: %m",
+                               src_path, dest_file->cur_path);
+               }
+               return -1;
+       }
+
+       dbox_save_add_to_index(ctx);
+       sdbox_save_add_file(_ctx, dest_file);
+       if (_ctx->dest_mail != NULL)
+               mail_set_seq(_ctx->dest_mail, ctx->seq);
+       return 1;
+}
+
+static bool
+sdbox_compatible_file_modes(struct mailbox *box1, struct mailbox *box2)
+{
+       return box1->file_create_mode == box2->file_create_mode &&
+               box1->file_create_gid == box2->file_create_gid;
+}
+
+int sdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
+{
+       struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
+       struct mailbox_transaction_context *_t = _ctx->transaction;
+       struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)_t->box;
+       int ret;
+
+       i_assert((_t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
+
+       ctx->finished = TRUE;
+       if (sdbox_compatible_file_modes(&mbox->box, mail->box)) {
+               T_BEGIN {
+                       ret = sdbox_copy_hardlink(_ctx, mail);
+               } T_END;
+
+               if (ret != 0) {
+                       index_save_context_free(_ctx);
+                       return ret > 0 ? 0 : -1;
+               }
+
+               /* non-fatal hardlinking failure, try the slow way */
+       }
+       return mail_storage_copy(_ctx, mail);
+}
index 15a4f9c1bef6a5558d6dd57204c58a5b8df97db7..22210b33a4d9c12756eb881f10210f87712bb168 100644 (file)
@@ -45,15 +45,19 @@ struct dbox_file *sdbox_file_init(struct sdbox_mailbox *mbox, uint32_t uid)
                }
        } T_END;
        dbox_file_init(&file->file);
-
-       if (uid == 0) {
-               file->file.fd = file->file.storage->v.
-                       file_create_fd(&file->file, file->file.primary_path,
-                                      FALSE);
-       }
        return &file->file;
 }
 
+struct dbox_file *sdbox_file_create(struct sdbox_mailbox *mbox)
+{
+       struct dbox_file *file;
+
+       file = sdbox_file_init(mbox, 0);
+       file->fd = file->storage->v.
+               file_create_fd(file, file->primary_path, FALSE);
+       return file;
+}
+
 int sdbox_file_assign_uid(struct sdbox_file *file, uint32_t uid)
 {
        const char *old_path, *new_fname, *new_path;
index 58df467a8bcf74ea965357039d9cac5cab1b37d4..4d4c08810054fdd487e8a973789fcb039e27f6da 100644 (file)
@@ -12,6 +12,7 @@ struct sdbox_file {
 };
 
 struct dbox_file *sdbox_file_init(struct sdbox_mailbox *mbox, uint32_t uid);
+struct dbox_file *sdbox_file_create(struct sdbox_mailbox *mbox);
 
 /* Assign UID for a newly created file (by renaming it) */
 int sdbox_file_assign_uid(struct sdbox_file *file, uint32_t uid);
index ca1d2a0bd16916c1ec5f02a45f24e11231621b33..86db14dcd4b866ce10a1d432a696900a9bbeeb13 100644 (file)
@@ -70,13 +70,20 @@ sdbox_save_alloc(struct mailbox_transaction_context *t)
        return t->save_ctx;
 }
 
+void sdbox_save_add_file(struct mail_save_context *_ctx, struct dbox_file *file)
+{
+       struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
+
+       array_append(&ctx->files, &file, 1);
+}
+
 int sdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
 {
        struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
        struct dbox_file *file;
        int ret;
 
-       file = sdbox_file_init(ctx->mbox, 0);
+       file = sdbox_file_create(ctx->mbox);
        ctx->append_ctx = dbox_file_append_init(file);
        ret = dbox_file_get_append_stream(ctx->append_ctx,
                                          &ctx->ctx.dbox_output);
@@ -93,7 +100,7 @@ int sdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
        if (ctx->first_saved_seq == 0)
                ctx->first_saved_seq = ctx->ctx.seq;
 
-       array_append(&ctx->files, &file, 1);
+       sdbox_save_add_file(_ctx, file);
        return ctx->ctx.failed ? -1 : 0;
 }
 
@@ -295,13 +302,3 @@ void sdbox_transaction_save_rollback(struct mail_save_context *_ctx)
                mail_free(&ctx->ctx.mail);
        i_free(ctx);
 }
-
-int sdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
-{
-       struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
-
-       /* FIXME: use hard linking */
-
-       ctx->finished = TRUE;
-       return mail_storage_copy(_ctx, mail);
-}
index c32d9d4d79cd4dfc1aefa85bbdec723b812e7564..1728a317514d41239c756b0edf714742cb292b4f 100644 (file)
@@ -53,6 +53,7 @@ void sdbox_save_cancel(struct mail_save_context *ctx);
 
 struct dbox_file *
 sdbox_save_file_get_file(struct mailbox_transaction_context *t, uint32_t seq);
+void sdbox_save_add_file(struct mail_save_context *ctx, struct dbox_file *file);
 
 int sdbox_transaction_save_commit_pre(struct mail_save_context *ctx);
 void sdbox_transaction_save_commit_post(struct mail_save_context *ctx,