Skip to content

Commit

Permalink
lib-storage: Hide and rmdir \NoSelect leaf mailboxes with NO-NOSELECT
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sirainen committed Jul 25, 2017
1 parent a90bb12 commit aebe1e7
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/lib-storage/list/mailbox-list-delete.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -463,4 +481,3 @@ int mailbox_list_delete_symlink_default(struct mailbox_list *list,
}
return -1;
}

3 changes: 3 additions & 0 deletions src/lib-storage/list/mailbox-list-delete.h
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/lib-storage/list/mailbox-list-fs-iter.c
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}

Expand Down
18 changes: 16 additions & 2 deletions src/lib-storage/list/mailbox-list-index-iter.c
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions 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;
Expand All @@ -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

0 comments on commit aebe1e7

Please sign in to comment.