changeset 1238:2512ad6fd9e9 HEAD

Index opening rewrites. We don't try to support .imap.index-<hostname> style indexes anymore. They just made things more difficult, and it's really not a good idea to use index files via NFS anyway. Added support for :INDEX=MEMORY in MAIL env to disable using index files. Also if we can't open or create index file for any reason, we now fallback to in-memory indexes. Before we fallbacked only with out of disk space errors. If .customflags can't be created, we still work now by not allowing to create new custom flags.
author Timo Sirainen <tss@iki.fi>
date Sun, 23 Feb 2003 23:06:57 +0200
parents 9b693201e075
children 844bf41d831b
files doc/index.txt doc/mail-storages.txt dovecot-example.conf src/lib-index/Makefile.am src/lib-index/mail-custom-flags.c src/lib-index/mail-index-compress.c src/lib-index/mail-index-data.c src/lib-index/mail-index-open.c src/lib-index/mail-index-util.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mail-lockdir.c src/lib-index/mail-lockdir.h src/lib-index/mail-modifylog.c src/lib-index/mail-tree.c src/lib-index/maildir/maildir-index.c src/lib-index/mbox/mbox-index.c src/lib-storage/index/index-storage.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-storage.c src/master/mail-process.c src/master/master-settings.c src/master/master-settings.h
diffstat 23 files changed, 410 insertions(+), 768 deletions(-) [+]
line wrap: on
line diff
--- a/doc/index.txt	Sun Feb 23 21:49:20 2003 +0200
+++ b/doc/index.txt	Sun Feb 23 23:06:57 2003 +0200
@@ -9,12 +9,6 @@
 No attempt is made to deal with incompatible index files, they're either
 overwritten or new files are created.
 
-Index file names begin with ".imap.index" or ".imap.index-<hostname>". The
-first form is used by default, the second when first is found to be
-incompatible. If the second is also incompatible, it's simply overwritten.
-This should allow us to be NFS-safe in an environment with multiple
-different computer architectures.
-
 Indexes are bound to each others by "indexid" field in headers. If they
 don't match, the file is assumed to be corrupted and will be rebuilt.
 
--- a/doc/mail-storages.txt	Sun Feb 23 21:49:20 2003 +0200
+++ b/doc/mail-storages.txt	Sun Feb 23 23:06:57 2003 +0200
@@ -53,6 +53,11 @@
 Adding :INDEX=<dir> to MAIL environment overrides the default location. The
 given directory must exist.
 
+It's also possible to disable index files by building them into memory.
+They're also automatically built into memory if the index files can't be
+opened or created for some reason (eg. out of disk space). To disable
+indexes always, add :INDEX=MEMORY to MAIL environment.
+
 
 Detecting what to use
 ---------------------
--- a/dovecot-example.conf	Sun Feb 23 21:49:20 2003 +0200
+++ b/dovecot-example.conf	Sun Feb 23 23:06:57 2003 +0200
@@ -294,12 +294,6 @@
 # lock file after this many seconds.
 #mbox_dotlock_change_timeout = 30
 
-# If main index file is incompatible with us, should we overwrite it or
-# create a new index with another name. Unless you are running Dovecot in
-# multiple computers with different architectures accessing the same
-# mailboxes (eg. via NFS), it's safe to set this "yes".
-#overwrite_incompatible_index = no
-
 # umask to use for mail files and directories
 #umask = 0077
 
--- a/src/lib-index/Makefile.am	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/Makefile.am	Sun Feb 23 23:06:57 2003 +0200
@@ -17,7 +17,6 @@
         mail-index-update.c \
         mail-index-update-cache.c \
         mail-index-util.c \
-        mail-lockdir.c \
 	mail-modifylog.c \
 	mail-tree.c \
 	mail-tree-redblack.c
@@ -27,6 +26,5 @@
 	mail-index.h \
         mail-index-data.h \
         mail-index-util.h \
-        mail-lockdir.h \
 	mail-modifylog.h \
 	mail-tree.h
--- a/src/lib-index/mail-custom-flags.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-custom-flags.c	Sun Feb 23 23:06:57 2003 +0200
@@ -9,9 +9,10 @@
 #include "mail-index-util.h"
 #include "mail-custom-flags.h"
 
+#include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <ctype.h>
+#include <sys/stat.h>
 
 /* Header is simply a counter which is increased every time the file is
    updated. This allows other processes to easily notice if there's been
@@ -44,6 +45,11 @@
 {
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		mcf->index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(mcf->index, "%s failed with custom flags file %s: %m",
 			function, mcf->filepath);
 	return FALSE;
@@ -69,8 +75,8 @@
 static int custom_flags_init(struct mail_custom_flags *mcf)
 {
 	static char buf[HEADER_SIZE] = "0000\n";
+	struct stat st;
 	int failed;
-	off_t pos;
 
 	if (!lock_file(mcf, F_WRLCK))
 		return FALSE;
@@ -78,22 +84,15 @@
 	failed = FALSE;
 
 	/* make sure it's still empty after locking */
-	pos = lseek(mcf->fd, 0, SEEK_END);
-	if (pos >= 0 && pos < HEADER_SIZE)
-		pos = lseek(mcf->fd, 0, SEEK_SET);
-
-	if (pos < 0) {
-		index_cf_set_syscall_error(mcf, "lseek()");
+	if (fstat(mcf->fd, &st) < 0) {
+		index_cf_set_syscall_error(mcf, "fstat()");
 		failed = TRUE;
-	}
-
-	/* write the header - it's a 4 byte counter as hex */
-	if (!failed && write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
-		if (errno == ENOSPC)
-			mcf->index->nodiskspace = TRUE;
-
-		index_cf_set_syscall_error(mcf, "write_full()");
-		failed = TRUE;
+	} else if (st.st_size < HEADER_SIZE) {
+		/* write the header - it's a 4 byte counter as hex */
+		if (write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
+			index_cf_set_syscall_error(mcf, "write_full()");
+			failed = TRUE;
+		}
 	}
 
 	if (!lock_file(mcf, F_UNLCK))
@@ -183,6 +182,11 @@
 		if (mcf->lock_type == F_RDLCK)
 			(void)lock_file(mcf, F_UNLCK);
 
+		if (lseek(mcf->fd, 0, SEEK_SET) < 0) {
+			index_cf_set_syscall_error(mcf, "lseek()");
+			return FALSE;
+		}
+
 		if (!custom_flags_init(mcf))
 			return FALSE;
 
@@ -200,9 +204,13 @@
 	if (mcf->lock_type == type)
 		return TRUE;
 
-	/* FIXME: possibility to use .lock file instead */
-	if (file_wait_lock(mcf->fd, type) <= 0)
-		return index_cf_set_syscall_error(mcf, "file_wait_lock()");
+	if (mcf->fd != -1) {
+		/* FIXME: possibility to use .lock file instead */
+		if (file_wait_lock(mcf->fd, type) <= 0) {
+			index_cf_set_syscall_error(mcf, "file_wait_lock()");
+			return FALSE;
+		}
+	}
 
 	mcf->lock_type = type;
 
@@ -230,13 +238,14 @@
 	const char *path;
 	int fd;
 
-	path = t_strconcat(index->dir, "/", CUSTOM_FLAGS_FILE_NAME, NULL);
-	fd = open(path, O_RDWR | O_CREAT, 0660);
-	if (fd == -1) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
-		return index_file_set_syscall_error(index, path, "open()");
+	path = t_strconcat(index->custom_flags_dir, "/",
+			   CUSTOM_FLAGS_FILE_NAME, NULL);
+	if (path == NULL)
+		fd = -1;
+	else {
+		fd = open(path, O_RDWR | O_CREAT, 0660);
+		if (fd == -1)
+			index_file_set_syscall_error(index, path, "open()");
 	}
 
 	mcf = i_new(struct mail_custom_flags, 1);
@@ -244,22 +253,25 @@
 	mcf->filepath = i_strdup(path);
 	mcf->fd = fd;
 
-	if (!update_mmap(mcf)) {
-		mail_custom_flags_free(mcf);
-		return FALSE;
+	if (fd != -1) {
+		if (!update_mmap(mcf)) {
+			(void)close(mcf->fd);
+			mcf->fd = -1;
+		}
+
+		if (mcf->mmap_length < HEADER_SIZE) {
+			/* we just created it, write the header */
+			mcf->syncing = TRUE;
+			if (!custom_flags_init(mcf) || !update_mmap(mcf)) {
+				(void)close(mcf->fd);
+				mcf->fd = -1;
+			}
+			mcf->syncing = FALSE;
+		}
 	}
 
-	if (mcf->mmap_length < HEADER_SIZE) {
-		/* we just created it, write the header */
-		mcf->syncing = TRUE;
-		if ((!custom_flags_init(mcf) || !update_mmap(mcf)) &&
-		    !index->nodiskspace) {
-			mail_custom_flags_free(mcf);
-			return FALSE;
-		}
-		mcf->syncing = FALSE;
-		mcf->noupdate = index->nodiskspace;
-	}
+	mcf->noupdate = mcf->fd == -1;
+	mcf->index->allow_new_custom_flags = mcf->fd != -1;
 
 	custom_flags_sync(mcf);
 
@@ -279,8 +291,10 @@
 			index_cf_set_syscall_error(mcf, "munmap()");
 	}
 
-	if (close(mcf->fd) < 0)
-		index_cf_set_syscall_error(mcf, "close()");
+	if (mcf->fd != -1) {
+		if (close(mcf->fd) < 0)
+			index_cf_set_syscall_error(mcf, "close()");
+	}
 
 	i_free(mcf->filepath);
 	i_free(mcf);
--- a/src/lib-index/mail-index-compress.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index-compress.c	Sun Feb 23 23:06:57 2003 +0200
@@ -132,9 +132,6 @@
 	memset(&data_hdr, 0, sizeof(data_hdr));
 	data_hdr.indexid = index->indexid;
 	if (write_full(fd, &data_hdr, sizeof(data_hdr)) < 0) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
 		index_file_set_syscall_error(index, path, "write_full()");
 		return FALSE;
 	}
