bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen#include "lib.h"
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen#include "ioloop.h"
a8fe899601735459641edae975c0fa08be8482e2Timo Sirainen#include "mailbox-list-iter.h"
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen#include "quota-private.h"
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainenstruct count_quota_root {
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen struct quota_root root;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen struct timeval cache_timeval;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen uint64_t cached_bytes, cached_count;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen};
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainenstruct quota_mailbox_iter {
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct quota_root *root;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct mail_namespace *ns;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen unsigned int ns_idx;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct mailbox_list_iterate_context *iter;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct mailbox_info info;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *error;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen};
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainenextern struct quota_backend quota_backend_count;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenstatic int
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenquota_count_mailbox(struct quota_root *root, struct mail_namespace *ns,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *vname, uint64_t *bytes, uint64_t *count,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi enum quota_get_result *error_result_r,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char **error_r)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen{
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen struct quota_rule *rule;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen struct mailbox *box;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen struct mailbox_metadata metadata;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen struct mailbox_status status;
a254a0d7cf6bd3be2095e397e0230fe730d6a312Timo Sirainen enum mail_error error;
e7c8048ee5e707cf7c287f0e3ab60343fadfdf58Timo Sirainen const char *errstr;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen int ret;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
cc5e3d3391d7e54b643ab4949e8df465f37234bbTimo Sirainen rule = quota_root_rule_find(root->set, vname);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (rule != NULL && rule->ignore) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* mailbox not included in quota */
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen return 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY);
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen mailbox_set_reason(box, "quota count");
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0) {
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen /* quota doesn't exist for this mailbox/storage */
9d44feefe824e808fce433edd5a7a3b20c6f4b58Timo Sirainen ret = 0;
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen } else if (mailbox_get_metadata(box, root->quota->set->vsizes ?
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen MAILBOX_METADATA_VIRTUAL_SIZE :
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen MAILBOX_METADATA_PHYSICAL_SIZE,
9e99739b14df2035477ee58668b91a800dfee260Timo Sirainen &metadata) < 0 ||
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen mailbox_get_status(box, STATUS_MESSAGES, &status) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi errstr = mailbox_get_last_internal_error(box, &error);
e7c8048ee5e707cf7c287f0e3ab60343fadfdf58Timo Sirainen if (error == MAIL_ERROR_TEMP) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Couldn't get size of mailbox %s: %s",
e7c8048ee5e707cf7c287f0e3ab60343fadfdf58Timo Sirainen vname, errstr);
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi *error_result_r = QUOTA_GET_RESULT_INTERNAL_ERROR;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen ret = -1;
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen } else if (error == MAIL_ERROR_INUSE) {
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen /* started on background. don't log an error. */
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi "Ongoing quota calculation blocked getting size of %s: %s",
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi vname, errstr);
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi *error_result_r = QUOTA_GET_RESULT_BACKGROUND_CALC;
a758be690d736655ed7c1e3dfb46d3aaf4dd5db2Timo Sirainen ret = -1;
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen } else {
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen /* non-temporary error, e.g. ACLs denied access. */
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen ret = 0;
e7c8048ee5e707cf7c287f0e3ab60343fadfdf58Timo Sirainen }
c16bf6335c393c00465903f7a46ce2b7ceb6726eTimo Sirainen } else {
92c671c1667ea1bea90030a2b69298bf8c541623Timo Sirainen ret = 0;
d46f8fb3c628fd267c4a5705e6209497eb740f5dTimo Sirainen *bytes += root->quota->set->vsizes ?
93f1642397e46497894e6695749e5c52fda61774Timo Sirainen metadata.virtual_size : metadata.physical_size;
d46f8fb3c628fd267c4a5705e6209497eb740f5dTimo Sirainen *count += status.messages;
a254a0d7cf6bd3be2095e397e0230fe730d6a312Timo Sirainen }
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen mailbox_free(&box);
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen return ret;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen}
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainenstatic struct quota_mailbox_iter *
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainenquota_mailbox_iter_begin(struct quota_root *root)
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen{
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct quota_mailbox_iter *iter;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter = i_new(struct quota_mailbox_iter, 1);
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->root = root;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi iter->error = "";
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen return iter;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen}
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenstatic int
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärviquota_mailbox_iter_deinit(struct quota_mailbox_iter **_iter,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char **error_r)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen{
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct quota_mailbox_iter *iter = *_iter;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi int ret = *iter->error != '\0' ? -1 : 0;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen *_iter = NULL;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *error2 = "";
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen if (iter->iter != NULL) {
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen if (mailbox_list_iter_deinit(&iter->iter) < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi error2 = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Listing namespace '%s' failed: %s",
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->ns->prefix,
d4847b921058734e0668bc7690465c91523d9ec0Martti Rannanjärvi mailbox_list_get_last_internal_error(iter->ns->list, NULL));
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen ret = -1;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen }
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (ret < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *separator =
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *iter->error != '\0' && *error2 != '\0' ? " and " : "";
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf("%s%s%s",
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi iter->error, separator, error2);
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen i_free(iter);
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen return ret;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen}
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainenstatic const struct mailbox_info *
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainenquota_mailbox_iter_next(struct quota_mailbox_iter *iter)
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen{
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct mail_namespace *const *namespaces;
61e84692827b6a64912343f515c984853021483aTimo Sirainen const struct mailbox_info *info;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen unsigned int count;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen if (iter->iter == NULL) {
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen namespaces = array_get(&iter->root->quota->namespaces, &count);
c80cf58a347d1b6777e12b3bdd38cc52f6a45f73Timo Sirainen do {
c80cf58a347d1b6777e12b3bdd38cc52f6a45f73Timo Sirainen if (iter->ns_idx >= count)
c80cf58a347d1b6777e12b3bdd38cc52f6a45f73Timo Sirainen return NULL;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
c80cf58a347d1b6777e12b3bdd38cc52f6a45f73Timo Sirainen iter->ns = namespaces[iter->ns_idx++];
c80cf58a347d1b6777e12b3bdd38cc52f6a45f73Timo Sirainen } while (!quota_root_is_namespace_visible(iter->root, iter->ns));
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->iter = mailbox_list_iter_init(iter->ns->list, "*",
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen MAILBOX_LIST_ITER_SKIP_ALIASES |
bb1c6e2b0337990c8125e214534fcdf8165646e7Timo Sirainen MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
bb1c6e2b0337990c8125e214534fcdf8165646e7Timo Sirainen MAILBOX_LIST_ITER_NO_AUTO_BOXES);
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen while ((info = mailbox_list_iter_next(iter->iter)) != NULL) {
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen if ((info->flags & (MAILBOX_NONEXISTENT |
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen MAILBOX_NOSELECT)) == 0)
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen return info;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen if (mailbox_list_iter_deinit(&iter->iter) < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi iter->error = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Listing namespace '%s' failed: %s",
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->ns->prefix,
d4847b921058734e0668bc7690465c91523d9ec0Martti Rannanjärvi mailbox_list_get_last_internal_error(iter->ns->list, NULL));
e7c8048ee5e707cf7c287f0e3ab60343fadfdf58Timo Sirainen }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen if (iter->ns->prefix_len > 0 &&
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen (iter->ns->prefix_len != 6 ||
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen strncasecmp(iter->ns->prefix, "INBOX", 5) != 0)) {
87b71ffbf111ce67a8392c8d4ef0055f208cc88aTimo Sirainen /* if the namespace prefix itself exists, count it also */
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->info.ns = iter->ns;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->info.vname = t_strndup(iter->ns->prefix,
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter->ns->prefix_len-1);
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen return &iter->info;
87b71ffbf111ce67a8392c8d4ef0055f208cc88aTimo Sirainen }
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen /* try the next namespace */
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen return quota_mailbox_iter_next(iter);
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen}
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärviint quota_count(struct quota_root *root, uint64_t *bytes_r, uint64_t *count_r,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi enum quota_get_result *error_result_r, const char **error_r)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen{
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen struct quota_mailbox_iter *iter;
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen const struct mailbox_info *info;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *error1 = "", *error2 = "";
92c671c1667ea1bea90030a2b69298bf8c541623Timo Sirainen int ret = 1;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen *bytes_r = *count_r = 0;
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen if (root->recounting)
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen return 0;
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen root->recounting = TRUE;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
88b06199c3b87b14c41a636219a19156a5df2485Timo Sirainen iter = quota_mailbox_iter_begin(root);
617092b0f17b37625e354d45108ad62baa65a858Timo Sirainen while ((info = quota_mailbox_iter_next(iter)) != NULL) {
92c671c1667ea1bea90030a2b69298bf8c541623Timo Sirainen if (quota_count_mailbox(root, info->ns, info->vname,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi bytes_r, count_r, error_result_r,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi &error1) < 0) {
617092b0f17b37625e354d45108ad62baa65a858Timo Sirainen ret = -1;
617092b0f17b37625e354d45108ad62baa65a858Timo Sirainen break;
617092b0f17b37625e354d45108ad62baa65a858Timo Sirainen }
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen }
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi if (quota_mailbox_iter_deinit(&iter, &error2) < 0) {
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi *error_result_r = QUOTA_GET_RESULT_INTERNAL_ERROR;
f165d31e1f062ab71dfc82a3f9d7fad5e497dfe3Timo Sirainen ret = -1;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi }
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (ret < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *separator =
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error1 != '\0' && *error2 != '\0' ? " and " : "";
de338ef27767268c2018f54f0b5ddeff7fca3870Martti Rannanjärvi *error_r = t_strconcat(error1, separator, error2, NULL);
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi }
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen root->recounting = FALSE;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen return ret;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen}
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvistatic enum quota_get_result
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärviquota_count_cached(struct count_quota_root *root,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi uint64_t *bytes_r, uint64_t *count_r,
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi const char **error_r)
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen{
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen int ret;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen if (root->cache_timeval.tv_usec == ioloop_timeval.tv_usec &&
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen root->cache_timeval.tv_sec == ioloop_timeval.tv_sec &&
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen ioloop_timeval.tv_sec != 0) {
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen *bytes_r = root->cached_bytes;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen *count_r = root->cached_count;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen }
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi enum quota_get_result error_res;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi ret = quota_count(&root->root, bytes_r, count_r, &error_res, error_r);
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi if (ret < 0) {
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return error_res;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi } else if (ret > 0) {
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen root->cache_timeval = ioloop_timeval;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen root->cached_bytes = *bytes_r;
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen root->cached_count = *count_r;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen }
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstatic struct quota_root *count_quota_alloc(void)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen struct count_quota_root *root;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen root = i_new(struct count_quota_root, 1);
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen return &root->root;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstatic int count_quota_init(struct quota_root *root, const char *args,
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen const char **error_r)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen if (!root->quota->set->vsizes) {
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen *error_r = "quota count backend requires quota_vsizes=yes";
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen return -1;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen }
e2e64c109827f782e9e20b50a15c7489479bcadaTimo Sirainen root->auto_updating = TRUE;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen return quota_root_default_init(root, args, error_r);
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstatic void count_quota_deinit(struct quota_root *_root)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen i_free(_root);
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstatic const char *const *
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainencount_quota_root_get_resources(struct quota_root *root ATTR_UNUSED)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen static const char *resources[] = {
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES, QUOTA_NAME_MESSAGES, NULL
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen };
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen return resources;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvistatic enum quota_get_result
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainencount_quota_get_resource(struct quota_root *_root,
a525be16a69367f43765d20c873b5f168c5b7ea3Martti Rannanjärvi const char *name, uint64_t *value_r,
a525be16a69367f43765d20c873b5f168c5b7ea3Martti Rannanjärvi const char **error_r)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
ad3bf867168121a1255720487457d8bffc3f5e48Timo Sirainen struct count_quota_root *root = (struct count_quota_root *)_root;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen uint64_t bytes, count;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi enum quota_get_result ret;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi ret = quota_count_cached(root, &bytes, &count, error_r);
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi if (ret <= QUOTA_GET_RESULT_INTERNAL_ERROR)
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return ret;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen *value_r = bytes;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen *value_r = count;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi else {
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = QUOTA_UNKNOWN_RESOURCE_ERROR_STRING;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_UNKNOWN_RESOURCE;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi }
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvistatic int quota_count_recalculate_box(struct mailbox *box,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char **error_r)
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen{
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen struct mail_index_transaction *trans;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen struct mailbox_metadata metadata;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen struct mailbox_index_vsize vsize_hdr;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen const char *errstr;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen enum mail_error error;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen if (mailbox_open(box) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi errstr = mailbox_get_last_internal_error(box, &error);
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen if (error != MAIL_ERROR_TEMP) {
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen /* non-temporary error, e.g. ACLs denied access. */
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return 0;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen }
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Couldn't open mailbox %s: %s", box->vname, errstr);
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return -1;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen }
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen /* reset the vsize header first */
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen trans = mail_index_transaction_begin(box->view,
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&vsize_hdr);
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen mail_index_update_header_ext(trans, box->vsize_hdr_ext_id,
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen 0, &vsize_hdr, sizeof(vsize_hdr));
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (mail_index_transaction_commit(&trans) < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Couldn't commit mail index transaction for %s: %s",
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi box->vname,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi mail_index_get_error_message(box->view->index));
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return -1;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi }
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen /* getting the vsize now forces its recalculation */
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_VIRTUAL_SIZE,
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen &metadata) < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Couldn't get mailbox %s vsize: %s", box->vname,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return -1;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen }
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen /* call sync to write the change to mailbox list index */
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FAST) < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "Couldn't sync mailbox %s: %s", box->vname,
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, NULL));
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return -1;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen }
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return 0;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen}
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvistatic int quota_count_recalculate(struct quota_root *root,
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char **error_r)
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen{
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen struct quota_mailbox_iter *iter;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen const struct mailbox_info *info;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen struct mailbox *box;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen int ret = 0;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *error1 = "", *error2 = "";
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen iter = quota_mailbox_iter_begin(root);
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen while ((info = quota_mailbox_iter_next(iter)) != NULL) {
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen box = mailbox_alloc(info->ns->list, info->vname, 0);
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen mailbox_set_reason(box, "quota recalculate");
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (quota_count_recalculate_box(box, &error1) < 0)
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen ret = -1;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen mailbox_free(&box);
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen }
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (quota_mailbox_iter_deinit(&iter, &error2) < 0)
f165d31e1f062ab71dfc82a3f9d7fad5e497dfe3Timo Sirainen ret = -1;
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (ret < 0) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi const char *separator =
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error1 != '\0' && *error2 != '\0' ? " and " : "";
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi *error_r = t_strdup_printf(
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi "quota-count: recalculate failed: %s%s%s",
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi error1, separator, error2);
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi }
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return ret;
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen}
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstatic int
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainencount_quota_update(struct quota_root *root,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi struct quota_transaction_context *ctx,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi const char **error_r)
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen{
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen struct count_quota_root *croot = (struct count_quota_root *)root;
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen
464db6d9d6d9126ac87143fc7a466120ff5b70f4Timo Sirainen croot->cache_timeval.tv_sec = 0;
39dea5f2e78f6bfc3adc0655176f596ee211938fTimo Sirainen if (ctx->recalculate == QUOTA_RECALCULATE_FORCED) {
d2cbbecf76de3f4eb945895fab5760ed0a28281cMartti Rannanjärvi if (quota_count_recalculate(root, error_r) < 0)
ddd7c3b36893263c7de0df139a266daf75bcca60Timo Sirainen return -1;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen }
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen return 0;
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen}
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainenstruct quota_backend quota_backend_count = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .name = "count",
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .v = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .alloc = count_quota_alloc,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .init = count_quota_init,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .deinit = count_quota_deinit,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resources = count_quota_root_get_resources,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resource = count_quota_get_resource,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .update = count_quota_update,
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen }
c4db1218645ed8ec8b5ae67c05bc5d7a80c1b8aeTimo Sirainen};