view src/lib-storage/index/dbox/dbox-sync-rebuild.c @ 6429:65c69a53a7be HEAD

Replaced my Copyright notices. The year range always ends with 2007 now. My name was replaced with "Dovecot authors". In many cases I didn't really even own the copyright, so this is more correct.
author Timo Sirainen <tss@iki.fi>
date Sun, 16 Sep 2007 14:34:22 +0300
parents 8476d665530f
children 47c3c4d41b26
line wrap: on
line source

/* Copyright (c) 2007-2007 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "dbox-storage.h"
#include "dbox-index.h"
#include "dbox-file.h"
#include "dbox-sync.h"

#include <stdlib.h>
#include <dirent.h>

struct dbox_sync_rebuild_context {
	struct dbox_mailbox *mbox;
	struct mail_index_transaction *trans;
};

static int dbox_sync_set_uidvalidity(struct dbox_sync_rebuild_context *ctx)
{
	uint32_t uid_validity;

	if (dbox_index_get_uid_validity(ctx->mbox->dbox_index,
					&uid_validity) < 0)
		return -1;

	mail_index_update_header(ctx->trans,
		offsetof(struct mail_index_header, uid_validity),
		&uid_validity, sizeof(uid_validity), TRUE);
	return 0;
}

static void dbox_sync_index_metadata(struct dbox_sync_rebuild_context *ctx,
				     struct dbox_file *file, uint32_t seq)
{
	const char *value;
	struct mail_keywords *keywords;
	enum mail_flags flags = 0;
	unsigned int i;

	value = dbox_file_metadata_get(file, DBOX_METADATA_FLAGS);
	if (value != NULL) {
		for (i = 0; value[i] != '\0'; i++) {
			if (value[i] != '0' && i < DBOX_METADATA_FLAGS_COUNT)
				flags |= dbox_mail_flags_map[i];
		}
		mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, flags);
	}

	value = dbox_file_metadata_get(file, DBOX_METADATA_KEYWORDS);
	if (value != NULL) {
		t_push();
		keywords = mail_index_keywords_create(ctx->mbox->ibox.index,
						t_strsplit_spaces(value, " "));
		mail_index_update_keywords(ctx->trans, seq, MODIFY_REPLACE,
					   keywords);
		mail_index_keywords_free(&keywords);
		t_pop();
	}
}

static int dbox_sync_index_file_next(struct dbox_sync_rebuild_context *ctx,
				     struct dbox_file *file, uoff_t *offset)
{
	uint32_t seq, uid;
	uoff_t metadata_offset, physical_size;
	bool expunged;
	int ret;

	ret = dbox_file_seek_next(file, offset, &uid, &physical_size);
	if (ret <= 0) {
		if (ret < 0)
			return -1;

		if (uid == 0 && (file->file_id & DBOX_FILE_ID_FLAG_UID) != 0) {
			/* EOF */
			return 0;
		}

		i_warning("%s: Ignoring broken file (header)", file->path);
		return 0;
	}
	if ((file->file_id & DBOX_FILE_ID_FLAG_UID) != 0 &&
	    uid != (file->file_id & ~DBOX_FILE_ID_FLAG_UID)) {
		i_warning("%s: Header contains wrong UID %u", file->path, uid);
		return 0;
	}

	metadata_offset =
		dbox_file_get_metadata_offset(file, *offset, physical_size);
	ret = dbox_file_metadata_seek(file, metadata_offset, &expunged);
	if (ret <= 0) {
		if (ret < 0)
			return -1;
		i_warning("%s: Ignoring broken file (metadata)", file->path);
		return 0;
	}
	if (!expunged) {
		mail_index_append(ctx->trans, uid, &seq);
		dbox_sync_index_metadata(ctx, file, seq);
	}
	return 1;
}

static int
dbox_sync_index_uid_file(struct dbox_sync_rebuild_context *ctx,
			 const char *fname)
{
	struct dbox_file *file;
	unsigned long uid;
	char *p;
	uoff_t offset = 0;
	int ret;

	fname += sizeof(DBOX_MAIL_FILE_MULTI_PREFIX)-1;
	uid = strtoul(fname, &p, 10);
	if (*p != '\0' || uid == 0 || uid >= (uint32_t)-1) {
		i_warning("dbox %s: Ignoring invalid filename %s",
			  ctx->mbox->path, fname);
		return 0;
	}

	file = dbox_file_init(ctx->mbox, uid | DBOX_FILE_ID_FLAG_UID);
	ret = dbox_sync_index_file_next(ctx, file, &offset) < 0 ? -1 : 0;
	dbox_file_unref(&file);
	return ret;
}

static int
dbox_sync_index_multi_file(struct dbox_sync_rebuild_context *ctx,
			   const char *fname)
{
	/* FIXME */
	return 0;
}

static int dbox_sync_index_rebuild_ctx(struct dbox_sync_rebuild_context *ctx)
{
	struct mail_storage *storage = ctx->mbox->ibox.box.storage;
	DIR *dir;
	struct dirent *d;
	int ret = 0;

	if (dbox_sync_set_uidvalidity(ctx) < 0)
		return -1;

	dir = opendir(ctx->mbox->path);
	if (dir == NULL) {
		if (errno == ENOENT) {
			ctx->mbox->ibox.mailbox_deleted = TRUE;
			return -1;
		}
		mail_storage_set_critical(storage,
			"opendir(%s) failed: %m", ctx->mbox->path);
		return -1;
	}
	errno = 0;
	for (; ret == 0 && (d = readdir(dir)) != NULL; errno = 0) {
		if (strncmp(d->d_name, DBOX_MAIL_FILE_UID_PREFIX,
			    sizeof(DBOX_MAIL_FILE_UID_PREFIX)-1) == 0)
			ret = dbox_sync_index_uid_file(ctx, d->d_name);
		else if (strncmp(d->d_name, DBOX_MAIL_FILE_MULTI_PREFIX,
				 sizeof(DBOX_MAIL_FILE_MULTI_PREFIX)-1) == 0)
			ret = dbox_sync_index_multi_file(ctx, d->d_name);
	}
	if (errno != 0) {
		mail_storage_set_critical(storage,
			"readdir(%s) failed: %m", ctx->mbox->path);
		ret = -1;
	}

	if (closedir(dir) < 0) {
		mail_storage_set_critical(storage,
			"closedir(%s) failed: %m", ctx->mbox->path);
		ret = -1;
	}
	return ret;
}

int dbox_sync_index_rebuild(struct dbox_mailbox *mbox)
{
	struct dbox_sync_rebuild_context ctx;
	struct mail_index_view *view;
	uint32_t seq;
	uoff_t offset;
	int ret;

	memset(&ctx, 0, sizeof(ctx));
	ctx.mbox = mbox;
	view = mail_index_view_open(mbox->ibox.index);
	ctx.trans = mail_index_transaction_begin(view,
					MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
	mail_index_reset(ctx.trans);

	if ((ret = dbox_sync_index_rebuild_ctx(&ctx)) < 0)
		mail_index_transaction_rollback(&ctx.trans);
	else
		ret = mail_index_transaction_commit(&ctx.trans, &seq, &offset);
	mail_index_view_close(&view);
	return ret;
}