From: Timo Sirainen Date: Tue, 25 Jul 2017 17:53:18 +0000 (+0300) Subject: lib-storage: Hide and rmdir \NoSelect leaf mailboxes with NO-NOSELECT X-Git-Tag: 2.2.32.rc1~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=aebe1e749a910bc87c691c7a53c5de09eed79cfd;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: Hide and rmdir \NoSelect leaf mailboxes with NO-NOSELECT 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. --- diff --git a/src/lib-storage/list/mailbox-list-delete.c b/src/lib-storage/list/mailbox-list-delete.c index d4965dac51..ab22a37fa8 100644 --- a/src/lib-storage/list/mailbox-list-delete.c +++ b/src/lib-storage/list/mailbox-list-delete.c @@ -320,6 +320,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) { @@ -463,4 +481,3 @@ int mailbox_list_delete_symlink_default(struct mailbox_list *list, } return -1; } - diff --git a/src/lib-storage/list/mailbox-list-delete.h b/src/lib-storage/list/mailbox-list-delete.h index ed6b5846d1..fc8e77c068 100644 --- a/src/lib-storage/list/mailbox-list-delete.h +++ b/src/lib-storage/list/mailbox-list-delete.h @@ -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); diff --git a/src/lib-storage/list/mailbox-list-fs-iter.c b/src/lib-storage/list/mailbox-list-fs-iter.c index 0c8d3384a3..d2d8c63e0e 100644 --- a/src/lib-storage/list/mailbox-list-fs-iter.c +++ b/src/lib-storage/list/mailbox-list-fs-iter.c @@ -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 @@ -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; } diff --git a/src/lib-storage/list/mailbox-list-index-iter.c b/src/lib-storage/list/mailbox-list-index-iter.c index 2887c17f22..c5bd968865 100644 --- a/src/lib-storage/list/mailbox-list-index-iter.c +++ b/src/lib-storage/list/mailbox-list-index-iter.c @@ -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 diff --git a/src/lib-storage/list/mailbox-list-iter-private.h b/src/lib-storage/list/mailbox-list-iter-private.h index be2397e41a..47de2ce865 100644 --- a/src/lib-storage/list/mailbox-list-iter-private.h +++ b/src/lib-storage/list/mailbox-list-iter-private.h @@ -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