sdbox-copy.c revision 7f735cb86b2d8abd8f230089065eacfc24e9e5d6
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "lib.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "nfs-workarounds.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "fs-api.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "dbox-save.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen#include "dbox-attachment.h"
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen#include "sdbox-storage.h"
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen#include "sdbox-file.h"
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen#include "mail-copy.h"
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainenstatic int
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainensdbox_file_copy_attachments(struct sdbox_file *src_file,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen struct sdbox_file *dest_file)
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen{
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen struct dbox_storage *src_storage = src_file->file.storage;
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen struct dbox_storage *dest_storage = dest_file->file.storage;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen ARRAY_TYPE(mail_attachment_extref) extrefs;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen const struct mail_attachment_extref *extref;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen const char *extrefs_line, *src, *dest, *dest_relpath;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen pool_t pool;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen int ret;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen if (src_storage->attachment_dir == NULL) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen /* no attachments in source storage */
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return 1;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen if (dest_storage->attachment_dir == NULL ||
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi strcmp(src_storage->attachment_dir,
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi dest_storage->attachment_dir) != 0) {
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen /* different attachment dirs between storages.
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi have to copy the slow way. */
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi return 0;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainen if ((ret = sdbox_file_get_attachments(&src_file->file,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen &extrefs_line)) <= 0)
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return ret < 0 ? -1 : 1;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen pool = pool_alloconly_create("sdbox attachments copy", 1024);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen p_array_init(&extrefs, pool, 16);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen if (!dbox_attachment_parse_extref(extrefs_line, pool, &extrefs)) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen mail_storage_set_critical(&dest_storage->storage,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen "Can't copy %s with corrupted extref metadata: %s",
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen src_file->file.cur_path, extrefs_line);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen pool_unref(&pool);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return -1;
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen }
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen dest_file->attachment_pool =
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen pool_alloconly_create("sdbox attachment copy paths", 512);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen p_array_init(&dest_file->attachment_paths, dest_file->attachment_pool,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen array_count(&extrefs));
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen ret = 1;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen array_foreach(&extrefs, extref) T_BEGIN {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen src = t_strdup_printf("%s/%s", dest_storage->attachment_dir,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen sdbox_file_attachment_relpath(src_file, extref->path));
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dest_relpath = p_strconcat(dest_file->attachment_pool,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen extref->path, "-",
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen mail_generate_guid_string(), NULL);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dest = t_strdup_printf("%s/%s", dest_storage->attachment_dir,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dest_relpath);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen if (fs_link(dest_storage->attachment_fs, src, dest) < 0) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen mail_storage_set_critical(&dest_storage->storage, "%s",
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen fs_last_error(dest_storage->attachment_fs));
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen ret = -1;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen } else {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen array_append(&dest_file->attachment_paths,
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen &dest_relpath, 1);
4e8e7a93628b4ed60aaaa47c6f72c1433f21e81dTimo Sirainen }
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi } T_END;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen pool_unref(&pool);
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi return ret;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen}
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainenstatic int
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainensdbox_copy_hardlink(struct mail_save_context *_ctx, struct mail *mail)
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen{
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen struct sdbox_mailbox *dest_mbox =
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen (struct sdbox_mailbox *)_ctx->transaction->box;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen struct sdbox_mailbox *src_mbox;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen struct dbox_file *src_file, *dest_file;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen const char *src_path;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen int ret;
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen if (strcmp(mail->box->storage->name, SDBOX_STORAGE_NAME) == 0)
86bdb644d147a73df85abce4325254d694217a5fTimo Sirainen src_mbox = (struct sdbox_mailbox *)mail->box;
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi else {
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi /* Source storage isn't sdbox, can't hard link */
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi return 0;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen src_file = sdbox_file_init(src_mbox, mail->uid);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen dest_file = sdbox_file_init(dest_mbox, 0);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen src_path = src_file->primary_path;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = nfs_safe_link(src_path, dest_file->cur_path, FALSE);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (ret < 0 && errno == ENOENT && src_file->alt_path != NULL) {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen src_path = src_file->alt_path;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = nfs_safe_link(src_path, dest_file->cur_path, FALSE);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen }
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (ret < 0) {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (ECANTLINK(errno))
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ret = 0;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen else if (errno == ENOENT)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen mail_set_expunged(mail);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen else {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen mail_storage_set_critical(
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen _ctx->transaction->box->storage,
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen "link(%s, %s) failed: %m",
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen src_path, dest_file->cur_path);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dbox_file_unref(&src_file);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dbox_file_unref(&dest_file);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return ret;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen ret = sdbox_file_copy_attachments((struct sdbox_file *)src_file,
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen (struct sdbox_file *)dest_file);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen if (ret <= 0) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen sdbox_file_unlink_aborted_save((struct sdbox_file *)dest_file);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen dbox_file_unref(&src_file);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dbox_file_unref(&dest_file);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return ret;
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen dbox_save_add_to_index(ctx);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen index_copy_cache_fields(_ctx, mail, ctx->seq);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen sdbox_save_add_file(_ctx, dest_file);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (_ctx->dest_mail != NULL) {
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen mail_set_seq(_ctx->dest_mail, ctx->seq);
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen _ctx->dest_mail->saving = TRUE;
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen }
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen dbox_file_unref(&src_file);
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen return 1;
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen}
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainen
a18e2525cb076066784967d6c8118a01dd38ac6bTimo Sirainenint sdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen{
2eccb2637d0153bb7f9ad39a70f254cece74342cTimo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)_t->box;
202b4674243a4a4826c35ed4d089831985c47256Timo Sirainen int ret;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen i_assert((_t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen ctx->finished = TRUE;
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen if (mail_storage_copy_can_use_hardlink(mail->box, &mbox->box)) {
7877db7b5daad125b6cb3e015574f33871c9a51bTimo Sirainen T_BEGIN {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen ret = sdbox_copy_hardlink(_ctx, mail);
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi } T_END;
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi
a01faca549a403b2eda938cea0b1fb76c3ff44b6Aki Tuomi if (ret != 0) {
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen index_save_context_free(_ctx);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return ret > 0 ? 0 : -1;
95f5b08fa73ddd9a9de40a97aa141e9c74e0645eAki Tuomi }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen /* non-fatal hardlinking failure, try the slow way */
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen }
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen return mail_storage_copy(_ctx, mail);
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen}
ae9691f7ef36d5272d72c90fa51393dfea5dd126Timo Sirainen