@@ -164,9 +161,6 @@
 
 		if (write_full(fd, mmap_data + rec->data_position,
 			       rec_hdr->data_size) < 0) {
-			if (errno == ENOSPC)
-				index->nodiskspace = TRUE;
-
 			index_file_set_syscall_error(index, path,
 						     "write_full()");
 			return FALSE;
@@ -207,11 +201,8 @@
 		return FALSE;
 
 	fd = mail_index_create_temp_file(index, &temppath);
-	if (fd == -1) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
+	if (fd == -1)
 		return FALSE;
-	}
 
 	failed = !mail_index_copy_data(index, fd, temppath);
 
--- a/src/lib-index/mail-index-data.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index-data.c	Sun Feb 23 23:06:57 2003 +0200
@@ -66,6 +66,11 @@
 {
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		data->index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(data->index, "%s failed with index data file %s: %m",
 			function, data->filepath);
 	return FALSE;
@@ -243,68 +248,52 @@
 	return TRUE;
 }
 
-static const char *init_data_file(struct mail_index *index,
-				  struct mail_index_data_header *hdr,
-				  int fd, const char *temppath)
+static int mail_index_data_init(struct mail_index *index,
+				struct mail_index_data_header *hdr,
+				const char *path, int fd)
 {
-	const char *realpath;
-
 	if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
-		index_file_set_syscall_error(index, temppath, "write_full()");
-		return NULL;
+		index_file_set_syscall_error(index, path, "write_full()");
+		return FALSE;
 	}
 
 	if (file_set_size(fd, INDEX_DATA_INITIAL_SIZE) < 0) {
-		index_file_set_syscall_error(index, temppath,
-					     "file_set_size()");
-		return NULL;
+		index_file_set_syscall_error(index, path, "file_set_size()");
+		return FALSE;
 	}
 
-	/* 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) < 0) {
-		index_set_error(index, "rename(%s, %s) failed: %m",
-				temppath, realpath);
-		return NULL;
-	}
-
-	return realpath;
+	return TRUE;
 }
 
 int mail_index_data_create(struct mail_index *index)
 {
         struct mail_index_data_header hdr;
 	struct mail_index_data *data;
-	const char *temppath, *realpath;
+	const char *path;
 	int fd;
 
+	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
+
 	memset(&hdr, 0, sizeof(struct mail_index_data_header));
 	hdr.indexid = index->indexid;
 	hdr.used_file_size = sizeof(struct mail_index_data_header);
 
-	realpath = NULL;
-
 	/* we'll do anon-mmaping only if initially requested. if we fail
 	   because of out of disk space, we'll just let the main index code
 	   know it and fail. */
-	if (index->nodiskspace) {
+	if (INDEX_IS_IN_MEMORY(index)) {
 		fd = -1;
+		path = NULL;
 	} else {
-		fd = mail_index_create_temp_file(index, &temppath);
+		path = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
+		fd = open(path, O_RDWR | O_CREAT, 0660);
 		if (fd == -1) {
-			if (errno == ENOSPC)
-				index->nodiskspace = TRUE;
+			index_file_set_syscall_error(index, path, "open()");
 			return FALSE;
 		}
 
-		realpath = init_data_file(index, &hdr, fd, temppath);
-		if (realpath == NULL) {
-			if (errno == ENOSPC)
-				index->nodiskspace = TRUE;
-
+		if (!mail_index_data_init(index, &hdr, path, fd)) {
 			(void)close(fd);
-			(void)unlink(temppath);
 			return FALSE;
 		}
 	}
@@ -320,9 +309,11 @@
 		data->mmap_used_length = data->header->used_file_size;
 
 		data->anon_mmap = TRUE;
-		data->filepath = i_strdup("(in-memory index data)");
+		data->filepath =
+			i_strdup_printf("(in-memory index data index for %s)",
+					index->mailbox_path);
 	} else {
-		data->filepath = i_strdup(realpath);
+		data->filepath = i_strdup(path);
 	}
 
 	data->index = index;
@@ -360,20 +351,14 @@
 		return TRUE;
 	}
 
-	if (file_set_size(data->fd, INDEX_DATA_INITIAL_SIZE) < 0) {
-		if (errno == ENOSPC)
-			data->index->nodiskspace = TRUE;
+	if (file_set_size(data->fd, INDEX_DATA_INITIAL_SIZE) < 0)
 		return index_data_set_syscall_error(data, "file_set_size()");
-	}
 
 	if (lseek(data->fd, 0, SEEK_SET) < 0)
 		return index_data_set_syscall_error(data, "lseek()");
 
-	if (write_full(data->fd, &hdr, sizeof(hdr)) < 0) {
-		if (errno == ENOSPC)
-			data->index->nodiskspace = TRUE;
+	if (write_full(data->fd, &hdr, sizeof(hdr)) < 0)
 		return index_data_set_syscall_error(data, "write_full()");
-	}
 
 	data->modified = FALSE;
 	data->fsynced = FALSE;
@@ -440,11 +425,8 @@
 	if (pos < (off_t)sizeof(struct mail_index_data_header))
 		return index_data_set_corrupted(data, "Header is missing");
 
-	if (file_set_size(data->fd, (off_t)new_fsize) < 0) {
-		if (errno == ENOSPC)
-			data->index->nodiskspace = TRUE;
+	if (file_set_size(data->fd, (off_t)new_fsize) < 0)
 		return index_data_set_syscall_error(data, "file_set_size()");
-	}
 
 	return mmap_update(data, 0, 0);
 }
--- a/src/lib-index/mail-index-open.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index-open.c	Sun Feb 23 23:06:57 2003 +0200
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "ioloop.h"
@@ -12,7 +12,6 @@
 #include "mail-index-data.h"
 #include "mail-index-util.h"
 #include "mail-tree.h"
-#include "mail-lockdir.h"
 #include "mail-modifylog.h"
 #include "mail-custom-flags.h"
 
