]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Mailbox renaming API changed.
authorTimo Sirainen <tss@iki.fi>
Sun, 14 Feb 2010 20:32:59 +0000 (22:32 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 14 Feb 2010 20:32:59 +0000 (22:32 +0200)
--HG--
branch : HEAD

24 files changed:
src/dsync/dsync-worker-local.c
src/imap/cmd-rename.c
src/lib-storage/index/cydir/cydir-storage.c
src/lib-storage/index/dbox-common/dbox-storage.c
src/lib-storage/index/dbox-common/dbox-storage.h
src/lib-storage/index/dbox-multi/mdbox-storage.c
src/lib-storage/index/dbox-single/sdbox-storage.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-storage.h
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/raw/raw-storage.c
src/lib-storage/index/shared/shared-list.c
src/lib-storage/list/mailbox-list-fs.c
src/lib-storage/list/mailbox-list-maildir.c
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mailbox-list-private.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h
src/lib-storage/test-mailbox.c
src/plugins/lazy-expunge/lazy-expunge-plugin.c
src/plugins/virtual/virtual-storage.c

index a2d010d5d690a8613e3c4793d9920c1f037b55e1..ff9de9282c27653ef13ad9ca14e8222037ba9334 100644 (file)
@@ -1136,6 +1136,7 @@ local_worker_rename_mailbox(struct dsync_worker *_worker,
                (struct local_dsync_worker *)_worker;
        struct local_dsync_mailbox *lbox;
        struct mailbox_list *list;
+       struct mailbox *old_box, *new_box;
        const char *newname;
 
        lbox = hash_table_lookup(worker->mailbox_hash, mailbox);
@@ -1156,14 +1157,19 @@ local_worker_rename_mailbox(struct dsync_worker *_worker,
        }
 
        mailbox_list_set_changelog_timestamp(list, dsync_box->last_change);
-       if (mailbox_list_rename_mailbox(list, lbox->storage_name,
-                                       list, newname, FALSE) < 0) {
+       old_box = mailbox_alloc(list, lbox->storage_name, 0);
+       new_box = mailbox_alloc(list, newname, 0);
+       if (mailbox_rename(old_box, new_box, FALSE) < 0) {
+               struct mail_storage *storage = mailbox_get_storage(old_box);
+
                i_error("Can't rename mailbox %s to %s: %s", lbox->storage_name,
-                       newname, mailbox_list_get_last_error(list, NULL));
+                       newname, mail_storage_get_last_error(storage, NULL));
                dsync_worker_set_failure(_worker);
        } else {
                lbox->storage_name = p_strdup(worker->pool, newname);
        }
+       mailbox_free(&old_box);
+       mailbox_free(&new_box);
        mailbox_list_set_changelog_timestamp(list, (time_t)-1);
 }
 
index 1063e5110fe487dbbdd40dbb25930187d519b33b..567e3df05523ec1a0c1cc022181b3cd88c40c5c7 100644 (file)
@@ -7,6 +7,7 @@
 bool cmd_rename(struct client_command_context *cmd)
 {
        struct mail_namespace *old_ns, *new_ns;
+       struct mailbox *old_box, *new_box;
        const char *oldname, *newname;
        unsigned int oldlen;
 
@@ -37,10 +38,13 @@ bool cmd_rename(struct client_command_context *cmd)
                }
        }
 
-       if (mailbox_list_rename_mailbox(old_ns->list, oldname,
-                                       new_ns->list, newname, TRUE) < 0)
-               client_send_list_error(cmd, old_ns->list);
+       old_box = mailbox_alloc(old_ns->list, oldname, 0);
+       new_box = mailbox_alloc(new_ns->list, newname, 0);
+       if (mailbox_rename(old_box, new_box, TRUE) < 0)
+               client_send_storage_error(cmd, mailbox_get_storage(old_box));
        else
                client_send_tagline(cmd, "OK Rename completed.");
+       mailbox_free(&old_box);
+       mailbox_free(&new_box);
        return TRUE;
 }
index 8f44c35ba95029502dcb51a0c1cfeddceb227164..7492b86326ba9b083a99d5dfc363cbeb4c006348 100644 (file)
@@ -203,6 +203,7 @@ struct mailbox cydir_mailbox = {
                cydir_mailbox_create,
                index_storage_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                NULL,
                NULL,
index 7567240b46c17af739ebf7d6522b134e0f188147..569853a32d74997a85359774fba88374c37ca67d 100644 (file)
@@ -124,26 +124,6 @@ int dbox_mailbox_open(struct mailbox *box)
        }
 }
 
-static const char *
-dbox_get_alt_path(struct mailbox_list *list, const char *path)
-{
-       struct mail_storage *storage = list->ns->storage;
-       const char *root;
-       unsigned int len;
-
-       if (list->set.alt_dir == NULL ||
-           (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0)
-               return NULL;
-
-       root = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
-       len = strlen(root);
-       if (strncmp(path, root, len) != 0 && path[len] == '/') {
-               /* can't determine the alt path - shouldn't happen */
-               return NULL;
-       }
-       return t_strconcat(list->set.alt_dir, path + len, NULL);
-}
-
 int dbox_mailbox_create(struct mailbox *box,
                        const struct mailbox_update *update, bool directory)
 {
@@ -226,94 +206,3 @@ int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx ATTR_UNUS
        }
        return ret;
 }
