changeset 221:ed0d5b17c7a4 HEAD

Added extra functions for easier printing of error messages. Moved file_set_size() to generic function in lib. If there's no space to build hash file, it builds itself in anon-mmaped memory and stays there.
author Timo Sirainen <tss@iki.fi>
date Fri, 13 Sep 2002 03:01:23 +0300
parents 94382d79ae47
children cf4d065f2f85
files src/lib-index/mail-custom-flags.c src/lib-index/mail-hash.c src/lib-index/mail-index-compress.c src/lib-index/mail-index-data.c src/lib-index/mail-index-data.h src/lib-index/mail-index-update.c src/lib-index/mail-index-util.c src/lib-index/mail-index-util.h src/lib-index/mail-index.c src/lib-index/mail-modifylog.c src/lib-index/maildir/maildir-build.c src/lib-index/maildir/maildir-index.c src/lib-index/maildir/maildir-open.c src/lib-index/maildir/maildir-rebuild.c src/lib-index/maildir/maildir-sync.c src/lib-index/mbox/mbox-fsck.c src/lib-index/mbox/mbox-index.c src/lib-index/mbox/mbox-index.h src/lib-index/mbox/mbox-open.c src/lib-index/mbox/mbox-rebuild.c src/lib-index/mbox/mbox-rewrite.c src/lib-index/mbox/mbox-sync.c src/lib-storage/index/index-status.c src/lib/Makefile.am src/lib/file-set-size.c src/lib/file-set-size.h src/lib/mmap-util.c src/lib/mmap-util.h
diffstat 28 files changed, 468 insertions(+), 393 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-custom-flags.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-custom-flags.c	Fri Sep 13 03:01:23 2002 +0300
@@ -21,7 +21,7 @@
 
 struct _MailCustomFlags {
 	MailIndex *index;
-	char *path;
+	char *filepath;
 	int fd;
 	int lock_type;
 
@@ -37,13 +37,21 @@
 
 static int lock_file(MailCustomFlags *mcf, int type);
 
+static void index_cf_set_syscall_error(MailCustomFlags *mcf,
+				       const char *function)
+{
+	i_assert(function != NULL);
+
+	index_set_error(mcf->index, "%s failed with custom flags file %s: %m",
+			function, mcf->filepath);
+}
+
 static int update_mmap(MailCustomFlags *mcf)
 {
 	mcf->mmap_base = mmap_rw_file(mcf->fd, &mcf->mmap_length);
 	if (mcf->mmap_base == MAP_FAILED) {
 		mcf->mmap_base = NULL;
-		index_set_error(mcf->index, "mmap() failed for "
-				"custom flags file %s: %m", mcf->path);
+		index_cf_set_syscall_error(mcf, "mmap()");
 		return FALSE;
 	}
 
@@ -65,15 +73,13 @@
 		pos = lseek(mcf->fd, 0, SEEK_SET);
 
 	if (pos == -1) {
-		index_set_error(mcf->index, "lseek() failed for "
-				"custom flags file %s: %m", mcf->path);
+		index_cf_set_syscall_error(mcf, "lseek()");
 		return FALSE;
 	}
 
 	/* write the header - it's a 4 byte counter as hex */
 	if (write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
-		index_set_error(mcf->index, "write() failed for "
-				"custom flags file %s: %m", mcf->path);
+		index_cf_set_syscall_error(mcf, "write_full()");
 		return FALSE;
 	}
 
@@ -133,7 +139,8 @@
 
 			if (mcf->custom_flags[num] != NULL) {
 				i_warning("Error in custom flags file %s: "
-					  "Duplicated ID %u", mcf->path, num);
+					  "Duplicated ID %u", mcf->filepath,
+					  num);
 				i_free(mcf->custom_flags[num]);
 			}
 
@@ -188,8 +195,7 @@
 
 	while (fcntl(mcf->fd, F_SETLKW, &fl) == -1) {
 		if (errno != EINTR) {
-			index_set_error(mcf->index, "fcntl() failed for "
-					"custom flags file %s: %m", mcf->path);
+			index_cf_set_syscall_error(mcf, "fcntl(F_SETLKW)");
 			return FALSE;
 		}
 	}
@@ -230,7 +236,7 @@
 
 	mcf = i_new(MailCustomFlags, 1);
 	mcf->index = index;
-	mcf->path = i_strdup(path);
+	mcf->filepath = i_strdup(path);
 	mcf->fd = fd;
 
 	if (!update_mmap(mcf)) {
@@ -264,7 +270,7 @@
 	(void)munmap(mcf->mmap_base, mcf->mmap_length);
 	(void)close(mcf->fd);
 
-	i_free(mcf->path);
+	i_free(mcf->filepath);
 	i_free(mcf);
 }
 
@@ -272,9 +278,8 @@
 {
 	int i;
 
-	if (lseek(mcf->fd, 0, SEEK_SET) == -1) {
-		index_set_error(mcf->index, "lseek() failed for "
-				"custom flags file %s: %m", mcf->path);
+	if (lseek(mcf->fd, 0, SEEK_SET) < 0) {
+		index_cf_set_syscall_error(mcf, "lseek()");
 		return FALSE;
 	}
 
@@ -294,8 +299,7 @@
 	}
 
 	if (write_full(mcf->fd, mcf->sync_counter, COUNTER_SIZE) < 0) {
-		index_set_error(mcf->index, "write() failed for "
-				"custom flags file %s: %m", mcf->path);
+		index_cf_set_syscall_error(mcf, "write_full()");
 		return FALSE;
 	}
 
@@ -316,16 +320,15 @@
 
 	/* add the flag */
 	pos = lseek(mcf->fd, 0, SEEK_END);
-	if (pos == -1) {
-		index_set_error(mcf->index, "lseek() failed for "
-				"custom flags file %s: %m", mcf->path);
+	if (pos < 0) {
+		index_cf_set_syscall_error(mcf, "lseek()");
 		return FALSE;
 	}
 
 	if (pos != (off_t)mcf->mmap_length) {
-		index_set_error(mcf->index, "custom flags file %s was "
+		index_set_error(mcf->index, "Custom flags file %s was "
 				"changed by someone while we were"
-				"trying to modify it", mcf->path);
+				"trying to modify it", mcf->filepath);
 		return FALSE;
 	}
 
@@ -339,8 +342,7 @@
 	}
 
 	if (write_full(mcf->fd, buf, len) < 0) {
-		index_set_error(mcf->index, "write() failed for "
-				"custom flags file %s: %m", mcf->path);
+		index_cf_set_syscall_error(mcf, "write_full()");
 		return FALSE;
 	}
 
@@ -387,10 +389,7 @@
 
 			mcf->mmap_length -= linelen;
 			if (ftruncate(mcf->fd, (off_t) mcf->mmap_length) == -1) {
-				index_set_error(mcf->index,
-						"ftruncate() failed for "
-						"custom flags file %s: %m",
-						mcf->path);
+				index_cf_set_syscall_error(mcf, "ftruncate()");
 				return FALSE;
 			}
 
--- a/src/lib-index/mail-hash.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-hash.c	Fri Sep 13 03:01:23 2002 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "file-set-size.h"
 #include "primes.h"
 #include "mmap-util.h"
 #include "write-full.h"
@@ -35,6 +36,9 @@
    through lots of records just to find an empty spot */
 #define HASH_FUNC(uid) (uid * 2)
 
+#define HASH_FILE_SIZE(records) \
+	(sizeof(MailHashHeader) + (records) * sizeof(MailHashRecord))
+
 struct _MailHash {
 	MailIndex *index;
 
@@ -48,12 +52,15 @@
 	size_t mmap_length;
 
 	MailHashHeader *header;
+	unsigned int anon_mmap:1;
 	unsigned int dirty_mmap:1;
 	unsigned int modified:1;
 };
 
 static int mmap_update_real(MailHash *hash)
 {
+	i_assert(!hash->anon_mmap);
+
 	if (hash->mmap_base != NULL)
 		(void)munmap(hash->mmap_base, hash->mmap_length);
 
@@ -187,83 +194,36 @@
 		hash->mmap_base = NULL;
 	}
 
-	(void)close(hash->fd);
+	if (hash->fd != -1)
+		(void)close(hash->fd);
 	i_free(hash->filepath);
 	i_free(hash);
 }
 
-static int file_set_size(int fd, off_t size)
+int mail_hash_sync_file(MailHash *hash)
 {
-	char block[1024];
-	int ret, old_errno;
-	off_t pos;
-
-	i_assert(size >= 0);
+	if (!hash->modified)
+		return TRUE;
+	hash->modified = FALSE;
 
-	/* try truncating it to the size we want. if this succeeds, the written
-	   area is full of zeros - exactly what we want. however, this may not
-	   work at all, in which case we fallback to write()ing the zeros. */
-	ret = ftruncate(fd, size);
-	old_errno = errno;
-
-	pos = lseek(fd, 0, SEEK_END);
-	if (ret != -1 && pos == size)
-		return lseek(fd, 0, SEEK_SET) == 0;
-
-	if (pos == -1)
-		return FALSE;
-	if (pos > size) {
-		/* ftruncate() failed for some reason, even while we were
-		   trying to make the file smaller */
-		errno = old_errno;
+	if (hash->anon_mmap ||
+	    msync(hash->mmap_base, hash->mmap_length, MS_SYNC) == 0)
+		return TRUE;
+	else {
+		index_set_error(hash->index, "msync() failed for %s: %m",
+				hash->filepath);
 		return FALSE;
 	}
-
-	/* start growing the file */
-	size -= pos;
-	memset(block, 0, sizeof(block));
-
-	while ((uoff_t)size > sizeof(block)) {
-		/* write in 1kb blocks */
-		if (write_full(fd, block, sizeof(block)) < 0)
-			return FALSE;
-		size -= sizeof(block);
-	}
-
-	/* write the remainder */
-	return write_full(fd, block, (size_t)size) == 0;
 }
 
-static int hash_rebuild_to_file(MailIndex *index, int fd,
-				unsigned int hash_size,
-				unsigned int messages_count)
+static void hash_build(MailIndex *index, void *mmap_base,
+		       unsigned int hash_size)
 {
 	MailHashHeader *hdr;
         MailHashRecord *rec;
+	MailIndexHeader *idx_hdr;
 	MailIndexRecord *idx_rec;
-	void *mmap_base;
 	unsigned int i, count;
-	size_t mmap_length;
-	size_t new_size;
-
-	i_assert(hash_size < MAX_HASH_SIZE);
-
-	/* fill the file with zeros */
-	new_size = sizeof(MailHashHeader) + hash_size * sizeof(MailHashRecord);
-	if (!file_set_size(fd, (off_t)new_size)) {
-		index_set_error(index, "Failed to fill temp hash to size "
-				"%"PRIuSIZE_T": %m", new_size);
-		return FALSE;
-	}
-
-	/* now, mmap() it */
-	mmap_base = mmap_rw_file(fd, &mmap_length);
-	if (mmap_base == MAP_FAILED) {
-		index_set_error(index, "mmap()ing temp hash failed: %m");
-		return FALSE;
-	}
-
-	i_assert(mmap_length == new_size);
 
 	/* we have empty hash file mmap()ed now. fill it by reading the
 	   messages from index. */
@@ -276,12 +236,12 @@
 		idx_rec = index->next(index, idx_rec);
 	}
 
-	if (count != messages_count) {
+	idx_hdr = index->get_header(index);
+	if (count != idx_hdr->messages_count) {
 		/* mark this as an error but don't fail because of it. */
-                INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Missing messages while rebuilding "
-				"hash file %s - %u found, header says %u",
-				index->filepath, count, messages_count);
+		index_set_corrupted(index, "Missing messages while rebuilding "
+				    "hash file - %u found, header says %u",
+				    count, idx_hdr->messages_count);
 	}
 
 	/* setup header */
@@ -289,23 +249,53 @@
 	hdr->indexid = index->indexid;
 	hdr->sync_id = ioloop_time;
 	hdr->used_records = count;
-
-	return munmap(mmap_base, mmap_length) == 0;
 }
 
-int mail_hash_sync_file(MailHash *hash)
+static int hash_rebuild_to_file(MailIndex *index, int fd, const char *path,
+				unsigned int hash_size)
 {
-	if (!hash->modified)
-		return TRUE;
-	hash->modified = FALSE;
+	void *mmap_base;
+	size_t mmap_length, new_size;
 
-	if (msync(hash->mmap_base, hash->mmap_length, MS_SYNC) == 0)
-		return TRUE;
-	else {
-		index_set_error(hash->index, "msync() failed for %s: %m",
-				hash->filepath);
+	i_assert(hash_size < MAX_HASH_SIZE);
+
+	new_size = HASH_FILE_SIZE(hash_size);
+
+	/* fill the file with zeros */
+	if (file_set_size(fd, (off_t)new_size) < 0) {
+		index_set_error(index, "Failed to fill temp hash to "
+				"size %"PRIuSIZE_T": %m", new_size);
 		return FALSE;
 	}
+
+	/* now, mmap() it */
+	mmap_base = mmap_rw_file(fd, &mmap_length);
+	if (mmap_base == MAP_FAILED) {
+		index_set_error(index,
+				"mmap()ing temp hash failed: %m");
+		return FALSE;
+	}
+	i_assert(mmap_length == new_size);
+
+	hash_build(index, mmap_base, hash_size);
+
+	if (msync(mmap_base, mmap_length, MS_SYNC) < 0) {
+		index_set_error(index, "msync() failed for temp hash %s: %m",
+				path);
+		(void)munmap(mmap_base, mmap_length);
+		return FALSE;
+	}
+
+	(void)munmap(mmap_base, mmap_length);
+
+	/* we don't want to leave partially written hash around */
+	if (fsync(fd) < 0) {
+		index_set_error(index, "fsync() failed with temp hash %s: %m",
+				path);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 int mail_hash_rebuild(MailHash *hash)
@@ -313,15 +303,13 @@
 	MailIndexHeader *index_header;
 	const char *path;
 	unsigned int hash_size;
-	int fd;
+	int fd, failed;
 
 	if (!hash->index->set_lock(hash->index, MAIL_LOCK_EXCLUSIVE))
 		return FALSE;
 
-	/* first get the number of messages in index */
+	/* figure out size for our hash */
 	index_header = hash->index->get_header(hash->index);
-
-	/* then figure out size for our hash */
 	hash_size = primes_closest(index_header->messages_count * 100 /
 				   MIN_PERCENTAGE);
 	if (hash_size < MIN_HASH_SIZE)
@@ -332,47 +320,59 @@
 		/* either our calculation overflowed, or we reached the
 		   max. value primes_closest() gave us. and there's more
 		   mails - very unlikely. */
-		index_set_error(hash->index, "Too many mails in mailbox (%u), "
-				"max. hash file size reached for %s",
-				index_header->messages_count, hash->filepath);
+		index_set_corrupted(hash->index, "Too many mails in mailbox "
+				    "(%u)", index_header->messages_count);
 		return FALSE;
 	}
 
-	/* create the hash in a new temp file */
+	/* build the hash in a temp file, renaming it to the real hash
+	   once finished */
 	fd = mail_index_create_temp_file(hash->index, &path);
-	if (fd == -1)
-		return FALSE;
+	if (fd != -1) {
+		failed = !hash_rebuild_to_file(hash->index, fd,
+					       path, hash_size);
 
-	if (!hash_rebuild_to_file(hash->index, fd, hash_size,
-				  index_header->messages_count)) {
-		(void)close(fd);
-		(void)unlink(path);
-		return FALSE;
+		if (!failed && rename(path, hash->filepath) < 0) {
+			index_set_error(hash->index, "rename(%s, %s) failed: %m",
+					path, hash->filepath);
+			failed = TRUE;
+		}
+
+		if (failed) {
+			int old_errno = errno;
+
+			(void)close(fd);
+			(void)unlink(path);
+			fd = -1;
+
+			errno = old_errno;
+		}
 	}
 
-	if (fsync(fd) == -1) {
-		index_set_error(hash->index,
-				"fsync() failed with temp hash %s: %m", path);
-		(void)close(fd);
-		(void)unlink(path);
-		return FALSE;
-	}
+	if (fd == -1) {
+		/* building hash to file failed. if it was because there
+		   was no space in disk, we could just as well keep it in
+		   memory */
+		if (errno != ENOSPC)
+			return FALSE;
 
-	/* replace old hash file with this new one */
-	if (rename(path, hash->filepath) == -1) {
-		index_set_error(hash->index, "rename(%s, %s) failed: %m",
-				path, hash->filepath);
+		if (hash->mmap_base != NULL)
+			(void)munmap(hash->mmap_base, hash->mmap_length);
 
-		(void)close(fd);
-		(void)unlink(path);
-		return FALSE;
+		hash->mmap_length = HASH_FILE_SIZE(hash_size);
+		hash->mmap_base = mmap_anonymous(hash->mmap_length);
+		hash_build(hash->index, hash->mmap_base, hash_size);
+
+		/* make sure it doesn't exist anymore */
+		(void)unlink(hash->filepath);
 	}
 
 	/* switch fds */
 	if (hash->fd != -1)
 		(void)close(hash->fd);
 	hash->fd = fd;
-	hash->dirty_mmap = TRUE;
+	hash->anon_mmap = fd == -1;
+	hash->dirty_mmap = !hash->anon_mmap;
 	return TRUE;
 }
 
--- a/src/lib-index/mail-index-compress.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-compress.c	Fri Sep 13 03:01:23 2002 +0300
@@ -52,8 +52,7 @@
 	/* truncate the file to get rid of the extra records */
 	fsize = (size_t) ((char *) hole_rec - (char *) index->mmap_base);
 	if (ftruncate(index->fd, (off_t)fsize) == -1) {
-		index_set_error(index, "ftruncate() failed for %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "ftruncate()");
 		return FALSE;
 	}
 
@@ -104,9 +103,8 @@
 	rec = index->lookup(index, 1);
 	while (rec != NULL) {
 		if (rec->data_position + rec->data_size > mmap_data_size) {
-			index_set_error(index, "Error in index file %s: "
-					"data_position+data_size points "
-					"outside file", index->filepath);
+			index_set_corrupted(index, "data_position+data_size "
+					    "points outside file");
 			return FALSE;
 		}
 
--- a/src/lib-index/mail-index-data.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-data.c	Fri Sep 13 03:01:23 2002 +0300
@@ -31,6 +31,29 @@
 	unsigned int dirty_mmap:1;
 };
 
+void index_data_set_corrupted(MailIndexData *data, const char *fmt, ...)
+{
+	va_list va;
+
+	INDEX_MARK_CORRUPTED(data->index);
+
+	va_start(va, fmt);
+	t_push();
+	index_set_error(data->index, "Corrupted index data file %s: %s",
+			data->filepath, t_strdup_vprintf(fmt, va));
+	t_pop();
+	va_end(va);
+}
+
+static void index_data_set_syscall_error(MailIndexData *data,
+					 const char *function)
+{
+	i_assert(function != NULL);
+
+	index_set_error(data->index, "%s failed with index data file %s: %m",
+			function, data->filepath);
+}
+
 static int mmap_update(MailIndexData *data, uoff_t pos, size_t size)
 {
 	if (!data->dirty_mmap && (size != 0 && pos+size <= data->mmap_length))
@@ -42,13 +65,10 @@
 	data->mmap_base = mmap_rw_file(data->fd, &data->mmap_length);
 	if (data->mmap_base == MAP_FAILED) {
 		data->mmap_base = NULL;
-		index_set_error(data->index, "index data: mmap() failed with "
-				"file %s: %m", data->filepath);
+		index_data_set_syscall_error(data, "mmap()");
 		return FALSE;
 	} else if (data->mmap_length < sizeof(MailIndexDataHeader)) {
-                INDEX_MARK_CORRUPTED(data->index);
-		index_set_error(data->index, "index data: truncated data "
-				"file %s", data->filepath);
+		index_data_set_corrupted(data, "File too small");
 		return FALSE;
 	} else {
 		data->dirty_mmap = FALSE;
@@ -119,7 +139,7 @@
 	/* move temp file into .data file, deleting old one
 	   if it already exists */
 	realpath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
-	if (rename(temppath, realpath) == -1) {
+	if (rename(temppath, realpath) < 0) {
 		index_set_error(index, "rename(%s, %s) failed: %m",
 				temppath, realpath);
 		(void)unlink(temppath);
@@ -174,9 +194,8 @@
 {
 	MailIndexDataHeader hdr;
 
-	if (ftruncate(data->fd, sizeof(MailIndexDataHeader)) == -1) {
-		index_set_error(data->index, "ftruncate() failed for data file "
-				"%s: %m", data->filepath);
+	if (ftruncate(data->fd, sizeof(MailIndexDataHeader)) < 0) {
+		index_data_set_syscall_error(data, "ftruncate()");
 		return FALSE;
 	}
 
@@ -184,15 +203,13 @@
 	hdr.indexid = data->index->indexid;
 	hdr.deleted_space = 0;
 
-	if (lseek(data->fd, 0, SEEK_SET) == -1) {
-		index_set_error(data->index, "lseek() failed for data file "
-				"%s: %m", data->filepath);
+	if (lseek(data->fd, 0, SEEK_SET) < 0) {
+		index_data_set_syscall_error(data, "lseek()");
 		return FALSE;
 	}
 
 	if (write_full(data->fd, &hdr, sizeof(hdr)) < 0) {
-		index_set_error(data->index, "write() failed for data file "
-				"%s: %m", data->filepath);
+		index_data_set_syscall_error(data, "write_full()");
 		return FALSE;
 	}
 
@@ -212,21 +229,18 @@
 	i_assert((size & (MEM_ALIGN_SIZE-1)) == 0);
 
 	pos = lseek(data->fd, 0, SEEK_END);
-	if (pos == -1) {
-		index_set_error(data->index, "lseek() failed with file %s: %m",
-				data->filepath);
+	if (pos < 0) {
+		index_data_set_syscall_error(data, "lseek()");
 		return 0;
 	}
 
 	if (pos < (int)sizeof(MailIndexDataHeader)) {
-		index_set_error(data->index, "Header missing from data file %s",
-				data->filepath);
+		index_data_set_corrupted(data, "Header is missing");
 		return 0;
 	}
 
 	if (write_full(data->fd, buffer, size) < 0) {
-		index_set_error(data->index, "Error appending to file %s: %m",
-				data->filepath);
+		index_data_set_syscall_error(data, "write_full()");
 		return 0;
 	}
 
@@ -260,16 +274,14 @@
 int mail_index_data_sync_file(MailIndexData *data)
 {
 	if (data->mmap_base != NULL) {
-		if (msync(data->mmap_base, data->mmap_length, MS_SYNC) == -1) {
-			index_set_error(data->index, "msync() failed for "
-					"%s: %m", data->filepath);
+		if (msync(data->mmap_base, data->mmap_length, MS_SYNC) < 0) {
+			index_data_set_syscall_error(data, "msync()");
 			return FALSE;
 		}
 	}
 
-	if (fsync(data->fd) == -1) {
-		index_set_error(data->index, "fsync() failed for %s: %m",
-				data->filepath);
+	if (fsync(data->fd) < 0) {
+		index_data_set_syscall_error(data, "fsync()");
 		return FALSE;
 	}
 
@@ -295,14 +307,13 @@
 	if (index_rec->data_position > data->mmap_length ||
 	    (data->mmap_length -
 	     index_rec->data_position < index_rec->data_size)) {
-		INDEX_MARK_CORRUPTED(data->index);
-		index_set_error(data->index, "Error in data file %s: "
-				"Given data size larger than file size "
-				"(%"PRIuUOFF_T" + %u > %"PRIuSIZE_T") "
-				"for record %u",
-				data->filepath, index_rec->data_position,
-				index_rec->data_size, data->mmap_length,
-				index_rec->uid);
+		index_data_set_corrupted(data, "Given data size larger than "
+					 "file size (%"PRIuUOFF_T
+					 " + %u > %"PRIuSIZE_T") for record %u",
+					 index_rec->data_position,
+					 index_rec->data_size,
+					 data->mmap_length,
+					 index_rec->uid);
 		return NULL;
 	}
 
@@ -317,11 +328,10 @@
 		   this as it won't crash and is quite likely noticed later. */
 		if (pos + sizeof(MailIndexDataRecord) > max_pos ||
 		    pos + DATA_RECORD_SIZE(rec) > max_pos) {
-			INDEX_MARK_CORRUPTED(data->index);
-			index_set_error(data->index, "Error in data file %s: "
-					"Field size points outside file "
-					"(%"PRIuUOFF_T" / %"PRIuUOFF_T")",
-					data->filepath, pos, max_pos);
+			index_data_set_corrupted(data, "Field size points "
+						 "outside file (%"PRIuUOFF_T
+						 " / %"PRIuUOFF_T")",
+						 pos, max_pos);
 			break;
 		}
 
@@ -361,12 +371,9 @@
 	rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
 	end_pos = pos + DATA_RECORD_SIZE(rec);
 	if (end_pos < pos || end_pos > max_pos) {
-		INDEX_MARK_CORRUPTED(data->index);
-		index_set_error(data->index, "Error in data file %s: "
-				"Field size points outside file "
-				"(%"PRIuUOFF_T" + %u > %"PRIuUOFF_T")",
-				data->filepath, pos, rec->full_field_size,
-				max_pos);
+		index_data_set_corrupted(data, "Field size points outside file "
+					 "(%"PRIuUOFF_T" + %u > %"PRIuUOFF_T")",
+					 pos, rec->full_field_size, max_pos);
 		return NULL;
 	}
 
@@ -380,9 +387,8 @@
 	if (rec->full_field_size > INT_MAX) {
 		/* we already check that the full_field_size is within file,
 		   so this can happen only if the file really is huge.. */
-		INDEX_MARK_CORRUPTED(data->index);
-		index_set_error(data->index, "Error in data file %s: "
-				"full_field_size > INT_MAX", data->filepath);
+		index_data_set_corrupted(data, "full_field_size (%u) > INT_MAX",
+					 rec->full_field_size);
 		return FALSE;
 	}
 
@@ -394,11 +400,9 @@
 		}
 	}
 
-	INDEX_MARK_CORRUPTED(data->index);
-	index_set_error(data->index, "Error in data file %s: "
-			"Missing \\0 with field %u (%"PRIuUOFF_T")",
-			data->filepath, rec->field,
-			DATA_FILE_POSITION(data, rec));
+	index_data_set_corrupted(data, "Missing \\0 with field %u "
+				 "(%"PRIuUOFF_T")", rec->field,
+				 DATA_FILE_POSITION(data, rec));
 	return FALSE;
 }
 
--- a/src/lib-index/mail-index-data.h	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-data.h	Fri Sep 13 03:01:23 2002 +0300
@@ -43,4 +43,8 @@
 /* Return the whole data file mmap()ed. */
 void *mail_index_data_get_mmaped(MailIndexData *data, size_t *size);
 
+/* "Error in index data file %s: ...". Also marks the index file as
+   corrupted. */
+void index_data_set_corrupted(MailIndexData *data, const char *fmt, ...);
+
 #endif
--- a/src/lib-index/mail-index-update.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-update.c	Fri Sep 13 03:01:23 2002 +0300
@@ -134,10 +134,8 @@
 
 	if (max_size > INT_MAX) {
 		/* rec->data_size most likely corrupted */
-		index_set_error(update->index, "Error in index file %s: "
-				"data_size points outside file",
-				update->index->filepath);
-		update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
+		index_set_corrupted(update->index,
+				    "data_size points outside file");
 		return FALSE;
 	}
 
@@ -171,13 +169,11 @@
 		if (src_size > max_size || max_size - src_size < pos) {
 			/* corrupted data file - old value had a field
 			   larger than expected */
-			index_set_error(update->index,
-					"Error in index file %s: "
-					"full_field_size points outside "
-					"data_size (field %d?)",
-					update->index->filepath,
-					rec == NULL ? -1 : (int)rec->field);
-			update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
+			index_set_corrupted(update->index,
+					    "full_field_size points outside "
+					    "data_size (field %d?)",
+					    update->index->filepath,
+					    rec == NULL ? -1 : (int)rec->field);
 			return FALSE;
 		}
 		memcpy(destrec->data, src, src_size);
@@ -418,10 +414,9 @@
 			part = message_part_deserialize(pool, value, size);
 			if (part == NULL) {
 				/* corrupted, rebuild it */
-				index_set_error(update->index, "Error in index "
-						"file %s: Corrupted cached "
-						"MessagePart data",
-						update->index->filepath);
+				index_set_corrupted(update->index,
+						    "Corrupted cached "
+						    "MessagePart data");
 			}
 		}
 
--- a/src/lib-index/mail-index-util.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-util.c	Fri Sep 13 03:01:23 2002 +0300
@@ -28,6 +28,29 @@
 	}
 }
 
+void index_set_corrupted(MailIndex *index, const char *fmt, ...)
+{
+	va_list va;
+
+	INDEX_MARK_CORRUPTED(index);
+	index->inconsistent = TRUE;
+
+	va_start(va, fmt);
+	t_push();
+	index_set_error(index, "Corrupted index file %s: %s",
+			index->filepath, t_strdup_vprintf(fmt, va));
+	t_pop();
+	va_end(va);
+}
+
+void index_set_syscall_error(MailIndex *index, const char *function)
+{
+	i_assert(function != NULL);
+
+	index_set_error(index, "%s failed with index file %s: %m",
+			function, index->filepath);
+}
+
 void index_reset_error(MailIndex *index)
 {
 	if (index->error != NULL) {
--- a/src/lib-index/mail-index-util.h	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index-util.h	Fri Sep 13 03:01:23 2002 +0300
@@ -5,6 +5,12 @@
 void index_set_error(MailIndex *index, const char *fmt, ...)
 	__attr_format__(2, 3);
 
+/* "Error in index file %s: ...". Also marks the index file as corrupted. */
+void index_set_corrupted(MailIndex *index, const char *fmt, ...);
+
+/* "%s failed with index file %s: %m" */
+void index_set_syscall_error(MailIndex *index, const char *function);
+
 /* Reset the current error */
 void index_reset_error(MailIndex *index);
 
--- a/src/lib-index/mail-index.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-index.c	Fri Sep 13 03:01:23 2002 +0300
@@ -40,15 +40,12 @@
 	index->mmap_base = mmap_rw_file(index->fd, &index->mmap_length);
 	if (index->mmap_base == MAP_FAILED) {
 		index->mmap_base = NULL;
-		index_set_error(index, "index: mmap() failed with file %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "mmap()");
 		return FALSE;
 	}
 
 	if (index->mmap_length < sizeof(MailIndexHeader)) {
-		index_set_error(index, "truncated index file %s",
-				index->filepath);
-                INDEX_MARK_CORRUPTED(index);
+                index_set_corrupted(index, "File too small");
 		return FALSE;
 	}
 
@@ -134,9 +131,8 @@
 		return FALSE;
 
 	if (index->mmap_base != NULL) {
-		if (msync(index->mmap_base, index->mmap_length, MS_SYNC) == -1) {
-			index_set_error(index, "msync() failed for %s: %m",
-					index->filepath);
+		if (msync(index->mmap_base, index->mmap_length, MS_SYNC) < 0) {
+			index_set_syscall_error(index, "msync()");
 			return FALSE;
 		}
 	}
@@ -151,15 +147,13 @@
 	/* keep index's modify stamp same as the sync file's stamp */
 	ut.actime = ioloop_time;
 	ut.modtime = index->file_sync_stamp;
-	if (utime(index->filepath, &ut) == -1) {
-		index_set_error(index, "utime() failed for %s: %m",
-				index->filepath);
+	if (utime(index->filepath, &ut) < 0) {
+		index_set_syscall_error(index, "utime()");
 		return FALSE;
 	}
 
-	if (fsync(index->fd) == -1) {
-		index_set_error(index, "fsync() failed for %s: %m",
-				index->filepath);
+	if (fsync(index->fd) < 0) {
+		index_set_syscall_error(index, "fsync()");
 		return FALSE;
 	}
 
@@ -170,14 +164,12 @@
 {
 	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
-	if (msync(index->mmap_base, size, MS_SYNC) == -1) {
-		index_set_error(index, "msync() failed for %s: %m",
-				index->filepath);
+	if (msync(index->mmap_base, size, MS_SYNC) < 0) {
+		index_set_syscall_error(index, "msync()");
 		return FALSE;
 	}
-	if (fsync(index->fd) == -1) {
-		index_set_error(index, "fsync() failed for %s: %m",
-				index->filepath);
+	if (fsync(index->fd) < 0) {
+		index_set_syscall_error(index, "fsync()");
 		return FALSE;
 	}
 
@@ -227,12 +219,9 @@
 	fl.l_start = 0;
 	fl.l_len = 0;
 
-	if (fcntl(index->fd, F_SETLK, &fl) == -1) {
-		if (errno != EINTR && errno != EACCES) {
-			index_set_error(index, "fcntl(F_SETLKW, %d) "
-					"failed for file %s: %m", fl.l_type,
-					index->filepath);
-		}
+	if (fcntl(index->fd, F_SETLK, &fl) < 0) {
+		if (errno != EINTR && errno != EACCES)
+			index_set_syscall_error(index, "fcntl(F_SETLK)");
 		return FALSE;
 	}
 
@@ -249,7 +238,7 @@
 
 	if (index->inconsistent) {
 		/* index is in inconsistent state and nothing else than
-		   free() is allowed for it. */
+		   free() is allowed for it. FIXME: what about msync()ing.. */
 		return FALSE;
 	}
 
@@ -287,11 +276,9 @@
 	fl.l_start = 0;
 	fl.l_len = 0;
 
-	while (fcntl(index->fd, F_SETLKW, &fl) == -1) {
+	while (fcntl(index->fd, F_SETLKW, &fl) < 0) {
 		if (errno != EINTR) {
-			index_set_error(index, "fcntl(F_SETLKW, %d) "
-					"failed for file %s: %m", fl.l_type,
-					index->filepath);
+			index_set_syscall_error(index, "fcntl(F_SETLKW)");
 			return FALSE;
 		}
 	}
@@ -692,7 +679,7 @@
 				   "-%s", my_hostname);
 		}
 
-		if (rename(path, index_path) == -1) {
+		if (rename(path, index_path) < 0) {
 			index_set_error(index, "rename(%s, %s) failed: %m",
 					path, index_path);
 			(void)close(fd);
@@ -817,19 +804,15 @@
 	if (hdr->first_hole_position < sizeof(MailIndexHeader) ||
 	    (hdr->first_hole_position -
 	     sizeof(MailIndexHeader)) % sizeof(MailIndexRecord) != 0) {
-		index_set_error(index, "Error in index file %s: "
-				"first_hole_position contains invalid value",
-				index->filepath);
-		INDEX_MARK_CORRUPTED(index);
+		index_set_corrupted(index, "first_hole_position contains "
+				    "invalid value");
 		return FALSE;
 	}
 
 	/* make sure position is in range.. */
 	if (hdr->first_hole_position >= index->mmap_length) {
-		index_set_error(index, "Error in index file %s: "
-				"first_hole_position points outside file",
-				index->filepath);
-		INDEX_MARK_CORRUPTED(index);
+		index_set_corrupted(index, "first_hole_position points "
+				    "outside file");
 		return FALSE;
 	}
 
@@ -839,10 +822,8 @@
 			 sizeof(MailIndexHeader)) / sizeof(MailIndexRecord);
 	if (index->header->first_hole_records > max_records ||
 	    first_records + index->header->first_hole_records > max_records) {
-		index_set_error(index, "Error in index file %s: "
-				"first_hole_records points outside file",
-				index->filepath);
-		INDEX_MARK_CORRUPTED(index);
+		index_set_corrupted(index, "first_hole_records points "
+				    "outside file");
 		return FALSE;
 	}
 
@@ -885,10 +866,8 @@
 				"isn't mmap()ed (dirty_mmap not properly set)");
 		}
 
-		index_set_error(index, "Error in index file %s: "
-				"Header contains invalid message count",
-				index->filepath);
-		index->set_flags |= MAIL_INDEX_FLAG_FSCK;
+		index_set_corrupted(index,
+				    "Header contains invalid message count");
 		return NULL;
 	}
 
@@ -905,10 +884,8 @@
 		i_assert(rec <= last_rec);
 
 		if (rec->uid == 0) {
-			index_set_error(index, "Error in index file %s: "
-					"first_hole_position wasn't updated "
-					"properly", index->filepath);
-			INDEX_MARK_CORRUPTED(index);
+			index_set_corrupted(index, "first_hole_position "
+					    "wasn't updated properly");
 			return NULL;
 		}
 		return rec;
@@ -1093,10 +1070,8 @@
 	datarec = mail_index_data_lookup(index->data, rec, field);
 	if (datarec == NULL) {
 		/* corrupted, the field should have been there */
-		index_set_error(index, "Error in index file %s: "
-				"Field not found from data file",
-				index->filepath);
-		INDEX_MARK_CORRUPTED(index);
+		index_set_corrupted(index, "Field %u not found from data file "
+				    "for record %u", field, rec->uid);
 		return NULL;
 	}
 
@@ -1192,10 +1167,12 @@
 		} else if (rec->uid < index->header->first_unseen_uid_lowwater)
 			index->header->first_unseen_uid_lowwater = rec->uid;
 
-		if (index->header->seen_messages_count == 0)
-                        INDEX_MARK_CORRUPTED(index);
-		else
+		if (index->header->seen_messages_count == 0) {
+			index_set_corrupted(index, "seen_messages_count in "
+					    "header is invalid");
+		} else {
 			index->header->seen_messages_count--;
+		}
 	}
 
 	if ((old_flags & MAIL_DELETED) == 0 &&
@@ -1211,10 +1188,12 @@
 	} else if ((old_flags & MAIL_DELETED) &&
 		   (new_flags & MAIL_DELETED) == 0) {
 		/* deleted -> undeleted */
-		if (index->header->deleted_messages_count == 0)
-                        INDEX_MARK_CORRUPTED(index);
-		else
+		if (index->header->deleted_messages_count == 0) {
+			index_set_corrupted(index, "deleted_messages_count in "
+					    "header is invalid");
+		} else {
 			index->header->deleted_messages_count--;
+		}
 	}
 }
 
@@ -1241,8 +1220,7 @@
 	/* truncate index file */
 	file_size = (off_t)index->header->first_hole_position;
 	if (ftruncate(index->fd, file_size) < 0) {
-		index_set_error(index, "ftruncate() failed for index file "
-				"%s: %m", index->filepath);
+		index_set_syscall_error(index, "ftruncate()");
 		return FALSE;
 	}
 
@@ -1335,10 +1313,8 @@
 	/* update message counts */
 	if (hdr->messages_count == 0) {
 		/* corrupted */
-		index_set_error(index, "Error in index file %s: "
-				"Header says there's no mail while expunging",
-				index->filepath);
-		INDEX_MARK_CORRUPTED(index);
+		index_set_corrupted(index, "Header says there's no mail "
+				    "while expunging");
 		return FALSE;
 	}
 
@@ -1385,14 +1361,12 @@
 
 	pos = lseek(index->fd, 0, SEEK_END);
 	if (pos < 0) {
-		index_set_error(index, "lseek() failed with file %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "lseek()");
 		return FALSE;
 	}
 
 	if (write_full(index->fd, *rec, sizeof(MailIndexRecord)) < 0) {
-		index_set_error(index, "Error appending to file %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "write_full()");
 		return FALSE;
 	}
 
@@ -1404,9 +1378,8 @@
 	index->header->sync_id++;
 	index->dirty_mmap = TRUE;
 
-	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) == -1) {
-		index_set_error(index, "msync() failed for %s: %m",
-				index->filepath);
+	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) < 0) {
+		index_set_syscall_error(index, "msync()");
 		return FALSE;
 	}
 
--- a/src/lib-index/mail-modifylog.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mail-modifylog.c	Fri Sep 13 03:01:23 2002 +0300
@@ -34,6 +34,25 @@
 	unsigned int second_log:1;
 };
 
+static void modifylog_set_syscall_error(MailModifyLog *log,
+					const char *function)
+{
+	i_assert(function != NULL);
+
+	index_set_error(log->index, "%s failed with modify log file %s: %m",
+			function, log->filepath);
+}
+
+static void modifylog_set_corrupted(MailModifyLog *log)
+{
+	index_set_error(log->index, "Modify log %s is corrupted",
+			log->filepath);
+
+	/* make sure we don't get back here */
+	log->index->inconsistent = TRUE;
+	(void)unlink(log->filepath);
+}
+
 static int file_lock(int fd, int wait_lock, int lock_type)
 {
 	struct flock fl;
@@ -58,21 +77,16 @@
 	int ret;
 
 	ret = file_lock(log->fd, FALSE, lock_type);
-	if (ret == -1) {
-		index_set_error(log->index, "fcntl() failed with file %s: %m",
-				log->filepath);
-	}
+	if (ret == -1)
+                modifylog_set_syscall_error(log, "fcntl(F_SETLK)");
 
 	return ret;
 }
 
 static int mail_modifylog_wait_lock(MailModifyLog *log)
 {
-	if (file_lock(log->fd, TRUE, F_RDLCK) < 1) {
-		index_set_error(log->index, "fcntl() failed with file %s: %m",
-				log->filepath);
-		return FALSE;
-	}
+	if (file_lock(log->fd, TRUE, F_RDLCK) < 1)
+                modifylog_set_syscall_error(log, "fcntl(F_SETLKW)");
 
 	return TRUE;
 }
@@ -115,9 +129,7 @@
 	if (log->mmap_base == MAP_FAILED) {
 		log->mmap_base = NULL;
 		log->header = NULL;
-		index_set_error(log->index,
-				"modify log: mmap() failed with file %s: %m",
-				log->filepath);
+		modifylog_set_syscall_error(log, "mmap()");
 		return FALSE;
 	}
 
@@ -188,7 +200,7 @@
 		return FALSE;
 	}
 
-	if (ftruncate(fd, sizeof(hdr)) == -1) {
+	if (ftruncate(fd, sizeof(hdr)) < 0) {
 		index_set_error(log->index, "ftruncate() failed for modify "
 				"log %s: %m", path);
 		return FALSE;
@@ -364,16 +376,14 @@
 		return TRUE;
 
 	if (log->mmap_base != NULL) {
-		if (msync(log->mmap_base, log->mmap_length, MS_SYNC) == -1) {
-			index_set_error(log->index, "msync() failed for %s: %m",
-					log->filepath);
+		if (msync(log->mmap_base, log->mmap_length, MS_SYNC) < 0) {
+			modifylog_set_syscall_error(log, "msync()");
 			return FALSE;
 		}
 	}
 
-	if (fsync(log->fd) == -1) {
-		index_set_error(log->index, "fsync() failed for %s: %m",
-				log->filepath);
+	if (fsync(log->fd) < 0) {
+		modifylog_set_syscall_error(log, "fsync()");
 		return FALSE;
 	}
 
@@ -399,15 +409,13 @@
 		}
 	}
 
-	if (lseek(log->fd, 0, SEEK_END) == -1) {
-		index_set_error(log->index, "lseek() failed with file %s: %m",
-				log->filepath);
+	if (lseek(log->fd, 0, SEEK_END) < 0) {
+		modifylog_set_syscall_error(log, "lseek()");
 		return FALSE;
 	}
 
 	if (write_full(log->fd, rec, sizeof(ModifyLogRecord)) < 0) {
-		index_set_error(log->index, "Error appending to file %s: %m",
-				log->filepath);
+                modifylog_set_syscall_error(log, "write_full()");
 		return FALSE;
 	}
 
@@ -597,9 +605,7 @@
 			if (max_records-- == 0) {
 				/* log contains more data than it should
 				   have - must be corrupted. */
-				index_set_error(log->index,
-						"Modify log %s is corrupted",
-						log->filepath);
+				modifylog_set_corrupted(log);
 				return NULL;
 			}
 
@@ -669,9 +675,7 @@
 			if (max_records-- == 0) {
 				/* log contains more data than it should
 				   have - must be corrupted. */
-				index_set_error(log->index,
-						"Modify log %s is corrupted",
-						log->filepath);
+				modifylog_set_corrupted(log);
 				return NULL;
 			}
 			*arr++ = rec->uid;
--- a/src/lib-index/maildir/maildir-build.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/maildir/maildir-build.c	Fri Sep 13 03:01:23 2002 +0300
@@ -39,7 +39,7 @@
 
 	/* check that file size is somewhat reasonable */
 	if (fstat(fd, &st) == -1) {
-		index_set_error(index, "fstat() failed with file %s: %m", path);
+		index_set_error(index, "fstat() failed for file %s: %m", path);
 		return FALSE;
 	}
 
@@ -123,7 +123,7 @@
 
 	dirp = opendir(source_dir);
 	if (dirp == NULL) {
-		index_set_error(index, "Couldn't build index from %s: %m",
+		index_set_error(index, "opendir() failed for dir %s: %m",
 				source_dir);
 		return FALSE;
 	}
--- a/src/lib-index/maildir/maildir-index.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/maildir/maildir-index.c	Fri Sep 13 03:01:23 2002 +0300
@@ -166,10 +166,8 @@
 	/* we need to update the flags in the file name */
 	old_fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
 	if (old_fname == NULL) {
-                INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Corrupted index file %s: "
-				"Missing location field for record %u",
-				index->filepath, rec->uid);
+		index_data_set_corrupted(index, "Missing location field for "
+					 "record %u", rec->uid);
 		return FALSE;
 	}
 
--- a/src/lib-index/maildir/maildir-open.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/maildir/maildir-open.c	Fri Sep 13 03:01:23 2002 +0300
@@ -15,10 +15,8 @@
 
 	fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
 	if (fname == NULL) {
-                INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Corrupted index file %s: "
-				"Missing location field for record %u",
-				index->filepath, rec->uid);
+		index_data_set_corrupted(index, "Missing location field for "
+					 "record %u", rec->uid);
 		return NULL;
 	}
 
--- a/src/lib-index/maildir/maildir-rebuild.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/maildir/maildir-rebuild.c	Fri Sep 13 03:01:23 2002 +0300
@@ -32,8 +32,7 @@
 	/* truncate the file first, so it won't contain
 	   any invalid data even if we crash */
 	if (ftruncate(index->fd, sizeof(MailIndexHeader)) == -1) {
-		index_set_error(index, "Can't truncate index file %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "ftruncate()");
 		return FALSE;
 	}
 
@@ -53,7 +52,7 @@
 
 	/* update sync stamp */
 	if (stat(cur_dir, &st) == -1) {
-		index_set_error(index, "fstat() failed for maildir %s: %m",
+		index_set_error(index, "stat() failed for maildir %s: %m",
 				cur_dir);
 		return FALSE;
 	}
--- a/src/lib-index/maildir/maildir-sync.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/maildir/maildir-sync.c	Fri Sep 13 03:01:23 2002 +0300
@@ -4,6 +4,7 @@
 #include "ioloop.h"
 #include "hash.h"
 #include "maildir-index.h"
+#include "mail-index-data.h"
 #include "mail-index-util.h"
 
 #include <stdlib.h>
@@ -37,7 +38,7 @@
 		/* file itself changed - reload the header */
 		fd = open(path, O_RDONLY);
 		if (fd == -1) {
-			index_set_error(index, "Error opening file %s: %m",
+			index_set_error(index, "open() failed for file %s: %m",
 					path);
 			failed = TRUE;
 		} else {
@@ -77,10 +78,9 @@
 	for (seq = 1; rec != NULL; rec = index->next(index, rec), seq++) {
 		fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
 		if (fname == NULL) {
-			INDEX_MARK_CORRUPTED(index);
-			index_set_error(index, "Corrupted index file %s: "
-					"Missing location field for record %u",
-					index->filepath, rec->uid);
+			index_data_set_corrupted(index->data,
+						 "Missing location field for "
+						 "record %u", rec->uid);
 			return FALSE;
 		}
 
@@ -109,7 +109,7 @@
 			file_changed = FALSE;
 		else {
 			if (stat(str, &st) == -1) {
-				index_set_error(index, "stat() failed with "
+				index_set_error(index, "stat() failed for "
 						"file %s: %m", str);
 				return FALSE;
 			}
@@ -181,10 +181,8 @@
 		return FALSE;
 
 	if (index->header->messages_count >= INT_MAX/32) {
-		INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Corrupted index file %s: Header "
-				"says %u messages", index->filepath,
-				index->header->messages_count);
+		index_set_corrupted(index, "Header says %u messages",
+				    index->header->messages_count);
 		return FALSE;
 	}
 
@@ -195,7 +193,7 @@
 	   files which will be added then. */
 	dirp = opendir(dir);
 	if (dirp == NULL) {
-		index_set_error(index, "Couldn't sync index in dir %s: %m",
+		index_set_error(index, "opendir() failed for dir %s: %m",
 				dir);
 		return FALSE;
 	}
@@ -247,8 +245,7 @@
 	i_assert(index->lock_type != MAIL_LOCK_SHARED);
 
 	if (fstat(index->fd, &sti) == -1) {
-		index_set_error(index, "fstat() failed with index file %s: %m",
-				index->filepath);
+		index_set_syscall_error(index, "fstat()");
 		return FALSE;
 	}
 
@@ -257,7 +254,7 @@
 	   mail. */
         cur_dir = t_strconcat(index->dir, "/cur", NULL);
 	if (stat(cur_dir, &std) == -1) {
-		index_set_error(index, "fstat() failed for maildir %s: %m",
+		index_set_error(index, "stat() failed for maildir %s: %m",
 				cur_dir);
 		return FALSE;
 	}
@@ -270,7 +267,7 @@
 	/* move mail from new/ to cur/ */
 	new_dir = t_strconcat(index->dir, "/new", NULL);
 	if (stat(new_dir, &std) == -1) {
-		index_set_error(index, "fstat() failed for maildir "
+		index_set_error(index, "stat() failed for maildir "
 				"%s: %m", new_dir);
 		return FALSE;
 	}
@@ -305,7 +302,7 @@
 
 	/* update sync stamp */
 	if (stat(cur_dir, &std) == -1) {
-		index_set_error(index, "fstat() failed for maildir %s: %m",
+		index_set_error(index, "stat() failed for maildir %s: %m",
 				cur_dir);
 		return FALSE;
 	}
--- a/src/lib-index/mbox/mbox-fsck.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-fsck.c	Fri Sep 13 03:01:23 2002 +0300
@@ -271,8 +271,7 @@
 	   but fcntl() locking requires it. */
 	fd = open(index->mbox_path, O_RDWR);
 	if (fd == -1) {
-		index_set_error(index, "Can't open mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "open()");
 		return FALSE;
 	}
 
--- a/src/lib-index/mbox/mbox-index.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.c	Fri Sep 13 03:01:23 2002 +0300
@@ -5,10 +5,19 @@
 #include "rfc822-tokenize.h"
 #include "mbox-index.h"
 #include "mail-index-util.h"
+#include "mail-index-data.h"
 #include "mail-custom-flags.h"
 
 static MailIndex mbox_index;
 
+void mbox_set_syscall_error(MailIndex *index, const char *function)
+{
+	i_assert(function != NULL);
+
+	index_set_error(index, "%s failed with mbox file %s: %m",
+			function, index->mbox_path);
+}
+
 void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index)
 {
 	memset(ctx, 0, sizeof(MboxHeaderContext));
@@ -300,17 +309,13 @@
 	location = index->lookup_field_raw(index, rec,
 					   FIELD_TYPE_LOCATION, &size);
 	if (location == NULL) {
-		INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Corrupted index file %s: "
-				"Missing location field for record %u",
-				index->filepath, rec->uid);
+		index_data_set_corrupted(index->data, "Missing location field "
+					 "for record %u", rec->uid);
 		*offset = 0;
 		return FALSE;
 	} else if (size != sizeof(uoff_t) || *location > OFF_T_MAX) {
-		INDEX_MARK_CORRUPTED(index);
-		index_set_error(index, "Corrupted index file %s: "
-				"Invalid location field for record %u",
-				index->filepath, rec->uid);
+		index_data_set_corrupted(index->data, "Invalid location field "
+					 "for record %u", rec->uid);
 		*offset = 0;
 		return FALSE;
 	} else {
--- a/src/lib-index/mbox/mbox-index.h	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.h	Fri Sep 13 03:01:23 2002 +0300
@@ -12,7 +12,7 @@
 	int received;
 } MboxHeaderContext;
 
-MailIndex *mbox_index_alloc(const char *dir, const char *mbox_path);
+void mbox_set_syscall_error(MailIndex *index, const char *function);;
 
 void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index);
 void mbox_header_free_context(MboxHeaderContext *ctx);
@@ -28,6 +28,7 @@
 int mbox_mail_get_start_offset(MailIndex *index, MailIndexRecord *rec,
 			       uoff_t *offset);
 
+MailIndex *mbox_index_alloc(const char *dir, const char *mbox_path);
 int mbox_index_rebuild(MailIndex *index);
 int mbox_index_sync(MailIndex *index);
 int mbox_index_fsck(MailIndex *index);
--- a/src/lib-index/mbox/mbox-open.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-open.c	Fri Sep 13 03:01:23 2002 +0300
@@ -25,15 +25,13 @@
 
 	fd = open(index->mbox_path, O_RDONLY);
 	if (fd == -1) {
-		index_set_error(index, "Can't open mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "open()");
 		return NULL;
 	}
 
 	pos = lseek(fd, (off_t)offset, SEEK_SET);
 	if (pos == -1) {
-		index_set_error(index, "lseek() failed with mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "lseek()");
 		(void)close(fd);
 		return NULL;
 	}
@@ -73,8 +71,7 @@
 
 	if (!failed) {
 		if (lseek(fd, (off_t)offset, SEEK_SET) < 0) {
-			index_set_error(index, "lseek() failed with mbox file "
-					"%s: %m", index->mbox_path);
+			mbox_set_syscall_error(index, "lseek()");
 			failed = TRUE;
 		}
 	} else {
--- a/src/lib-index/mbox/mbox-rebuild.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-rebuild.c	Fri Sep 13 03:01:23 2002 +0300
@@ -33,17 +33,15 @@
 	/* update indexid */
 	index->indexid = index->header->indexid;
 
-	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) == -1) {
-		index_set_error(index, "msync() failed for index file %s: %m",
-				index->filepath);
+	if (msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) < 0) {
+		index_set_syscall_error(index, "msync()");
 		return FALSE;
 	}
 
 	/* truncate the file first, so it won't contain
 	   any invalid data even if we crash */
-	if (ftruncate(index->fd, sizeof(MailIndexHeader)) == -1) {
-		index_set_error(index, "Can't truncate index file %s: %m",
-				index->filepath);
+	if (ftruncate(index->fd, sizeof(MailIndexHeader)) < 0) {
+		index_set_syscall_error(index, "ftruncate()");
 		return FALSE;
 	}
 
@@ -55,8 +53,7 @@
 	   but fcntl() locking requires it. */
 	fd = open(index->mbox_path, O_RDWR);
 	if (fd == -1) {
-		index_set_error(index, "Error opening mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "open()");
 		return FALSE;
 	}
 
@@ -80,8 +77,7 @@
 
 	/* update sync stamp */
 	if (stat(index->mbox_path, &st) == -1) {
-		index_set_error(index, "fstat() failed for mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "fstat()");
 		return FALSE;
 	}
 
--- a/src/lib-index/mbox/mbox-rewrite.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-rewrite.c	Fri Sep 13 03:01:23 2002 +0300
@@ -168,8 +168,7 @@
 	if (inbuf->offset >= end_offset) {
 		/* fsck should have noticed it.. */
 		index_set_error(index, "Error rewriting mbox file %s: "
-				"Unexpected end of file",
-				index->mbox_path);
+				"Unexpected end of file", index->mbox_path);
 		return FALSE;
 	}
 
@@ -269,10 +268,8 @@
 	MailIndexRecord *rec;
 	IOBuffer *inbuf, *outbuf;
 	uoff_t offset;
-	const uoff_t *location;
 	const char *path;
 	unsigned int seq;
-	size_t size;
 	int in_fd, out_fd, failed;
 
 	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
@@ -287,8 +284,7 @@
 
 	in_fd = open(index->mbox_path, O_RDWR);
 	if (in_fd == -1) {
-		index_set_error(index, "Can't open mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "open()");
 		return FALSE;
 	}
 	inbuf = io_buffer_create_mmap(in_fd, default_pool,
@@ -305,22 +301,14 @@
 	rec = index->lookup(index, 1);
 	while (rec != NULL) {
 		/* get offset to beginning of mail headers */
-		location = index->lookup_field_raw(index, rec,
-						   FIELD_TYPE_LOCATION, &size);
-		if (size != sizeof(uoff_t) || *location <= inbuf->offset) {
+		if (!mbox_mail_get_start_offset(index, rec, &offset)) {
 			/* fsck should have fixed it */
-			index_set_error(index, "Error rewriting mbox file %s: "
-					"Invalid location field in index",
-					index->mbox_path);
 			failed = TRUE;
 			break;
 		}
 
-		offset = *location;
 		if (offset + rec->header_size + rec->body_size > inbuf->size) {
-			index_set_error(index, "Error rewriting mbox file %s: "
-					"Invalid message size in index",
-					index->mbox_path);
+			index_set_corrupted(index, "Invalid message size");
 			failed = TRUE;
 			break;
 		}
@@ -354,8 +342,7 @@
 	(void)io_buffer_send(outbuf, "\n", 1);
 	if (outbuf->closed) {
 		errno = outbuf->buf_errno;
-		index_set_error(index, "Error rewriting mbox file %s: "
-				"write() failed: %m", index->mbox_path);
+		mbox_set_syscall_error(index, "write()");
 		failed = TRUE;
 	}
 
--- a/src/lib-index/mbox/mbox-sync.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-index/mbox/mbox-sync.c	Fri Sep 13 03:01:23 2002 +0300
@@ -60,8 +60,7 @@
 	i_assert(index->lock_type != MAIL_LOCK_SHARED);
 
 	if (stat(index->mbox_path, &st) == -1) {
-		index_set_error(index, "stat() failed with mbox file %s: %m",
-				index->mbox_path);
+		mbox_set_syscall_error(index, "stat()");
 		return FALSE;
 	}
 
--- a/src/lib-storage/index/index-status.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib-storage/index/index-status.c	Fri Sep 13 03:01:23 2002 +0300
@@ -52,8 +52,8 @@
 		rec = index->lookup_uid_range(index, lowwater_uid,
 					      hdr->next_uid - 1);
 		if (rec == NULL) {
-			i_warning("index header's seen_messages_count or "
-				  "first_unseen_uid_lowwater is invalid.");
+			i_error("index header's seen_messages_count or "
+				"first_unseen_uid_lowwater is invalid.");
                         INDEX_MARK_CORRUPTED(index);
 			return 0;
 		} else {
--- a/src/lib/Makefile.am	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib/Makefile.am	Fri Sep 13 03:01:23 2002 +0300
@@ -15,6 +15,7 @@
 	compat.c \
 	failures.c \
 	fdpass.c \
+	file-set-size.c \
 	gmtoff.c \
 	hash.c \
 	hex-binary.c \
@@ -47,6 +48,7 @@
 	compat.h \
 	failures.h \
 	fdpass.h \
+	file-set-size.h \
 	gmtoff.h \
 	hash.h \
 	hex-binary.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/file-set-size.c	Fri Sep 13 03:01:23 2002 +0300
@@ -0,0 +1,71 @@
+/*
+ file-set-size.c - portable way to grow/shrink file size
+
+    Copyright (c) 2002 Timo Sirainen
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    "Software"), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "lib.h"
+#include "write-full.h"
+
+#include <unistd.h>
+
+int file_set_size(int fd, off_t size)
+{
+	char block[1024];
+	int ret, old_errno;
+	off_t pos;
+
+	i_assert(size >= 0);
+
+	/* try truncating it to the size we want. if this succeeds, the written
+	   area is full of zeros - exactly what we want. however, this may not
+	   work at all, in which case we fallback to write()ing the zeros. */
+	ret = ftruncate(fd, size);
+	old_errno = errno;
+
+	pos = lseek(fd, 0, SEEK_END);
+	if (ret != -1 && pos == size)
+		return lseek(fd, 0, SEEK_SET) < 0 ? -1 : 0;
+
+	if (pos < 0)
+		return -1;
+	if (pos > size) {
+		/* ftruncate() failed for some reason, even while we were
+		   trying to make the file smaller */
+		errno = old_errno;
+		return -1;
+	}
+
+	/* start growing the file */
+	size -= pos;
+	memset(block, 0, sizeof(block));
+
+	while ((uoff_t)size > sizeof(block)) {
+		/* write in 1kb blocks */
+		if (write_full(fd, block, sizeof(block)) < 0)
+			return -1;
+		size -= sizeof(block);
+	}
+
+	/* write the remainder */
+	return write_full(fd, block, (size_t)size) < 0 ? -1 : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/file-set-size.h	Fri Sep 13 03:01:23 2002 +0300
@@ -0,0 +1,8 @@
+#ifndef __FILE_SET_SIZE_H
+#define __FILE_SET_SIZE_H
+
+/* Shrink/grow file. If file is grown, the new data is guaranteed to
+   be zeros. Returns -1 if failed, 0 if successful. */
+int file_set_size(int fd, off_t size);
+
+#endif
--- a/src/lib/mmap-util.c	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib/mmap-util.c	Fri Sep 13 03:01:23 2002 +0300
@@ -26,6 +26,10 @@
 #include "lib.h"
 #include "mmap-util.h"
 
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#  define MAP_ANONYMOUS MAP_ANON
+#endif
+
 static void *mmap_file(int fd, size_t *length, int access)
 {
 	off_t size;
@@ -81,6 +85,12 @@
 	return mmap_base;
 }
 
+void *mmap_anonymous(size_t length)
+{
+	return mmap(NULL, length, PROT_READ | PROT_WRITE,
+		    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+}
+
 #ifndef HAVE_MADVISE
 int madvise(void *start, size_t length, int advice)
 {
--- a/src/lib/mmap-util.h	Fri Sep 13 02:09:45 2002 +0300
+++ b/src/lib/mmap-util.h	Fri Sep 13 03:01:23 2002 +0300
@@ -21,4 +21,6 @@
 void *mmap_aligned(int fd, int access, off_t offset, size_t length,
 		   void **data_start, size_t *mmap_length);
 
+void *mmap_anonymous(size_t length);
+
 #endif