@@ -21,110 +20,16 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-static const char *index_file_prefixes[] =
-	{ "data", "tree", "log", "log.2", NULL };
-
-static int delete_index(const char *path)
-{
-	char tmp[PATH_MAX];
-	int i;
-
-	/* main index */
-	if (unlink(path) < 0)
-		return FALSE;
-
-	for (i = 0; index_file_prefixes[i] != NULL; i++) {
-		if (i_snprintf(tmp, sizeof(tmp), "%s.%s",
-			       path, index_file_prefixes[i]) < 0)
-			return FALSE;
-
-		if (unlink(tmp) < 0)
-			return FALSE;
-		i++;
-	}
-
-	return TRUE;
-}
-
-static int read_and_verify_header(int fd, struct mail_index_header *hdr,
-				  int check_version)
-{
-	/* read the header */
-	if (lseek(fd, 0, SEEK_SET) != 0)
-		return FALSE;
-
-	if (read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
-		return FALSE;
-
-	/* check the compatibility */
-	return hdr->compat_data[1] == MAIL_INDEX_COMPAT_FLAGS &&
-		hdr->compat_data[2] == sizeof(unsigned int) &&
-		hdr->compat_data[3] == sizeof(time_t) &&
-		hdr->compat_data[4] == sizeof(uoff_t) &&
-		hdr->compat_data[5] == MEM_ALIGN_SIZE &&
-		(!check_version || hdr->compat_data[0] == MAIL_INDEX_VERSION);
-}
-
-/* Returns TRUE if we're compatible with given index file. May delete the
-   file if it's from older version. */
-static int mail_check_compatible_index(struct mail_index *index,
-				       const char *path)
-{
-        struct mail_index_header hdr;
-	int fd, compatible;
-
-	fd = open(path, O_RDONLY);
-	if (fd == -1) {
-		if (errno != ENOENT)
-			index_file_set_syscall_error(index, path, "open()");
-		return FALSE;
-	}
-
-	compatible = read_and_verify_header(fd, &hdr, FALSE);
-	if (hdr.compat_data[0] != MAIL_INDEX_VERSION) {
-		/* version mismatch */
-		compatible = FALSE;
-		if (hdr.compat_data[0] < MAIL_INDEX_VERSION) {
-			/* of older version, we don't need it anymore */
-			(void)delete_index(path);
-		}
-	}
-
-	(void)close(fd);
-	return compatible;
-}
-
-/* Returns a file name of compatible index */
-static const char *mail_find_index(struct mail_index *index)
-{
-	const char *name;
-	char path[PATH_MAX];
-
-	hostpid_init();
-
-	/* first try .imap.index-<hostname> */
-	name = t_strconcat(INDEX_FILE_PREFIX "-", my_hostname, NULL);
-	if (str_path(path, sizeof(path), index->dir, name) == 0 &&
-	    mail_check_compatible_index(index, path))
-		return name;
-
-	/* then try the generic .imap.index */
-	name = INDEX_FILE_PREFIX;
-	if (str_path(path, sizeof(path), index->dir, name) == 0 &&
-	    mail_check_compatible_index(index, path))
-		return name;
-
-	return NULL;
-}
-
-static int mail_index_open_init(struct mail_index *index, int update_recent)
+static int mail_index_open_init(struct mail_index *index,
+				enum mail_index_open_flags flags)
 {
 	struct mail_index_header *hdr;
 
 	hdr = index->header;
 
 	/* update \Recent message counters */
-	if (update_recent && hdr->last_nonrecent_uid != hdr->next_uid-1) {
+	if ((flags & MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT) != 0 &&
+	    hdr->last_nonrecent_uid != hdr->next_uid-1) {
 		/* keep last_recent_uid to next_uid-1 */
 		if (index->lock_type == MAIL_LOCK_SHARED) {
 			if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
@@ -157,24 +62,24 @@
 }
 
 static int index_open_and_fix(struct mail_index *index,
-			      int update_recent, int fast)
+			      enum mail_index_open_flags flags)
 {
-	int rebuild;
-
-	if (!mail_index_mmap_update(index))
-		return FALSE;
-
-	rebuild = FALSE;
+	/* open/create the index files */
+	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) {
+		if (!mail_index_data_open(index)) {
+			if ((index->set_flags & MAIL_INDEX_FLAG_REBUILD) == 0)
+				return FALSE;
 
-	/* open/create the index files */
-	if (!mail_index_data_open(index)) {
-		if ((index->set_flags & MAIL_INDEX_FLAG_REBUILD) == 0)
-			return FALSE;
+			/* data file is corrupted, need to rebuild index */
+			flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
+			index->set_flags = 0;
+			index->inconsistent = FALSE;
+		}
+	}
 
-		/* data file is corrupted, need to rebuild index */
-		rebuild = TRUE;
-		index->set_flags = 0;
-
+	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) != 0) {
+		if (!mail_index_set_lock(index, MAIL_LOCK_EXCLUSIVE))
+			return FALSE;
 		if (!mail_index_data_create(index))
 			return FALSE;
 	}
@@ -184,20 +89,27 @@
 	if (!mail_custom_flags_open_or_create(index))
 		return FALSE;
 
-	if (rebuild || (index->header->flags & MAIL_INDEX_FLAG_REBUILD)) {
-		/* index is corrupted, rebuild */
+	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) != 0 ||
+	    (index->header->flags & MAIL_INDEX_FLAG_REBUILD) != 0) {
 		if (!index->rebuild(index))
 			return FALSE;
 
-		/* no inconsistency problems while still opening
+		/* no inconsistency problems since we're still opening
 		   the index */
 		index->inconsistent = FALSE;
 	}
 
-	if (!mail_tree_open_or_create(index))
-		return FALSE;
-	if (!mail_modifylog_open_or_create(index))
-		return FALSE;
+	if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) {
+		if (!mail_tree_open_or_create(index))
+			return FALSE;
+		if (!mail_modifylog_open_or_create(index))
+			return FALSE;
+	} else {
+		if (!mail_tree_create(index))
+			return FALSE;
+		if (!mail_modifylog_create(index))
+			return FALSE;
+	}
 
 	if (index->header->flags & MAIL_INDEX_FLAG_FSCK) {
 		/* index needs fscking */
@@ -205,18 +117,12 @@
 			return FALSE;
 	}
 
-	if (!fast && (index->header->flags & MAIL_INDEX_FLAG_COMPRESS)) {
-		/* remove deleted blocks from index file */
-		if (!mail_index_compress(index))
-			return FALSE;
-	}
-
-	if (index->header->flags & MAIL_INDEX_FLAG_REBUILD_TREE) {
+	if ((index->header->flags & MAIL_INDEX_FLAG_REBUILD_TREE) != 0) {
 		if (!mail_tree_rebuild(index->tree))
 			return FALSE;
 	}
 
-	/* sync ourself - before updating cache and compression which
+	/* sync ourself. do it before updating cache and compression which
 	   may happen because of this. */
 	if (!index->sync_and_lock(index, MAIL_LOCK_SHARED, NULL))
 		return FALSE;
@@ -229,262 +135,91 @@
 			return FALSE;
 	}
 
-	if (!fast && (index->header->flags & MAIL_INDEX_FLAG_CACHE_FIELDS)) {
-		/* need to update cached fields */
-		if (!mail_index_update_cache(index))
-			return FALSE;
+	if ((flags & MAIL_INDEX_OPEN_FLAG_FAST) == 0) {
+		if (index->header->flags & MAIL_INDEX_FLAG_COMPRESS) {
+			/* remove deleted blocks from index file */
+			if (!mail_index_compress(index))
+				return FALSE;
+		}
+
+		if (index->header->flags & MAIL_INDEX_FLAG_CACHE_FIELDS) {
+			/* need to update cached fields */
+			if (!mail_index_update_cache(index))
+				return FALSE;
+		}
+
+		if (index->header->flags & MAIL_INDEX_FLAG_COMPRESS_DATA) {
+			/* remove unused space from index data file.
+			   keep after cache updates which may move data
+			   and create unused space */
+			if (!mail_index_compress_data(index))
+				return FALSE;
+		}
 	}
 
-	if (!fast && (index->header->flags & MAIL_INDEX_FLAG_COMPRESS_DATA)) {
-		/* remove unused space from index data file.
-		   keep after cache_fields which may move data
-		   and create unused space.. */
-		if (!mail_index_compress_data(index))
-			return FALSE;
-	}
-
-	if (!mail_index_open_init(index, update_recent))
+	if (!mail_index_open_init(index, flags))
 		return FALSE;
 
 	return TRUE;
 }
 
