view src/lib-index/mbox/mbox-sync.c @ 903:fd8888f6f037 HEAD

Naming style changes, finally got tired of most of the typedefs. Also the previous enum -> macro change reverted so that we don't use the highest bit anymore, that's incompatible with old indexes so they will be rebuilt.
author Timo Sirainen <tss@iki.fi>
date Sun, 05 Jan 2003 15:09:51 +0200
parents 86cf24da85f1
children 2ea9661542ee
line wrap: on
line source

/* Copyright (C) 2002 Timo Sirainen */

#include "lib.h"
#include "mbox-index.h"
#include "mbox-lock.h"
#include "mail-index-util.h"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

static uoff_t get_indexed_mbox_size(struct mail_index *index)
{
	struct mail_index_record *rec;
	uoff_t offset, hdr_size, body_size;

	if (index->lock_type == MAIL_LOCK_UNLOCK) {
		if (!mail_index_set_lock(index, MAIL_LOCK_SHARED))
			return 0;
	}

	/* get the last record */
	rec = index->header->messages_count == 0 ? NULL :
		index->lookup(index, index->header->messages_count);

	offset = 0;
	if (rec != NULL) {
		/* get the offset + size of last message, which tells the
		   last known mbox file size */
		if (mbox_mail_get_location(index, rec, &offset,
					   &hdr_size, &body_size))
			offset += hdr_size + body_size;
	}

	if (offset > OFF_T_MAX) {
		/* too large to fit in off_t */
		return 0;
	}

	return offset + 1; /* +1 for trailing \n */
}

static int mbox_lock_and_sync_full(struct mail_index *index,
				   enum mail_lock_type data_lock_type)
{
        enum mail_lock_type lock_type;

	/* syncing needs exclusive index lock and shared
	   mbox lock, but if we'd want exclusive mbox lock
	   we need to set it here already */
	if (index->lock_type == MAIL_LOCK_SHARED)
		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);

	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
		return FALSE;

	if (index->mbox_lock_type == MAIL_LOCK_UNLOCK) {
		lock_type = data_lock_type == MAIL_LOCK_EXCLUSIVE ?
			MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED;
		if (!mbox_lock(index, lock_type))
			return FALSE;
	}

	return mbox_sync_full(index);
}

int mbox_index_sync(struct mail_index *index,
		    enum mail_lock_type data_lock_type, int *changes)
{
	struct stat st;
	time_t index_mtime;
	uoff_t filesize;
	int count, fd;

	i_assert(index->lock_type != MAIL_LOCK_SHARED);

	if (changes != NULL)
		*changes = FALSE;

	if (index->mbox_sync_counter == index->mbox_lock_counter) {
		/* we've already synced in this locking session */
		return TRUE;
	}

	if (index->fd == -1) {
		/* anon-mmaped */
		index_mtime = index->file_sync_stamp;
	} else {
		if (fstat(index->fd, &st) < 0)
			return index_set_syscall_error(index, "fstat()");
		index_mtime = st.st_mtime;
	}

	count = 0;
	while (stat(index->mailbox_path, &st) < 0) {
		if (errno != ENOENT || ++count == 3)
			return mbox_set_syscall_error(index, "stat()");

		/* mbox was deleted by someone - happens with some MUAs
		   when all mail is expunged. easiest way to deal with this
		   is to recreate the file. */
		fd = open(index->mailbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
		if (fd != -1)
			(void)close(fd);
		else if (errno != EEXIST)
			return mbox_set_syscall_error(index, "open()");
	}
	filesize = st.st_size;

	if (index->mbox_ino != st.st_ino ||
            !CMP_DEV_T(index->mbox_dev, st.st_dev)) {
		/* mbox file was overwritten, close it if it was open */
		index->mbox_dev = st.st_dev;
		index->mbox_ino = st.st_ino;
		index->mbox_size = (uoff_t)-1;

                mbox_file_close_fd(index);
	}

	if (index_mtime != st.st_mtime || index->mbox_size != filesize) {
		mbox_file_close_stream(index);

		index->mbox_size = get_indexed_mbox_size(index);
		if (index->file_sync_stamp == 0 &&
		    index->mbox_size == filesize) {
			/* just opened the mailbox, and the file size is same
			   as we expected. don't bother checking it any
			   further. */
		} else {
			if (changes != NULL)
				*changes = TRUE;

			if (!mbox_lock_and_sync_full(index, data_lock_type))
				return FALSE;

			index->mbox_size = filesize;
		}

		index->file_sync_stamp = st.st_mtime;
	}

	/* we need some index lock to be able to lock mbox */
	if (index->lock_type == MAIL_LOCK_UNLOCK) {
		if (!index->set_lock(index, MAIL_LOCK_SHARED))
			return FALSE;
	}

	if (data_lock_type == MAIL_LOCK_UNLOCK) {
		if (!mbox_unlock(index))
			return FALSE;
	} else {
		if (!mbox_lock(index, data_lock_type))
			return FALSE;
	}

	index->mbox_sync_counter = index->mbox_lock_counter;
	return TRUE;
}