-
-static int
-dbox_list_rename_get_alt_paths(struct mailbox_list *oldlist,
-                              const char *oldname,
-                              struct mailbox_list *newlist,
-                              const char *newname,
-                              enum mailbox_list_path_type path_type,
-                              const char **oldpath_r, const char **newpath_r)
-{
-       const char *path;
-
-       path = mailbox_list_get_path(oldlist, oldname, path_type);
-       *oldpath_r = dbox_get_alt_path(oldlist, path);
-       if (*oldpath_r == NULL)
-               return 0;
-
-       path = mailbox_list_get_path(newlist, newname, path_type);
-       *newpath_r = dbox_get_alt_path(newlist, path);
-       if (*newpath_r == NULL) {
-               /* destination dbox storage doesn't have alt-path defined.
-                  we can't do the rename easily. */
-               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
-                       "Can't rename mailboxes across specified storages.");
-               return -1;
-       }
-       return 1;
-}
-
-int dbox_list_rename_mailbox_pre(struct mailbox_list *oldlist,
-                                const char *oldname,
-                                struct mailbox_list *newlist,
-                                const char *newname)
-{
-       const char *alt_oldpath, *alt_newpath;
-       struct stat st;
-       int ret;
-
-       ret = dbox_list_rename_get_alt_paths(oldlist, oldname, newlist, newname,
-                                            MAILBOX_LIST_PATH_TYPE_DIR,
-                                            &alt_oldpath, &alt_newpath);
-       if (ret <= 0)
-               return ret;
-
-       if (stat(alt_newpath, &st) == 0) {
-               /* race condition or a directory left there lying around?
-                  safest to just report error. */
-               mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
-                                      "Target mailbox already exists");
-               return -1;
-       } else if (errno != ENOENT) {
-               mailbox_list_set_critical(oldlist, "stat(%s) failed: %m",
-                                         alt_newpath);
-               return -1;
-       }
-       return 0;
-}
-
-int dbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
-                            struct mailbox_list *newlist, const char *newname,
-                            bool rename_children)
-{
-       enum mailbox_list_path_type path_type;
-       const char *alt_oldpath, *alt_newpath, *path;
-       int ret;
-
-       path_type = rename_children ? MAILBOX_LIST_PATH_TYPE_DIR :
-               MAILBOX_LIST_PATH_TYPE_MAILBOX;
-       ret = dbox_list_rename_get_alt_paths(oldlist, oldname, newlist, newname,
-                                            path_type, &alt_oldpath,
-                                            &alt_newpath);
-       if (ret <= 0)
-               return ret;
-
-       if (rename(alt_oldpath, alt_newpath) == 0) {
-               /* ok */
-               if (!rename_children) {
-                       path = mailbox_list_get_path(oldlist, oldname,
-                                                    MAILBOX_LIST_PATH_TYPE_DIR);
-                       if (rmdir(path) < 0 &&
-                           errno != ENOENT && errno != ENOTEMPTY) {
-                               mailbox_list_set_critical(oldlist,
-                                       "rmdir(%s) failed: %m", path);
-                       }
-               }
-       } else if (errno != ENOENT) {
-               /* renaming is done already, so just log the error */
-               mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
-                                         alt_oldpath, alt_newpath);
-       }
-       return 0;
-}
index 2f3e7d216f764f6cc997426a47172bd82c3d91fc..145c13964b4042bd86acf17642f3849668e807dd 100644 (file)
@@ -54,12 +54,5 @@ int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
                              const char *mailbox_name,
                              enum mailbox_list_file_type type,
                              enum mailbox_info_flags *flags);
-int dbox_list_rename_mailbox_pre(struct mailbox_list *oldlist,
-                                const char *oldname,
-                                struct mailbox_list *newlist,
-                                const char *newname);
-int dbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
-                            struct mailbox_list *newlist, const char *newname,
-                            bool rename_children);
 
 #endif
index 6856be4bee2d273478795b316bd7b2f6629e910b..3db6943ec84af0aff45f96a4a605c151ab09cb7f 100644 (file)
@@ -313,21 +313,6 @@ static int mdbox_mailbox_delete(struct mailbox *box)
        return index_storage_mailbox_delete(box);
 }
 
-static int
-mdbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
-                         struct mailbox_list *newlist, const char *newname,
-                         bool rename_children)
-{
-       struct mdbox_mailbox_list *oldmlist = MDBOX_LIST_CONTEXT(oldlist);
-
-       if (oldmlist->module_ctx.super.
-                       rename_mailbox(oldlist, oldname, newlist, newname,
-                                      rename_children) < 0)
-               return -1;
-       return dbox_list_rename_mailbox(oldlist, oldname, newlist, newname,
-                                       rename_children);
-}
-
 static void dbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
                                  struct mailbox_list *list)
 {
@@ -335,10 +320,7 @@ static void dbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
 
        mlist = p_new(list->pool, struct mdbox_mailbox_list, 1);
        mlist->module_ctx.super = list->v;
-
        list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
-       list->v.rename_mailbox = mdbox_list_rename_mailbox;
-       list->v.rename_mailbox_pre = dbox_list_rename_mailbox_pre;
 
        MODULE_CONTEXT_SET(list, mdbox_mailbox_list_module, mlist);
 }
@@ -370,6 +352,7 @@ struct mailbox mdbox_mailbox = {
                dbox_mailbox_create,
                mdbox_mailbox_update,
                mdbox_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                mdbox_mailbox_get_guid,
                NULL,
index 3b40bd672dbddef178e4a57639353599ab1f4e21..ffd319c562a3ea5cf475bfc4c2e25866a29b1ca3 100644 (file)
@@ -203,21 +203,6 @@ dbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
        return sdbox_write_index_header(box, update);
 }
 
-static int
-sdbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
-                         struct mailbox_list *newlist, const char *newname,
-                         bool rename_children)
-{
-       struct sdbox_mailbox_list *oldmlist = SDBOX_LIST_CONTEXT(oldlist);
-
-       if (oldmlist->module_ctx.super.
-                       rename_mailbox(oldlist, oldname, newlist, newname,
-                                      rename_children) < 0)
-               return -1;
-       return dbox_list_rename_mailbox(oldlist, oldname, newlist, newname,
-                                       rename_children);
-}
-
 static void sdbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
                                   struct mailbox_list *list)
 {
@@ -225,10 +210,7 @@ static void sdbox_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
 
        mlist = p_new(list->pool, struct sdbox_mailbox_list, 1);
        mlist->module_ctx.super = list->v;
-
        list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
-       list->v.rename_mailbox = sdbox_list_rename_mailbox;
-       list->v.rename_mailbox_pre = dbox_list_rename_mailbox_pre;
 
        MODULE_CONTEXT_SET(list, sdbox_mailbox_list_module, mlist);
 }
@@ -260,6 +242,7 @@ struct mailbox sdbox_mailbox = {
                dbox_mailbox_create,
                dbox_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                sdbox_mailbox_get_guid,
                NULL,
index d800dd95feaf7bd30fff586569335e47f9f4a4f7..29a3edc4dd51eb8e658d6aaa47de45ce56734d79 100644 (file)
@@ -475,6 +475,23 @@ int index_storage_mailbox_delete(struct mailbox *box)
        return index_storage_mailbox_delete_dir(box, TRUE);
 }
 
