quota.c revision de5c7c99783cd86f3bdbc057345cbee923b51a20
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2005 Timo Sirainen */
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#include "lib.h"
6f9a5ecb55d8c024a0953647b77711b5622e9bbbTimo Sirainen#include "array.h"
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#include "hash.h"
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen#include "quota-private.h"
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#include "quota-fs.h"
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen#include <stdlib.h>
f5be4f5b4a1bba7f3497f52d01e582b82af2b355Timo Sirainen
951c92a29c36d22a60e56cae4b47d5d0fa5dd6b5Timo Sirainen#define RULE_NAME_ALL_MAILBOXES "*"
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainenstruct quota_root_iter {
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainen struct quota *quota;
6e1cac3defe84a222b804f3ef41ff558e1a86391Timo Sirainen struct mailbox *box;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen unsigned int i;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen};
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenunsigned int quota_module_id = 0;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenextern struct quota_backend quota_backend_dict;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenextern struct quota_backend quota_backend_dirsize;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenextern struct quota_backend quota_backend_fs;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenextern struct quota_backend quota_backend_maildir;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic const struct quota_backend *quota_backends[] = {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#ifdef HAVE_FS_QUOTA
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen &quota_backend_fs,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#endif
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen &quota_backend_dict,
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen &quota_backend_dirsize,
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen &quota_backend_maildir
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen};
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen#define QUOTA_CLASS_COUNT (sizeof(quota_backends)/sizeof(quota_backends[0]))
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen uoff_t size, bool *too_large_r);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstruct quota *quota_init(void)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct quota *quota;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen quota = i_new(struct quota, 1);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen quota->test_alloc = quota_default_test_alloc;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen quota->debug = getenv("DEBUG") != NULL;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen i_array_init(&quota->roots, 4);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen i_array_init(&quota->storages, 8);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen return quota;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenvoid quota_deinit(struct quota *quota)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen struct quota_root **root;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
d6c06730a0a1ba6ac784d95eadc42c8c9a62661cTimo Sirainen while (array_count(&quota->roots) > 0) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen root = array_idx_modifiable(&quota->roots, 0);
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen quota_root_deinit(*root);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen array_free(&quota->roots);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen array_free(&quota->storages);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen i_free(quota);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen unsigned int i;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen for (i = 0; i < QUOTA_CLASS_COUNT; i++) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (strcmp(quota_backends[i]->name, name) == 0)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return quota_backends[i];
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return NULL;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenstruct quota_root *quota_root_init(struct quota *quota, const char *root_def)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
df48643c3c240ad5b8a3e2e2132c46f7dc541b5eTimo Sirainen struct quota_root *root;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen const struct quota_backend *backend;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen const char *p, *args, *backend_name;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
f5be4f5b4a1bba7f3497f52d01e582b82af2b355Timo Sirainen t_push();
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen /* <backend>[:<quota root name>[:<backend args>]] */
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen p = strchr(root_def, ':');
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainen if (p == NULL) {
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainen backend_name = root_def;
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainen args = NULL;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen } else {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen backend_name = t_strdup_until(root_def, p);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen args = p + 1;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen }
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen backend = quota_backend_find(backend_name);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (backend == NULL)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen i_fatal("Unknown quota backend: %s", backend_name);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen t_pop();
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen root = backend->v.alloc();
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen root->quota = quota;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen root->backend = *backend;
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen root->pool = pool_alloconly_create("quota root", 512);
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (args != NULL) {
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen /* save root's name */
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen p = strchr(args, ':');
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen if (p == NULL) {
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen root->name = p_strdup(root->pool, args);
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen args = NULL;
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen } else {
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen root->name = p_strdup_until(root->pool, args, p);
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen args = p + 1;
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen }
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen } else {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen root->name = "";
951c92a29c36d22a60e56cae4b47d5d0fa5dd6b5Timo Sirainen }
951c92a29c36d22a60e56cae4b47d5d0fa5dd6b5Timo Sirainen
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen i_array_init(&root->rules, 4);
951c92a29c36d22a60e56cae4b47d5d0fa5dd6b5Timo Sirainen array_create(&root->quota_module_contexts, default_pool,
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen sizeof(void *), 5);
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen array_append(&quota->roots, &root, 1);
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen if (backend->v.init != NULL) {
fda7b3649d2ccdb4a95f5bf09eb8cf5435d57261Timo Sirainen if (backend->v.init(root, args) < 0) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen quota_root_deinit(root);
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen return NULL;
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen }
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen }
29371e68adc180501454783b44ec8e43b4e6ddc1Timo Sirainen return root;
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainen}
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenvoid quota_root_deinit(struct quota_root *root)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen pool_t pool = root->pool;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct quota_root *const *roots;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen unsigned int i, count;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen roots = array_get(&root->quota->roots, &count);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen for (i = 0; i < count; i++) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (roots[i] == root)
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen array_delete(&root->quota->roots, i, 1);
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen array_free(&root->rules);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen array_free(&root->quota_module_contexts);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen root->backend.v.deinit(root);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen pool_unref(pool);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
b50e80d237435686c4ea525643f266731a600981Timo Sirainenstatic struct quota_rule *
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenquota_root_rule_find(struct quota_root *root, const char *name)
b50e80d237435686c4ea525643f266731a600981Timo Sirainen{
b50e80d237435686c4ea525643f266731a600981Timo Sirainen struct quota_rule *rules;
8c98b8adba0e70743d5d8c35ae922038881b1f47Timo Sirainen unsigned int i, count;
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen rules = array_get_modifiable(&root->rules, &count);
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen for (i = 0; i < count; i++) {
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen if (strcmp(rules[i].mailbox_name, name) == 0)
ad9403d54b5a0f312de6fa22abda6c120988d3deTimo Sirainen return &rules[i];
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
b50e80d237435686c4ea525643f266731a600981Timo Sirainen return NULL;
b50e80d237435686c4ea525643f266731a600981Timo Sirainen}
b50e80d237435686c4ea525643f266731a600981Timo Sirainen
b50e80d237435686c4ea525643f266731a600981Timo Sirainenint quota_root_add_rule(struct quota_root *root, const char *rule_def,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen const char **error_r)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct quota_rule *rule;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen const char **args;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen int ret = 0;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (*rule_def == '\0') {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen *error_r = "Empty rule";
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen return -1;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen /* <mailbox name>:<quota limits> */
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen t_push();
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen args = t_strsplit(rule_def, ":");
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainen rule = quota_root_rule_find(root, *args);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (rule == NULL) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (strcmp(*args, RULE_NAME_ALL_MAILBOXES) == 0)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen rule = &root->default_rule;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen else {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen rule = array_append_space(&root->rules);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen rule->mailbox_name = p_strdup(root->pool, *args);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen for (args++; *args != NULL; args++) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen if (strncmp(*args, "storage=", 8) == 0)
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen rule->bytes_limit = strtoll(*args + 8, NULL, 10) * 1024;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen else if (strncmp(*args, "messages=", 9) == 0)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen rule->count_limit = strtoll(*args + 9, NULL, 10);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen else {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen *error_r = p_strdup_printf(root->pool,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen "Invalid rule limit: %s", *args);
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen ret = -1;
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen break;
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen }
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen }
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen if (root->quota->debug) {
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen i_info("Quota rule: root=%s mailbox=%s "
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen "storage=%lldkB messages=%lld", root->name,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen rule->mailbox_name != NULL ? rule->mailbox_name : "",
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen (long long)rule->bytes_limit / 1024,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen (long long)rule->count_limit);
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen }
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen t_pop();
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen return ret;
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen}
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainenstatic bool quota_root_get_rule_limits(struct quota_root *root,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen const char *mailbox_name,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen uint64_t *bytes_limit_r,
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen uint64_t *count_limit_r)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen{
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct quota_rule *rule;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen int64_t bytes_limit, count_limit;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen bool found;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen bytes_limit = root->default_rule.bytes_limit;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen count_limit = root->default_rule.count_limit;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
8a26102b8b1e08a774398980a8f92ae8f8575da8Timo Sirainen /* if default rule limits are 0, this rule applies only to specific
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen mailboxes */
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen found = bytes_limit != 0 || count_limit != 0;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen rule = quota_root_rule_find(root, mailbox_name);
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen if (rule != NULL) {
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen bytes_limit += rule->bytes_limit;
719bda7961b0ceced935b56a4f4494f2f6191b15Timo Sirainen count_limit += rule->count_limit;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen found = TRUE;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen }
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
0bf0c44fce1df29e60f4f5b312ebe862d44aa237Timo Sirainen *bytes_limit_r = bytes_limit <= 0 ? 0 : bytes_limit;
0bf0c44fce1df29e60f4f5b312ebe862d44aa237Timo Sirainen *count_limit_r = count_limit <= 0 ? 0 : count_limit;
0bf0c44fce1df29e60f4f5b312ebe862d44aa237Timo Sirainen return found;
0bf0c44fce1df29e60f4f5b312ebe862d44aa237Timo Sirainen}
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainenvoid quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen{
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen struct quota_root *const *roots;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct mail_storage *const *storages;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct quota_backend **backends;
c6033074ada5c7441ff7bb12c4b433cae737fea2Timo Sirainen const char *path, *path2;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen unsigned int i, j, count;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen bool is_file;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen /* first check if there already exists a storage with the exact same
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen path. we don't want to count them twice. */
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen path = mail_storage_get_mailbox_path(storage, "", &is_file);
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen if (path != NULL) {
97dc3902e9bcf2e17b9c249999bffba908231b62Timo Sirainen storages = array_get(&quota->storages, &count);
8a26102b8b1e08a774398980a8f92ae8f8575da8Timo Sirainen for (i = 0; i < count; i++) {
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen path2 = mail_storage_get_mailbox_path(storages[i], "",
8a26102b8b1e08a774398980a8f92ae8f8575da8Timo Sirainen &is_file);
8a26102b8b1e08a774398980a8f92ae8f8575da8Timo Sirainen if (path2 != NULL && strcmp(path, path2) == 0) {
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen /* duplicate */
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen return;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen }
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen }
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen }
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen array_append(&quota->storages, &storage, 1);
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen
c5d6b453eccc0962eae967abc10e028a740e1256Timo Sirainen roots = array_get(&quota->roots, &count);
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen /* @UNSAFE: get different backends into one array */
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen backends = t_new(struct quota_backend *, count + 1);
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen for (i = 0; i < count; i++) {
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen for (j = 0; backends[j] != NULL; j++) {
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen if (backends[j]->name == roots[i]->backend.name)
de26c21cfadf24c1fa59f06414854d58b3d8baadTimo Sirainen break;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (backends[j] == NULL)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen backends[j] = &roots[i]->backend;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen for (i = 0; backends[i] != NULL; i++) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (backends[i]->v.storage_added != NULL)
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen backends[i]->v.storage_added(quota, storage);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen}
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainenvoid quota_remove_user_storage(struct quota *quota,
bfc7fcde95de729c7e5f18cca7566a3cf754c0ceTimo Sirainen struct mail_storage *storage)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen{
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct mail_storage *const *storages;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen unsigned int i, count;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen storages = array_get(&quota->storages, &count);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen for (i = 0; i < count; i++) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (storages[i] == storage) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen array_delete(&quota->storages, i, 1);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen break;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen}
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenstruct quota_root_iter *
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenquota_root_iter_init(struct quota *quota, struct mailbox *box)
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen{
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen struct quota_root_iter *iter;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen iter = i_new(struct quota_root_iter, 1);
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen iter->quota = quota;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen iter->box = box;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen return iter;
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen}
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainenstruct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
4ee385fb4e4b007d3fa907b7616988006a21e85fTimo Sirainen{
af466fd3ee9d17f2e7b264079d25306c5598b200Timo Sirainen struct quota_root *const *roots, *root = NULL;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen unsigned int count;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen uint64_t value, limit;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen int ret;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen roots = array_get(&iter->quota->roots, &count);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (iter->i >= count)
3ec969c5cee55a7b08ab5c5bf7afae310176e2bdTimo Sirainen return NULL;
b720f55c568cce0a1c8c2be74e588b66bb467e82Timo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen for (; iter->i < count; iter->i++) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen ret = quota_get_resource(roots[iter->i], "",
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen &value, &limit);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen if (ret == 0) {
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen ret = quota_get_resource(roots[iter->i], "",
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen QUOTA_NAME_MESSAGES,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen &value, &limit);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (ret > 0) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen root = roots[iter->i];
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen break;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen iter->i++;
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen return root;
9a7f22e2c14b507e6044e5534df978a0c3b638d0Timo Sirainen}
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainenvoid quota_root_iter_deinit(struct quota_root_iter *iter)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen i_free(iter);
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen}
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenstruct quota_root *quota_root_lookup(struct quota *quota, const char *name)
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen{
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen struct quota_root *const *roots;
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen unsigned int i, count;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen roots = array_get(&quota->roots, &count);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen for (i = 0; i < count; i++) {
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen if (strcmp(roots[i]->name, name) == 0)
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen return roots[i];
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return NULL;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
90de49eb151c2be7655ce6aef5aa3b58295d5c84Timo Sirainenconst char *quota_root_get_name(struct quota_root *root)
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return root->name;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenconst char *const *quota_root_get_resources(struct quota_root *root)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return root->backend.v.get_resources(root);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenint quota_get_resource(struct quota_root *root, const char *mailbox_name,
feccf3f8679807f25d105521d5f6ddce6df7cdceTimo Sirainen const char *name, uint64_t *value_r, uint64_t *limit_r)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen uint64_t bytes_limit, count_limit;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen bool kilobytes = FALSE;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen int ret;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen name = QUOTA_NAME_STORAGE_BYTES;
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen kilobytes = TRUE;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen (void)quota_root_get_rule_limits(root, mailbox_name,
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen &bytes_limit, &count_limit);
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen *limit_r = bytes_limit;
d30c35e25ea6d935393e031509e6e22422b1e006Timo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen *limit_r = count_limit;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen else
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen *limit_r = 0;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen ret = root->backend.v.get_resource(root, name, value_r, limit_r);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (kilobytes && ret > 0) {
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen *value_r /= 1024;
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen *limit_r /= 1024;
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen }
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen return ret <= 0 ? ret :
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen (*limit_r == 0 ? 0 : 1);
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen}
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainenint quota_set_resource(struct quota_root *root __attr_unused__,
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen const char *name __attr_unused__,
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen uint64_t value __attr_unused__, const char **error_r)
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen{
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen /* the quota information comes from userdb (or even config file),
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen so there's really no way to support this until some major changes
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen are done */
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen *error_r = MAIL_STORAGE_ERR_NO_PERMISSION;
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen return -1;
1228c0604b8e21e170bba3e2060331599a378110Timo Sirainen}
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainenstruct quota_transaction_context *quota_transaction_begin(struct quota *quota,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen struct mailbox *box)
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen{
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen struct quota_transaction_context *ctx;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen struct quota_root *const *roots;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen const char *mailbox_name;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen unsigned int i, count;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen uint64_t current, limit, left;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen int ret;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen mailbox_name = mailbox_get_name(box);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx = i_new(struct quota_transaction_context, 1);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->quota = quota;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->box = box;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->bytes_left = (uint64_t)-1;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->count_left = (uint64_t)-1;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen if (quota->counting) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen /* we got here through quota_count_storage() */
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen return ctx;
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen }
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen /* find the lowest quota limits from all roots and use them */
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen roots = array_get(&quota->roots, &count);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen for (i = 0; i < count; i++) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen QUOTA_NAME_STORAGE_BYTES,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen &current, &limit);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen if (ret > 0) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen left = limit < current ? 0 : limit - current;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen if (ctx->bytes_left > left)
b2048c45f6c6ace7d90a2c05f0f3fc6e03e30f38Timo Sirainen ctx->bytes_left = left;
b2048c45f6c6ace7d90a2c05f0f3fc6e03e30f38Timo Sirainen } else if (ret < 0) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->failed = TRUE;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen break;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen }
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen QUOTA_NAME_MESSAGES, &current, &limit);
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen if (ret > 0) {
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen left = limit < current ? 0 : limit - current;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen if (ctx->count_left > left)
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen ctx->count_left = left;
f87844c400cf9741abad57d9815121d0738a738fTimo Sirainen } else if (ret < 0) {
f87844c400cf9741abad57d9815121d0738a738fTimo Sirainen ctx->failed = TRUE;
f87844c400cf9741abad57d9815121d0738a738fTimo Sirainen break;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen }
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return ctx;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenint quota_transaction_commit(struct quota_transaction_context *ctx)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen struct quota_root *const *roots;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen unsigned int i, count;
03f2a189a0985d87cfe443a1a5cc8ab6da052c30Timo Sirainen int ret = 0;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (ctx->failed)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen ret = -1;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen else {
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen for (i = 0; i < count; i++) {
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen if (roots[i]->backend.v.update(roots[i], ctx) < 0)
ce7c2091ca9f19a13c835d1d522832a73f7cfaa0Timo Sirainen ret = -1;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
c5c71245fec4331d6598376f0ff2f3b9d4372cc8Timo Sirainen i_free(ctx);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen return ret;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen}
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenvoid quota_transaction_rollback(struct quota_transaction_context *ctx)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen i_free(ctx);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen}
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen struct mail *mail, bool *too_large_r)
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen{
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen int ret;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen ret = quota_test_alloc(ctx, mail_get_physical_size(mail), too_large_r);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen if (ret <= 0)
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen return ret;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen quota_alloc(ctx, mail);
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen return 1;
13f6c879a84b3edd2fcc8f9832812be1f8c5d3b6Timo Sirainen}
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainenint quota_test_alloc(struct quota_transaction_context *ctx,
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen uoff_t size, bool *too_large_r)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen return ctx->quota->test_alloc(ctx, size, too_large_r);
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen}
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen
8e1dbcb9b249c37d00b420705777b103ffa6145dTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen uoff_t size, bool *too_large_r)
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen{
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen struct quota_root *const *roots;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen unsigned int i, count;
df452e9628fe8d3356c42dd644b020ea9733c0c1Timo Sirainen
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen *too_large_r = FALSE;
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen if (ctx->failed)
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen return -1;
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen if (ctx->count_left != 0 && ctx->bytes_left >= ctx->bytes_used + size)
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen return 1;
edcd6f7223568e080d5a6767c5038e3bc891e963Timo Sirainen
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen for (i = 0; i < count; i++) {
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen uint64_t bytes_limit, count_limit;
fb37a9b7bb71807a394e3ecdb74511f32a79c39bTimo Sirainen
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen if (!quota_root_get_rule_limits(roots[i],
1a878b9d2a823abc6b1c8b1631e50a15d534665fTimo Sirainen mailbox_get_name(ctx->box),
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen &bytes_limit, &count_limit))
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen continue;
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen /* if size is bigger than any limit, then
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen it is bigger than the lowest limit */
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen if (size > bytes_limit) {
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainen *too_large_r = TRUE;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen break;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen }
689b06e33729491b593fe34ad3267d65b79be149Timo Sirainen
51130f00bbd1e119ec042d63c148a78ac06ab85eTimo Sirainen return 0;
51130f00bbd1e119ec042d63c148a78ac06ab85eTimo Sirainen}
51130f00bbd1e119ec042d63c148a78ac06ab85eTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainenvoid quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen{
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen uoff_t size;
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen size = mail_get_physical_size(mail);
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen if (size != (uoff_t)-1)
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen ctx->bytes_used += size;
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen ctx->count_used++;
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen}
2dc23f3416724163cc5d7162c577a8ed9f985fedTimo Sirainen
afb49e8adab954708e3f192386a3c7faa07e5ae5Timo Sirainenvoid quota_free(struct quota_transaction_context *ctx, struct mail *mail)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen{
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen uoff_t size;
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen size = mail_get_physical_size(mail);
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen if (size != (uoff_t)-1)
9fb018dea4e2073639249ea8a14ae27cab2c0aacTimo Sirainen ctx->bytes_used -= size;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen ctx->count_used--;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen}
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen