]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Hide and rmdir \NoSelect leaf mailboxes with NO-NOSELECT
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 25 Jul 2017 17:53:18 +0000 (20:53 +0300)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Tue, 25 Jul 2017 19:06:12 +0000 (22:06 +0300)
If the leaf is successfully rmdir()ed, rmdir() also its parents.

This doesn't work perfectly with if there are multiple levels of \NoSelect
mailboxes. For example with "a/b/c" the listing will already have returned
"a" and "a/b" before it reaches the "a/b/c" code, which will rmdir all of
them, but it's a bit too late at that point. It's too much work to fix
though, and the situation will be fixed on the next list anyway.

src/lib-storage/list/mailbox-list-delete.c
src/lib-storage/list/mailbox-list-delete.h
src/lib-storage/list/mailbox-list-fs-iter.c
src/lib-storage/list/mailbox-list-index-iter.c
src/lib-storage/list/mailbox-list-iter-private.h

index d05567fa755eb8f3df24c48abc0e74f0c1b022db..54953a9bd6b9d18037b77a9bdda107748085681d 100644 (file)
@@ -321,6 +321,24 @@ void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path,
        }
 }
 
+void mailbox_list_delete_mailbox_until_root(struct mailbox_list *list,
+                                           const char *storage_name)
+{
+       enum mailbox_list_path_type types[] = {
+               MAILBOX_LIST_PATH_TYPE_DIR,
+               MAILBOX_LIST_PATH_TYPE_ALT_DIR,
+               MAILBOX_LIST_PATH_TYPE_CONTROL,
+               MAILBOX_LIST_PATH_TYPE_INDEX,
+               MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
+       };
+       const char *path;
+
+       for (unsigned int i = 0; i < N_ELEMENTS(types); i++) {
+               if (mailbox_list_get_path(list, storage_name, types[i], &path) > 0)
+                       mailbox_list_delete_until_root(list, path, types[i]);
+       }
+}
+
 static int mailbox_list_try_delete(struct mailbox_list *list, const char *name,
                                   enum mailbox_list_path_type type)
 {
@@ -464,4 +482,3 @@ int mailbox_list_delete_symlink_default(struct mailbox_list *list,
        }
        return -1;
 }
-
index 83952a54730e8e39b12a550ca6b7867d811b896d..9b466385573716c1883bd16e029ad478c154a03e 100644 (file)
@@ -65,6 +65,9 @@ int mailbox_list_delete_finish_ret(struct mailbox_list *list,
    The root isn't rmdir()ed. */
 void mailbox_list_delete_until_root(struct mailbox_list *list, const char *path,
                                    enum mailbox_list_path_type type);
+/* Call mailbox_list_delete_until_root() for all the paths of the mailbox. */
+void mailbox_list_delete_mailbox_until_root(struct mailbox_list *list,
+                                           const char *storage_name);
 /* Wrapper to unlink_directory(UNLINK_DIRECTORY_FLAG_RMDIR). If it fails due
    to ELOOP, try to unlink() the path instead. */
 int mailbox_list_delete_trash(const char *path, const char **error_r);
index 6dd84ad10853f568a9b3883abed888d67295ac51..60705312f9da8690b434ed07328f26954c250ba2 100644 (file)
@@ -9,6 +9,7 @@
 #include "mail-storage.h"
 #include "mailbox-tree.h"
 #include "mailbox-list-subscriptions.h"
+#include "mailbox-list-iter-private.h"
 #include "mailbox-list-fs.h"
 
 #include <stdio.h>
@@ -741,6 +742,8 @@ fs_list_entry(struct fs_list_iterate_context *ctx,
                   doesn't */
                return 0;
        }
+       if (mailbox_list_iter_try_delete_noselect(&ctx->ctx, &ctx->info, storage_name))
+               return 0;
        return 1;
 }
 
index 2887c17f22e60286834f00c29a9704659692557f..c5bd968865b9262aa941d05307913671462cf532 100644 (file)
@@ -5,6 +5,7 @@
 #include "imap-match.h"
 #include "mail-storage.h"
 #include "mailbox-list-subscriptions.h"
+#include "mailbox-list-iter-private.h"
 #include "mailbox-list-index.h"
 
 static bool iter_use_index(struct mailbox_list *list,
@@ -174,8 +175,21 @@ mailbox_list_index_iter_next(struct mailbox_list_iterate_context *_ctx)
                follow_children = (match & (IMAP_MATCH_YES |
                                            IMAP_MATCH_CHILDREN)) != 0;
                if (match == IMAP_MATCH_YES && iter_subscriptions_ok(ctx)) {
-                       mailbox_list_index_update_next(ctx, TRUE);
-                       return &ctx->info;
+                       /* If this is a) \NoSelect leaf, b) not LAYOUT=index
+                          and c) NO-NOSELECT is set, try to rmdir the leaf
+                          directores from filesystem. (With LAYOUT=index the
+                          \NoSelect mailboxes aren't on the filesystem.) */
+                       if (ilist->has_backing_store &&
+                           mailbox_list_iter_try_delete_noselect(_ctx, &ctx->info,
+                                                                 str_c(ctx->path))) {
+                               /* Deleted \NoSelect leaf. Refresh the index
+                                  later on so it gets removed from the index
+                                  as well. */
+                               mailbox_list_index_refresh_later(_ctx->list);
+                       } else {
+                               mailbox_list_index_update_next(ctx, TRUE);
+                               return &ctx->info;
+                       }
                } else if ((_ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0 &&
                           (ctx->info.flags & MAILBOX_CHILD_SUBSCRIBED) == 0) {
                        /* listing only subscriptions, but there are no
index be2397e41a8830550af754c0fa9a3fac17a4baa0..47de2ce86514ab37e0eddea124ba7bf76da43c22 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef MAILBOX_LIST_ITER_PRIVATE_H
 #define MAILBOX_LIST_ITER_PRIVATE_H
 
+#include "mailbox-list-private.h"
 #include "mailbox-list-iter.h"
+#include "mailbox-list-delete.h"
 
 struct autocreate_box {
        const char *name;
@@ -21,4 +23,20 @@ struct mailbox_list_autocreate_iterate_context {
        bool listing_autoboxes:1;
 };
 
+static inline bool
+mailbox_list_iter_try_delete_noselect(struct mailbox_list_iterate_context *ctx,
+                                     const struct mailbox_info *info,
+                                     const char *storage_name)
+{
+       if ((info->flags & (MAILBOX_NOSELECT|MAILBOX_NOCHILDREN)) ==
+           (MAILBOX_NOSELECT|MAILBOX_NOCHILDREN) &&
+           ctx->list->set.no_noselect) {
+               /* Try to rmdir() all \NoSelect mailbox leafs and
+                  afterwards their parents. */
+               mailbox_list_delete_mailbox_until_root(ctx->list, storage_name);
+               return TRUE;
+       }
+       return FALSE;
+}
+
 #endif