From: Timo Sirainen Date: Wed, 4 Oct 2017 07:46:47 +0000 (+0300) Subject: quota: quota_get_resource() - return enum to make the result more exact X-Git-Tag: 2.3.0.rc1~938 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e07e3182f355cf04a1461dd7f893d0ebc818764;p=thirdparty%2Fdovecot%2Fcore.git quota: quota_get_resource() - return enum to make the result more exact This is mainly to differentiate between "resource name unknown" and "unlimited quota". This also fixes quota_clone plugin to update quota even when quota is unlimited. It was supposed to have been skipped only when the resource names weren't known. The private quota.get_resource() API is unchanged. The backends were already returning 0 only when the resource name was unknown. --- diff --git a/src/plugins/imap-quota/imap-quota-plugin.c b/src/plugins/imap-quota/imap-quota-plugin.c index 5bac7a2382..8ac283c268 100644 --- a/src/plugins/imap-quota/imap-quota-plugin.c +++ b/src/plugins/imap-quota/imap-quota-plugin.c @@ -39,7 +39,7 @@ quota_reply_write(string_t *str, struct mail_user *user, unsigned int i; uint64_t value, limit; size_t prefix_len, orig_len = str_len(str); - int ret = 0; + enum quota_get_result ret = QUOTA_GET_RESULT_UNLIMITED; str_append(str, "* QUOTA "); name = imap_quota_root_get_name(user, owner, root); @@ -50,9 +50,9 @@ quota_reply_write(string_t *str, struct mail_user *user, list = quota_root_get_resources(root); for (i = 0; *list != NULL; list++) { ret = quota_get_resource(root, "", *list, &value, &limit); - if (ret < 0) + if (ret == QUOTA_GET_RESULT_INTERNAL_ERROR) break; - if (ret > 0) { + if (ret == QUOTA_GET_RESULT_LIMITED) { if (i > 0) str_append_c(str, ' '); str_printfa(str, "%s %llu %llu", *list, @@ -67,7 +67,7 @@ quota_reply_write(string_t *str, struct mail_user *user, } else { str_append(str, ")\r\n"); } - return ret < 0 ? -1 : 0; + return ret == QUOTA_GET_RESULT_INTERNAL_ERROR ? -1 : 0; } static bool cmd_getquotaroot(struct client_command_context *cmd) diff --git a/src/plugins/quota-clone/quota-clone-plugin.c b/src/plugins/quota-clone/quota-clone-plugin.c index eefb2f8cc9..4ec1cb750c 100644 --- a/src/plugins/quota-clone/quota-clone-plugin.c +++ b/src/plugins/quota-clone/quota-clone-plugin.c @@ -48,7 +48,7 @@ static void quota_clone_flush_real(struct mailbox *box) struct quota_root *root; uint64_t bytes_value, count_value, limit; const char *error; - int ret_bytes, ret_count; + enum quota_get_result ret_bytes, ret_count; /* we'll clone the first quota root */ iter = quota_root_iter_init(box); @@ -63,18 +63,19 @@ static void quota_clone_flush_real(struct mailbox *box) /* get new values first */ ret_bytes = quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES, &bytes_value, &limit); - if (ret_bytes < 0) { + if (ret_bytes == QUOTA_GET_RESULT_INTERNAL_ERROR) { i_error("quota_clone_plugin: Failed to lookup current quota bytes"); return; } ret_count = quota_get_resource(root, "", QUOTA_NAME_MESSAGES, &count_value, &limit); - if (ret_count < 0) { + if (ret_count == QUOTA_GET_RESULT_INTERNAL_ERROR) { i_error("quota_clone_plugin: Failed to lookup current quota count"); return; } - if (ret_bytes == 0 && ret_count == 0) { - /* quota isn't enabled - no point in updating it */ + if (ret_bytes == QUOTA_GET_RESULT_UNKNOWN_RESOURCE && + ret_count == QUOTA_GET_RESULT_UNKNOWN_RESOURCE) { + /* quota resources don't exist - no point in updating it */ return; } @@ -83,11 +84,13 @@ static void quota_clone_flush_real(struct mailbox *box) the special case of ret_count changing between 1 and 0. Note that ret_count==1 also when quota is unlimited. */ trans = dict_transaction_begin(quser->dict); - if (ret_bytes > 0) { + if (ret_bytes == QUOTA_GET_RESULT_LIMITED || + ret_bytes == QUOTA_GET_RESULT_UNLIMITED) { dict_set(trans, DICT_QUOTA_CLONE_BYTES_PATH, t_strdup_printf("%llu", (unsigned long long)bytes_value)); } - if (ret_count > 0) { + if (ret_count == QUOTA_GET_RESULT_LIMITED || + ret_count == QUOTA_GET_RESULT_UNLIMITED) { dict_set(trans, DICT_QUOTA_CLONE_COUNT_PATH, t_strdup_printf("%llu", (unsigned long long)count_value)); } diff --git a/src/plugins/quota/doveadm-quota.c b/src/plugins/quota/doveadm-quota.c index d9922f9d9e..ac3727d795 100644 --- a/src/plugins/quota/doveadm-quota.c +++ b/src/plugins/quota/doveadm-quota.c @@ -16,21 +16,21 @@ static void cmd_quota_get_root(struct quota_root *root) { const char *const *res; uint64_t value, limit; - int ret; + enum quota_get_result ret; res = quota_root_get_resources(root); for (; *res != NULL; res++) { ret = quota_get_resource(root, "", *res, &value, &limit); doveadm_print(root->set->name); doveadm_print(*res); - if (ret > 0) { + if (ret == QUOTA_GET_RESULT_LIMITED) { doveadm_print_num(value); doveadm_print_num(limit); if (limit > 0) doveadm_print_num(value*100 / limit); else doveadm_print("0"); - } else if (ret == 0) { + } else if (ret == QUOTA_GET_RESULT_UNLIMITED) { doveadm_print_num(value); doveadm_print("-"); doveadm_print("0"); diff --git a/src/plugins/quota/quota-private.h b/src/plugins/quota/quota-private.h index b99764f8a4..6427b61886 100644 --- a/src/plugins/quota/quota-private.h +++ b/src/plugins/quota/quota-private.h @@ -65,6 +65,8 @@ struct quota_backend_vfuncs { struct mail_namespace *ns); const char *const *(*get_resources)(struct quota_root *root); + /* Returns 1 if value was returned, 0 if resource name doesn't exist, + -1 if internal error. */ int (*get_resource)(struct quota_root *root, const char *name, uint64_t *value_r); diff --git a/src/plugins/quota/quota.c b/src/plugins/quota/quota.c index 4ef9765e68..c5343772d3 100644 --- a/src/plugins/quota/quota.c +++ b/src/plugins/quota/quota.c @@ -747,8 +747,9 @@ bool quota_root_is_hidden(struct quota_root *root) return root->hidden; } -int quota_get_resource(struct quota_root *root, const char *mailbox_name, - const char *name, uint64_t *value_r, uint64_t *limit_r) +enum quota_get_result +quota_get_resource(struct quota_root *root, const char *mailbox_name, + const char *name, uint64_t *value_r, uint64_t *limit_r) { uint64_t bytes_limit, count_limit; bool ignored, kilobytes = FALSE; @@ -764,13 +765,15 @@ int quota_get_resource(struct quota_root *root, const char *mailbox_name, /* Get the value first. This call may also update quota limits if they're defined externally. */ ret = root->backend.v.get_resource(root, name, value_r); - if (ret <= 0) - return ret; + if (ret < 0) + return QUOTA_GET_RESULT_INTERNAL_ERROR; + if (ret == 0) + return QUOTA_GET_RESULT_UNKNOWN_RESOURCE; if (quota_root_get_rule_limits(root, mailbox_name, &bytes_limit, &count_limit, &ignored) < 0) - return -1; + return QUOTA_GET_RESULT_INTERNAL_ERROR; if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0) *limit_r = bytes_limit; @@ -783,7 +786,7 @@ int quota_get_resource(struct quota_root *root, const char *mailbox_name, *value_r = (*value_r + 1023) / 1024; *limit_r = (*limit_r + 1023) / 1024; } - return *limit_r == 0 ? 0 : 1; + return *limit_r == 0 ? QUOTA_GET_RESULT_UNLIMITED : QUOTA_GET_RESULT_LIMITED; } int quota_set_resource(struct quota_root *root, const char *name, @@ -890,7 +893,7 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx) unsigned int i, count; uint64_t bytes_limit, count_limit, current, limit, diff; bool use_grace, ignored; - int ret; + enum quota_get_result ret; if (ctx->limits_set) return 0; @@ -919,7 +922,7 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx) ret = quota_get_resource(roots[i], mailbox_name, QUOTA_NAME_STORAGE_BYTES, ¤t, &limit); - if (ret > 0) { + if (ret == QUOTA_GET_RESULT_LIMITED) { if (limit <= current) { /* over quota */ ctx->bytes_ceil = 0; @@ -936,7 +939,7 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx) if (ctx->bytes_ceil > diff) ctx->bytes_ceil = diff; } - } else if (ret < 0) { + } else if (ret == QUOTA_GET_RESULT_INTERNAL_ERROR) { ctx->failed = TRUE; return -1; } @@ -946,7 +949,7 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx) ret = quota_get_resource(roots[i], mailbox_name, QUOTA_NAME_MESSAGES, ¤t, &limit); - if (ret > 0) { + if (ret == QUOTA_GET_RESULT_LIMITED) { if (limit <= current) { /* over quota */ ctx->count_ceil = 0; @@ -958,7 +961,7 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx) if (ctx->count_ceil > diff) ctx->count_ceil = diff; } - } else if (ret < 0) { + } else if (ret == QUOTA_GET_RESULT_INTERNAL_ERROR) { ctx->failed = TRUE; return -1; } @@ -1036,10 +1039,10 @@ static void quota_warnings_execute(struct quota_transaction_context *ctx, return; if (quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES, - &bytes_current, &bytes_limit) < 0) + &bytes_current, &bytes_limit) == QUOTA_GET_RESULT_INTERNAL_ERROR) return; if (quota_get_resource(root, "", QUOTA_NAME_MESSAGES, - &count_current, &count_limit) < 0) + &count_current, &count_limit) == QUOTA_GET_RESULT_INTERNAL_ERROR) return; if (ctx->bytes_used > 0 && bytes_current < (uint64_t)ctx->bytes_used) @@ -1164,7 +1167,7 @@ static void quota_over_flag_check_root(struct quota_root *root) uint64_t value, limit; bool cur_overquota = FALSE; bool quota_over_status; - int ret; + enum quota_get_result ret; if (root->quota_over_flag_checked) return; @@ -1195,7 +1198,7 @@ static void quota_over_flag_check_root(struct quota_root *root) resources = quota_root_get_resources(root); for (i = 0; resources[i] != NULL; i++) { ret = quota_get_resource(root, "", resources[i], &value, &limit); - if (ret < 0) { + if (ret == QUOTA_GET_RESULT_INTERNAL_ERROR) { /* can't reliably verify this */ if (root->quota->set->debug) { i_debug("quota: Quota %s lookup failed - can't verify quota_over_flag", @@ -1209,7 +1212,7 @@ static void quota_over_flag_check_root(struct quota_root *root) (unsigned long long)value, (unsigned long long)limit); } - if (ret > 0 && value >= limit) + if (ret == QUOTA_GET_RESULT_LIMITED && value >= limit) cur_overquota = TRUE; } if (root->quota->set->debug) { diff --git a/src/plugins/quota/quota.h b/src/plugins/quota/quota.h index 44b82c704c..206f8b7a36 100644 --- a/src/plugins/quota/quota.h +++ b/src/plugins/quota/quota.h @@ -49,6 +49,17 @@ enum quota_alloc_result { QUOTA_ALLOC_RESULT_OVER_QUOTA_LIMIT, }; +enum quota_get_result { + /* Quota limit exists and was returned successfully */ + QUOTA_GET_RESULT_LIMITED, + /* Quota is unlimited, but its value was returned */ + QUOTA_GET_RESULT_UNLIMITED, + /* Quota resource name doesn't exist */ + QUOTA_GET_RESULT_UNKNOWN_RESOURCE, + /* Internal error */ + QUOTA_GET_RESULT_INTERNAL_ERROR = -1, +}; + const char *quota_alloc_result_errstr(enum quota_alloc_result res, struct quota_transaction_context *qt); @@ -89,8 +100,9 @@ bool quota_root_is_hidden(struct quota_root *root); /* Returns 1 if values were successfully returned, 0 if resource name doesn't exist or isn't enabled, -1 if error. */ -int quota_get_resource(struct quota_root *root, const char *mailbox_name, - const char *name, uint64_t *value_r, uint64_t *limit_r); +enum quota_get_result +quota_get_resource(struct quota_root *root, const char *mailbox_name, + const char *name, uint64_t *value_r, uint64_t *limit_r); /* Returns 0 if OK, -1 if error (eg. permission denied, invalid name). */ int quota_set_resource(struct quota_root *root, const char *name, uint64_t value, const char **error_r);