Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7355:5193f5c6ab5d HEAD
dbox: Fixes to creating, deleting and renaming mailboxes when using alt
directories.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 05 Mar 2008 03:53:39 +0200 |
parents | de47a37ca0c1 |
children | 25551453b13c |
files | src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/list/mailbox-list-fs.c src/lib-storage/list/mailbox-list-maildir.c src/lib-storage/mailbox-list-private.h |
diffstat | 4 files changed, 118 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- 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 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 @@ 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 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 @@ 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 @@ 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 @@ "can't delete it.", name)); return -1; } - return 0; + return 1; } static int @@ -404,6 +426,7 @@ 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 @@ /* 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 @@ } } + 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) { @@ -467,6 +491,78 @@ 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) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
--- 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 @@ 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, '/'); @@ -321,6 +321,11 @@ 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 the next time it's needed. */ if (rename(oldpath, newpath) < 0) { @@ -372,6 +377,7 @@ NULL, fs_list_set_subscribed, fs_list_delete_mailbox, - fs_list_rename_mailbox + fs_list_rename_mailbox, + NULL } };
--- 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 @@ NULL, maildir_list_set_subscribed, maildir_list_delete_mailbox, - maildir_list_rename_mailbox + maildir_list_rename_mailbox, + NULL } }; @@ -482,6 +483,7 @@ NULL, maildir_list_set_subscribed, maildir_list_delete_mailbox, - maildir_list_rename_mailbox + maildir_list_rename_mailbox, + NULL } };
--- 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 @@ 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 {