changeset 6777:186b164a9579 HEAD

Delay creating directories until we really need them.
author Timo Sirainen <tss@iki.fi>
date Sun, 11 Nov 2007 17:46:47 +0200
parents 47c746a769ba
children 460eec427d23
files src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/index-storage.c src/lib-storage/index/maildir/maildir-keywords.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-sync.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-util.c src/lib-storage/mail-storage-private.h src/lib-storage/mailbox-list.c
diffstat 11 files changed, 237 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/cydir/cydir-storage.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Sun Nov 11 17:46:47 2007 +0200
@@ -150,9 +150,6 @@
 
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (create_cydir(_storage, path) < 0)
-		return NULL;
-
 	index = index_storage_alloc(_storage, name, flags, CYDIR_INDEX_PREFIX);
 	mail_index_set_fsync_types(index, MAIL_INDEX_SYNC_TYPE_APPEND |
 				   MAIL_INDEX_SYNC_TYPE_EXPUNGE);
@@ -186,14 +183,17 @@
 		return NULL;
 	}
 
-	if (strcmp(name, "INBOX") == 0)
-		return cydir_open(storage, "INBOX", flags);
-
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (stat(path, &st) == 0) {
+	if (stat(path, &st) == 0)
 		return cydir_open(storage, name, flags);
-	} else if (errno == ENOENT) {
+	else if (errno == ENOENT) {
+		if (strcmp(name, "INBOX") == 0) {
+			/* INBOX always exists, create it */
+			if (create_cydir(_storage, path) < 0)
+				return NULL;
+			return cydir_open(storage, "INBOX", flags);
+		}
 		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
 			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return NULL;
--- a/src/lib-storage/index/dbox/dbox-storage.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Sun Nov 11 17:46:47 2007 +0200
@@ -169,8 +169,6 @@
 
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (create_dbox(_storage, path) < 0)
-		return NULL;
 
 	index = index_storage_alloc(_storage, name, flags, DBOX_INDEX_PREFIX);
 	mail_index_set_fsync_types(index, MAIL_INDEX_SYNC_TYPE_APPEND |
@@ -241,14 +239,18 @@
 		return NULL;
 	}
 
-	if (strcmp(name, "INBOX") == 0)
-		return dbox_open(storage, "INBOX", flags);
-
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (stat(path, &st) == 0) {
+	if (stat(path, &st) == 0)
 		return dbox_open(storage, name, flags);
-	} else if (errno == ENOENT) {
+	else if (errno == ENOENT) {
+		if (strcmp(name, "INBOX") == 0) {
+			/* INBOX always exists, create it */
+			if (create_dbox(_storage, path) < 0)
+				return NULL;
+			return dbox_open(storage, name, flags);
+		}
+
 		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
 			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return NULL;
--- a/src/lib-storage/index/index-storage.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/index-storage.c	Sun Nov 11 17:46:47 2007 +0200
@@ -406,6 +406,7 @@
 	ibox->box.name = p_strdup(ibox->box.pool, name);
 	if (ibox->box.file_create_mode == 0) {
 		ibox->box.file_create_mode = 0600;
+		ibox->box.dir_create_mode = 0700;
 		ibox->box.file_create_gid = (gid_t)-1;
 	}
 
--- a/src/lib-storage/index/maildir/maildir-keywords.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-keywords.c	Sun Nov 11 17:46:47 2007 +0200
@@ -342,26 +342,36 @@
 	struct dotlock *dotlock;
 	const char *lock_path;
 	mode_t old_mask;
-	int fd;
+	int i, fd;
 
 	mk->synced = FALSE;
 
 	if (!mk->changed || mk->mbox == NULL)
 		return 0;
 
-	/* we could just create the temp file directly, but doing it this
-	   ways avoids potential problems with overwriting contents in
-	   malicious symlinks */
 	lock_path = t_strconcat(mk->path, ".lock", NULL);
 	(void)unlink(lock_path);
-        old_mask = umask(0777 & ~mk->mbox->ibox.box.file_create_mode);
-	fd = file_dotlock_open(&mk->dotlock_settings, mk->path,
-			       DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
-	umask(old_mask);
-	if (fd == -1) {
-		mail_storage_set_critical(mk->storage,
-			"file_dotlock_open(%s) failed: %m", mk->path);
-		return -1;
+
+	for (i = 0;; i++) {
+		/* we could just create the temp file directly, but doing it
+		   this ways avoids potential problems with overwriting
+		   contents in malicious symlinks */
+		old_mask = umask(0777 & ~mk->mbox->ibox.box.file_create_mode);
+		fd = file_dotlock_open(&mk->dotlock_settings, mk->path,
+				       DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
+		umask(old_mask);
+		if (fd != -1)
+			break;
+
+		if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
+			mail_storage_set_critical(mk->storage,
+				"file_dotlock_open(%s) failed: %m", mk->path);
+			return -1;
+		}
+		/* the control dir doesn't exist. create it unless the whole
+		   mailbox was just deleted. */
+		if (maildir_set_deleted(mk->mbox))
+			return -1;
 	}
 
 	if (maildir_keywords_write_fd(mk, lock_path, fd) < 0) {
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sun Nov 11 17:46:47 2007 +0200
@@ -41,7 +41,6 @@
 				  &mailbox_list_module_register);
 static const char *maildir_subdirs[] = { "cur", "new", "tmp" };
 
-static int verify_inbox(struct mail_storage *storage);
 static int
 maildir_list_delete_mailbox(struct mailbox_list *list, const char *name);
 static int
@@ -249,9 +248,6 @@
 			p_strconcat(_storage->pool,
 				    "tmp/", storage->temp_prefix, NULL);
 	}
-
-	if ((_storage->ns->flags & NAMESPACE_FLAG_INBOX) != 0)
-		(void)verify_inbox(_storage);
 	return 0;
 }
 
@@ -312,69 +308,54 @@
 	return -1;
 }
 
-/* create or fix maildir, ignore if it already exists */
-static int create_maildir(struct mail_storage *storage,
-			  const char *dir, bool verify)
+static int maildir_check_tmp(struct mail_storage *storage, const char *dir)
 {
 	const char *path;
 	struct stat st;
 
-	if (mkdir_verify(storage, t_strconcat(dir, "/cur", NULL), verify) < 0)
-		return -1;
-	if (mkdir_verify(storage, t_strconcat(dir, "/new", NULL), verify) < 0)
-		return -1;
-
 	/* if tmp/ directory exists, we need to clean it up once in a while */
 	path = t_strconcat(dir, "/tmp", NULL);
-	if (stat(path, &st) == 0) {
-		if (st.st_atime >
-		    st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
-			/* the directory should be empty. we won't do anything
-			   until ctime changes. */
-		} else if (st.st_atime < ioloop_time - MAILDIR_TMP_SCAN_SECS) {
-			/* time to scan */
-			(void)maildir_tmp_cleanup(storage, path);
-		}
-	} else if (errno == ENOENT) {
-		if (mkdir_verify(storage, path, verify) < 0)
-			return -1;
-	} else {
+	if (stat(path, &st) < 0) {
+		if (errno == ENOENT)
+			return 0;
 		mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
 		return -1;
 	}
 
-	return 0;
+	if (st.st_atime > st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
+		/* the directory should be empty. we won't do anything
+		   until ctime changes. */
+	} else if (st.st_atime < ioloop_time - MAILDIR_TMP_SCAN_SECS) {
+		/* time to scan */
+		(void)maildir_tmp_cleanup(storage, path);
+	}
+	return 1;
 }
 
-static int create_control_dir(struct mail_storage *storage, const char *name)
+/* create or fix maildir, ignore if it already exists */
+static int create_maildir(struct mail_storage *storage,
+			  const char *dir, bool verify)
 {
-	const char *control_dir, *root_dir;
+	int ret;
 
-	control_dir = mailbox_list_get_path(storage->list, name,
-					    MAILBOX_LIST_PATH_TYPE_CONTROL);
-	root_dir = mailbox_list_get_path(storage->list, name,
-					 MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (strcmp(control_dir, root_dir) == 0)
-		return 0;
-
-	if (mkdir_parents(control_dir, CREATE_MODE) < 0 && errno != EEXIST) {
-		mail_storage_set_critical(storage,
-					  "mkdir(%s) failed: %m", control_dir);
+	ret = maildir_check_tmp(storage, dir);
+	if (ret > 0) {
+		if (!verify) {
+			mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
+					       "Mailbox already exists");
+			return -1;
+		}
+		return 1;
+	}
+	if (ret < 0)
 		return -1;
-	}
 
-	return 0;
-}
-
-static int verify_inbox(struct mail_storage *storage)
-{
-	const char *path;
-
-	path = mailbox_list_get_path(storage->list, "INBOX",
-				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (create_maildir(storage, path, TRUE) < 0)
+	/* doesn't exist, create */
+	if (mkdir_verify(storage, t_strconcat(dir, "/cur", NULL), verify) < 0)
 		return -1;
-	if (create_control_dir(storage, "INBOX") < 0)
+	if (mkdir_verify(storage, t_strconcat(dir, "/new", NULL), verify) < 0)
+		return -1;
+	if (mkdir_verify(storage, t_strconcat(dir, "/tmp", NULL), verify) < 0)
 		return -1;
 	return 0;
 }
@@ -384,6 +365,15 @@
 	(void)maildir_uidlist_lock_touch(mbox->uidlist);
 }
 
+static mode_t get_dir_mode(mode_t mode)
+{
+	/* add the execute bit if either read or write bit is set */
+	if ((mode & 0600) != 0) mode |= 0100;
+	if ((mode & 0060) != 0) mode |= 0010;
+	if ((mode & 0006) != 0) mode |= 0001;
+	return mode;
+}
+
 static struct mailbox *
 maildir_open(struct maildir_storage *storage, const char *name,
 	     enum mailbox_open_flags flags)
@@ -409,7 +399,6 @@
 
 	mbox->storage = storage;
 	mbox->path = p_strdup(pool, path);
-	mbox->control_dir = p_strdup(pool, control_dir);
 
 	index = index_storage_alloc(&storage->storage, name, flags,
 				    MAILDIR_INDEX_PREFIX);
@@ -425,6 +414,8 @@
 		mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid);
 
 		mbox->ibox.box.file_create_mode = st.st_mode & 0666;
+		mbox->ibox.box.dir_create_mode =
+			get_dir_mode(st.st_mode & 0666);
 		mbox->ibox.box.file_create_gid = st.st_gid;
 		mbox->ibox.box.private_flags_mask = MAIL_SEEN;
 	}
@@ -464,6 +455,7 @@
 	struct maildir_storage *storage = (struct maildir_storage *)_storage;
 	const char *path;
 	struct stat st;
+	int ret;
 
 	if (input != NULL) {
 		mail_storage_set_critical(_storage,
@@ -471,19 +463,31 @@
 		return NULL;
 	}
 
+	path = mailbox_list_get_path(_storage->list, name,
+				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
+
 	if (strcmp(name, "INBOX") == 0 &&
 	    (_storage->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
-		if (verify_inbox(_storage) < 0)
+		/* INBOX always exists */
+		if (create_maildir(_storage, path, TRUE) < 0)
 			return NULL;
 		return maildir_open(storage, "INBOX", flags);
 	}
 
-	path = mailbox_list_get_path(_storage->list, name,
-				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
+	/* begin by checking if tmp/ directory exists and if it should be
+	   cleaned up. */
+	ret = maildir_check_tmp(_storage, path);
+	if (ret > 0) {
+		/* exists */
+		return maildir_open(storage, name, flags);
+	}
+	if (ret < 0)
+		return NULL;
+
+	/* tmp/ directory doesn't exist. does the maildir? */
 	if (stat(path, &st) == 0) {
-		/* exists - make sure the required directories are also there */
-		if (create_maildir(_storage, path, TRUE) < 0 ||
-		    create_control_dir(_storage, name) < 0)
+		/* yes, we'll need to create the missing dirs */
+		if (create_maildir(_storage, path, TRUE) < 0)
 			return NULL;
 
 		return maildir_open(storage, name, flags);
--- a/src/lib-storage/index/maildir/maildir-storage.h	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Sun Nov 11 17:46:47 2007 +0200
@@ -42,6 +42,11 @@
 #define MAILDIR_SAVE_FLAG_HARDLINK 0x10000000
 #define MAILDIR_SAVE_FLAG_DELETED  0x20000000
 
+/* If an operation fails with ENOENT, we'll check if the mailbox is deleted
+   or if some directory is just missing. If it's missing, we'll create the
+   directories and try again this many times before failing. */
+#define MAILDIR_DELETE_RETRY_COUNT 3
+
 #include "index-storage.h"
 #include "mailbox-list-private.h"
 
@@ -76,7 +81,7 @@
 	struct index_mailbox ibox;
 	struct maildir_storage *storage;
 
-	const char *path, *control_dir;
+	const char *path;
 	struct timeout *keep_lock_to;
 
 	/* maildir sync: */
@@ -116,6 +121,7 @@
 #endif
 
 void maildir_tmp_cleanup(struct mail_storage *storage, const char *dir);
+bool maildir_set_deleted(struct maildir_mailbox *mbox);
 
 void maildir_transaction_class_init(void);
 void maildir_transaction_class_deinit(void);
--- a/src/lib-storage/index/maildir/maildir-sync.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-sync.c	Sun Nov 11 17:46:47 2007 +0200
@@ -338,12 +338,17 @@
 static int
 maildir_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st_r)
 {
-	if (nfs_safe_stat(path, st_r) == 0)
-		return 0;
-	if (errno == ENOENT) {
-		/* if mailbox gets deleted under us, don't log an error */
-		mailbox_set_deleted(&mbox->ibox.box);
-		return -1;
+	int i;
+
+	for (i = 0;; i++) {
+		if (nfs_safe_stat(path, st_r) == 0)
+			return 0;
+		if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT)
+			break;
+
+		if (maildir_set_deleted(mbox))
+			return -1;
+		/* try again */
 	}
 
 	mail_storage_set_critical(mbox->ibox.box.storage,
@@ -366,15 +371,20 @@
 	bool move_new, check_touch, dir_changed = FALSE;
 
 	path = new_dir ? ctx->new_dir : ctx->cur_dir;
-	dirp = opendir(path);
-	if (dirp == NULL) {
-		if (errno == ENOENT) {
-			mailbox_set_deleted(&ctx->mbox->ibox.box);
+	for (i = 0;; i++) {
+		dirp = opendir(path);
+		if (dirp != NULL)
+			break;
+
+		if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
+			mail_storage_set_critical(storage,
+				"opendir(%s) failed: %m", path);
 			return -1;
 		}
-		mail_storage_set_critical(storage,
-					  "opendir(%s) failed: %m", path);
-		return -1;
+
+		if (maildir_set_deleted(ctx->mbox))
+			return -1;
+		/* try again */
 	}
 
 #ifdef HAVE_DIRFD
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Nov 11 17:46:47 2007 +0200
@@ -127,7 +127,9 @@
 	struct mailbox *box = &uidlist->ibox->box;
 	const char *control_dir, *path;
 	mode_t old_mask;
-	int ret;
+	const enum dotlock_create_flags dotlock_flags =
+		nonblock ? DOTLOCK_CREATE_FLAG_NONBLOCK : 0;
+	int i, ret;
 
 	if (uidlist->lock_count > 0) {
 		uidlist->lock_count++;
@@ -136,22 +138,32 @@
 
 	control_dir = mailbox_list_get_path(box->storage->list, box->name,
 					    MAILBOX_LIST_PATH_TYPE_CONTROL);
+	path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
 
-	path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
-        old_mask = umask(0777 & ~box->file_create_mode);
-	ret = file_dotlock_create(&uidlist->dotlock_settings, path,
-				  nonblock ? DOTLOCK_CREATE_FLAG_NONBLOCK : 0,
-				  &uidlist->dotlock);
-	umask(old_mask);
-	if (ret <= 0) {
+	for (i = 0;; i++) {
+		old_mask = umask(0777 & ~box->file_create_mode);
+		ret = file_dotlock_create(&uidlist->dotlock_settings, path,
+					  dotlock_flags, &uidlist->dotlock);
+		umask(old_mask);
+		if (ret > 0)
+			break;
+
+		/* failure */
 		if (ret == 0) {
 			mail_storage_set_error(box->storage,
 				MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
 			return 0;
 		}
-		mail_storage_set_critical(box->storage,
-			"file_dotlock_open(%s) failed: %m", path);
-		return -1;
+		if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
+		    uidlist->mbox == NULL) {
+			mail_storage_set_critical(box->storage,
+				"file_dotlock_create(%s) failed: %m", path);
+			return -1;
+		}
+		/* the control dir doesn't exist. create it unless the whole
+		   mailbox was just deleted. */
+		if (maildir_set_deleted(uidlist->mbox))
+			return -1;
 	}
 
 	uidlist->lock_count++;
@@ -898,21 +910,30 @@
 	struct stat st;
 	mode_t old_mask;
 	uoff_t file_size;
-	int fd, ret;
+	int i, fd, ret;
 
 	control_dir = mailbox_list_get_path(box->storage->list, box->name,
 					    MAILBOX_LIST_PATH_TYPE_CONTROL);
 	temp_path = t_strconcat(control_dir,
 				"/" MAILDIR_UIDLIST_NAME ".tmp", NULL);
 
-	old_mask = umask(0777 & ~box->file_create_mode);
-	fd = open(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0777);
-	umask(old_mask);
+	for (i = 0;; i++) {
+		old_mask = umask(0777 & ~box->file_create_mode);
+		fd = open(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0777);
+		umask(old_mask);
+		if (fd != -1)
+			break;
 
-	if (fd == -1) {
-		mail_storage_set_critical(box->storage,
-			"open(%s, O_CREAT) failed: %m", temp_path);
-		return -1;
+		if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
+		    uidlist->mbox == NULL) {
+			mail_storage_set_critical(box->storage,
+				"open(%s, O_CREAT) failed: %m", temp_path);
+			return -1;
+		}
+		/* the control dir doesn't exist. create it unless the whole
+		   mailbox was just deleted. */
+		if (maildir_set_deleted(uidlist->mbox))
+			return -1;
 	}
 
 	if (box->file_create_gid != (gid_t)-1) {
--- a/src/lib-storage/index/maildir/maildir-util.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-util.c	Sun Nov 11 17:46:47 2007 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "str.h"
+#include "mkdir-parents.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
 #include "maildir-sync.h"
@@ -152,3 +153,66 @@
 			"closedir(%s) failed: %m", dir);
 	}
 }
+
+static int maildir_create_subdirs(struct maildir_mailbox *mbox)
+{
+	static const char *subdirs[] = { "cur", "new", "tmp" };
+	const char *dirs[N_ELEMENTS(subdirs) + 2];
+	struct mailbox *box = &mbox->ibox.box;
+	struct stat st;
+	const char *path;
+	unsigned int i;
+
+	t_push();
+	/* @UNSAFE: get a list of directories we want to create */
+	for (i = 0; i < N_ELEMENTS(subdirs); i++)
+		dirs[i] = t_strconcat(mbox->path, "/", subdirs[i], NULL);
+	dirs[i++] = mail_storage_get_mailbox_control_dir(box->storage,
+							 box->name);
+	dirs[i++] = mail_storage_get_mailbox_index_dir(box->storage,
+						       box->name);
+	i_assert(i == N_ELEMENTS(dirs));
+
+	for (i = 0; i < N_ELEMENTS(dirs); i++) {
+		path = dirs[i];
+		if (path == NULL || stat(path, &st) == 0)
+			continue;
+		if (errno != ENOENT) {
+			mail_storage_set_critical(box->storage,
+						  "stat(%s) failed: %m", path);
+			break;
+		}
+		if (mkdir_parents(path, box->dir_create_mode) < 0 &&
+		    errno != EEXIST) {
+			if (errno == ENOENT) {
+				/* mailbox was being deleted just now */
+				mailbox_set_deleted(box);
+				break;
+			}
+			mail_storage_set_critical(box->storage,
+						  "mkdir(%s) failed: %m", path);
+			break;
+		}
+	}
+	t_pop();
+	return i == N_ELEMENTS(dirs) ? 0 : -1;
+}
+
+bool maildir_set_deleted(struct maildir_mailbox *mbox)
+{
+	struct mailbox *box = &mbox->ibox.box;
+	struct stat st;
+
+	if (stat(mbox->path, &st) < 0) {
+		if (errno == ENOENT)
+			mailbox_set_deleted(box);
+		else {
+			mail_storage_set_critical(box->storage,
+				"stat(%s) failed: %m", mbox->path);
+		}
+		return TRUE;
+	}
+	/* maildir itself exists. create all of its subdirectories in case
+	   they got lost. */
+	return maildir_create_subdirs(mbox) < 0 ? TRUE : FALSE;
+}
--- a/src/lib-storage/mail-storage-private.h	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/mail-storage-private.h	Sun Nov 11 17:46:47 2007 +0200
@@ -181,8 +181,8 @@
 	/* User's private flags if this is a shared mailbox */
 	enum mail_flags private_flags_mask;
 
-	/* mode and GID to use for newly created files */
-	mode_t file_create_mode;
+	/* mode and GID to use for newly created files/dirs */
+	mode_t file_create_mode, dir_create_mode;
 	gid_t file_create_gid;
 
 	/* Mailbox notification settings: */
--- a/src/lib-storage/mailbox-list.c	Sun Nov 11 17:43:56 2007 +0200
+++ b/src/lib-storage/mailbox-list.c	Sun Nov 11 17:46:47 2007 +0200
@@ -4,7 +4,6 @@
 #include "array.h"
 #include "ioloop.h"
 #include "home-expand.h"
-#include "mkdir-parents.h"
 #include "unlink-directory.h"
 #include "imap-match.h"
 #include "mailbox-tree.h"
@@ -182,18 +181,6 @@
 		strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
 		p_strdup(list->pool, set->control_dir);
 
-	if (list->set.index_dir != NULL &&
-	   *list->set.index_dir != '\0') {
-		if (mkdir_parents(list->set.index_dir, 0700) < 0 &&
-		    errno != EEXIST)
-			i_error("mkdir(%s) failed: %m", list->set.index_dir);
-	}
-	if (list->set.control_dir != NULL) {
-		if (mkdir_parents(list->set.control_dir, 0700) < 0 &&
-		    errno != EEXIST)
-			i_error("mkdir(%s) failed: %m", list->set.control_dir);
-	}
-
 	list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
 	list->set.subscription_fname =
 		p_strdup(list->pool, set->subscription_fname);