view src/lib-index/mail-index-fsck.c @ 3863:55df57c028d4 HEAD

Added "bool" type and changed all ints that were used as booleans to bool.
author Timo Sirainen <tss@iki.fi>
date Fri, 13 Jan 2006 22:25:57 +0200
parents 76f4be7ae499
children 595dcb33802f
line wrap: on
line source

/* Copyright (C) 2004 Timo Sirainen */

#include "lib.h"
#include "mail-index-private.h"
#include "mail-transaction-log.h"

static void mail_index_fsck_error(struct mail_index *index,
				  const char *fmt, ...) __attr_format__(2, 3);
static void mail_index_fsck_error(struct mail_index *index,
				  const char *fmt, ...)
{
	va_list va;

	va_start(va, fmt);
	mail_index_set_error(index, "Fixed index file %s: %s",
			     index->filepath, t_strdup_vprintf(fmt, va));
	va_end(va);
}

#define CHECK(field, oper) \
	if (hdr.field oper index->hdr->field) { \
		mail_index_fsck_error(index, #field" %u -> %u", \
				      index->hdr->field, hdr.field); \
	}

static int mail_index_fsck_locked(struct mail_index *index,
				  const char **error_r)
{
	struct mail_index_header hdr;
	const struct mail_index_record *rec;
	uint32_t i, last_uid, log_seq;
	uoff_t log_offset;

	*error_r = NULL;

	/* locking already does the most important sanity checks for header */
	hdr = *index->hdr;

	if (hdr.uid_validity == 0 && hdr.next_uid != 1) {
		*error_r = "uid_validity = 0 && next_uid != 1";
		return 0;
	}

	mail_transaction_log_get_head(index->log, &log_seq, &log_offset);
	if (hdr.log_file_int_offset > hdr.log_file_ext_offset) {
		mail_index_fsck_error(index,
			"log_file_int_offset > log_file_ext_offset");
		hdr.log_file_int_offset = hdr.log_file_ext_offset;
	}
	if ((hdr.log_file_seq == log_seq &&
	     hdr.log_file_ext_offset > log_offset) ||
	    (hdr.log_file_seq != log_seq &&
	     !mail_transaction_log_is_head_prev(index->log,
						hdr.log_file_seq,
						hdr.log_file_ext_offset))) {
		mail_index_fsck_error(index,
			"log file sync pos %u,%u -> %u, %"PRIuUOFF_T,
			hdr.log_file_seq, hdr.log_file_ext_offset,
			log_seq, log_offset);
		hdr.log_file_seq = log_seq;
		hdr.log_file_int_offset = hdr.log_file_ext_offset = log_offset;
	}

	hdr.flags &= ~MAIL_INDEX_HDR_FLAG_FSCK;

	hdr.messages_count = 0;
	hdr.recent_messages_count = 0;
	hdr.seen_messages_count = 0;
	hdr.deleted_messages_count = 0;

	hdr.first_recent_uid_lowwater = 0;
	hdr.first_unseen_uid_lowwater = 0;
	hdr.first_deleted_uid_lowwater = 0;

	rec = index->map->records; last_uid = 0;
	for (i = 0; i < index->map->records_count; i++) {
		if (rec->uid <= last_uid) {
			*error_r = "Record UIDs are not ordered";
			return 0;
		}

		hdr.messages_count++;
		if ((rec->flags & MAIL_RECENT) != 0)
			hdr.recent_messages_count++;
		if ((rec->flags & MAIL_SEEN) != 0)
			hdr.seen_messages_count++;
		if ((rec->flags & MAIL_DELETED) != 0)
			hdr.deleted_messages_count++;

		if ((rec->flags & MAIL_RECENT) != 0 &&
		    hdr.first_recent_uid_lowwater == 0)
			hdr.first_recent_uid_lowwater = rec->uid;
		if ((rec->flags & MAIL_SEEN) == 0 &&
		    hdr.first_unseen_uid_lowwater == 0)
			hdr.first_unseen_uid_lowwater = rec->uid;
		if ((rec->flags & MAIL_DELETED) != 0 &&
		    hdr.first_deleted_uid_lowwater == 0)
			hdr.first_deleted_uid_lowwater = rec->uid;

		last_uid = rec->uid;
		rec = CONST_PTR_OFFSET(rec, hdr.record_size);
	}

	if (hdr.next_uid <= last_uid) {
		mail_index_fsck_error(index, "next_uid %u -> %u",
				      hdr.next_uid, last_uid+1);
		hdr.next_uid = last_uid+1;
	}

	if (hdr.first_recent_uid_lowwater == 0)
                hdr.first_recent_uid_lowwater = hdr.next_uid;
	if (hdr.first_unseen_uid_lowwater == 0)
                hdr.first_unseen_uid_lowwater = hdr.next_uid;
	if (hdr.first_deleted_uid_lowwater == 0)
                hdr.first_deleted_uid_lowwater = hdr.next_uid;

        CHECK(messages_count, !=);
        CHECK(recent_messages_count, !=);
        CHECK(seen_messages_count, !=);
        CHECK(deleted_messages_count, !=);

        CHECK(first_recent_uid_lowwater, <);
        CHECK(first_unseen_uid_lowwater, <);
        CHECK(first_deleted_uid_lowwater, <);

	if (mail_index_write_base_header(index, &hdr) < 0)
		return -1;

	return 1;
}

int mail_index_fsck(struct mail_index *index)
{
	const char *error;
	unsigned int lock_id;
	uint32_t file_seq;
	uoff_t file_offset;
	int ret;
	bool lock_log;

	if (index->sync_update) {
		/* we're modifying index, don't do anything */
		return 1;
	}

        lock_log = !index->log_locked;
	if (lock_log) {
		if (mail_transaction_log_sync_lock(index->log, &file_seq,
						   &file_offset) < 0)
			return -1;
	}
	if (mail_index_lock_exclusive(index, &lock_id) < 0) {
                mail_transaction_log_sync_unlock(index->log);
		return -1;
	}

	error = NULL;
	ret = mail_index_map(index, TRUE);
	if (ret > 0)
		ret = mail_index_fsck_locked(index, &error);

	mail_index_unlock(index, lock_id);
	if (lock_log)
		mail_transaction_log_sync_unlock(index->log);

	if (error != NULL) {
		mail_index_set_error(index, "Corrupted index file %s: %s",
				     index->filepath, error);
	}
	if (ret == 0)
		mail_index_mark_corrupted(index);
	return ret;
}