Mercurial > dovecot > core-2.2
changeset 13219:7098642a0374
lib-storage: Added mailbox_alloc_guid() for opening mailbox by its GUID.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 11 Aug 2011 18:03:20 +0300 |
parents | bd0e7cdbb6b2 |
children | 19d8ec0db2e3 |
files | src/lib-storage/Makefile.am src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/mailbox-guid-cache.c src/lib-storage/mailbox-guid-cache.h src/lib-storage/mailbox-list-private.h src/lib-storage/mailbox-list.c |
diffstat | 8 files changed, 205 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/Makefile.am Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/Makefile.am Thu Aug 11 18:03:20 2011 +0300 @@ -36,6 +36,7 @@ mail-thread.c \ mail-user.c \ mailbox-get.c \ + mailbox-guid-cache.c \ mailbox-header.c \ mailbox-keywords.c \ mailbox-list.c \ @@ -62,6 +63,7 @@ mail-storage-service.h \ mail-storage-settings.h \ mail-user.h \ + mailbox-guid-cache.h \ mailbox-list.h \ mailbox-list-private.h \ mailbox-search-result-private.h \
--- a/src/lib-storage/mail-storage-private.h Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/mail-storage-private.h Thu Aug 11 18:03:20 2011 +0300 @@ -234,6 +234,10 @@ /* default vfuncs for new struct mails. */ const struct mail_vfuncs *mail_vfuncs; + /* If non-zero, fail mailbox_open() with this error. mailbox_alloc() + can set this to force open to fail. */ + enum mail_error open_error; + struct istream *input; const char *index_prefix; enum mailbox_flags flags;
--- a/src/lib-storage/mail-storage.c Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/mail-storage.c Thu Aug 11 18:03:20 2011 +0300 @@ -18,6 +18,7 @@ #include "mail-search.h" #include "mail-search-register.h" #include "mailbox-search-result-private.h" +#include "mailbox-guid-cache.h" #include <stdlib.h> #include <ctype.h> @@ -600,6 +601,52 @@ return box; } +struct mailbox *mailbox_alloc_guid(struct mailbox_list *list, + uint8_t guid[MAIL_GUID_128_SIZE], + enum mailbox_flags flags) +{ + struct mailbox *box = NULL; + struct mailbox_metadata metadata; + enum mail_error open_error = MAIL_ERROR_TEMP; + const char *vname; + + if (mailbox_guid_cache_find(list, guid, &vname) < 0) { + vname = NULL; + } else if (vname != NULL) { + box = mailbox_alloc(list, vname, flags); + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, + &metadata) < 0) { + } else if (memcmp(metadata.guid, guid, + sizeof(metadata.guid)) != 0) { + /* GUID mismatch, refresh cache and try again */ + mailbox_free(&box); + mailbox_guid_cache_refresh(list); + return mailbox_alloc_guid(list, guid, flags); + } else { + /* successfully opened the correct mailbox */ + return box; + } + i_error("mailbox_alloc_guid(%s): " + "Couldn't verify mailbox GUID: %s", + mail_guid_128_to_string(guid), + mailbox_get_last_error(box, NULL)); + vname = NULL; + mailbox_free(&box); + } else { + vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)", + mail_guid_128_to_string(guid)); + open_error = MAIL_ERROR_NOTFOUND; + } + + if (vname == NULL) { + vname = t_strdup_printf("(error in mailbox with GUID=%s)", + mail_guid_128_to_string(guid)); + } + box = mailbox_alloc(list, vname, flags); + box->open_error = open_error; + return box; +} + static bool have_listable_namespace_prefix(struct mail_namespace *ns, const char *name) { @@ -625,6 +672,16 @@ int mailbox_exists(struct mailbox *box, bool auto_boxes, enum mailbox_existence *existence_r) { + switch (box->open_error) { + case 0: + break; + case MAIL_ERROR_NOTFOUND: + *existence_r = MAILBOX_EXISTENCE_NONE; + return 0; + default: + /* unsure if this exists or not */ + return -1; + } if (!mailbox_list_is_valid_existing_name(box->list, box->name)) { /* report it as not selectable, since it exists but we won't let it be opened. */ @@ -691,6 +748,18 @@ if (box->opened) return 0; + switch (box->open_error) { + case 0: + break; + case MAIL_ERROR_NOTFOUND: + mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND, + T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname)); + return -1; + default: + mail_storage_set_internal_error(box->storage); + box->storage->error = box->open_error; + return -1; + } if (mailbox_check_mismatching_separators(box) < 0) return -1;
--- a/src/lib-storage/mail-storage.h Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/mail-storage.h Thu Aug 11 18:03:20 2011 +0300 @@ -365,6 +365,10 @@ with possibly different readonly-state. */ struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname, enum mailbox_flags flags); +/* Like mailbox_alloc(), but use mailbox GUID. */ +struct mailbox *mailbox_alloc_guid(struct mailbox_list *list, + uint8_t guid[MAIL_GUID_128_SIZE], + enum mailbox_flags flags); /* Get mailbox existence state. If auto_boxes=FALSE, return MAILBOX_EXISTENCE_NONE for autocreated mailboxes that haven't been physically created yet */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-guid-cache.c Thu Aug 11 18:03:20 2011 +0300 @@ -0,0 +1,107 @@ +/* Copyright (c) 2005-2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "mail-storage.h" +#include "mailbox-list-private.h" +#include "mailbox-guid-cache.h" + +struct mailbox_guid_cache_rec { + uint8_t guid[MAIL_GUID_128_SIZE]; + const char *vname; +}; + +static unsigned int guid_cache_rec_hash(const void *_rec) +{ + const struct mailbox_guid_cache_rec *rec = _rec; + unsigned int i, g, h = 0; + + for (i = 0; i < sizeof(rec->guid); i++) { + h = (h << 4) + rec->guid[i]; + if ((g = h & 0xf0000000UL)) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + return h; +} + +static int guid_cache_rec_cmp(const void *_r1, const void *_r2) +{ + const struct mailbox_guid_cache_rec *r1 = _r1, *r2 = _r2; + + return memcmp(r1->guid, r2->guid, sizeof(r1->guid)); +} + +int mailbox_guid_cache_find(struct mailbox_list *list, + uint8_t guid[MAIL_GUID_128_SIZE], + const char **vname_r) +{ + const struct mailbox_guid_cache_rec *rec; + struct mailbox_guid_cache_rec lookup_rec; + + memcpy(lookup_rec.guid, guid, sizeof(lookup_rec.guid)); + if (list->guid_cache == NULL) { + mailbox_guid_cache_refresh(list); + rec = hash_table_lookup(list->guid_cache, &lookup_rec); + } else { + rec = hash_table_lookup(list->guid_cache, &lookup_rec); + if (rec == NULL) { + mailbox_guid_cache_refresh(list); + rec = hash_table_lookup(list->guid_cache, &lookup_rec); + } + } + if (rec == NULL) { + *vname_r = NULL; + return list->guid_cache_errors ? -1 : 0; + } + *vname_r = rec->vname; + return 0; +} + +void mailbox_guid_cache_refresh(struct mailbox_list *list) +{ + struct mailbox_list_iterate_context *ctx; + const struct mailbox_info *info; + struct mailbox *box; + struct mailbox_metadata metadata; + struct mailbox_guid_cache_rec *rec; + + if (list->guid_cache == NULL) { + list->guid_cache_pool = + pool_alloconly_create("guid cache", 1024*16); + list->guid_cache = hash_table_create(default_pool, + list->guid_cache_pool, 0, + guid_cache_rec_hash, + guid_cache_rec_cmp); + } else { + hash_table_clear(list->guid_cache, TRUE); + p_clear(list->guid_cache_pool); + } + list->guid_cache_errors = FALSE; + + ctx = mailbox_list_iter_init(list, "*", + MAILBOX_LIST_ITER_NO_AUTO_BOXES); + while ((info = mailbox_list_iter_next(ctx)) != NULL) { + if ((info->flags & + (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0) + continue; + + box = mailbox_alloc(list, info->name, MAILBOX_FLAG_KEEP_RECENT); + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, + &metadata) < 0) { + i_error("Couldn't get mailbox %s GUID: %s", + info->name, mailbox_get_last_error(box, NULL)); + list->guid_cache_errors = TRUE; + } else { + rec = p_new(list->guid_cache_pool, + struct mailbox_guid_cache_rec, 1); + memcpy(rec->guid, metadata.guid, sizeof(rec->guid)); + rec->vname = p_strdup(list->guid_cache_pool, info->name); + hash_table_insert(list->guid_cache, rec, rec); + } + mailbox_free(&box); + } + if (mailbox_list_iter_deinit(&ctx) < 0) + list->guid_cache_errors = TRUE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-guid-cache.h Thu Aug 11 18:03:20 2011 +0300 @@ -0,0 +1,9 @@ +#ifndef MAILBOX_GUID_CACHE_H +#define MAILBOX_GUID_CACHE_H + +int mailbox_guid_cache_find(struct mailbox_list *list, + uint8_t guid[MAIL_GUID_128_SIZE], + const char **vname_r); +void mailbox_guid_cache_refresh(struct mailbox_list *list); + +#endif
--- a/src/lib-storage/mailbox-list-private.h Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/mailbox-list-private.h Thu Aug 11 18:03:20 2011 +0300 @@ -123,6 +123,10 @@ struct mailbox_log *changelog; time_t changelog_timestamp; + pool_t guid_cache_pool; + struct hash_table *guid_cache; + bool guid_cache_errors; + char *error_string; enum mail_error error; bool temporary_error;
--- a/src/lib-storage/mailbox-list.c Thu Aug 11 18:02:25 2011 +0300 +++ b/src/lib-storage/mailbox-list.c Thu Aug 11 18:03:20 2011 +0300 @@ -6,6 +6,7 @@ #include "mkdir-parents.h" #include "str.h" #include "sha1.h" +#include "hash.h" #include "home-expand.h" #include "close-keep-errno.h" #include "eacces-error.h" @@ -543,6 +544,11 @@ *_list = NULL; i_free_and_null(list->error_string); + if (list->guid_cache != NULL) { + hash_table_destroy(&list->guid_cache); + pool_unref(&list->guid_cache_pool); + } + if (list->subscriptions != NULL) mailbox_tree_deinit(&list->subscriptions); if (list->changelog != NULL)