sdbox-copy.c revision 2a77044395c864cc791cecd34b03002094f4973b
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "nfs-workarounds.h"
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen#include "fs-api.h"
55a210942dc7da58b2fd0b11bed8da6b030af5c1Timo Sirainen#include "dbox-save.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "dbox-attachment.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "sdbox-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "sdbox-file.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-copy.h"
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainensdbox_file_copy_attachments(struct sdbox_file *src_file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sdbox_file *dest_file)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dbox_storage *src_storage = src_file->file.storage;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct dbox_storage *dest_storage = dest_file->file.storage;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct fs_file *src_fsfile, *dest_fsfile;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen ARRAY_TYPE(mail_attachment_extref) extrefs;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen const struct mail_attachment_extref *extref;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen const char *extrefs_line, *src, *dest, *dest_relpath;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen pool_t pool;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (src_storage->attachment_dir == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* no attachments in source storage */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (dest_storage->attachment_dir == NULL ||
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen strcmp(src_storage->attachment_dir,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest_storage->attachment_dir) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* different attachment dirs between storages.
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen have to copy the slow way. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = sdbox_file_get_attachments(&src_file->file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &extrefs_line)) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret < 0 ? -1 : 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool = pool_alloconly_create("sdbox attachments copy", 1024);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen p_array_init(&extrefs, pool, 16);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!index_attachment_parse_extrefs(extrefs_line, pool, &extrefs)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(&dest_storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Can't copy %s with corrupted extref metadata: %s",
659fe5d24825b160cae512538088020d97a60239Timo Sirainen src_file->file.cur_path, extrefs_line);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_unref(&pool);
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest_file->attachment_pool =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_alloconly_create("sdbox attachment copy paths", 512);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen p_array_init(&dest_file->attachment_paths, dest_file->attachment_pool,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen array_count(&extrefs));
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = 1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen array_foreach(&extrefs, extref) T_BEGIN {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen src = t_strdup_printf("%s/%s", dest_storage->attachment_dir,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen sdbox_file_attachment_relpath(src_file, extref->path));
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen dest_relpath = p_strconcat(dest_file->attachment_pool,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen extref->path, "-",
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen guid_generate(), NULL);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen dest = t_strdup_printf("%s/%s", dest_storage->attachment_dir,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen dest_relpath);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen src_fsfile = fs_file_init(src_storage->attachment_fs, src,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen FS_OPEN_MODE_READONLY);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen dest_fsfile = fs_file_init(dest_storage->attachment_fs, dest,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen FS_OPEN_MODE_READONLY);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (fs_copy(src_fsfile, dest_fsfile) < 0) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen mail_storage_set_critical(&dest_storage->storage, "%s",
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen fs_last_error(dest_storage->attachment_fs));
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&dest_file->attachment_paths,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &dest_relpath, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fs_file_deinit(&src_fsfile);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fs_file_deinit(&dest_fsfile);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_unref(&pool);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainensdbox_copy_hardlink(struct mail_save_context *_ctx, struct mail *mail)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sdbox_mailbox *dest_mbox =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct sdbox_mailbox *)_ctx->transaction->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sdbox_mailbox *src_mbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dbox_file *src_file, *dest_file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *src_path, *dest_path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(mail->box->storage->name, SDBOX_STORAGE_NAME) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen src_mbox = (struct sdbox_mailbox *)mail->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Source storage isn't sdbox, can't hard link */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen src_file = sdbox_file_init(src_mbox, mail->uid);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest_file = sdbox_file_init(dest_mbox, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->ctx.data.flags &= ~DBOX_INDEX_FLAG_ALT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen src_path = src_file->primary_path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest_path = dest_file->primary_path;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen ret = nfs_safe_link(src_path, dest_path, FALSE);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (ret < 0 && errno == ENOENT && src_file->alt_path != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen src_path = src_file->alt_path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (dest_file->alt_path != NULL) {
8a3d609fdd84f5938c82e8e7eeb84a24ab41b317Timo Sirainen dest_path = dest_file->cur_path = dest_file->alt_path;
8a3d609fdd84f5938c82e8e7eeb84a24ab41b317Timo Sirainen ctx->ctx.data.flags |= DBOX_INDEX_FLAG_ALT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = nfs_safe_link(src_path, dest_path, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ECANTLINK(errno))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (errno == ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* try if the fallback copying code can still
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen read the file (the mail could still have the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream open) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _ctx->transaction->box->storage,
"link(%s, %s) failed: %m", src_path, dest_path);
}
dbox_file_unref(&src_file);
dbox_file_unref(&dest_file);
return ret;
}
ret = sdbox_file_copy_attachments((struct sdbox_file *)src_file,
(struct sdbox_file *)dest_file);
if (ret <= 0) {
(void)sdbox_file_unlink_aborted_save((struct sdbox_file *)dest_file);
dbox_file_unref(&src_file);
dbox_file_unref(&dest_file);
return ret;
}
((struct sdbox_file *)dest_file)->written_to_disk = TRUE;
dbox_save_add_to_index(ctx);
index_copy_cache_fields(_ctx, mail, ctx->seq);
sdbox_save_add_file(_ctx, dest_file);
if (_ctx->dest_mail != NULL)
mail_set_seq_saving(_ctx->dest_mail, ctx->seq);
dbox_file_unref(&src_file);
return 1;
}
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 (mail_storage_copy_can_use_hardlink(mail->box, &mbox->box) &&
_ctx->data.guid == NULL) {
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);
}