-static int mail_index_verify_header(struct mail_index *index,
-				    struct mail_index_header *hdr)
+static int mail_index_read_header(struct mail_index *index,
+				  struct mail_index_header *hdr)
 {
-	/* if index is being created, we'll wait here until it's finished */
-	if (!mail_index_wait_lock(index, F_RDLCK))
-		return FALSE;
+	ssize_t ret;
+
+	ret = read(index->fd, hdr, sizeof(*hdr));
+	if (ret < 0) {
+		index_set_syscall_error(index, "read()");
+		return -1;
+	}
+
+	if (ret != sizeof(*hdr)) {
+		/* missing data */
+		return 0;
+	}
+
+	return 1;
+}
 
-	/* check the compatibility anyway just to be sure */
-	if (!read_and_verify_header(index->fd, hdr, TRUE)) {
-		index_set_error(index, "Non-compatible index file %s",
-				index->filepath);
-		(void)mail_index_wait_lock(index, F_UNLCK);
+static int mail_index_is_compatible(const struct mail_index_header *hdr)
+{
+	return hdr->compat_data[0] == MAIL_INDEX_VERSION &&
+		hdr->compat_data[1] == MAIL_INDEX_COMPAT_FLAGS &&
+		hdr->compat_data[2] == sizeof(unsigned int) &&
+		hdr->compat_data[3] == sizeof(time_t) &&
+		hdr->compat_data[4] == sizeof(uoff_t) &&
+		hdr->compat_data[5] == MEM_ALIGN_SIZE;
+}
+
+static int mail_index_init_file(struct mail_index *index,
+				struct mail_index_header *hdr)
+{
+	hdr->used_file_size = sizeof(*hdr) +
+		INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record);
+
+	if (lseek(index->fd, 0, SEEK_SET) < 0) {
+		index_set_syscall_error(index, "lseek()");
 		return FALSE;
 	}
 
-	if (!mail_index_wait_lock(index, F_UNLCK))
-		return FALSE;
-
-	return TRUE;
-}
-
-static int mail_index_open_file(struct mail_index *index, const char *path,
-				int update_recent, int fast)
-{
-        struct mail_index_header hdr;
-
-	/* the index file should already be checked that it exists and
-	   we're compatible with it. */
-
-	index->fd = open(path, O_RDWR);
-	if (index->fd == -1)
-		return index_file_set_syscall_error(index, path, "open()");
-	index->filepath = i_strdup(path);
-
-	if (!mail_index_verify_header(index, &hdr)) {
-		(void)close(index->fd);
-		index->fd = -1;
-
-		i_free(index->filepath);
-		index->filepath = NULL;
+	if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
+		index_set_syscall_error(index, "write_full()");
 		return FALSE;
 	}
 
-	index->indexid = hdr.indexid;
-
-	/* the shared lock set is just to make sure we drop exclusive lock */
-	if (!index_open_and_fix(index, update_recent, fast) ||
-	    !index->set_lock(index, MAIL_LOCK_UNLOCK)) {
-		mail_index_close(index);
+	if (file_set_size(index->fd, (off_t)hdr->used_file_size) < 0) {
+		index_set_syscall_error(index, "file_set_size()");
 		return FALSE;
 	}
 
 	return TRUE;
 }
 
-static int mail_index_init_new_file(struct mail_index *index,
-				    struct mail_index_header *hdr,
-				    const char *temp_path)
-{
-	const char *index_path;
-	off_t fsize;
-
-	/* set the index's path temporarily */
-	index->filepath = t_strdup_noconst(temp_path);
-
-	if (write_full(index->fd, hdr, sizeof(struct mail_index_header)) < 0) {
-		index_set_syscall_error(index, "write_full()");
-		index->filepath = NULL;
-		return FALSE;
-	}
-
-	fsize = sizeof(struct mail_index_header) +
-		INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record);
-	if (file_set_size(index->fd, fsize) < 0) {
-		index_set_syscall_error(index, "file_set_size()");
-		index->filepath = NULL;
-		return FALSE;
-	}
-
-	if (mail_index_wait_lock(index, F_WRLCK) <= 0) {
-		index->filepath = NULL;
-		return FALSE;
-	}
-	index->filepath = NULL;
-
-	/* move the temp index into the real one. we also need to figure
-	   out what to call ourself on the way. */
-	index_path = t_strconcat(index->dir, "/"INDEX_FILE_PREFIX, NULL);
-	if (link(temp_path, index_path) == 0) {
-		if (unlink(temp_path) < 0) {
-			/* doesn't really matter, log anyway */
-			index_file_set_syscall_error(index, temp_path,
-						     "unlink()");
-		}
-	} else {
-		if (errno != EEXIST) {
-			/* fatal error */
-			index_set_error(index, "link(%s, %s) failed: %m",
-					temp_path, index_path);
-			return FALSE;
-		}
-
-		if (getenv("OVERWRITE_INCOMPATIBLE_INDEX") != NULL) {
-			/* don't try to support different architectures,
-			   just overwrite the index if it's already there. */
-		} else {
-			/* fallback to .imap.index-hostname - we require each
-			   system to have a different hostname so it's safe to
-			   override previous index as well */
-			hostpid_init();
-
-			index_path = t_strconcat(index_path, "-",
-						 my_hostname, NULL);
-		}
-
-		if (rename(temp_path, index_path) < 0) {
-			index_set_error(index, "rename(%s, %s) failed: %m",
-					temp_path, index_path);
-			return FALSE;
-		}
-	}
-
-	index->filepath = i_strdup(index_path);
-	return TRUE;
-}
-
-static int mail_index_create(struct mail_index *index, int *dir_unlocked,
-			     int update_recent)
-{
-	struct mail_index_header hdr;
-	const char *path;
-	int nodiskspace;
-
-	*dir_unlocked = FALSE;
-
-	mail_index_init_header(index, &hdr);
-
-	if (index->nodiskspace) {
-		/* don't even bother trying to create it */
-	} else {
-		/* first create the index into temporary file. */
-		index->fd = mail_index_create_temp_file(index, &path);
-		if (index->fd != -1) {
-			if (!mail_index_init_new_file(index, &hdr, path)) {
-				int old_errno = errno;
-
-				(void)close(index->fd);
-				(void)unlink(path);
-				index->fd = -1;
-
-				errno = old_errno;
-			}
-		}
-
-		if (index->fd == -1 && errno != ENOSPC) {
-			/* fatal failure */
-			return FALSE;
-		}
-	}
-
-	if (index->fd == -1) {
-		/* no space for index files, keep it in memory */
-		index->mmap_full_length = INDEX_FILE_MIN_SIZE;
-		index->mmap_base = mmap_anon(index->mmap_full_length);
-
-		memcpy(index->mmap_base, &hdr, sizeof(hdr));
-		index->header = index->mmap_base;
-		index->mmap_used_length = index->header->used_file_size;
-
-		index->anon_mmap = TRUE;
-		index->filepath = i_strdup("(in-memory index)");
-	}
-
-	index->indexid = hdr.indexid;
-
-	/* the fd is actually already locked, now we're just making it
-	   clear to the indexing code. */
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) {
-		mail_index_close(index);
-		return FALSE;
-	}
-
-	/* it's not good to keep the directory locked too long. our index file
-	   is locked which is enough. */
-	if (!*dir_unlocked && mail_index_lock_dir(index, MAIL_LOCK_UNLOCK))
-		*dir_unlocked = TRUE;
-
-	do {
-		if (!mail_custom_flags_open_or_create(index))
-			break;
-		if (!mail_index_data_create(index))
-			break;
-
-		nodiskspace = index->nodiskspace;
-		if (!index->rebuild(index)) {
-			if (!index->anon_mmap && index->nodiskspace) {
-				/* we're out of disk space, keep it in
-				   memory this time */
-				mail_index_close(index);
-
-                                index->nodiskspace = TRUE;
-				return mail_index_create(index, dir_unlocked,
-							 update_recent);
-			}
-			break;
-		}
-
-		/* rebuild() resets the nodiskspace variable */
-		index->nodiskspace = nodiskspace;
-
-		if (!mail_tree_create(index))
-			break;
-		if (!mail_modifylog_create(index))
-			break;
-
-		index->inconsistent = FALSE;
-
-		if (!mail_index_open_init(index, update_recent))
-			break;
-
-		if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-			break;
-
-		return TRUE;
-	} while (0);
-
-	(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
-
-	mail_index_close(index);
-	return FALSE;
-}
-
 void mail_index_init_header(struct mail_index *index,
 			    struct mail_index_header *hdr)
 {
-	memset(hdr, 0, sizeof(struct mail_index_header));
+	memset(hdr, 0, sizeof(*hdr));
 	hdr->compat_data[0] = MAIL_INDEX_VERSION;
 	hdr->compat_data[1] = MAIL_INDEX_COMPAT_FLAGS;
 	hdr->compat_data[2] = sizeof(unsigned int);
@@ -516,73 +251,136 @@
 	size_t len;
 
 	index->fd = -1;
-	index->dir = i_strdup(dir);
+
+	if (dir != NULL) {
+		index->dir = i_strdup(dir);
 
-	len = strlen(index->dir);
-	if (index->dir[len-1] == '/')
-		index->dir[len-1] = '\0';
+		len = strlen(index->dir);
+		if (index->dir[len-1] == '/')
+			index->dir[len-1] = '\0';
+	}
 
 	index->mail_read_mmaped = getenv("MAIL_READ_MMAPED") != NULL;
 }
 
