Mercurial > dovecot > core-2.2
view src/lib-storage/index/dbox-single/sdbox-copy.c @ 12672:384d8615039f
dbox: If mail GUID is changed for copied mail, create a new copy of it so it changes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 03 Jan 2011 18:57:05 +0200 |
parents | 10c2540e91b9 |
children | 447bce266022 |
line wrap: on
line source
/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "nfs-workarounds.h" #include "fs-api.h" #include "dbox-save.h" #include "dbox-attachment.h" #include "sdbox-storage.h" #include "sdbox-file.h" #include "mail-copy.h" static int sdbox_file_copy_attachments(struct sdbox_file *src_file, struct sdbox_file *dest_file) { struct dbox_storage *src_storage = src_file->file.storage; struct dbox_storage *dest_storage = dest_file->file.storage; ARRAY_TYPE(mail_attachment_extref) extrefs; const struct mail_attachment_extref *extref; const char *extrefs_line, *src, *dest, *dest_relpath; pool_t pool; int ret; if (src_storage->attachment_dir == NULL) { /* no attachments in source storage */ return 1; } if (dest_storage->attachment_dir == NULL || strcmp(src_storage->attachment_dir, dest_storage->attachment_dir) != 0) { /* different attachment dirs between storages. have to copy the slow way. */ return 0; } if ((ret = sdbox_file_get_attachments(&src_file->file, &extrefs_line)) <= 0) return ret < 0 ? -1 : 1; pool = pool_alloconly_create("sdbox attachments copy", 1024); p_array_init(&extrefs, pool, 16); if (!dbox_attachment_parse_extref(extrefs_line, pool, &extrefs)) { mail_storage_set_critical(&dest_storage->storage, "Can't copy %s with corrupted extref metadata: %s", src_file->file.cur_path, extrefs_line); pool_unref(&pool); return -1; } dest_file->attachment_pool = pool_alloconly_create("sdbox attachment copy paths", 512); p_array_init(&dest_file->attachment_paths, dest_file->attachment_pool, array_count(&extrefs)); ret = 1; array_foreach(&extrefs, extref) T_BEGIN { src = t_strdup_printf("%s/%s", dest_storage->attachment_dir, sdbox_file_attachment_relpath(src_file, extref->path)); dest_relpath = p_strconcat(dest_file->attachment_pool, extref->path, "-", mail_generate_guid_string(), NULL); dest = t_strdup_printf("%s/%s", dest_storage->attachment_dir, dest_relpath); if (fs_link(dest_storage->attachment_fs, src, dest) < 0) { mail_storage_set_critical(&dest_storage->storage, "%s", fs_last_error(dest_storage->attachment_fs)); ret = -1; } else { array_append(&dest_file->attachment_paths, &dest_relpath, 1); } } T_END; pool_unref(&pool); return ret; } 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)) ret = 0; else 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); } 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) { sdbox_file_unlink_aborted_save((struct sdbox_file *)dest_file); dbox_file_unref(&src_file); dbox_file_unref(&dest_file); return ret; } 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(_ctx->dest_mail, ctx->seq); _ctx->dest_mail->saving = TRUE; } 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->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); }