+int index_storage_mailbox_rename(struct mailbox *src, struct mailbox *dest,
+                                bool rename_children)
+{
+       uint8_t guid[MAIL_GUID_128_SIZE];
+
+       if (src->list->v.rename_mailbox(src->list, src->name,
+                                       dest->list, dest->name,
+                                       rename_children) < 0)
+               return -1;
+
+       /* we'll track mailbox names, instead of GUIDs. We may be renaming a
+          non-selectable mailbox (directory), which doesn't even have a GUID */
+       mailbox_name_get_sha128(dest->name, guid);
+       mailbox_list_add_change(src->list, MAILBOX_LOG_RECORD_RENAME, guid);
+       return 0;
+}
+
 bool index_storage_is_readonly(struct mailbox *box)
 {
        return (box->flags & MAILBOX_FLAG_READONLY) != 0 ||
index a22bc9a31d7a991b332bc2ad6a988a5a7db9aec8..2b96dbb63cc3ae12f94ac1ea4ee85fc4b5b66f97 100644 (file)
@@ -77,6 +77,8 @@ int index_storage_mailbox_update(struct mailbox *box,
                                 const struct mailbox_update *update);
 int index_storage_mailbox_delete(struct mailbox *box);
 int index_storage_mailbox_delete_dir(struct mailbox *box, bool mailbox_deleted);
+int index_storage_mailbox_rename(struct mailbox *src, struct mailbox *dest,
+                                bool rename_children);
 
 bool index_storage_is_readonly(struct mailbox *box);
 bool index_storage_allow_new_keywords(struct mailbox *box);
index 49669c56f9511dd4f06aad4ea1f942b6109814ed..3b02bb61e1e954ae1c9dd7a545f92cfbc71ce698 100644 (file)
@@ -24,12 +24,6 @@ struct maildir_mailbox_list_context {
        const struct maildir_settings *set;
 };
 
-struct rename_context {
-       bool found;
-       size_t oldnamelen;
-       const char *newname;
-};
-
 extern struct mail_storage maildir_storage;
 extern struct mailbox maildir_mailbox;
 
@@ -507,34 +501,6 @@ maildir_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
        return maildir_uidlist_get_mailbox_guid(mbox->uidlist, guid);
 }
 
-static int
-maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
-                           struct mailbox_list *newlist, const char *newname,
-                           bool rename_children)
-{
-       struct maildir_mailbox_list_context *oldmlist =
-               MAILDIR_LIST_CONTEXT(oldlist);
-       const char *path1, *path2;
-
-       if (strcmp(oldname, "INBOX") == 0) {
-               /* INBOX often exists as the root ~/Maildir.
-                  We can't rename it then. */
-               path1 = mailbox_list_get_path(oldlist, oldname,
-                                             MAILBOX_LIST_PATH_TYPE_MAILBOX);
-               path2 = mailbox_list_get_path(oldlist, NULL,
-                                             MAILBOX_LIST_PATH_TYPE_MAILBOX);
-               if (strcmp(path1, path2) == 0) {
-                       mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
-                               "Renaming INBOX isn't supported.");
-                       return -1;
-               }
-       }
-
-       return oldmlist->module_ctx.super.
-               rename_mailbox(oldlist, oldname, newlist, newname,
-                              rename_children);
-}
-
 static void maildir_mailbox_close(struct mailbox *box)
 {
        struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
@@ -773,7 +739,6 @@ static void maildir_storage_add_list(struct mail_storage *storage,
                        maildir_storage_is_valid_create_name;
                list->v.iter_is_mailbox = maildir_list_iter_is_mailbox;
        }
-       list->v.rename_mailbox = maildir_list_rename_mailbox;
        MODULE_CONTEXT_SET(list, maildir_mailbox_list_module, mlist);
 }
 