-int mail_index_open(struct mail_index *index, int update_recent, int fast)
+static int mail_index_create_memory(struct mail_index *index,
+				    enum mail_index_open_flags flags)
 {
-	const char *name, *path;
-
-	i_assert(!index->opened);
-
-	/* this isn't initialized anywhere else */
-	index->fd = -1;
-
-	mail_index_cleanup_temp_files(index->dir);
-
-	name = mail_find_index(index);
-	if (name == NULL)
+	if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
 		return FALSE;
 
-	path = t_strconcat(index->dir, "/", name, NULL);
-	if (!mail_index_open_file(index, path, update_recent, fast))
+	flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
+
+	index->mmap_full_length = INDEX_FILE_MIN_SIZE;
+	index->mmap_base = mmap_anon(index->mmap_full_length);
+
+	mail_index_init_header(index, index->mmap_base);
+	index->header = index->mmap_base;
+	index->mmap_used_length = index->header->used_file_size;
+
+	index->anon_mmap = TRUE;
+	index->lock_type = MAIL_LOCK_EXCLUSIVE;
+	index->indexid = index->header->indexid;
+	index->filepath = i_strdup_printf("(in-memory index for %s)",
+					  index->mailbox_path);
+
+	if (!index_open_and_fix(index, flags)) {
+		mail_index_close(index);
 		return FALSE;
+	}
 
-	index->opened = TRUE;
 	return TRUE;
 }
 
-int mail_index_open_or_create(struct mail_index *index,
-			      int update_recent, int fast)
+int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
 {
-	int failed, dir_unlocked;
+        struct mail_index_header hdr;
+	const char *path;
+	int ret;
 
 	i_assert(!index->opened);
 
+	if (index->dir == NULL)
+		return mail_index_create_memory(index, flags);
+
 	mail_index_cleanup_temp_files(index->dir);
 
-	if (index->open(index, update_recent, fast))
-	        return TRUE;
-
-	if (index->index_lock_timeout || index->mailbox_lock_timeout)
-		return FALSE;
-
-	/* index wasn't found or it was broken. lock the directory and check
-	   again, just to make sure we don't end up having two index files
-	   due to race condition with another process. */
-	if (!mail_index_lock_dir(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
-
-	failed = FALSE;
-	if (index->open(index, update_recent, fast))
-		dir_unlocked = FALSE;
-	else if (!index->index_lock_timeout && !index->mailbox_lock_timeout) {
-		if (!mail_index_create(index, &dir_unlocked, update_recent))
-			failed = TRUE;
+	/* open/create the file */
+        path = t_strconcat(index->dir, "/", INDEX_FILE_PREFIX, NULL);
+	if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) != 0)
+		index->fd = open(path, O_RDWR | O_CREAT, 0660);
+	else
+		index->fd = open(path, O_RDWR);
+	if (index->fd == -1) {
+		if (errno != ENOENT)
+			index_file_set_syscall_error(index, path, "open()");
+		return mail_index_create_memory(index, flags);
 	}
 
-	if (!dir_unlocked && !mail_index_lock_dir(index, MAIL_LOCK_UNLOCK))
-		return FALSE;
+	index->filepath = i_strdup(path);
+
+	for (;;) {
+		/* if index is being created, we'll wait here until it's
+		   finished */
+		if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0)
+			index->lock_type = MAIL_LOCK_SHARED;
+		else
+			index->lock_type = MAIL_LOCK_EXCLUSIVE;
+		if (!mail_index_wait_lock(index,
+					  MAIL_LOCK_TO_FLOCK(index->lock_type)))
+			break;
+
+		if ((ret = mail_index_read_header(index, &hdr)) < 0)
+			break;
+
+		if (ret == 0 || !mail_index_is_compatible(&hdr)) {
+			if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
+				break;
+
+			flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
+
+			/* so, we're creating the index */
+			if (index->lock_type != MAIL_LOCK_EXCLUSIVE) {
+				/* have to get exclusive lock first */
+				if (!mail_index_wait_lock(index, F_UNLCK))
+					break;
+				continue;
+			}
 
-	if (failed)
-		return FALSE;
+			mail_index_init_header(index, &hdr);
+			if (!mail_index_init_file(index, &hdr))
+				break;
+		}
+
+		index->indexid = hdr.indexid;
+
+		if (!mail_index_mmap_update(index))
+			break;
+
+		if (index->lock_type == MAIL_LOCK_SHARED) {
+			/* we don't want to keep the shared lock while opening
+			   indexes. opening should work unlocked and some
+			   things want exclusive lock */
+			if (!mail_index_wait_lock(index, F_UNLCK))
+				break;
+			index->lock_type = MAIL_LOCK_UNLOCK;
+		}
 
-	index->opened = TRUE;
-	return TRUE;
+		if (!index_open_and_fix(index, flags) ||
+		    !index->set_lock(index, MAIL_LOCK_UNLOCK)) {
+			mail_index_close(index);
+			return mail_index_create_memory(index, flags);
+		}
+
+		index->opened = TRUE;
+		return TRUE;
+	}
+
+	(void)close(index->fd);
+	index->fd = -1;
+
+	i_free(index->filepath);
+	index->filepath = NULL;
+
+	return mail_index_create_memory(index, flags);
 }
--- a/src/lib-index/mail-index-util.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index-util.c	Sun Feb 23 23:06:57 2003 +0200
@@ -52,6 +52,11 @@
 {
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(index, "%s failed with index file %s: %m",
 			function, index->filepath);
 	return FALSE;
@@ -63,6 +68,11 @@
 	i_assert(filepath != NULL);
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(index, "%s failed with file %s: %m",
 			function, filepath);
 
@@ -100,8 +110,10 @@
 	if (fd == -1) {
 		if (errno == ENOSPC)
 			index->nodiskspace = TRUE;
-
-		index_set_error(index, "Can't create temp index %s: %m", *path);
+		else {
+			index_set_error(index, "Can't create temp index %s: %m",
+					*path);
+		}
 	}
 
 	return fd;
--- a/src/lib-index/mail-index.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index.c	Sun Feb 23 23:06:57 2003 +0200
@@ -170,6 +170,11 @@
                 index->custom_flags = NULL;
 	}
 
