]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: quota_get_resource() - return enum to make the result more exact
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 4 Oct 2017 07:46:47 +0000 (10:46 +0300)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Wed, 4 Oct 2017 09:40:01 +0000 (12:40 +0300)
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.

src/plugins/imap-quota/imap-quota-plugin.c
src/plugins/quota-clone/quota-clone-plugin.c
src/plugins/quota/doveadm-quota.c
src/plugins/quota/quota-private.h
src/plugins/quota/quota.c
src/plugins/quota/quota.h

index 5bac7a2382c38bde804c644db84c4b4b381e54af..8ac283c268360912381c6dba364755f512cee40c 100644 (file)
@@ -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)
index eefb2f8cc9679807d01388d547edcacb14c41c8a..4ec1cb750c37d1527436ae79de93a73e204bc8b5 100644 (file)
@@ -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));
        }
index d9922f9d9e5a7363b25a54caba56cf5e9ad3be43..ac3727d7953d48d9a115546653e80bf43f62f05c 100644 (file)
@@ -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");
index b99764f8a49ed72c14f2307e638b9cabb3e5c052..6427b618869675142054390bf34a732555274362 100644 (file)
@@ -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);
 
index 4ef9765e6898f5514b3965ee259549b26afd242e..c5343772d3f7e71a91f216ea20bacccbbb68bb7b 100644 (file)
@@ -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,
                                                 &current, &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,
                                                 &current, &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) {
index 44b82c704cb00af5be6f05ef4ca10cbd47ac0938..206f8b7a36c4c00a81a50614933568fe5e3d0477 100644 (file)
@@ -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);