quota.c revision e392fcb39a06609af20a9e79017683f194de3dde
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenunsigned int quota_module_id = 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_dict;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_dirsize;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_maildir;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backends[] = {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#define QUOTA_CLASS_COUNT (sizeof(quota_backends)/sizeof(quota_backends[0]))
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = array_idx_modifiable("a->roots, 0);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen unsigned int i;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen for (i = 0; i < QUOTA_CLASS_COUNT; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(quota_backends[i]->name, name) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_init(struct quota *quota, const char *root_def)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <backend>[:<quota root name>[:<backend args>]] */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_fatal("Unknown quota backend: %s", backend_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->pool = pool_alloconly_create("quota root", 512);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* save root's name */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->name = p_strdup_until(root->pool, args, p);
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen array_create(&root->quota_module_contexts, default_pool,
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen sizeof(void *), 5);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid quota_root_deinit(struct quota_root *root)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&root->quota->roots, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_rule *
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenquota_root_rule_find(struct quota_root *root, const char *name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rules = array_get_modifiable(&root->rules, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_root_add_rule(struct quota_root *root, const char *rule_def,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char **error_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char **args;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <mailbox name>:<quota limits> */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (strcmp(*args, RULE_NAME_ALL_MAILBOXES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule->mailbox_name = p_strdup(root->pool, *args);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule->bytes_limit = strtoll(*args + 8, NULL, 10) * 1024;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule->count_limit = strtoll(*args + 9, NULL, 10);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic bool quota_root_get_rule_limits(struct quota_root *root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if default rule limits are 0, this rule applies only to specific
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rule = quota_root_rule_find(root, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *bytes_limit_r = bytes_limit <= 0 ? 0 : bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *count_limit_r = count_limit <= 0 ? 0 : count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, j, 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++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (backends[j]->name == roots[i]->backend.name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_remove_user_storage(struct quota *quota,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen storages = array_get("a->storages, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenquota_root_iter_init(struct quota *quota, struct mailbox *box)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots, *root = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&iter->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_root_iter_deinit(struct quota_root_iter *iter)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_lookup(struct quota *quota, const char *name)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *quota_root_get_name(struct quota_root *root)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *const *quota_root_get_resources(struct quota_root *root)
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)
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)quota_root_get_rule_limits(root, mailbox_name,
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen ret = root->backend.v.get_resource(root, name, value_r, limit_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_set_resource(struct quota_root *root __attr_unused__,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t value __attr_unused__, const char **error_r)
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 Sirainenstruct quota_transaction_context *quota_transaction_begin(struct quota *quota,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx = i_new(struct quota_transaction_context, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* find the lowest quota limits from all roots and use them */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (ret < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (ret < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_transaction_commit(struct quota_transaction_context *ctx)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
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 Sirainenvoid quota_transaction_rollback(struct quota_transaction_context *ctx)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_test_alloc(ctx, mail_get_physical_size(mail), too_large_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_test_alloc(struct quota_transaction_context *ctx,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return ctx->quota->test_alloc(ctx, size, too_large_r);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ctx->count_left != 0 && ctx->bytes_left >= ctx->bytes_used + size)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if size is bigger than any limit, then
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it is bigger than the lowest limit */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_free(struct quota_transaction_context *ctx, struct mail *mail)