+	if (index->custom_flags_dir != NULL) {
+		i_free(index->custom_flags_dir);
+                index->custom_flags_dir = NULL;
+	}
+
 	if (index->error != NULL) {
 		i_free(index->error);
 		index->error = NULL;
@@ -946,11 +951,8 @@
 		return mmap_verify(index);
 	}
 
-	if (file_set_size(index->fd, (off_t)pos) < 0) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
+	if (file_set_size(index->fd, (off_t)pos) < 0)
 		return index_set_syscall_error(index, "file_set_size()");
-	}
 
 	/* file size changed, let others know about it too by changing
 	   sync_id in header. */
--- a/src/lib-index/mail-index.h	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-index.h	Sun Feb 23 23:06:57 2003 +0200
@@ -9,6 +9,18 @@
 
 #define INDEX_FILE_PREFIX ".imap.index"
 
+enum mail_index_open_flags {
+	/* Create index if it doesn't exist */
+	MAIL_INDEX_OPEN_FLAG_CREATE		= 0x01,
+	/* Update \Recent flag counters */
+	MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT	= 0x02,
+	/* Compressing and cache updates are not performed */
+	MAIL_INDEX_OPEN_FLAG_FAST		= 0x04,
+
+	/* internal: we're creating the index */
+	_MAIL_INDEX_OPEN_FLAG_CREATING		= 0x10
+};
+
 enum mail_index_header_compat {
 	MAIL_INDEX_COMPAT_LITTLE_ENDIAN	= 0x01
 };
@@ -174,14 +186,11 @@
         (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
 
 struct mail_index {
-	/* If fast is TRUE, compressing and cache updates are not performed.
-	   Note that opening same index twice in the same process is a bad
+	/* Note that opening same index twice in the same process is a bad
 	   idea since they share the same file locks. As soon one of the
 	   indexes is closed, the locks in second index are dropped which
 	   especially hurts modify log since it keeps locks all the time. */
-	int (*open)(struct mail_index *index, int update_recent, int fast);
-	int (*open_or_create)(struct mail_index *index,
-			      int update_recent, int fast);
+	int (*open)(struct mail_index *index, enum mail_index_open_flags flags);
 
 	/* Free index from memory. */
 	void (*free)(struct mail_index *index);
@@ -358,6 +367,7 @@
 	char *dir; /* directory where to place the index files */
 	char *filepath; /* index file path */
 	char *mailbox_path; /* file/directory for mailbox location */
+	char *custom_flags_dir; /* destination for .customflags file */
 	enum mail_data_field default_cache_fields, never_cache_fields;
 	unsigned int indexid;
 	unsigned int sync_id;
@@ -407,6 +417,7 @@
 	unsigned int inconsistent:1;
 	unsigned int nodiskspace:1;
 	unsigned int index_lock_timeout:1;
+	unsigned int allow_new_custom_flags:1;
 	unsigned int mailbox_lock_timeout:1;
 };
 
@@ -420,16 +431,14 @@
    members.. */
 #define MAIL_INDEX_PRIVATE_FILL \
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, \
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0
+	0, 0, 0, 0
 #endif
 
 /* defaults - same as above but prefixed with mail_index_. */
-int mail_index_open(struct mail_index *index, int update_recent, int fast);
-int mail_index_open_or_create(struct mail_index *index,
-			      int update_recent, int fast);
+int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
 int mail_index_set_lock(struct mail_index *index,
 			enum mail_lock_type lock_type);
 int mail_index_try_lock(struct mail_index *index,
@@ -567,4 +576,7 @@
         ((lock_type) == MAIL_LOCK_EXCLUSIVE ? F_WRLCK : \
 		(lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_UNLCK)
 
+#define INDEX_IS_IN_MEMORY(index) \
+	((index)->anon_mmap)
+
 #endif
--- a/src/lib-index/mail-lockdir.c	Sun Feb 23 21:49:20 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "hostpid.h"
-#include "unlink-lockfiles.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-lockdir.h"
-
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#define DIRLOCK_FILE_PREFIX ".imap.dirlock"
-
-/* 0.1 .. 0.2msec */
-#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
-
-/* The dirlock should be used only while creating the index file. After the
-   header is written, the file itself should be locked and dirlock dropped
-   before index is built. So, this value shouldn't be very large, probably
-   even a few seconds would more than enough but we'll use a safe 10 seconds
-   by default. */
-#define MAX_LOCK_WAIT_SECONDS 10
-
-/* Non-local locks have a life time of 30 minutes, just to be sure that
-   small clock differences won't break things. */
-#define NFS_LOCK_TIMEOUT (60*30)
-
-static int mail_index_cleanup_dir_locks(const char *dir)
-{
-	const char *hostprefix, *path;
-	struct stat st;
-
-	hostprefix = t_strconcat(DIRLOCK_FILE_PREFIX ".",
-				 my_hostname, ".", NULL);
-
-	unlink_lockfiles(dir, hostprefix, DIRLOCK_FILE_PREFIX ".",
-			 time(NULL) - NFS_LOCK_TIMEOUT);
-
-	/* if hard link count has dropped to 1, we've unlocked the file */
-	path = t_strconcat(dir, "/" DIRLOCK_FILE_PREFIX, NULL);
-	if (stat(path, &st) == 0 && st.st_nlink == 1) {
-		/* only itself, safe to delete */
-		(void)unlink(path);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static int mail_index_unlock_dir(struct mail_index *index,
-				 const char *private_path, const char *lockpath)
-{
-	struct stat st, lockst;
-
-	if (stat(lockpath, &st) < 0)
-		return index_file_set_syscall_error(index, lockpath, "stat()");
-
-	if (st.st_nlink > 1) {
-		/* make sure we're really the one who's locked it */
-		if (stat(private_path, &lockst) < 0) {
-			return index_file_set_syscall_error(index, private_path,
-							    "stat()");
-		}
-
-		if (st.st_dev != lockst.st_dev ||
-		    st.st_ino != lockst.st_ino) {
-			index_set_error(index, "Unlocking file %s failed: "
-					"we're not the lock owner "
-					"(%lu,%lu vs %lu,%lu)", lockpath,
-					(unsigned long) st.st_dev,
-					(unsigned long) st.st_ino,
-					(unsigned long) lockst.st_dev,
-					(unsigned long) lockst.st_ino);
-			return FALSE;
-		}
-	}
-
-	/* first unlink the actual lock file */
-	if (unlink(lockpath) < 0) {
-		index_file_set_syscall_error(index, lockpath, "unlink()");
-		return FALSE;
-	}
-
-	if (unlink(private_path) < 0) {
-		/* non-fatal */
-		index_file_set_syscall_error(index, private_path, "unlink()");
-	}
-	return TRUE;
-}
-
-int mail_index_lock_dir(struct mail_index *index,
-			enum mail_lock_type lock_type)
-{
-	struct stat st;
-	const char *private_path, *lockpath;
-	int fd, orig_errno, first;
-	time_t max_wait_time;
-
-	i_assert(lock_type == MAIL_LOCK_EXCLUSIVE ||
-		 lock_type == MAIL_LOCK_UNLOCK);
-
-	hostpid_init();
-
-	/* use .dirlock.host.pid as our lock indicator file and
-	   .dirlock as the real lock */
-	private_path = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX ".",
-				   my_hostname, ".", my_pid, NULL);
-	lockpath = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX, NULL);
-
-	if (lock_type == MAIL_LOCK_UNLOCK)
-		return mail_index_unlock_dir(index, private_path, lockpath);
-
-	(void)unlink(private_path);
-	fd = open(private_path, O_RDWR | O_CREAT | O_EXCL, 0660);
-	if (fd == -1) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-		index_file_set_syscall_error(index, private_path, "open()");
-		return FALSE;
-	}
-
-	/* try to link the file into lock file. */
-	first = TRUE; max_wait_time = time(NULL) + MAX_LOCK_WAIT_SECONDS;
-	while (link(private_path, lockpath) < 0) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
-		if (errno != EEXIST) {
-			orig_errno = errno;
-
-			/* NFS may die and link() fail even if it really
-			   was created */
-			if (stat(private_path, &st) == 0 && st.st_nlink == 2)
-				break;
-
-			errno = orig_errno;
-			index_set_error(index, "link(%s, %s) lock failed: %m",
-					private_path, lockpath);
-			return FALSE;
-		}
-
-		if (first) {
-			/* cleanup lock files once */
-			first = FALSE;
-			if (mail_index_cleanup_dir_locks(index->dir))
-				continue; /* lock was deleted, try again */
-		}
-
-		if (time(NULL) > max_wait_time) {
-			index_set_error(index,
-				"Timeout waiting for lock in directory %s",
-				index->dir);
-			return FALSE;
-		}
-
-		usleep(LOCK_RANDOM_USLEEP_TIME);
-	}
-
-	return TRUE;
-}
--- a/src/lib-index/mail-lockdir.h	Sun Feb 23 21:49:20 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#ifndef __MAIL_LOCKDIR_H
-#define __MAIL_LOCKDIR_H
-
-/* Exclusively lock whole directory where index is located. */
-int mail_index_lock_dir(struct mail_index *index,
-			enum mail_lock_type lock_type);
-
-#endif
--- a/src/lib-index/mail-modifylog.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-modifylog.c	Sun Feb 23 23:06:57 2003 +0200
@@ -72,6 +72,11 @@
 {
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		file->log->index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(file->log->index,
 			"%s failed with modify log file %s: %m",
 			function, file->filepath);
@@ -318,25 +323,15 @@
 
 static int mail_modifylog_init_fd(struct modify_log_file *file, int fd)
 {
-	struct mail_index *index = file->log->index;
         struct modify_log_header hdr;
 
         mail_modifylog_init_header(file->log, &hdr);
-	if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
-		modifylog_set_syscall_error(file, "write_full()");
-		return FALSE;
-	}
 
-	if (file_set_size(fd, MODIFY_LOG_INITIAL_SIZE) < 0) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
+	if (write_full(fd, &hdr, sizeof(hdr)) < 0)
+		return modifylog_set_syscall_error(file, "write_full()");
 
-		modifylog_set_syscall_error(file, "file_set_size()");
-		return FALSE;
-	}
+	if (file_set_size(fd, MODIFY_LOG_INITIAL_SIZE) < 0)
+		return modifylog_set_syscall_error(file, "file_set_size()");
 
 	return TRUE;
 }