@@ -804,6 +769,7 @@ struct mailbox maildir_mailbox = {
                maildir_mailbox_create,
                maildir_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                maildir_mailbox_get_guid,
                maildir_list_index_has_changed,
index 56e8a148e56e6008df25515d9e7504e09d371405..f022715a9c0cfdc920a77902d97aa7887f3701d4 100644 (file)
@@ -792,6 +792,7 @@ struct mailbox mbox_mailbox = {
                mbox_mailbox_create,
                mbox_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                mbox_mailbox_get_guid,
                NULL,
index ad8d25ab683c54c005a92cc7d6e1fa8b58826d83..6bba98968061887a56608deaa8f353dc78caf391 100644 (file)
@@ -185,6 +185,7 @@ struct mailbox raw_mailbox = {
                raw_mailbox_create,
                raw_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                NULL,
                NULL,
index 2d39ef10d6d864f290ae1d6d9c7b7ab55aaddb1a..4d0263fffca72f0b91bebc18b28880bce393dff8 100644 (file)
@@ -306,27 +306,9 @@ shared_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
        if (shared_list_rename_get_ns(oldlist, &oldname,
                                      newlist, &newname, &ns) < 0)
                return -1;
-       ret = mailbox_list_rename_mailbox(ns->list, oldname, ns->list, newname,
-                                         rename_children);
-       if (ret < 0)
-               shared_list_copy_error(oldlist, ns);
-       return ret;
-}
-
-static int
-shared_list_rename_mailbox_pre(struct mailbox_list *oldlist,
-                              const char *oldname,
-                              struct mailbox_list *newlist,
-                              const char *newname)
-{
-       struct mail_namespace *ns;
-       int ret;
 
-       if (shared_list_rename_get_ns(oldlist, &oldname,
-                                     newlist, &newname, &ns) < 0)
-               return -1;
-       ret = ns->list->v.rename_mailbox_pre(ns->list, oldname,
-                                            ns->list, newname);
+       ret = ns->list->v.rename_mailbox(ns->list, oldname, ns->list, newname,
+                                        rename_children);
        if (ret < 0)
                shared_list_copy_error(oldlist, ns);
        return ret;
@@ -358,7 +340,6 @@ struct mailbox_list shared_mailbox_list = {
                shared_list_create_mailbox_dir,
                shared_list_delete_mailbox,
                shared_list_delete_dir,
-               shared_list_rename_mailbox,
-               shared_list_rename_mailbox_pre
+               shared_list_rename_mailbox
        }
 };
index 2e72ecdb3ececcd3c53f850b7286a8be503c9434..922c9afa5a268693f4ebe486edcaa6d9639b1bae 100644 (file)
@@ -471,8 +471,9 @@ static int fs_list_rename_mailbox(struct mailbox_list *oldlist,
                                  const char *newname, bool rename_children)
 {
        struct mail_storage *oldstorage;
-       const char *oldpath, *newpath, *p, *origin;
-       enum mailbox_list_path_type path_type;
+       const char *oldpath, *newpath, *alt_oldpath, *alt_newpath, *root_path;
+       const char *p, *origin;
+       enum mailbox_list_path_type path_type, alt_path_type;
        struct stat st;
        mode_t mode;
        gid_t gid;
@@ -481,12 +482,14 @@ static int fs_list_rename_mailbox(struct mailbox_list *oldlist,
        if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
                return -1;
 
-       if (rename_children)
+       if (rename_children) {
                path_type = MAILBOX_LIST_PATH_TYPE_DIR;
-       else if (mail_storage_is_mailbox_file(oldstorage) ||
-                *oldlist->set.maildir_name != '\0')
+               alt_path_type = MAILBOX_LIST_PATH_TYPE_ALT_DIR;
+       } else if (mail_storage_is_mailbox_file(oldstorage) ||
+                  *oldlist->set.maildir_name != '\0') {
                path_type = MAILBOX_LIST_PATH_TYPE_MAILBOX;
-       else {
+               alt_path_type = MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX;
+       } else {
                /* we can't do this, our children would get renamed with us */
                mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
                        "Can't rename mailbox without its children.");
@@ -495,6 +498,18 @@ static int fs_list_rename_mailbox(struct mailbox_list *oldlist,
 
        oldpath = mailbox_list_get_path(oldlist, oldname, path_type);
        newpath = mailbox_list_get_path(newlist, newname, path_type);
+       alt_oldpath = mailbox_list_get_path(oldlist, oldname, alt_path_type);
+       alt_newpath = mailbox_list_get_path(newlist, newname, alt_path_type);
+
+       root_path = mailbox_list_get_path(oldlist, NULL,
+                                         MAILBOX_LIST_PATH_TYPE_MAILBOX);
+       if (strcmp(oldpath, root_path) == 0) {
+               /* most likely INBOX */
+               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
+                       t_strdup_printf("Renaming %s isn't supported.",
+                                       oldname));
+               return -1;
+       }
 
        /* create the hierarchy */
        p = strrchr(newpath, '/');
@@ -531,14 +546,30 @@ static int fs_list_rename_mailbox(struct mailbox_list *oldlist,
                return -1;
        }
 
-       if (oldlist->v.rename_mailbox_pre != NULL) {
-               if (oldlist->v.rename_mailbox_pre(oldlist, oldname,
-                                                 newlist, newname) < 0)
+       if ((alt_newpath != NULL && alt_oldpath == NULL) ||
+           (alt_newpath == NULL && alt_oldpath != NULL)) {
+               /* both or neither source/dest must to have alt path defined.
+                  otherwise we'd have to do the merging ourself, which would
+                  be possible but a bit too much trouble for now */
+               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
+                       "Can't rename mailboxes across specified storages.");
+               return -1;
+       }
+
+       if (alt_newpath != NULL) {
+               if (stat(alt_newpath, &st) == 0) {
+                       /* race condition or a directory left there lying around?
+                          safest to just report error. */
+                       mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
+                                              "Target mailbox already exists");
                        return -1;
+               } else if (errno != ENOENT) {
+                       mailbox_list_set_critical(oldlist, "stat(%s) failed: %m",
+                                                 alt_newpath);
+                       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) {
                if (ENOTFOUND(errno)) {
                        mailbox_list_set_error(oldlist, MAIL_ERROR_NOTFOUND,
@@ -563,6 +594,10 @@ static int fs_list_rename_mailbox(struct mailbox_list *oldlist,
                }
        }
 
+       if (alt_newpath != NULL) {
+               (void)rename_dir(oldlist, oldname, newlist, newname,
+                                alt_path_type, rmdir_parent);
+       }
        (void)rename_dir(oldlist, oldname, newlist, newname,
                         MAILBOX_LIST_PATH_TYPE_CONTROL, rmdir_parent);
        (void)rename_dir(oldlist, oldname, newlist, newname,
@@ -596,7 +631,6 @@ struct mailbox_list fs_mailbox_list = {
                fs_list_create_mailbox_dir,
                fs_list_delete_mailbox,
                fs_list_delete_dir,
-               fs_list_rename_mailbox,
-               NULL
+               fs_list_rename_mailbox
        }
 };
index f0b7d1d758086aef9de25c51063be97840e44b80..8ae113502c59f71b2a837227558cfa603ba18f7c 100644 (file)
@@ -289,116 +289,6 @@ static int maildir_list_set_subscribed(struct mailbox_list *_list,
                                       name, set);
 }
 
-static int rename_dir(struct mailbox_list *oldlist, const char *oldname,
-                     struct mailbox_list *newlist, const char *newname,
-                     enum mailbox_list_path_type type)
-{
-       const char *oldpath, *newpath;
-
-       oldpath = mailbox_list_get_path(oldlist, oldname, type);
-       newpath = mailbox_list_get_path(newlist, newname, type);
-
-       if (strcmp(oldpath, newpath) == 0)
-               return 0;
-
-       if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
-               mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
-                                         oldpath, newpath);
-               return -1;
-       }
-       return 0;
-}
-
-static int
-maildir_rename_children(struct mailbox_list *oldlist, const char *oldname,
-                       struct mailbox_list *newlist, const char *newname)
-{
-       struct mailbox_list_iterate_context *iter;
-        const struct mailbox_info *info;
-       ARRAY_DEFINE(names_arr, const char *);
-       const char *pattern, *oldpath, *newpath, *old_listname, *new_listname;
-       const char *const *names;
-       unsigned int i, count;
-       size_t oldnamelen;
-       pool_t pool;
-       char old_sep;
-       int ret;
-
-       ret = 0;
-       oldnamelen = strlen(oldname);
-
-       /* first get the list of the children and save them to memory, because
-          we can't rely on readdir() not skipping files while the directory
-          is being modified. this doesn't protect against modifications by
-          other processes though. */
-       pool = pool_alloconly_create("Maildir++ children list", 1024);
-       i_array_init(&names_arr, 64);
-
-       old_sep = mailbox_list_get_hierarchy_sep(oldlist);
-       pattern = t_strdup_printf("%s%c*", oldname, old_sep);
-       iter = mailbox_list_iter_init(oldlist, pattern,
-                                     MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
-                                     MAILBOX_LIST_ITER_RAW_LIST);
-       while ((info = mailbox_list_iter_next(iter)) != NULL) {
-               const char *name;
-
-               /* verify that the prefix matches, otherwise we could have
-                  problems with mailbox names containing '%' and '*' chars */
-               if (strncmp(info->name, oldname, oldnamelen) == 0 &&
-                   info->name[oldnamelen] == old_sep) {
-                       name = p_strdup(pool, info->name + oldnamelen);
-                       array_append(&names_arr, &name, 1);
-               }
-       }
-       if (mailbox_list_iter_deinit(&iter) < 0) {
-               ret = -1;
-               names = NULL; count = 0;
-       } else {
-               names = array_get(&names_arr, &count);
-       }
-
-       for (i = 0; i < count; i++) {
-               old_listname = t_strconcat(oldname, names[i], NULL);
-               if (strcmp(old_listname, newname) == 0) {
-                       /* When doing RENAME "a" "a.b" we see "a.b" here.
-                          We don't want to rename it anymore to "a.b.b". */
-                       continue;
-               }
-
-               new_listname = t_strconcat(newname, names[i], NULL);
-               oldpath = mailbox_list_get_path(oldlist, old_listname,
-                                               MAILBOX_LIST_PATH_TYPE_MAILBOX);
-               newpath = mailbox_list_get_path(newlist, new_listname,
-                                               MAILBOX_LIST_PATH_TYPE_MAILBOX);
-
-               /* FIXME: it's possible to merge two mailboxes if either one of
-                  them doesn't have existing root mailbox. We could check this
-                  but I'm not sure if it's worth it. It could be even
-                  considered as a feature.
-
-                  Anyway, the bug with merging is that if both mailboxes have
-                  identically named child mailbox they conflict. Just ignore
-                  those and leave them under the old mailbox. */
-               if (rename(oldpath, newpath) == 0 || EDESTDIREXISTS(errno))
-                       ret = 1;
-               else {
-                       mailbox_list_set_critical(oldlist,
-                               "rename(%s, %s) failed: %m", oldpath, newpath);
-                       ret = -1;
-                       break;
-               }
-
-               (void)rename_dir(oldlist, old_listname, newlist, new_listname,
-                                MAILBOX_LIST_PATH_TYPE_CONTROL);
-               (void)rename_dir(oldlist, old_listname, newlist, new_listname,
-                                MAILBOX_LIST_PATH_TYPE_INDEX);
-       }
-       array_free(&names_arr);
-       pool_unref(&pool);
-
-       return ret;
-}
-
 static int
 maildir_list_create_maildirfolder_file(struct mailbox_list *list,
                                       const char *dir)
@@ -547,12 +437,122 @@ static int maildir_list_delete_dir(struct mailbox_list *list, const char *name)
        return -1;
 }
 
+static int rename_dir(struct mailbox_list *oldlist, const char *oldname,
+                     struct mailbox_list *newlist, const char *newname,
+                     enum mailbox_list_path_type type)
+{
+       const char *oldpath, *newpath;
+
+       oldpath = mailbox_list_get_path(oldlist, oldname, type);
+       newpath = mailbox_list_get_path(newlist, newname, type);
+
+       if (strcmp(oldpath, newpath) == 0)
+               return 0;
+
+       if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
+               mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
+                                         oldpath, newpath);
+               return -1;
+       }
+       return 0;
+}
+
+static int
+maildir_rename_children(struct mailbox_list *oldlist, const char *oldname,
+                       struct mailbox_list *newlist, const char *newname)
+{
+       struct mailbox_list_iterate_context *iter;
+        const struct mailbox_info *info;
+       ARRAY_DEFINE(names_arr, const char *);
+       const char *pattern, *oldpath, *newpath, *old_listname, *new_listname;
+       const char *const *names;
+       unsigned int i, count;
+       size_t oldnamelen;
+       pool_t pool;
+       char old_sep;
+       int ret;
+
+       ret = 0;
+       oldnamelen = strlen(oldname);
+
+       /* first get the list of the children and save them to memory, because
+          we can't rely on readdir() not skipping files while the directory
+          is being modified. this doesn't protect against modifications by
+          other processes though. */
+       pool = pool_alloconly_create("Maildir++ children list", 1024);
+       i_array_init(&names_arr, 64);
+
+       old_sep = mailbox_list_get_hierarchy_sep(oldlist);
+       pattern = t_strdup_printf("%s%c*", oldname, old_sep);
+       iter = mailbox_list_iter_init(oldlist, pattern,
+                                     MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
+                                     MAILBOX_LIST_ITER_RAW_LIST);
+       while ((info = mailbox_list_iter_next(iter)) != NULL) {
+               const char *name;
+
+               /* verify that the prefix matches, otherwise we could have
+                  problems with mailbox names containing '%' and '*' chars */
+               if (strncmp(info->name, oldname, oldnamelen) == 0 &&
+                   info->name[oldnamelen] == old_sep) {
+                       name = p_strdup(pool, info->name + oldnamelen);
+                       array_append(&names_arr, &name, 1);
+               }
+       }
+       if (mailbox_list_iter_deinit(&iter) < 0) {
+               ret = -1;
+               names = NULL; count = 0;
+       } else {
+               names = array_get(&names_arr, &count);
+       }
+
+       for (i = 0; i < count; i++) {
+               old_listname = t_strconcat(oldname, names[i], NULL);
+               if (strcmp(old_listname, newname) == 0) {
+                       /* When doing RENAME "a" "a.b" we see "a.b" here.
+                          We don't want to rename it anymore to "a.b.b". */
+                       continue;
+               }
+
+               new_listname = t_strconcat(newname, names[i], NULL);
+               oldpath = mailbox_list_get_path(oldlist, old_listname,
+                                               MAILBOX_LIST_PATH_TYPE_MAILBOX);
+               newpath = mailbox_list_get_path(newlist, new_listname,
+                                               MAILBOX_LIST_PATH_TYPE_MAILBOX);
+
+               /* FIXME: it's possible to merge two mailboxes if either one of
+                  them doesn't have existing root mailbox. We could check this
+                  but I'm not sure if it's worth it. It could be even
+                  considered as a feature.
+
+                  Anyway, the bug with merging is that if both mailboxes have
+                  identically named child mailbox they conflict. Just ignore
+                  those and leave them under the old mailbox. */
+               if (rename(oldpath, newpath) == 0 || EDESTDIREXISTS(errno))
+                       ret = 1;
+               else {
+                       mailbox_list_set_critical(oldlist,
+                               "rename(%s, %s) failed: %m", oldpath, newpath);
+                       ret = -1;
+                       break;
+               }
+
+               (void)rename_dir(oldlist, old_listname, newlist, new_listname,
+                                MAILBOX_LIST_PATH_TYPE_CONTROL);
+               (void)rename_dir(oldlist, old_listname, newlist, new_listname,
+                                MAILBOX_LIST_PATH_TYPE_INDEX);
+       }
+       array_free(&names_arr);
+       pool_unref(&pool);
+
+       return ret;
+}
+
 static int
 maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
                            struct mailbox_list *newlist, const char *newname,
                            bool rename_children)
 {
-       const char *oldpath, *newpath;
+       const char *oldpath, *newpath, *root_path;
        int ret;
         bool found;
 
@@ -563,6 +563,16 @@ maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
        newpath = mailbox_list_get_path(newlist, newname,
                                        MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
+       root_path = mailbox_list_get_path(oldlist, NULL,
+                                         MAILBOX_LIST_PATH_TYPE_MAILBOX);
+       if (strcmp(oldpath, root_path) == 0) {
+               /* most likely INBOX */
+               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
+                       t_strdup_printf("Renaming %s isn't supported.",
+                                       oldname));
+               return -1;
+       }
+
        ret = rename(oldpath, newpath);
        if (ret == 0 || errno == ENOENT) {
                (void)rename_dir(oldlist, oldname, newlist, newname,
@@ -602,6 +612,7 @@ struct mailbox_list maildir_mailbox_list = {
        .name = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS,
        .hierarchy_sep = '.',
        .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
+               MAILBOX_LIST_PROP_NO_ALT_DIR |
                MAILBOX_LIST_PROP_NO_NOSELECT,
        .mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
 
@@ -625,8 +636,7 @@ struct mailbox_list maildir_mailbox_list = {
                maildir_list_create_mailbox_dir,
                maildir_list_delete_mailbox,
                maildir_list_delete_dir,
-               maildir_list_rename_mailbox,
-               NULL
+               maildir_list_rename_mailbox
        }
 };
 
@@ -634,6 +644,7 @@ struct mailbox_list imapdir_mailbox_list = {
        .name = MAILBOX_LIST_NAME_IMAPDIR,
        .hierarchy_sep = '.',
        .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
+               MAILBOX_LIST_PROP_NO_ALT_DIR |
                MAILBOX_LIST_PROP_NO_NOSELECT,
        .mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
 
@@ -657,7 +668,6 @@ struct mailbox_list imapdir_mailbox_list = {
                maildir_list_create_mailbox_dir,
                maildir_list_delete_mailbox,
                maildir_list_delete_dir,
-               maildir_list_rename_mailbox,
-               NULL
+               maildir_list_rename_mailbox
        }
 };
index 3528ba99fb6ad2ae2033e96e1c86538c3547a5be..93961d2f832797046d61a753864ff7e125856980 100644 (file)
@@ -98,6 +98,8 @@ struct mailbox_vfuncs {
                      bool directory);
        int (*update)(struct mailbox *box, const struct mailbox_update *update);
        int (*delete)(struct mailbox *box);
+       int (*rename)(struct mailbox *src, struct mailbox *dest,
+                     bool rename_children);
 
        void (*get_status)(struct mailbox *box, enum mailbox_status_items items,
                           struct mailbox_status *status_r);
index 803febba4cc7d6407ee31bafbb0876772b9dff55..bc9accb1de216d3fc9efa3bca83e27ffc73a1ea3 100644 (file)
@@ -270,8 +270,11 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
                if (mail_storage_is_mailbox_file(storage_class))
                        list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
                if (mailbox_list_create(list_set.layout, ns, &list_set,
-                                       list_flags, error_r) < 0)
+                                       list_flags, error_r) < 0) {
+                       *error_r = t_strdup_printf("Mailbox list driver %s: %s",
+                                                  list_set.layout, *error_r);
                        return -1;
+               }
                if (mail_storage_create_root(ns->list, flags, error_r) < 0)
                        return -1;
        }
