Mercurial > dovecot > core-2.2
changeset 12215:ecc0bc80288c
acl: Avoid opening two dict iterators at the same time.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 30 Sep 2010 20:28:54 +0100 |
parents | e3fbe13c0eab |
children | e12b7ee0a9dc |
files | src/plugins/acl/acl-lookup-dict.c |
diffstat | 1 files changed, 41 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/src/plugins/acl/acl-lookup-dict.c Thu Sep 30 19:18:13 2010 +0100 +++ b/src/plugins/acl/acl-lookup-dict.c Thu Sep 30 20:28:54 2010 +0100 @@ -24,12 +24,10 @@ pool_t pool; struct acl_lookup_dict *dict; + pool_t iter_value_pool; ARRAY_TYPE(const_string) iter_ids; - struct dict_iterate_context *dict_iter; - unsigned int iter_idx; - - const char *prefix; - unsigned int prefix_len; + ARRAY_TYPE(const_string) iter_values; + unsigned int iter_idx, iter_value_idx; unsigned int failed:1; }; @@ -245,18 +243,35 @@ return ret; } -static void acl_lookup_dict_iterate_start(struct acl_lookup_dict_iter *iter) +static void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter) { - const char *const *idp; + struct dict_iterate_context *dict_iter; + const char *const *idp, *prefix, *key, *value; + unsigned int prefix_len; idp = array_idx(&iter->iter_ids, iter->iter_idx); iter->iter_idx++; - iter->prefix = p_strconcat(iter->pool, DICT_PATH_SHARED - DICT_SHARED_BOXES_PATH, *idp, "/", NULL); - iter->prefix_len = strlen(iter->prefix); + iter->iter_value_idx = 0; + + prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH, + *idp, "/", NULL); + prefix_len = strlen(prefix); - iter->dict_iter = dict_iterate_init(iter->dict->dict, iter->prefix, - DICT_ITERATE_FLAG_RECURSE); + /* read all of it to memory. at least currently dict-proxy can support + only one iteration at a time, but the acl code can end up rebuilding + the dict, which opens another iteration. */ + p_clear(iter->iter_value_pool); + array_clear(&iter->iter_values); + dict_iter = dict_iterate_init(iter->dict->dict, prefix, + DICT_ITERATE_FLAG_RECURSE); + while (dict_iterate(dict_iter, &key, &value)) { + i_assert(prefix_len < strlen(key)); + + key = p_strdup(iter->iter_value_pool, key + prefix_len); + array_append(&iter->iter_values, &key, 1); + } + if (dict_iterate_deinit(&dict_iter) < 0) + iter->failed = TRUE; } struct acl_lookup_dict_iter * @@ -268,7 +283,7 @@ unsigned int i; pool_t pool; - pool = pool_alloconly_create("acl lookup dict iter", 512); + pool = pool_alloconly_create("acl lookup dict iter", 1024); iter = p_new(pool, struct acl_lookup_dict_iter, 1); iter->pool = pool; iter->dict = dict; @@ -279,6 +294,10 @@ id = p_strconcat(pool, "user/", dict->user->username, NULL); array_append(&iter->iter_ids, &id, 1); + i_array_init(&iter->iter_values, 64); + iter->iter_value_pool = + pool_alloconly_create("acl lookup dict iter values", 1024); + /* get all groups we belong to */ if (auser->groups != NULL) { for (i = 0; auser->groups[i] != NULL; i++) { @@ -291,28 +310,23 @@ /* iterate through all identifiers that match us, start with the first one */ if (dict->dict != NULL) - acl_lookup_dict_iterate_start(iter); + acl_lookup_dict_iterate_read(iter); return iter; } const char * acl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter) { - const char *key, *value; - - if (iter->dict_iter == NULL) - return 0; + const char *const *keys; + unsigned int count; - if (dict_iterate(iter->dict_iter, &key, &value)) { - i_assert(iter->prefix_len < strlen(key)); - return key + iter->prefix_len; - } - if (dict_iterate_deinit(&iter->dict_iter) < 0) - iter->failed = TRUE; + keys = array_get(&iter->iter_values, &count); + if (iter->iter_value_idx < count) + return keys[iter->iter_value_idx++]; if (iter->iter_idx < array_count(&iter->iter_ids)) { /* get to the next iterator */ - acl_lookup_dict_iterate_start(iter); + acl_lookup_dict_iterate_read(iter); return acl_lookup_dict_iterate_visible_next(iter); } return NULL; @@ -324,10 +338,8 @@ int ret = iter->failed ? -1 : 0; *_iter = NULL; - if (iter->dict_iter != NULL) { - if (dict_iterate_deinit(&iter->dict_iter) < 0) - ret = -1; - } + array_free(&iter->iter_values); + pool_unref(&iter->iter_value_pool); pool_unref(&iter->pool); return ret; }