@@ -372,14 +367,11 @@
 	struct mail_index *index = file->log->index;
 	int fd, ret;
 
-	if (index->nodiskspace)
+	if (INDEX_IS_IN_MEMORY(index))
 		return -1;
 
 	fd = open(file->filepath, O_RDWR | O_CREAT, 0660);
 	if (fd == -1) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
 		modifylog_set_syscall_error(file, "open()");
 		return -1;
 	}
@@ -532,7 +524,8 @@
 	file->synced_position = file->mmap_used_length;
 
 	file->anon_mmap = TRUE;
-	file->filepath = i_strdup("(in-memory modify log)");
+	file->filepath = i_strdup_printf("(in-memory modify log for %s)",
+					 file->log->index->mailbox_path);
 }
 
 int mail_modifylog_create(struct mail_index *index)
@@ -544,7 +537,7 @@
 
 	log = mail_modifylog_new(index);
 
-	if (index->nodiskspace)
+	if (INDEX_IS_IN_MEMORY(index))
 		modifylog_create_anon(&log->file1);
 	else {
 		ret = modifylog_reuse_or_create_file(&log->file1);
@@ -687,11 +680,8 @@
 		return TRUE;
 	}
 
-	if (file_set_size(file->fd, (off_t)new_fsize) < 0) {
-		if (errno == ENOSPC)
-			file->log->index->nodiskspace = TRUE;
+	if (file_set_size(file->fd, (off_t)new_fsize) < 0)
 		return modifylog_set_syscall_error(file, "file_set_size()");
-	}
 
 	if (!mmap_update(file, TRUE))
 		return FALSE;
--- a/src/lib-index/mail-tree.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mail-tree.c	Sun Feb 23 23:06:57 2003 +0200
@@ -19,6 +19,11 @@
 {
 	i_assert(function != NULL);
 
+	if (errno == ENOSPC) {
+		tree->index->nodiskspace = TRUE;
+		return FALSE;
+	}
+
 	index_set_error(tree->index, "%s failed with binary tree file %s: %m",
 			function, tree->filepath);
 	return FALSE;
@@ -153,9 +158,6 @@
 	path = t_strconcat(index->filepath, ".tree", NULL);
 	fd = open(path, O_RDWR | O_CREAT, 0660);
 	if (fd == -1) {
-		if (errno == ENOSPC)
-			index->nodiskspace = TRUE;
-
 		index_file_set_syscall_error(index, path, "open()");
 		return NULL;
 	}
@@ -177,7 +179,8 @@
 	tree->anon_mmap = TRUE;
 	tree->fd = -1;
 	tree->index = index;
-	tree->filepath = i_strdup("(in-memory tree)");
+	tree->filepath = i_strdup_printf("(in-memory tree index for %s)",
+					 index->mailbox_path);
 
 	index->tree = tree;
 	return tree;
@@ -189,7 +192,7 @@
 
 	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
-	tree = !index->nodiskspace ? mail_tree_open(index) :
+	tree = !INDEX_IS_IN_MEMORY(index) ? mail_tree_open(index) :
 		mail_tree_create_anon(index);
 	if (tree == NULL)
 		return FALSE;
@@ -306,19 +309,11 @@
 	if (lseek(tree->fd, 0, SEEK_SET) < 0)
 		return tree_set_syscall_error(tree, "lseek()");
 
-	if (write_full(tree->fd, &hdr, sizeof(hdr)) < 0) {
-		if (errno == ENOSPC)
-			tree->index->nodiskspace = TRUE;
-
+	if (write_full(tree->fd, &hdr, sizeof(hdr)) < 0)
 		return tree_set_syscall_error(tree, "write_full()");
-	}
 
-	if (file_set_size(tree->fd, MAIL_TREE_MIN_SIZE) < 0) {
-		if (errno == ENOSPC)
-			tree->index->nodiskspace = TRUE;
-
+	if (file_set_size(tree->fd, MAIL_TREE_MIN_SIZE) < 0)
 		return tree_set_syscall_error(tree, "file_set_size()");
-	}
 
 	return TRUE;
 }
@@ -398,11 +393,8 @@
 		return mmap_verify(tree);
 	}
 
-	if (file_set_size(tree->fd, (off_t)new_fsize) < 0) {
-		if (errno == ENOSPC)
-			tree->index->nodiskspace = TRUE;
+	if (file_set_size(tree->fd, (off_t)new_fsize) < 0)
 		return tree_set_syscall_error(tree, "file_set_size()");
-	}
 
 	/* file size changed, let others know about it too by changing
 	   sync_id in header. */