@@ -656,6 +659,42 @@ int mailbox_delete(struct mailbox *box)
        return ret;
 }
 
+static bool nullequals(const void *p1, const void *p2)
+{
+       return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
+}
+
+int mailbox_rename(struct mailbox *src, struct mailbox *dest,
+                  bool rename_children)
+{
+       if (!mailbox_list_is_valid_existing_name(src->list, src->name) ||
+           *src->name == '\0' ||
+           !mailbox_list_is_valid_create_name(dest->list, dest->name)) {
+               mailbox_list_set_error(src->list, MAIL_ERROR_PARAMS,
+                                      "Invalid mailbox name");
+               return -1;
+       }
+       if (strcmp(src->storage->name, dest->storage->name) != 0) {
+               mailbox_list_set_error(src->list, MAIL_ERROR_NOTPOSSIBLE,
+                       "Can't rename mailbox to another storage type.");
+               return -1;
+       }
+       if (!nullequals(src->list->set.index_dir, dest->list->set.index_dir) ||
+           !nullequals(src->list->set.control_dir, dest->list->set.control_dir)) {
+               mailbox_list_set_error(src->list, MAIL_ERROR_NOTPOSSIBLE,
+                       "Can't rename mailboxes across specified storages.");
+               return -1;
+       }
+       if (src->list->ns->type != NAMESPACE_PRIVATE ||
+           dest->list->ns->type != NAMESPACE_PRIVATE) {
+               mailbox_list_set_error(src->list, MAIL_ERROR_NOTPOSSIBLE,
+                       "Renaming not supported across non-private namespaces.");
+               return -1;
+       }
+
+       return src->v.rename(src, dest, rename_children);
+}
+
 struct mail_storage *mailbox_get_storage(const struct mailbox *box)
 {
        return box->storage;
index f67c11da33d92a96a49c61cb0084d3233aa4a719..646f45eedc8d6295e67d3d1bd6892509292c01a4 100644 (file)
@@ -346,6 +346,11 @@ int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
 int mailbox_update(struct mailbox *box, const struct mailbox_update *update);
 /* Delete mailbox (and its parent directory, if it has no siblings) */
 int mailbox_delete(struct mailbox *box);
+/* Rename mailbox. Renaming across different mailbox lists is possible only
+   between private namespaces and storages of the same type. If the rename
+   fails, the error is set to src's storage. */
+int mailbox_rename(struct mailbox *src, struct mailbox *dest,
+                  bool rename_children);
 
 /* Enable the given feature for the mailbox. */
 int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
index 7d3441a0f7cccc50c5fe886ba8635c5cafcfa46f..b4d5575accc5b577e5b04322cf5edcb608840f3f 100644 (file)
@@ -68,11 +68,6 @@ struct mailbox_list_vfuncs {
        int (*rename_mailbox)(struct mailbox_list *oldlist, const char *oldname,
                              struct mailbox_list *newlist, const char *newname,
                              bool rename_children);
-       /* called by rename_mailbox() just before running the actual rename() */
-       int (*rename_mailbox_pre)(struct mailbox_list *oldlist,
-                                 const char *oldname,
-                                 struct mailbox_list *newlist,
-                                 const char *newname);
 };
 
 struct mailbox_list_module_register {
index b8dd6a45f330da40ef0dff66467747b73becc379..3465b53ce38ca70381bdbb8ea535d6bf806d2b20 100644 (file)
@@ -108,12 +108,22 @@ int mailbox_list_create(const char *driver, struct mail_namespace *ns,
                 *set->subscription_fname != '\0');
 
        if (!mailbox_list_driver_find(driver, &idx)) {
-               *error_r = t_strdup_printf("Unknown mailbox list driver: %s",
-                                          driver);
+               *error_r = "Unknown driver name";
                return -1;
        }
 
        class_p = array_idx(&mailbox_list_drivers, idx);
+       if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
+           set->maildir_name != NULL) {
+               *error_r = "maildir_name not supported by this driver";
+               return -1;
+       }
+       if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
+           set->alt_dir != NULL) {
+               *error_r = "alt_dir not supported by this driver";
+               return -1;
+       }
+
        list = (*class_p)->v.alloc();
        array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
 
