maildir-copy.c revision 7ede6554e451ec039a67beec7d6ee4aff61d386e
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainenstatic int do_save_mail_size(struct maildir_mailbox *mbox, const char *path,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
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);
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen ctx->dest_fname = strrchr(str_c(ctx->dest_path), '/') + 1;
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainenstatic void do_save_mail_vsize(const char *path, struct hardlink_ctx *ctx)
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen str_insert(ctx->dest_path, ctx->base_end_pos, str);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ctx->dest_fname = strrchr(str_c(ctx->dest_path), '/') + 1;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainenstatic int do_hardlink(struct maildir_mailbox *mbox, const char *path,
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if ((ret = do_save_mail_size(mbox, path, ctx)) <= 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* set virtual size if it's in the original file name */
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (mbox->storage->storage.set->mail_nfs_storage)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ret = nfs_safe_link(path, str_c(ctx->dest_path), FALSE);
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
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 mail_storage_set_critical(&mbox->storage->storage,
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen "link(%s, %s) failed: %m",
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainenmaildir_copy_hardlink(struct maildir_transaction_context *t, struct mail *mail,
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
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 */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Can't hard link files from the source storage */
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen t->save_ctx = maildir_save_transaction_init(t);
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen /* don't allow caller to specify recent flag */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen do_ctx.dest_path = str_new(default_pool, 512);
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen if (dest_mbox->storage->set->maildir_copy_preserve_filename &&
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. */
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen maildir_uidlist_refresh(dest_mbox->uidlist) >= 0 &&
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen maildir_uidlist_get_full_filename(dest_mbox->uidlist,
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();
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 (keywords == NULL || keywords->count == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* no keywords, hardlink directly to destination */
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path) +
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* keywords, hardlink to tmp/ with basename and later when we
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen have uidlist locked, move it to new/cur. */
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen do_ctx.base_end_pos = str_len(do_ctx.dest_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* maildir */
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen /* raw / lda */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME,
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (do_hardlink(dest_mbox, path, &do_ctx) < 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* couldn't copy with hardlinking, fallback to copying */
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (keywords == NULL || keywords->count == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* hardlinked to destination, set hardlinked-flag */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* hardlinked to tmp/, treat as normal copied mail */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen maildir_save_add(t, do_ctx.dest_fname, flags, keywords,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenmaildir_compatible_file_modes(struct mailbox *box1, struct mailbox *box2)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return box1->file_create_mode == box2->file_create_mode &&
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen box1->file_create_gid == box2->file_create_gid;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainenint maildir_copy(struct mail_save_context *ctx, struct mail *mail)
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen (struct maildir_transaction_context *)ctx->transaction;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (mbox->storage->set->maildir_copy_with_hardlinks &&
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen maildir_compatible_file_modes(&mbox->ibox.box, mail->box)) {
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen ret = maildir_copy_hardlink(t, mail, ctx->flags,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* non-fatal hardlinking failure, try the slow way */