--- a/src/lib-index/maildir/maildir-index.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/maildir/maildir-index.c	Sun Feb 23 23:06:57 2003 +0200
@@ -12,10 +12,10 @@
 extern struct mail_index maildir_index;
 
 static int maildir_index_open(struct mail_index *index,
-			      int update_recent, int fast)
+			      enum mail_index_open_flags flags)
 {
 	maildir_clean_tmp(t_strconcat(index->mailbox_path, "/tmp", NULL));
-	return mail_index_open(index, update_recent, fast);
+	return mail_index_open(index, flags);
 }
 
 enum mail_flags maildir_filename_get_flags(const char *fname,
@@ -145,7 +145,6 @@
 {
 	struct mail_index *index;
 
-	i_assert(dir != NULL);
 	i_assert(maildir != NULL);
 
 	index = i_new(struct mail_index, 1);
@@ -244,7 +243,6 @@
 
 struct mail_index maildir_index = {
 	maildir_index_open,
-	mail_index_open_or_create,
 	maildir_index_free,
 	mail_index_set_lock,
 	mail_index_try_lock,
--- a/src/lib-index/mbox/mbox-index.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-index/mbox/mbox-index.c	Sun Feb 23 23:06:57 2003 +0200
@@ -730,7 +730,7 @@
 {
 	struct mail_index *index;
 
-	i_assert(dir != NULL);
+	i_assert(mbox_path != NULL);
 
 	index = i_new(struct mail_index, 1);
 	memcpy(index, &mbox_index, sizeof(struct mail_index));
@@ -801,7 +801,6 @@
 
 struct mail_index mbox_index = {
 	mail_index_open,
-	mail_index_open_or_create,
 	mbox_index_free,
 	mbox_index_set_lock,
 	mbox_index_try_lock,
--- a/src/lib-storage/index/index-storage.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-storage/index/index-storage.c	Sun Feb 23 23:06:57 2003 +0200
@@ -226,6 +226,7 @@
 		   int readonly, int fast)
 {
 	struct index_mailbox *ibox;
+	enum mail_index_open_flags flags;
 
 	i_assert(name != NULL);
 
@@ -236,7 +237,6 @@
 		ibox->box.storage = storage;
 		ibox->box.name = i_strdup(name);
 		ibox->box.readonly = readonly;
-		ibox->box.allow_custom_flags = TRUE;
 
 		ibox->index = index;
 
@@ -249,13 +249,29 @@
 				get_default_cache_fields();
 			index->never_cache_fields =
 				get_never_cache_fields();
-			if (!index->open_or_create(index, !readonly, fast))
+
+			flags = MAIL_INDEX_OPEN_FLAG_CREATE;
+			if (fast)
+				flags |= MAIL_INDEX_OPEN_FLAG_FAST;
+			if (!readonly)
+				flags |= MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT;
+
+			if (!index->open(index, flags))
 				break;
+
+			if (INDEX_IS_IN_MEMORY(index) &&
+			    storage->index_dir != NULL) {
+				storage->callbacks->notify_no(&ibox->box,
+					"Couldn't use index files",
+					storage->callback_context);
+			}
 		}
 
 		if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED))
 			break;
 
+		ibox->box.allow_custom_flags =
+			ibox->index->allow_new_custom_flags;
 		ibox->synced_messages_count =
 			mail_index_get_header(index)->messages_count;
 
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sun Feb 23 23:06:57 2003 +0200
@@ -65,6 +65,8 @@
 
 	if (index_dir == NULL)
 		index_dir = root_dir;
+	else if (strcmp(index_dir, "MEMORY") == 0)
+		index_dir = NULL;
 
 	storage = i_new(struct mail_storage, 1);
 	memcpy(storage, &maildir_storage, sizeof(struct mail_storage));
@@ -90,6 +92,8 @@
 {
 	struct stat st;
 
+	data = t_strcut(data, ':');
+
 	return stat(t_strconcat(data, "/cur", NULL), &st) == 0 &&
 		S_ISDIR(st.st_mode);
 }
@@ -134,6 +138,9 @@
 static const char *maildir_get_index_path(struct mail_storage *storage,
 					  const char *name)
 {
+	if (storage->index_dir == NULL)
+		return NULL;
+
 	if (full_filesystem_access && (*name == '/' || *name == '~'))
 		return maildir_get_absolute_path(name);
 
@@ -209,6 +216,7 @@
 	index = index_storage_lookup_ref(index_dir);
 	if (index == NULL) {
 		index = maildir_index_alloc(index_dir, path);
+		index->custom_flags_dir = i_strdup(path);
 		index_storage_add(index);
 	}
 
--- a/src/lib-storage/index/mbox/mbox-storage.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Sun Feb 23 23:06:57 2003 +0200
@@ -54,6 +54,8 @@
 	const char *path;
 	struct stat st;
 
+	data = t_strcut(data, ':');
+
 	/* Is it INBOX file? */
 	if (*data != '\0' && stat(data, &st) == 0 && !S_ISDIR(st.st_mode) &&
 	    access(data, R_OK|W_OK) == 0)
@@ -191,8 +193,11 @@
 
 	if (inbox_file == NULL)
 		inbox_file = get_inbox_file(root_dir, !autodetect);
+
 	if (index_dir == NULL)
 		index_dir = root_dir;
+	else if (strcmp(index_dir, "MEMORY") == 0)
+		index_dir = NULL;
 
 	storage = i_new(struct mail_storage, 1);
 	memcpy(storage, &mbox_storage, sizeof(struct mail_storage));
@@ -254,6 +259,9 @@
 {
 	const char *p;
 
+	if (storage->index_dir == NULL)
+		return NULL;
+
 	if (full_filesystem_access && (*name == '/' || *name == '~')) {
 		name = home_expand(name);
 		p = strrchr(name, '/');
@@ -277,6 +285,9 @@
 	const char *index_dir, *imap_dir;
 
 	index_dir = mbox_get_index_dir(storage, name);
+	if (index_dir == NULL)
+		return TRUE;
+
 	imap_dir = t_strdup_until(index_dir, strstr(index_dir, ".imap/") + 5);
 
 	if (mkdir(imap_dir, CREATE_MODE) == -1 && errno != EEXIST)
@@ -333,6 +344,7 @@
 	index = index_storage_lookup_ref(index_dir);
 	if (index == NULL) {
 		index = mbox_index_alloc(index_dir, path);
+		index->custom_flags_dir = i_strdup(index_dir);
 		index_storage_add(index);
 	}
 
@@ -511,7 +523,8 @@
 
 	/* next delete the index directory */
 	index_dir = mbox_get_index_dir(storage, name);
-	if (unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
+	if (index_dir != NULL &&
+	    unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
 		mail_storage_set_critical(storage, "unlink_directory(%s) "
 					  "failed: %m", index_dir);
 		return FALSE;
@@ -566,7 +579,8 @@
 	/* we need to rename the index directory as well */
 	old_indexdir = mbox_get_index_dir(storage, oldname);
 	new_indexdir = mbox_get_index_dir(storage, newname);
-	(void)rename(old_indexdir, new_indexdir);
+	if (old_indexdir != NULL)
+		(void)rename(old_indexdir, new_indexdir);
 
 	return TRUE;
 }
--- a/src/master/mail-process.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/master/mail-process.c	Sun Feb 23 23:06:57 2003 +0200
@@ -175,8 +175,6 @@
 		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
 	if (set->maildir_check_content_changes)
 		env_put("MAILDIR_CHECK_CONTENT_CHANGES=1");
-	if (set->overwrite_incompatible_index)
-		env_put("OVERWRITE_INCOMPATIBLE_INDEX=1");
 	if (set->mail_full_filesystem_access)
 		env_put("FULL_FILESYSTEM_ACCESS=1");
 	(void)umask(set->umask);
--- a/src/master/master-settings.c	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/master/master-settings.c	Sun Feb 23 23:06:57 2003 +0200
@@ -67,7 +67,6 @@
 	DEF(SET_BOOL, mbox_read_dotlock),
 	DEF(SET_INT, mbox_lock_timeout),
 	DEF(SET_INT, mbox_dotlock_change_timeout),
-	DEF(SET_BOOL, overwrite_incompatible_index),
 	DEF(SET_INT, umask),
 	DEF(SET_BOOL, mail_drop_priv_before_exec),
 
@@ -174,7 +173,6 @@
 	MEMBER(mbox_read_dotlock) FALSE,
 	MEMBER(mbox_lock_timeout) 300,
 	MEMBER(mbox_dotlock_change_timeout) 30,
-	MEMBER(overwrite_incompatible_index) FALSE,
 	MEMBER(umask) 0077,
 	MEMBER(mail_drop_priv_before_exec) FALSE,
 
--- a/src/master/master-settings.h	Sun Feb 23 21:49:20 2003 +0200
+++ b/src/master/master-settings.h	Sun Feb 23 23:06:57 2003 +0200
@@ -51,7 +51,6 @@
 	int mbox_read_dotlock;
 	unsigned int mbox_lock_timeout;
 	unsigned int mbox_dotlock_change_timeout;
-	int overwrite_incompatible_index;
 	unsigned int umask;
 	int mail_drop_priv_before_exec;