@@ -137,8 +147,7 @@ int mailbox_list_create(const char *driver, struct mail_namespace *ns,
        list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
        list->set.subscription_fname =
                p_strdup(list->pool, set->subscription_fname);
-       list->set.maildir_name = set->maildir_name == NULL ||
-               (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
+       list->set.maildir_name = set->maildir_name == NULL ? "" :
                p_strdup(list->pool, set->maildir_name);
        list->set.mailbox_dir_name =
                p_strdup(list->pool, set->mailbox_dir_name);
@@ -741,62 +750,6 @@ int mailbox_list_delete_dir(struct mailbox_list *list, const char *name)
        return list->v.delete_dir(list, name);
 }
 
-static bool nullequals(const void *p1, const void *p2)
-{
-       return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
-}
-
-int mailbox_list_rename_mailbox(struct mailbox_list *oldlist,
-                               const char *oldname,
-                               struct mailbox_list *newlist,
-                               const char *newname, bool rename_children)
-{
-       struct mail_storage *oldstorage;
-       struct mail_storage *newstorage;
-       uint8_t guid[MAIL_GUID_128_SIZE];
-
-       if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
-               return -1;
-
-       newstorage = oldstorage;
-       mailbox_list_get_closest_storage(newlist, &newstorage);
-
-       if (!mailbox_list_is_valid_existing_name(oldlist, oldname) ||
-           *oldname == '\0' ||
-           !mailbox_list_is_valid_create_name(newlist, newname)) {
-               mailbox_list_set_error(oldlist, MAIL_ERROR_PARAMS,
-                                      "Invalid mailbox name");
-               return -1;
-       }
-       if (strcmp(oldstorage->name, newstorage->name) != 0) {
-               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
-                       "Can't rename mailbox to another storage type.");
-               return -1;
-       }
-       if (!nullequals(oldlist->set.index_dir, newlist->set.index_dir) ||
-           !nullequals(oldlist->set.control_dir, newlist->set.control_dir)) {
-               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
-                       "Can't rename mailboxes across specified storages.");
-               return -1;
-       }
-       if (oldlist->ns->type != NAMESPACE_PRIVATE ||
-           newlist->ns->type != NAMESPACE_PRIVATE) {
-               mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
-                       "Renaming not supported across non-private namespaces.");
-               return -1;
-       }
-
-       if (oldlist->v.rename_mailbox(oldlist, oldname, newlist, newname,
-                                     rename_children) < 0)
-               return -1;
-
-       /* we'll track mailbox names, instead of GUIDs. We may be renaming a
-          non-selectable mailbox (directory), which doesn't even have a GUID */
-       mailbox_name_get_sha128(newname, guid);
-       mailbox_list_add_change(oldlist, MAILBOX_LOG_RECORD_RENAME, guid);
-       return 0;
-}
-
 void mailbox_name_get_sha128(const char *name, uint8_t guid[MAIL_GUID_128_SIZE])
 {
        unsigned char sha[SHA1_RESULTLEN];
index 4addc28bbf06bed28c762e1f40a0637d82323a39..ba98442ef870e01bc32cbd2a004f74a9d715741e 100644 (file)
@@ -18,8 +18,10 @@ struct mailbox_list_iterate_context;
 enum mailbox_list_properties {
        /* maildir_name must always be empty */
        MAILBOX_LIST_PROP_NO_MAILDIR_NAME       = 0x01,
+       /* alt directories not supported */
+       MAILBOX_LIST_PROP_NO_ALT_DIR            = 0x02,
        /* no support for \noselect directories, only mailboxes */
-       MAILBOX_LIST_PROP_NO_NOSELECT           = 0x02
+       MAILBOX_LIST_PROP_NO_NOSELECT           = 0x04
 };
 
 enum mailbox_list_flags {
@@ -250,13 +252,6 @@ int mailbox_list_set_subscribed(struct mailbox_list *list,
 
 /* Delete a non-selectable mailbox. Fail if the mailbox is selectable. */
 int mailbox_list_delete_dir(struct mailbox_list *list, const char *name);
-/* Rename mailbox. Renaming across different mailbox lists is possible only
-   between private namespaces and storages of the same type. If the rename
-   fails, the error is set to oldlist. */
-int mailbox_list_rename_mailbox(struct mailbox_list *oldlist,
-                               const char *oldname,
-                               struct mailbox_list *newlist,
-                               const char *newname, bool rename_children);
 
 /* Returns the error message of last occurred error. */
 const char *mailbox_list_get_last_error(struct mailbox_list *list,
index 6cd18663bb39224dfc03c1a45fc8ad25e6c3b251..cd1bfe0e68841e2616c4dc893b2df650263f09b8 100644 (file)
@@ -59,6 +59,15 @@ static int test_mailbox_delete(struct mailbox *box)
        return -1;
 }
 
+static int test_mailbox_rename(struct mailbox *src,
+                              struct mailbox *dest ATTR_UNUSED,
+                              bool rename_children ATTR_UNUSED)
+{
+       mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
+                              "Test mailbox rename isn't supported");
+       return -1;
+}
+
 static void test_mailbox_get_status(struct mailbox *box ATTR_UNUSED,
                                    enum mailbox_status_items items ATTR_UNUSED,
                                    struct mailbox_status *status_r)
@@ -316,6 +325,7 @@ struct mailbox test_mailbox = {
                test_mailbox_create,
                test_mailbox_update,
                test_mailbox_delete,
+               test_mailbox_rename,
                test_mailbox_get_status,
                NULL,
                NULL,
index 8de527d9cd9b79d194e81eccd69a2347fd95ec32..6ec7908f0e3d1c42fbee7743e71489dd17a3fed2 100644 (file)
@@ -231,10 +231,12 @@ lazy_expunge_mail_alloc(struct mailbox_transaction_context *t,
 }
 
 static int
-mailbox_move(struct mailbox_list *src_list, const char *src_name,
-            struct mailbox_list *dest_list, const char **_dest_name)
+mailbox_move(struct mailbox *src_box, struct mailbox_list *dest_list,
+            const char *wanted_destname, struct mailbox **dest_box_r)
 {
-       const char *dir, *origin, *dest_name = *_dest_name;
+       const char *dest_name = wanted_destname;
+       struct mailbox *dest_box;
+       const char *dir, *origin;
        enum mail_error error;
        mode_t mode;
        gid_t gid;
@@ -244,14 +246,19 @@ mailbox_move(struct mailbox_list *src_list, const char *src_name,
        dir = mailbox_list_get_path(dest_list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
        if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
            errno != EEXIST) {
-               mailbox_list_set_critical(src_list,
+               mail_storage_set_critical(src_box->storage,
                        "mkdir_parents(%s) failed: %m", dir);
                return -1;
        }
 
-       while (mailbox_list_rename_mailbox(src_list, src_name,
-                                          dest_list, dest_name, FALSE) < 0) {
-               mailbox_list_get_last_error(src_list, &error);
+       for (;;) {
+               dest_box = mailbox_alloc(dest_list, dest_name,
+                                        MAILBOX_FLAG_OPEN_DELETED);
+               if (mailbox_rename(src_box, dest_box, FALSE) == 0)
+                       break;
+               mailbox_free(&dest_box);
+
+               mail_storage_get_last_error(src_box->storage, &error);
                switch (error) {
                case MAIL_ERROR_EXISTS:
                        break;
@@ -261,12 +268,12 @@ mailbox_move(struct mailbox_list *src_list, const char *src_name,
                        return -1;
                }
 
-               /* mailbox is being deleted multiple times per second.
-                  update the filename. */
-               dest_name = t_strdup_printf("%s-%04u", *_dest_name,
+               /* destination already exists. generate a different name. */
+               dest_name = t_strdup_printf("%s-%04u", wanted_destname,
                                            (uint32_t)random());
        }
-       *_dest_name = dest_name;
+
+       *dest_box_r = dest_box;
        return 1;
 }
 
@@ -378,10 +385,11 @@ static int lazy_expunge_mailbox_delete(struct mailbox *box)
        }
 
        /* first move the actual mailbox */
-       if ((ret = mailbox_move(list, box->name, dest_ns->list, &destname)) < 0)
+       if ((ret = mailbox_move(box, dest_ns->list, destname,
+                               &expunge_box)) < 0)
                return -1;
        if (ret == 0) {
-               mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+               mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
                        T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name));
                return -1;
        }
@@ -389,12 +397,10 @@ static int lazy_expunge_mailbox_delete(struct mailbox *box)
        /* other sessions now see the mailbox completely deleted.
           since it's not really deleted in the lazy-expunge namespace,
           we might want to change it again. so mark the index undeleted. */
-       expunge_box = mailbox_alloc(dest_ns->list, destname,
-                                   MAILBOX_FLAG_OPEN_DELETED);
        if (mailbox_open(expunge_box) < 0) {
                str = mail_storage_get_last_error(expunge_box->storage, &error);
                i_error("lazy_expunge: Couldn't open DELETEd mailbox "
-                       "%s: %s", destname, str);
+                       "%s: %s", expunge_box->name, str);
                mailbox_free(&expunge_box);
                return -1;
        }
@@ -403,7 +409,7 @@ static int lazy_expunge_mailbox_delete(struct mailbox *box)
                return -1;
        }
 
-       if (expunge_ns == dest_ns && strcmp(destname, box->name) != 0)
+       if (expunge_ns == dest_ns && strcmp(expunge_box->name, box->name) != 0)
                ret = mailbox_move_all_mails(expunge_box, box->name);
        else
                ret = 0;
@@ -412,11 +418,16 @@ static int lazy_expunge_mailbox_delete(struct mailbox *box)
        /* next move the expunged messages mailbox, if it exists */
        dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE_EXPUNGE);
        if (expunge_ns != dest_ns) {
-               if (mailbox_move(expunge_ns->list, box->name,
-                                dest_ns->list, &destname) < 0)
-                       ret = -1;
+               struct mailbox *ret_box;
+
+               expunge_box = mailbox_alloc(expunge_ns->list, box->name, 0);
+               ret = mailbox_move(expunge_box, dest_ns->list,
+                                  destname, &ret_box);
+               if (ret > 0)
+                       mailbox_free(&ret_box);
+               mailbox_free(&expunge_box);
        }
-       return ret;
+       return ret < 0 ? -1 : 0;
 }
 
 static void lazy_expunge_mailbox_allocated(struct mailbox *box)
index a2e260bfbf0a0327e9207a0b11182a4c03492f07..00066cde4efd0973d2ba6a2d128e6d660c79853f 100644 (file)
@@ -481,6 +481,7 @@ struct mailbox virtual_mailbox = {
                virtual_mailbox_create,
                virtual_mailbox_update,
                index_storage_mailbox_delete,
+               index_storage_mailbox_rename,
                index_storage_get_status,
                NULL,
                NULL,