dovecot-2.1: lib-storage: FS layout mailbox list iteration code ...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Dec 10 07:07:20 EET 2011
details: http://hg.dovecot.org/dovecot-2.1/rev/ab696ead12cc
changeset: 13835:ab696ead12cc
user: Timo Sirainen <tss at iki.fi>
date: Sat Dec 10 07:05:56 2011 +0200
description:
lib-storage: FS layout mailbox list iteration code rewrite.
This fixes listing non-ASCII mailboxes. Also the new way no longer keeps
more than one file descriptor open.
diffstat:
src/lib-storage/list/mailbox-list-fs-flags.c | 4 +-
src/lib-storage/list/mailbox-list-fs-iter.c | 1005 +++++++++++--------------
2 files changed, 454 insertions(+), 555 deletions(-)
diffs (truncated from 1193 to 300 lines):
diff -r 5366e59d573f -r ab696ead12cc src/lib-storage/list/mailbox-list-fs-flags.c
--- a/src/lib-storage/list/mailbox-list-fs-flags.c Sat Dec 10 07:03:09 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-fs-flags.c Sat Dec 10 07:05:56 2011 +0200
@@ -117,7 +117,7 @@
*flags_r = 0;
if (*list->set.maildir_name != '\0') {
- /* maildir_name is set: we the code is common for all
+ /* maildir_name is set: the code is common for all
storage types */
return list_is_maildir_mailbox(list, dir, fname, type, flags_r);
}
@@ -131,7 +131,7 @@
switch (type) {
case MAILBOX_LIST_FILE_TYPE_DIR:
if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
- *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
+ *flags_r |= MAILBOX_NOSELECT;
return 1;
}
break;
diff -r 5366e59d573f -r ab696ead12cc src/lib-storage/list/mailbox-list-fs-iter.c
--- a/src/lib-storage/list/mailbox-list-fs-iter.c Sat Dec 10 07:03:09 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c Sat Dec 10 07:05:56 2011 +0200
@@ -14,193 +14,370 @@
struct list_dir_entry {
const char *fname;
- enum mailbox_list_file_type type;
+ enum mailbox_info_flags info_flags;
};
struct list_dir_context {
- struct list_dir_context *prev;
+ struct list_dir_context *parent;
- DIR *dirp;
- char *real_path, *virtual_path;
+ pool_t pool;
+ const char *storage_name;
+ /* this directory's info flags. */
+ enum mailbox_info_flags info_flags;
- const struct list_dir_entry *next_entry;
- struct list_dir_entry entry;
- char *entry_fname;
- struct mailbox_info info;
-
- unsigned int pattern_pos;
-
- unsigned int delayed_send:1;
+ /* all files in this directory */
+ ARRAY_DEFINE(entries, struct list_dir_entry);
+ unsigned int entry_idx;
};
struct fs_list_iterate_context {
struct mailbox_list_iterate_context ctx;
- ARRAY_DEFINE(valid_patterns, const char *);
+ const char *const *valid_patterns;
+ /* roots can be either /foo, ~user/bar or baz */
+ ARRAY_DEFINE(roots, const char *);
+ unsigned int root_idx;
char sep;
- enum mailbox_info_flags inbox_flags;
-
- const struct mailbox_info *(*next)(struct fs_list_iterate_context *ctx);
-
pool_t info_pool;
struct mailbox_info info;
- struct list_dir_context *dir;
+ /* current directory we're handling */
+ struct list_dir_context *dir;
- unsigned int inbox_match:1;
unsigned int inbox_found:1;
- unsigned int inbox_listed:1;
};
-static const struct mailbox_info *
-fs_list_next(struct fs_list_iterate_context *ctx);
+static int
+fs_get_existence_info_flag(struct fs_list_iterate_context *ctx,
+ const char *vname,
+ enum mailbox_info_flags *info_flags)
+{
+ struct mailbox *box;
+ enum mailbox_existence existence;
+ bool auto_boxes;
+ int ret;
+
+ auto_boxes = (ctx->ctx.flags & MAILBOX_LIST_ITER_NO_AUTO_BOXES) == 0;
+ box = mailbox_alloc(ctx->ctx.list, vname, 0);
+ ret = mailbox_exists(box, auto_boxes, &existence);
+ mailbox_free(&box);
+
+ if (ret < 0) {
+ /* this can only be an internal error */
+ mailbox_list_set_internal_error(ctx->ctx.list);
+ return -1;
+ }
+ switch (existence) {
+ case MAILBOX_EXISTENCE_NONE:
+ *info_flags |= MAILBOX_NONEXISTENT;
+ break;
+ case MAILBOX_EXISTENCE_NOSELECT:
+ *info_flags |= MAILBOX_NOSELECT;
+ break;
+ case MAILBOX_EXISTENCE_SELECT:
+ *info_flags |= MAILBOX_SELECT;
+ break;
+ }
+ return 0;
+}
static int
-pattern_get_path_pos(struct fs_list_iterate_context *ctx, const char *pattern,
- const char *path, unsigned int *pos_r)
+dir_entry_get(struct fs_list_iterate_context *ctx, const char *dir_path,
+ struct list_dir_context *dir, const struct dirent *d)
{
- unsigned int i, j;
+ const char *storage_name, *vname, *root_dir;
+ struct list_dir_entry *entry;
+ enum imap_match_result match;
+ enum mailbox_info_flags info_flags;
+ int ret;
- if (strncasecmp(path, "INBOX", 5) == 0 && path[5] == ctx->sep) {
- /* make sure INBOX prefix is matched case-insensitively */
- char *tmp = t_strdup_noconst(pattern);
+ /* skip . and .. */
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ return 0;
- if (strncmp(path, "INBOX", 5) != 0)
- path = t_strdup_printf("INBOX%c%s", ctx->sep, path + 6);
-
- for (i = 0; tmp[i] != ctx->sep && tmp[i] != '\0'; i++)
- tmp[i] = i_toupper(tmp[i]);
- pattern = tmp;
+ if (strcmp(d->d_name, ctx->ctx.list->set.maildir_name) == 0) {
+ /* mail storage's internal directory (e.g. dbox-Mails).
+ this also means that the parent is selectable */
+ dir->info_flags &= ~MAILBOX_NOSELECT;
+ dir->info_flags |= MAILBOX_SELECT;
+ return 0;
+ }
+ if (strcmp(d->d_name, ctx->ctx.list->set.subscription_fname) == 0) {
+ /* if this is the subscriptions file, skip it */
+ root_dir = mailbox_list_get_path(ctx->ctx.list, NULL,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ if (strcmp(root_dir, dir_path) == 0)
+ return 0;
}
- for (i = j = 0; path[i] != '\0'; i++) {
- if (pattern[j] == '*')
+ /* check the pattern */
+ storage_name = *dir->storage_name == '\0' ? d->d_name :
+ t_strconcat(dir->storage_name, "/", d->d_name, NULL);
+ vname = mailbox_list_get_vname(ctx->ctx.list, storage_name);
+ match = imap_match(ctx->ctx.glob, vname);
+
+ if ((dir->info_flags & (MAILBOX_CHILDREN | MAILBOX_NOCHILDREN |
+ MAILBOX_NOINFERIORS)) == 0 &&
+ (ctx->ctx.flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) != 0) {
+ /* we don't know yet if the parent has children. need to figure
+ out if this file is actually a visible mailbox */
+ } else if (match != IMAP_MATCH_YES &&
+ (match & IMAP_MATCH_CHILDREN) == 0) {
+ /* mailbox doesn't match any patterns, we don't care about it */
+ return 0;
+ }
+ ret = ctx->ctx.list->v.
+ get_mailbox_flags(ctx->ctx.list, dir_path, d->d_name,
+ mailbox_list_get_file_type(d), &info_flags);
+ if (ret <= 0)
+ return ret;
+ if (!MAILBOX_INFO_FLAGS_FINISHED(info_flags)) {
+ /* mailbox existence isn't known yet. need to figure it out
+ the hard way. */
+ if (fs_get_existence_info_flag(ctx, vname, &info_flags) < 0)
return -1;
+ }
+ if ((info_flags & MAILBOX_NONEXISTENT) != 0)
+ return 0;
- if (pattern[j] == '%') {
- /* skip until we're at the next hierarchy separator */
- if (path[i] == ctx->sep) {
- /* assume that pattern matches. we can't be
- sure, but it'll be checked later. */
- for (j++; pattern[j] != '\0'; j++) {
- if (pattern[j] == '*')
- return -1;
- if (pattern[j] == ctx->sep) {
- j++;
- break;
- }
- }
- }
- } else {
- if (path[i] != pattern[j]) {
- /* pattern doesn't match path at all */
- return 0;
- }
- j++;
- }
+ /* mailbox exists - make sure parent knows it has children */
+ dir->info_flags &= ~(MAILBOX_NOCHILDREN | MAILBOX_NOINFERIORS);
+ dir->info_flags |= MAILBOX_CHILDREN;
+
+ if (match != IMAP_MATCH_YES && (match & IMAP_MATCH_CHILDREN) == 0) {
+ /* this mailbox didn't actually match any pattern,
+ we just needed to know the children state */
+ return 0;
}
- *pos_r = j;
- return 1;
+
+ /* entry matched a pattern. we're going to return this. */
+ entry = array_append_space(&dir->entries);
+ entry->fname = p_strdup(dir->pool, d->d_name);
+ entry->info_flags = info_flags;
+ return 0;
}
static bool
-pattern_has_wildcard_at(struct fs_list_iterate_context *ctx,
- const char *pattern, const char *path)
+fs_list_get_storage_path(struct fs_list_iterate_context *ctx,
+ const char *storage_name, const char **path_r)
{
- unsigned int pos;
- int ret;
+ const char *root, *path = storage_name;
- if ((ret = pattern_get_path_pos(ctx, pattern, path, &pos)) < 0)
- return TRUE;
- if (ret == 0)
- return FALSE;
-
- if (pattern[pos] == '\0')
- return TRUE;
-
- for (; pattern[pos] != '\0' && pattern[pos] != ctx->sep; pos++) {
- if (pattern[pos] == '%' || pattern[pos] == '*')
- return TRUE;
+ if (*path == '~') {
+ if (!mailbox_list_try_get_absolute_path(ctx->ctx.list, &path)) {
+ /* couldn't expand ~user/ */
+ return FALSE;
+ }
+ /* NOTE: the path may have been translated to a storage_name
+ instead of path */
}
- return FALSE;
+ if (*path != '/') {
+ /* non-absolute path. add the mailbox root dir as prefix. */
+ root = mailbox_list_get_path(ctx->ctx.list, NULL,
+ MAILBOX_LIST_PATH_TYPE_MAILBOX);
+ path = t_strconcat(root, "/", path, NULL);
+ }
+ *path_r = path;
+ return TRUE;
}
-static int list_opendir(struct fs_list_iterate_context *ctx,
- const char *path, const char *list_path, DIR **dirp)
+static int
+fs_list_dir_read(struct fs_list_iterate_context *ctx,
+ struct list_dir_context *dir)
{
- const char *const *patterns;
- unsigned int i;
+ DIR *fsdir;
+ struct dirent *d;
+ struct list_dir_entry *entry;
+ const char *path, *vname;
+ int ret = 0;
- /* if no patterns have wildcards at this point of the path, we don't
- have to readdir() the files. instead we can just go through the
- mailboxes listed in patterns. */
- T_BEGIN {
- patterns = array_idx(&ctx->valid_patterns, 0);
- for (i = 0; patterns[i] != NULL; i++) {
- if (pattern_has_wildcard_at(ctx, patterns[i],
- list_path))
- break;
+ if (!fs_list_get_storage_path(ctx, dir->storage_name, &path))
+ return 0;
+
+ fsdir = opendir(path);
+ if (fsdir == NULL) {
More information about the dovecot-cvs
mailing list