From: Timo Sirainen Date: Sun, 21 Mar 2010 16:12:24 +0000 (+0200) Subject: sdbox: Copying is now done with hard links. X-Git-Tag: 2.0.beta4~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e8762c2b4914db7997fa9eb644a91586952d1876;p=thirdparty%2Fdovecot%2Fcore.git sdbox: Copying is now done with hard links. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/dbox-common/dbox-save.h b/src/lib-storage/index/dbox-common/dbox-save.h index ac7712a238..cc61dd0879 100644 --- a/src/lib-storage/index/dbox-common/dbox-save.h +++ b/src/lib-storage/index/dbox-common/dbox-save.h @@ -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; diff --git a/src/lib-storage/index/dbox-single/Makefile.am b/src/lib-storage/index/dbox-single/Makefile.am index 3dcceaaba8..7b97a28f56 100644 --- a/src/lib-storage/index/dbox-single/Makefile.am +++ b/src/lib-storage/index/dbox-single/Makefile.am @@ -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 index 0000000000..8b9f6b8072 --- /dev/null +++ b/src/lib-storage/index/dbox-single/sdbox-copy.c @@ -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); +} diff --git a/src/lib-storage/index/dbox-single/sdbox-file.c b/src/lib-storage/index/dbox-single/sdbox-file.c index 15a4f9c1be..22210b33a4 100644 --- a/src/lib-storage/index/dbox-single/sdbox-file.c +++ b/src/lib-storage/index/dbox-single/sdbox-file.c @@ -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; diff --git a/src/lib-storage/index/dbox-single/sdbox-file.h b/src/lib-storage/index/dbox-single/sdbox-file.h index 58df467a8b..4d4c088100 100644 --- a/src/lib-storage/index/dbox-single/sdbox-file.h +++ b/src/lib-storage/index/dbox-single/sdbox-file.h @@ -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); diff --git a/src/lib-storage/index/dbox-single/sdbox-save.c b/src/lib-storage/index/dbox-single/sdbox-save.c index ca1d2a0bd1..86db14dcd4 100644 --- a/src/lib-storage/index/dbox-single/sdbox-save.c +++ b/src/lib-storage/index/dbox-single/sdbox-save.c @@ -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); -} diff --git a/src/lib-storage/index/dbox-single/sdbox-storage.h b/src/lib-storage/index/dbox-single/sdbox-storage.h index c32d9d4d79..1728a31751 100644 --- a/src/lib-storage/index/dbox-single/sdbox-storage.h +++ b/src/lib-storage/index/dbox-single/sdbox-storage.h @@ -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,