int sdbox_read_header(struct sdbox_mailbox *mbox,
struct sdbox_index_header *hdr, bool log_error)
{
+ struct mail_index_view *view;
const void *data;
size_t data_size;
+ int ret;
- mail_index_get_header_ext(mbox->box.view, mbox->hdr_ext_id,
+ view = mail_index_view_open(mbox->box.index);
+ mail_index_get_header_ext(view, mbox->hdr_ext_id,
&data, &data_size);
if (data_size < SDBOX_INDEX_HEADER_MIN_SIZE &&
(!mbox->creating || data_size != 0)) {
"dbox %s: Invalid dbox header size",
mbox->box.path);
}
- return -1;
+ ret = -1;
+ } else {
+ memset(hdr, 0, sizeof(*hdr));
+ memcpy(hdr, data, I_MIN(data_size, sizeof(*hdr)));
+ ret = 0;
}
- memset(hdr, 0, sizeof(*hdr));
- memcpy(hdr, data, I_MIN(data_size, sizeof(*hdr)));
- return 0;
+ mail_index_view_close(&view);
+ return ret;
}
void sdbox_update_header(struct sdbox_mailbox *mbox,
return ret;
}
-static void sdbox_set_mailbox_corrupted(struct mailbox *box ATTR_UNUSED)
+static void sdbox_set_mailbox_corrupted(struct mailbox *box)
{
- /* FIXME */
+ struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
+ struct sdbox_index_header hdr;
+
+ if (sdbox_read_header(mbox, &hdr, TRUE) < 0 || hdr.rebuild_count == 0)
+ mbox->corrupted_rebuild_count = 1;
+ else
+ mbox->corrupted_rebuild_count = hdr.rebuild_count;
}
static void sdbox_set_file_corrupted(struct dbox_file *_file)
sdbox_set_mailbox_corrupted(&file->mbox->box);
}
+static void sdbox_mailbox_close(struct mailbox *box)
+{
+ struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
+
+ if (mbox->corrupted_rebuild_count != 0)
+ (void)sdbox_sync(mbox, 0);
+ index_storage_mailbox_close(box);
+}
+
static int
sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
dbox_mailbox_open,
- index_storage_mailbox_close,
+ sdbox_mailbox_close,
index_storage_mailbox_free,
dbox_mailbox_create,
dbox_mailbox_update,
#define SDBOX_INDEX_HEADER_MIN_SIZE (sizeof(uint32_t))
struct sdbox_index_header {
- uint32_t oldv1_highest_maildir_uid;
+ /* increased every time a full mailbox rebuild is done */
+ uint32_t rebuild_count;
uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
};
struct sdbox_storage *storage;
uint32_t hdr_ext_id;
+ /* if non-zero, storage should be rebuilt (except if rebuild_count
+ has changed from this value) */
+ uint32_t corrupted_rebuild_count;
unsigned int creating:1;
};
return 0;
ret = dbox_file_get_mail_stream(file, 0, NULL);
}
+ if (ret == 0) {
+ if ((ret = dbox_file_fix(file, 0)) == 0)
+ ret = dbox_file_get_mail_stream(file, 0, NULL);
+ }
if (ret <= 0) {
if (ret < 0)
return -1;
- i_warning("dbox: Ignoring broken file: %s", file->cur_path);
+ i_warning("dbox: Skipping unfixable file: %s", file->cur_path);
return 0;
}
memset(&hdr, 0, sizeof(hdr));
if (!mail_guid_128_is_empty(hdr.mailbox_guid))
mail_generate_guid_128(hdr.mailbox_guid);
+ if (++hdr.rebuild_count == 0)
+ hdr.rebuild_count = 1;
mail_index_update_header_ext(ctx->trans, mbox->hdr_ext_id, 0,
&hdr, sizeof(hdr));
}
return ret;
}
-int sdbox_sync_index_rebuild(struct sdbox_mailbox *mbox)
+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;
+ }
+ }
+
view = mail_index_view_open(mbox->box.index);
trans = mail_index_transaction_begin(view,
MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
else
ret = mail_index_transaction_commit(&trans);
mail_index_view_close(&view);
+ mbox->corrupted_rebuild_count = 0;
return ret;
}
const struct mail_index_header *hdr;
struct mail_index_sync_rec sync_rec;
uint32_t seq1, seq2;
- int ret = 1;
hdr = mail_index_get_header(ctx->sync_view);
if (hdr->uid_validity == 0) {
if (box->v.sync_notify != NULL)
box->v.sync_notify(box, 0, 0);
- return ret;
+ return 1;
}
static int
enum mail_index_sync_flags sync_flags;
unsigned int i;
int ret;
- bool rebuild;
+ bool rebuild, force_rebuild;
- rebuild = sdbox_refresh_header(mbox, TRUE, FALSE) < 0 ||
- (flags & SDBOX_SYNC_FLAG_FORCE_REBUILD) != 0;
+ force_rebuild = (flags & SDBOX_SYNC_FLAG_FORCE_REBUILD) != 0;
+ rebuild = force_rebuild ||
+ mbox->corrupted_rebuild_count != 0 ||
+ sdbox_refresh_header(mbox, TRUE, FALSE) < 0;
ctx = i_new(struct sdbox_sync_context, 1);
ctx->mbox = mbox;
return ret;
}
- /* now that we're locked, check again if we want to rebuild. */
- if (sdbox_refresh_header(mbox, FALSE, TRUE) < 0)
+ if (rebuild)
ret = 0;
else {
if ((ret = sdbox_sync_index(ctx)) > 0)
/* do a full resync and try again. */
i_warning("dbox %s: Rebuilding index",
ctx->mbox->box.path);
- ret = sdbox_sync_index_rebuild(mbox);
+ rebuild = FALSE;
+ ret = sdbox_sync_index_rebuild(mbox,
+ force_rebuild);
}
}
mail_index_sync_rollback(&ctx->index_sync_ctx);
int sdbox_sync_finish(struct sdbox_sync_context **ctx, bool success);
int sdbox_sync(struct sdbox_mailbox *mbox, enum sdbox_sync_flags flags);
-int sdbox_sync_index_rebuild(struct sdbox_mailbox *mbox);
+int sdbox_sync_index_rebuild(struct sdbox_mailbox *mbox, bool force);
struct mailbox_sync_context *
sdbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);