dovecot-1.1: dbox: Fixes to creating, deleting and renaming mail...

dovecot at dovecot.org dovecot at dovecot.org
Wed Mar 5 03:53:43 EET 2008


details:   http://hg.dovecot.org/dovecot-1.1/rev/5193f5c6ab5d
changeset: 7355:5193f5c6ab5d
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Mar 05 03:53:39 2008 +0200
description:
dbox: Fixes to creating, deleting and renaming mailboxes when using alt
directories.

diffstat:

4 files changed, 118 insertions(+), 11 deletions(-)
src/lib-storage/index/dbox/dbox-storage.c   |  108 +++++++++++++++++++++++++--
src/lib-storage/list/mailbox-list-fs.c      |   12 ++-
src/lib-storage/list/mailbox-list-maildir.c |    6 +
src/lib-storage/mailbox-list-private.h      |    3 

diffs (253 lines):

diff -r de47a37ca0c1 -r 5193f5c6ab5d src/lib-storage/index/dbox/dbox-storage.c
--- a/src/lib-storage/index/dbox/dbox-storage.c	Wed Mar 05 02:59:55 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Wed Mar 05 03:53:39 2008 +0200
@@ -33,6 +33,12 @@ static MODULE_CONTEXT_DEFINE_INIT(dbox_m
 
 static int
 dbox_list_delete_mailbox(struct mailbox_list *list, const char *name);
+static int
+dbox_list_rename_mailbox(struct mailbox_list *list,
+			 const char *oldname, const char *newname);
+static int
+dbox_list_rename_mailbox_pre(struct mailbox_list *list,
+			     const char *oldname, const char *newname);
 static int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
 				     const char *dir, const char *fname,
 				     enum mailbox_list_file_type type,
@@ -126,6 +132,8 @@ static int dbox_create(struct mail_stora
 	storage->alt_dir = p_strdup(_storage->pool, alt_dir);
 	_storage->list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
 	_storage->list->v.delete_mailbox = dbox_list_delete_mailbox;
+	_storage->list->v.rename_mailbox = dbox_list_rename_mailbox;
+	_storage->list->v.rename_mailbox_pre = dbox_list_rename_mailbox_pre;
 
 	MODULE_CONTEXT_SET_FULL(_storage->list, dbox_mailbox_list_module,
 				storage, &storage->list_module_ctx);
@@ -313,7 +321,8 @@ static int dbox_mailbox_create(struct ma
 static int dbox_mailbox_create(struct mail_storage *_storage,
 			       const char *name, bool directory ATTR_UNUSED)
 {
-	const char *path;
+	struct dbox_storage *storage = (struct dbox_storage *)_storage;
+	const char *path, *alt_path;
 	struct stat st;
 
 	path = mailbox_list_get_path(_storage->list, name,
@@ -324,6 +333,17 @@ static int dbox_mailbox_create(struct ma
 		return -1;
 	}
 
+	/* make sure the alt path doesn't exist yet. it shouldn't (except with
+	   race conditions with RENAME/DELETE), but if something crashed and
+	   left it lying around we don't want to start overwriting files in
+	   it. */
+	alt_path = dbox_get_alt_path(storage, path);
+	if (alt_path != NULL && stat(alt_path, &st) == 0) {
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				       "Mailbox already exists");
+		return -1;
+	}
+
 	return create_dbox(_storage, path);
 }
 
@@ -339,6 +359,8 @@ dbox_delete_nonrecursive(struct mailbox_
 
 	dir = opendir(path);
 	if (dir == NULL) {
+		if (errno == ENOENT)
+			return 0;
 		if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"opendir(%s) failed: %m", path);
@@ -394,7 +416,7 @@ dbox_delete_nonrecursive(struct mailbox_
 					"can't delete it.", name));
 		return -1;
 	}
-	return 0;
+	return 1;
 }
 
 static int
@@ -404,6 +426,7 @@ dbox_list_delete_mailbox(struct mailbox_
 	struct stat st;
 	const char *path, *alt_path;
 	bool deleted = FALSE;
+	int ret;
 
 	/* Make sure the indexes are closed before trying to delete the
 	   directory that contains them. It can still fail with some NFS
@@ -418,11 +441,8 @@ dbox_list_delete_mailbox(struct mailbox_
 	/* check if the mailbox actually exists */
 	path = mailbox_list_get_path(list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (stat(path, &st) == 0) {
+	if ((ret = dbox_delete_nonrecursive(list, path, name)) > 0) {
 		/* delete the mailbox first */
-		if (dbox_delete_nonrecursive(list, path, name) < 0)
-			return -1;
-
 		alt_path = dbox_get_alt_path(storage, path);
 		if (alt_path != NULL) {
 			if (dbox_delete_nonrecursive(list, alt_path, name) < 0)
@@ -452,6 +472,10 @@ dbox_list_delete_mailbox(struct mailbox_
 		}
 	}
 
+	alt_path = dbox_get_alt_path(storage, path);
+	if (alt_path != NULL)
+		(void)rmdir(alt_path);
+
 	if (rmdir(path) == 0)
 		return 0;
 	else if (errno == ENOTEMPTY) {
@@ -465,6 +489,78 @@ dbox_list_delete_mailbox(struct mailbox_
 					  path);
 	}
 	return -1;
+}
+
+static bool
+dbox_list_rename_get_alt_paths(struct mailbox_list *list,
+			       const char *oldname, const char *newname,
+			       const char **oldpath_r, const char **newpath_r)
+{
+	struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
+	const char *path;
+
+	if (storage->alt_dir == NULL)
+		return FALSE;
+
+	path = mailbox_list_get_path(list, oldname, MAILBOX_LIST_PATH_TYPE_DIR);
+	*oldpath_r = dbox_get_alt_path(storage, path);
+	if (*oldpath_r == NULL)
+		return FALSE;
+
+	path = mailbox_list_get_path(list, newname, MAILBOX_LIST_PATH_TYPE_DIR);
+	*newpath_r = dbox_get_alt_path(storage, path);
+	i_assert(*newpath_r != NULL);
+	return TRUE;
+}
+
+static int
+dbox_list_rename_mailbox_pre(struct mailbox_list *list,
+			     const char *oldname, const char *newname)
+{
+	const char *alt_oldpath, *alt_newpath;
+	struct stat st;
+
+	if (!dbox_list_rename_get_alt_paths(list, oldname, newname,
+					    &alt_oldpath, &alt_newpath))
+		return 0;
+
+	if (stat(alt_newpath, &st) == 0) {
+		/* race condition or a directory left there lying around?
+		   safest to just report error. */
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				       "Target mailbox already exists");
+		return -1;
+	} else if (errno != ENOENT) {
+		mailbox_list_set_critical(list, "stat(%s) failed: %m",
+					  alt_newpath);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+dbox_list_rename_mailbox(struct mailbox_list *list,
+			 const char *oldname, const char *newname)
+{
+	struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
+	const char *alt_oldpath, *alt_newpath;
+
+	if (storage->list_module_ctx.super.rename_mailbox(list, oldname,
+							  newname) < 0)
+		return -1;
+
+	if (!dbox_list_rename_get_alt_paths(list, oldname, newname,
+					    &alt_oldpath, &alt_newpath))
+		return 0;
+
+	if (rename(alt_oldpath, alt_newpath) == 0) {
+		/* ok */
+	} else if (errno != ENOENT) {
+		/* renaming is done already, so just log the error */
+		mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",
+					  alt_oldpath, alt_newpath);
+	}
+	return 0;
 }
 
 static void dbox_notify_changes(struct mailbox *box)
diff -r de47a37ca0c1 -r 5193f5c6ab5d src/lib-storage/list/mailbox-list-fs.c
--- a/src/lib-storage/list/mailbox-list-fs.c	Wed Mar 05 02:59:55 2008 +0200
+++ b/src/lib-storage/list/mailbox-list-fs.c	Wed Mar 05 03:53:39 2008 +0200
@@ -285,9 +285,9 @@ static int fs_list_rename_mailbox(struct
 	struct stat st;
 
 	oldpath = mailbox_list_get_path(list, oldname,
-					MAILBOX_LIST_PATH_TYPE_MAILBOX);
+					MAILBOX_LIST_PATH_TYPE_DIR);
 	newpath = mailbox_list_get_path(list, newname,
-					MAILBOX_LIST_PATH_TYPE_MAILBOX);
+					MAILBOX_LIST_PATH_TYPE_DIR);
 
 	/* create the hierarchy */
 	p = strrchr(newpath, '/');
@@ -319,6 +319,11 @@ static int fs_list_rename_mailbox(struct
 		mailbox_list_set_critical(list, "lstat(%s) failed: %m",
 					  newpath);
 		return -1;
+	}
+
+	if (list->v.rename_mailbox_pre != NULL) {
+		if (list->v.rename_mailbox_pre(list, oldname, newname) < 0)
+			return -1;
 	}
 
 	/* NOTE: renaming INBOX works just fine with us, it's simply recreated
@@ -372,6 +377,7 @@ struct mailbox_list fs_mailbox_list = {
 		NULL,
 		fs_list_set_subscribed,
 		fs_list_delete_mailbox,
-		fs_list_rename_mailbox
+		fs_list_rename_mailbox,
+		NULL
 	}
 };
diff -r de47a37ca0c1 -r 5193f5c6ab5d src/lib-storage/list/mailbox-list-maildir.c
--- a/src/lib-storage/list/mailbox-list-maildir.c	Wed Mar 05 02:59:55 2008 +0200
+++ b/src/lib-storage/list/mailbox-list-maildir.c	Wed Mar 05 03:53:39 2008 +0200
@@ -457,7 +457,8 @@ struct mailbox_list maildir_mailbox_list
 		NULL,
 		maildir_list_set_subscribed,
 		maildir_list_delete_mailbox,
-		maildir_list_rename_mailbox
+		maildir_list_rename_mailbox,
+		NULL
 	}
 };
 
@@ -482,6 +483,7 @@ struct mailbox_list imapdir_mailbox_list
 		NULL,
 		maildir_list_set_subscribed,
 		maildir_list_delete_mailbox,
-		maildir_list_rename_mailbox
+		maildir_list_rename_mailbox,
+		NULL
 	}
 };
diff -r de47a37ca0c1 -r 5193f5c6ab5d src/lib-storage/mailbox-list-private.h
--- a/src/lib-storage/mailbox-list-private.h	Wed Mar 05 02:59:55 2008 +0200
+++ b/src/lib-storage/mailbox-list-private.h	Wed Mar 05 03:53:39 2008 +0200
@@ -49,6 +49,9 @@ struct mailbox_list_vfuncs {
 	int (*delete_mailbox)(struct mailbox_list *list, const char *name);
 	int (*rename_mailbox)(struct mailbox_list *list, const char *oldname,
 			      const char *newname);
+	/* called by rename_mailbox() just before running the actual rename() */
+	int (*rename_mailbox_pre)(struct mailbox_list *list,
+				  const char *oldname, const char *newname);
 };
 
 struct mailbox_list_module_register {


More information about the dovecot-cvs mailing list