maildir-copy.c revision 7ede6554e451ec039a67beec7d6ee4aff61d386e
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "nfs-workarounds.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-uidlist.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-filename.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-keywords.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-sync.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-mail.h"
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include "mail-copy.h"
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <stdlib.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <unistd.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <sys/stat.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainenstruct hardlink_ctx {
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen string_t *dest_path;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen const char *dest_fname;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int base_end_pos;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int size_set:1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int vsize_set:1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int success:1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen unsigned int preserve_filename:1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen};
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainenstatic int do_save_mail_size(struct maildir_mailbox *mbox, const char *path,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct hardlink_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *fname, *str;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct stat st;
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen uoff_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen fname = strrchr(path, '/');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fname = fname != NULL ? fname + 1 : path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen &size)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stat(path, &st) < 0) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (errno == ENOENT)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen "stat(%s) failed: %m", path);
1a073dd6184645b026583274e05afba10dcc20bbTimo Sirainen return -1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen size = st.st_size;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_strdup_printf(",%c=%"PRIuUOFF_T, MAILDIR_EXTRA_FILE_SIZE, size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen str_insert(ctx->dest_path, ctx->base_end_pos, str);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen ctx->dest_fname = strrchr(str_c(ctx->dest_path), '/') + 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx->size_set = TRUE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen}
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainenstatic void do_save_mail_vsize(const char *path, struct hardlink_ctx *ctx)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen{
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen const char *fname, *str;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen uoff_t size;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen fname = strrchr(path, '/');
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen fname = fname != NULL ? fname + 1 : path;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen &size))
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen return;
b6d817f0effeff645aadc01fd468a7d4084ba1f2Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen str = t_strdup_printf(",%c=%"PRIuUOFF_T,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen MAILDIR_EXTRA_VIRTUAL_SIZE, size);
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen str_insert(ctx->dest_path, ctx->base_end_pos, str);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ctx->dest_fname = strrchr(str_c(ctx->dest_path), '/') + 1;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen ctx->vsize_set = TRUE;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen}
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainenstatic int do_hardlink(struct maildir_mailbox *mbox, const char *path,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct hardlink_ctx *ctx)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen int ret;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (!ctx->preserve_filename) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (mbox->storage->save_size_in_filename &&
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen !ctx->size_set) {
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if ((ret = do_save_mail_size(mbox, path, ctx)) <= 0)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return ret;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* set virtual size if it's in the original file name */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (!ctx->vsize_set)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen do_save_mail_vsize(path, ctx);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen }
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (mbox->storage->storage.set->mail_nfs_storage)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ret = nfs_safe_link(path, str_c(ctx->dest_path), FALSE);
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen else
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen ret = link(path, str_c(ctx->dest_path));
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (ret < 0) {
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (errno == ENOENT)
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen return 0;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (ENOSPACE(errno)) {
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen return -1;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen /* we could handle the EEXIST condition by changing the
6288d3611eda14a017dae9927b73f46afb646c96Timo Sirainen filename, but it practically never happens so just fallback
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen to standard copying for the rare cases when it does. */
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (errno == EACCES || ECANTLINK(errno) || errno == EEXIST)
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen return 1;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen "link(%s, %s) failed: %m",
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen path, str_c(ctx->dest_path));
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen return -1;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen ctx->success = TRUE;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen return 1;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen}
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainenstatic int
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainenmaildir_copy_hardlink(struct maildir_transaction_context *t, struct mail *mail,
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail *dest_mail)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct maildir_mailbox *dest_mbox =
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen (struct maildir_mailbox *)t->ictx.ibox;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen struct maildir_mailbox *src_mbox;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen struct hardlink_ctx do_ctx;
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen const char *path, *filename = NULL;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (strcmp(mail->box->storage->name, MAILDIR_STORAGE_NAME) == 0)
2e937ed8585299b2e879a28314902a5f644813d2Timo Sirainen src_mbox = (struct maildir_mailbox *)mail->box;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen else if (strcmp(mail->box->storage->name, "raw") == 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* lda uses raw format */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen src_mbox = NULL;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen } else {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Can't hard link files from the source storage */
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen if (t->save_ctx == NULL)
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen t->save_ctx = maildir_save_transaction_init(t);
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen /* don't allow caller to specify recent flag */
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen flags &= ~MAIL_RECENT;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen if (dest_mbox->ibox.keep_recent)
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen flags |= MAIL_RECENT;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen memset(&do_ctx, 0, sizeof(do_ctx));
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen do_ctx.dest_path = str_new(default_pool, 512);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen if (dest_mbox->storage->set->maildir_copy_preserve_filename &&
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen src_mbox != NULL) {
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen enum maildir_uidlist_rec_flag src_flags;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen const char *src_fname;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen /* see if the filename exists in destination maildir's
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen uidlist. if it doesn't, we can use it. otherwise generate
6f25019b337e27600159b596824da08732965576Timo Sirainen a new filename. FIXME: There's a race condition here if
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen another process is just doing the same copy. */
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (maildir_uidlist_lookup(src_mbox->uidlist,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail->uid, &src_flags,
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen &src_fname) > 0 &&
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen maildir_uidlist_refresh(dest_mbox->uidlist) >= 0 &&
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen maildir_uidlist_get_full_filename(dest_mbox->uidlist,
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen src_fname) == NULL)
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen filename = t_strcut(src_fname, ':');
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen if (filename == NULL) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* the generated filename is _always_ unique, so we don't
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen bother trying to check if it already exists */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen do_ctx.dest_fname = maildir_filename_generate();
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen do_ctx.dest_fname = filename;
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen do_ctx.preserve_filename = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* FIXME: We could hardlink the files directly to destination, but
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen that would require checking if someone else had already assigned
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen UIDs for them after we have the uidlist locked. Index would also
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen need to be properly not-updated somehow.. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen#if 0
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (keywords == NULL || keywords->count == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* no keywords, hardlink directly to destination */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (flags == MAIL_RECENT) {
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen str_printfa(do_ctx.dest_path, "%s/new/%s",
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen dest_mbox->path, do_ctx.dest_fname);
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen str_printfa(do_ctx.dest_path, "%s/cur/",
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen dest_mbox->path);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path) +
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen strlen(do_ctx.dest_fname);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_append(do_ctx.dest_path,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen maildir_filename_set_flags(NULL,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen do_ctx.dest_fname,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen flags, NULL));
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen#endif
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* keywords, hardlink to tmp/ with basename and later when we
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen have uidlist locked, move it to new/cur. */
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen str_printfa(do_ctx.dest_path, "%s/tmp/%s",
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen dest_mbox->path, do_ctx.dest_fname);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (src_mbox != NULL) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* maildir */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (maildir_file_do(src_mbox, mail->uid,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen do_hardlink, &do_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen /* raw / lda */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &path) < 0 || *path == '\0')
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (do_hardlink(dest_mbox, path, &do_ctx) < 0)
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen return -1;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (!do_ctx.success) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* couldn't copy with hardlinking, fallback to copying */
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen return 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen#if 0
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (keywords == NULL || keywords->count == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* hardlinked to destination, set hardlinked-flag */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen maildir_save_add(t, do_ctx.dest_fname,
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen flags | MAILDIR_SAVE_FLAG_HARDLINK, NULL,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen dest_mail);
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen } else
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen#endif
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* hardlinked to tmp/, treat as normal copied mail */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen maildir_save_add(t, do_ctx.dest_fname, flags, keywords,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen dest_mail);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic bool
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenmaildir_compatible_file_modes(struct mailbox *box1, struct mailbox *box2)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen{
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return box1->file_create_mode == box2->file_create_mode &&
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen box1->file_create_gid == box2->file_create_gid;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainenint maildir_copy(struct mail_save_context *ctx, struct mail *mail)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen{
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen struct maildir_transaction_context *t =
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen (struct maildir_transaction_context *)ctx->transaction;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen int ret;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (mbox->storage->set->maildir_copy_with_hardlinks &&
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen maildir_compatible_file_modes(&mbox->ibox.box, mail->box)) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen T_BEGIN {
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen ret = maildir_copy_hardlink(t, mail, ctx->flags,
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen ctx->keywords,
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen ctx->dest_mail);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen } T_END;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (ret != 0) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen index_save_context_free(ctx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return ret > 0 ? 0 : -1;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* non-fatal hardlinking failure, try the slow way */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return mail_storage_copy(ctx, mail);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen