Mercurial > dovecot > original-hg > dovecot-2.1
view src/lib-storage/index/dbox-single/sdbox-sync-rebuild.c @ 14914:b91e1b94af21
mdbox: If m.X file has no mails, don't try to fix it infinitely in storage rebuild.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 22 Feb 2013 10:01:06 +0200 |
parents | f30437ed63dc |
children |
line wrap: on
line source
/* Copyright (c) 2007-2012 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "dbox-sync-rebuild.h" #include "mail-cache.h" #include "sdbox-storage.h" #include "sdbox-file.h" #include "sdbox-sync.h" #include <stdlib.h> #include <dirent.h> static void sdbox_sync_set_uidvalidity(struct dbox_sync_rebuild_context *ctx) { uint32_t uid_validity; /* if uidvalidity is set in the old index, use it */ uid_validity = mail_index_get_header(ctx->view)->uid_validity; if (uid_validity == 0) uid_validity = dbox_get_uidvalidity_next(ctx->box->list); mail_index_update_header(ctx->trans, offsetof(struct mail_index_header, uid_validity), &uid_validity, sizeof(uid_validity), TRUE); } static int sdbox_sync_add_file_index(struct dbox_sync_rebuild_context *ctx, struct dbox_file *file, uint32_t uid, bool primary) { uint32_t seq; bool deleted; int ret; if ((ret = dbox_file_open(file, &deleted)) > 0) { if (deleted) return 0; ret = dbox_file_seek(file, 0); } if (ret == 0) { if ((ret = dbox_file_fix(file, 0)) > 0) ret = dbox_file_seek(file, 0); } if (ret <= 0) { if (ret < 0) return -1; i_warning("sdbox: Skipping unfixable file: %s", file->cur_path); return 0; } if (!dbox_file_is_in_alt(file) && !primary) { /* we were supposed to open the file in alt storage, but it exists in primary storage as well. skip it to avoid adding it twice. */ return 0; } mail_index_append(ctx->trans, uid, &seq); T_BEGIN { dbox_sync_rebuild_index_metadata(ctx, seq, uid); } T_END; return 0; } static int sdbox_sync_add_file(struct dbox_sync_rebuild_context *ctx, const char *fname, bool primary) { struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)ctx->box; struct dbox_file *file; uint32_t uid; int ret; if (strncmp(fname, SDBOX_MAIL_FILE_PREFIX, strlen(SDBOX_MAIL_FILE_PREFIX)) != 0) return 0; fname += strlen(SDBOX_MAIL_FILE_PREFIX); if (str_to_uint32(fname, &uid) < 0 || uid == 0) { i_warning("sdbox %s: Ignoring invalid filename %s", mailbox_get_path(ctx->box), fname); return 0; } file = sdbox_file_init(mbox, uid); if (!primary) file->cur_path = file->alt_path; ret = sdbox_sync_add_file_index(ctx, file, uid, primary); dbox_file_unref(&file); return ret; } static int sdbox_sync_index_rebuild_dir(struct dbox_sync_rebuild_context *ctx, const char *path, bool primary) { struct mail_storage *storage = ctx->box->storage; DIR *dir; struct dirent *d; int ret = 0; dir = opendir(path); if (dir == NULL) { if (errno == ENOENT) { if (!primary) { /* alt directory doesn't exist, ignore */ return 0; } mailbox_set_deleted(ctx->box); return -1; } mail_storage_set_critical(storage, "opendir(%s) failed: %m", path); return -1; } do { errno = 0; if ((d = readdir(dir)) == NULL) break; ret = sdbox_sync_add_file(ctx, d->d_name, primary); } while (ret >= 0); if (errno != 0) { mail_storage_set_critical(storage, "readdir(%s) failed: %m", path); ret = -1; } if (closedir(dir) < 0) { mail_storage_set_critical(storage, "closedir(%s) failed: %m", path); ret = -1; } return ret; } static void sdbox_sync_update_header(struct dbox_sync_rebuild_context *ctx) { struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)ctx->box; struct sdbox_index_header hdr; if (sdbox_read_header(mbox, &hdr, FALSE) < 0) memset(&hdr, 0, sizeof(hdr)); if (guid_128_is_empty(hdr.mailbox_guid)) guid_128_generate(hdr.mailbox_guid); if (++hdr.rebuild_count == 0) hdr.rebuild_count = 1; /* mailbox is being reset. this gets written directly there */ mail_index_set_ext_init_data(ctx->box->index, mbox->hdr_ext_id, &hdr, sizeof(hdr)); } static int sdbox_sync_index_rebuild_singles(struct dbox_sync_rebuild_context *ctx) { const char *path, *alt_path; int ret = 0; path = mailbox_get_path(ctx->box); alt_path = mailbox_list_get_path(ctx->box->list, ctx->box->name, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX); sdbox_sync_set_uidvalidity(ctx); if (sdbox_sync_index_rebuild_dir(ctx, path, TRUE) < 0) { mail_storage_set_critical(ctx->box->storage, "sdbox: Rebuilding failed on path %s", mailbox_get_path(ctx->box)); ret = -1; } else if (alt_path != NULL) { if (sdbox_sync_index_rebuild_dir(ctx, alt_path, FALSE) < 0) { mail_storage_set_critical(ctx->box->storage, "sdbox: Rebuilding failed on alt path %s", alt_path); ret = -1; } } sdbox_sync_update_header(ctx); return ret; } int sdbox_sync_index_rebuild(struct sdbox_mailbox *mbox, bool force) { struct dbox_sync_rebuild_context *ctx; struct mail_index_view *view; struct mail_index_transaction *trans; struct sdbox_index_header hdr; int ret; if (!force && sdbox_read_header(mbox, &hdr, FALSE) == 0) { if (hdr.rebuild_count != mbox->corrupted_rebuild_count && hdr.rebuild_count != 0) { /* already rebuilt by someone else */ return 0; } } i_warning("sdbox %s: Rebuilding index", mailbox_get_path(&mbox->box)); if (dbox_sync_rebuild_verify_alt_storage(mbox->box.list) < 0) { mail_storage_set_critical(mbox->box.storage, "sdbox %s: Alt storage not mounted, " "aborting index rebuild", mailbox_get_path(&mbox->box)); return -1; } view = mail_index_view_open(mbox->box.index); trans = mail_index_transaction_begin(view, MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); ctx = dbox_sync_index_rebuild_init(&mbox->box, view, trans); ret = sdbox_sync_index_rebuild_singles(ctx); dbox_sync_index_rebuild_deinit(&ctx); if (ret < 0) mail_index_transaction_rollback(&trans); else ret = mail_index_transaction_commit(&trans); mail_index_view_close(&view); mbox->corrupted_rebuild_count = 0; return ret; }