quota.c revision f3bf2314198da2877ce640360581a61d60c90991
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "hash.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mailbox-list-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-private.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "quota-fs.h"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#include <stdlib.h>
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#define RULE_NAME_ALL_MAILBOXES "*"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root_iter {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota *quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mailbox *box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenunsigned int quota_module_id = 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_dict;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_dirsize;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_fs;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_maildir;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backends[] = {
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#ifdef HAVE_FS_QUOTA
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_fs,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#endif
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_dict,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_dirsize,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_maildir
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen};
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#define QUOTA_CLASS_COUNT (sizeof(quota_backends)/sizeof(quota_backends[0]))
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uoff_t size, bool *too_large_r);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct quota *quota_init(void)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota *quota;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen quota = i_new(struct quota, 1);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen quota->test_alloc = quota_default_test_alloc;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen quota->debug = getenv("DEBUG") != NULL;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&quota->roots, 4);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&quota->storages, 8);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return quota;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_deinit(struct quota **_quota)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota *quota = *_quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root **root;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_quota = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen while (array_count(&quota->roots) > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = array_idx_modifiable(&quota->roots, 0);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_root_deinit(root);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_free(&quota->roots);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_free(&quota->storages);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(quota);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen unsigned int i;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen for (i = 0; i < QUOTA_CLASS_COUNT; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(quota_backends[i]->name, name) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return quota_backends[i];
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_init(struct quota *quota, const char *root_def)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *root;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen const struct quota_backend *backend;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *p, *args, *backend_name;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen t_push();
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <backend>[:<quota root name>[:<backend args>]] */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = strchr(root_def, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend_name = root_def;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend_name = t_strdup_until(root_def, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p + 1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend = quota_backend_find(backend_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backend == NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_fatal("Unknown quota backend: %s", backend_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen t_pop();
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = backend->v.alloc();
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->quota = quota;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen root->backend = *backend;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->pool = pool_alloconly_create("quota root", 512);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (args != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* save root's name */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = strchr(args, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->name = p_strdup(root->pool, args);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->name = p_strdup_until(root->pool, args, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p + 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->name = "";
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&root->rules, 4);
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen array_create(&root->quota_module_contexts, default_pool,
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen sizeof(void *), 5);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_append(&quota->roots, &root, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backend->v.init != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backend->v.init(root, args) < 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_root_deinit(&root);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return root;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_root_deinit(struct quota_root **_root)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_root *root = *_root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen pool_t pool = root->pool;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct quota_root *const *roots;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&root->quota->roots, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (roots[i] == root)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_delete(&root->quota->roots, i, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_root = NULL;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_free(&root->rules);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_free(&root->quota_module_contexts);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen root->backend.v.deinit(root);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen pool_unref(pool);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_rule *
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenquota_root_rule_find(struct quota_root *root, const char *name)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rules;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rules = array_get_modifiable(&root->rules, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(rules[i].mailbox_name, name) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return &rules[i];
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_root_add_rule(struct quota_root *root, const char *rule_def,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rule;
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen const char *p, *mailbox_name, **args;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen p = strchr(rule_def, ':');
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen if (p == NULL) {
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen *error_r = "Invalid rule";
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <mailbox name>:<quota limits> */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen t_push();
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen mailbox_name = t_strdup_until(rule_def, p++);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen rule = quota_root_rule_find(root, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (rule == NULL) {
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen if (strcmp(mailbox_name, RULE_NAME_ALL_MAILBOXES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule = &root->default_rule;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule = array_append_space(&root->rules);
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen rule->mailbox_name = p_strdup(root->pool, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen for (args = t_strsplit(p, ":"); *args != NULL; args++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strncmp(*args, "storage=", 8) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule->bytes_limit = strtoll(*args + 8, NULL, 10) * 1024;
8a161890eca262a2d5ff77c2153b7f78e72227b1Timo Sirainen else if (strncmp(*args, "bytes=", 6) == 0)
8a161890eca262a2d5ff77c2153b7f78e72227b1Timo Sirainen rule->bytes_limit = strtoll(*args + 6, NULL, 10);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strncmp(*args, "messages=", 9) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule->count_limit = strtoll(*args + 9, NULL, 10);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *error_r = p_strdup_printf(root->pool,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "Invalid rule limit: %s", *args);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen if (root->quota->debug) {
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen i_info("Quota rule: root=%s mailbox=%s "
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen "storage=%lldkB messages=%lld", root->name,
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen rule->mailbox_name != NULL ? rule->mailbox_name : "",
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen (long long)rule->bytes_limit / 1024,
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen (long long)rule->count_limit);
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen }
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen t_pop();
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic bool quota_root_get_rule_limits(struct quota_root *root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t *bytes_limit_r,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t *count_limit_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rule;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int64_t bytes_limit, count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bool found;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bytes_limit = root->default_rule.bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen count_limit = root->default_rule.count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if default rule limits are 0, this rule applies only to specific
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mailboxes */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen found = bytes_limit != 0 || count_limit != 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule = quota_root_rule_find(root, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (rule != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bytes_limit += rule->bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen count_limit += rule->count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen found = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *bytes_limit_r = bytes_limit <= 0 ? 0 : bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *count_limit_r = count_limit <= 0 ? 0 : count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return found;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen struct mail_storage *const *storages;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_backend **backends;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen const char *path, *path2;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, j, count;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen bool is_file;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* first check if there already exists a storage with the exact same
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path. we don't want to count them twice. */
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path = mail_storage_get_mailbox_path(storage, "", &is_file);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (path != NULL) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen storages = array_get(&quota->storages, &count);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen for (i = 0; i < count; i++) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path2 = mail_storage_get_mailbox_path(storages[i], "",
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen &is_file);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (path2 != NULL && strcmp(path, path2) == 0) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* duplicate */
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen return;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_append(&quota->storages, &storage, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* @UNSAFE: get different backends into one array */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backends = t_new(struct quota_backend *, count + 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (j = 0; backends[j] != NULL; j++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (backends[j]->name == roots[i]->backend.name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backends[j] == NULL)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen backends[j] = &roots[i]->backend;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; backends[i] != NULL; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backends[i]->v.storage_added != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backends[i]->v.storage_added(quota, storage);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_remove_user_storage(struct quota *quota,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *storage)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *const *storages;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen storages = array_get(&quota->storages, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (storages[i] == storage) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen array_delete(&quota->storages, i, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root_iter *
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenquota_root_iter_init(struct quota *quota, struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root_iter *iter;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter = i_new(struct quota_root_iter, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->quota = quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->box = box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return iter;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots, *root = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t value, limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&iter->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (iter->i >= count)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (; iter->i < count; iter->i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[iter->i], "",
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen &value, &limit);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[iter->i], "",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen QUOTA_NAME_MESSAGES,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen &value, &limit);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = roots[iter->i];
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->i++;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_root_iter_deinit(struct quota_root_iter **_iter)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_root_iter *iter = *_iter;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_iter = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(iter);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_lookup(struct quota *quota, const char *name)
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(roots[i]->name, name) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return roots[i];
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen}
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *quota_root_get_name(struct quota_root *root)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return root->name;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *const *quota_root_get_resources(struct quota_root *root)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return root->backend.v.get_resources(root);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_get_resource(struct quota_root *root, const char *mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *name, uint64_t *value_r, uint64_t *limit_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t bytes_limit, count_limit;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen bool kilobytes = FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen name = QUOTA_NAME_STORAGE_BYTES;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen kilobytes = TRUE;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)quota_root_get_rule_limits(root, mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen &bytes_limit, &count_limit);
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen ret = root->backend.v.get_resource(root, name, value_r, limit_r);
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (kilobytes && ret > 0) {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen *value_r /= 1024;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen *limit_r /= 1024;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret <= 0 ? ret :
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (*limit_r == 0 ? 0 : 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_set_resource(struct quota_root *root __attr_unused__,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *name __attr_unused__,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t value __attr_unused__, const char **error_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* the quota information comes from userdb (or even config file),
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen so there's really no way to support this until some major changes
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen are done */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = MAIL_ERRSTR_NO_PERMISSION;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_transaction_context *quota_transaction_begin(struct quota *quota,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_transaction_context *ctx;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *mailbox_name;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t current, limit, left;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mailbox_name = mailbox_get_name(box);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx = i_new(struct quota_transaction_context, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->quota = quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->box = box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->bytes_left = (uint64_t)-1;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen ctx->count_left = (uint64_t)-1;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen if (quota->counting) {
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen /* we got here through quota_count_storage() */
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen return ctx;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* find the lowest quota limits from all roots and use them */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen QUOTA_NAME_STORAGE_BYTES,
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen &current, &limit);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen left = limit < current ? 0 : limit - current;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->bytes_left > left)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->bytes_left = left;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (ret < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->failed = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen QUOTA_NAME_MESSAGES, &current, &limit);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen left = limit < current ? 0 : limit - current;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->count_left > left)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->count_left = left;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (ret < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->failed = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ctx;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenint quota_transaction_commit(struct quota_transaction_context **_ctx)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_transaction_context *ctx = *_ctx;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret = 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_ctx = NULL;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->failed)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (roots[i]->backend.v.update(roots[i], ctx) < 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(ctx);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_transaction_rollback(struct quota_transaction_context **_ctx)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_transaction_context *ctx = *_ctx;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_ctx = NULL;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen i_free(ctx);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail *mail, bool *too_large_r)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen int ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_test_alloc(ctx, mail_get_physical_size(mail), too_large_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret <= 0)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen quota_alloc(ctx, mail);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return 1;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_test_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uoff_t size, bool *too_large_r)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return ctx->quota->test_alloc(ctx, size, too_large_r);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen}
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uoff_t size, bool *too_large_r)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = FALSE;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->failed)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->count_left != 0 && ctx->bytes_left >= ctx->bytes_used + size)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 1;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t bytes_limit, count_limit;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (!quota_root_get_rule_limits(roots[i],
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mailbox_get_name(ctx->box),
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen &bytes_limit, &count_limit))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen continue;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if size is bigger than any limit, then
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it is bigger than the lowest limit */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (size > bytes_limit) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen uoff_t size;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen size = mail_get_physical_size(mail);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (size != (uoff_t)-1)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->bytes_used += size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->count_used++;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_free(struct quota_transaction_context *ctx, struct mail *mail)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen uoff_t size;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen size = mail_get_physical_size(mail);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (size == (uoff_t)-1)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_recalculate(ctx);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen else
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_free_bytes(ctx, size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_free_bytes(struct quota_transaction_context *ctx,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen uoff_t physical_size)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->bytes_used -= physical_size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->count_used--;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_recalculate(struct quota_transaction_context *ctx)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->recalculate = TRUE;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}