quota.c revision 7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen#define DEFAULT_QUOTA_EXCEEDED_MSG "Quota exceeded"
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[] = {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen quota->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE");
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen quota->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen root_p = array_idx_modifiable("a->roots, 0);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen unsigned int i;
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen for (i = 0; i < N_ELEMENTS(quota_backends); 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);
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen i_info("Quota root: name=%s backend=%s args=%s",
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen root->name, backend_name, args == NULL ? "" : args);
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen array_create(&root->quota_module_contexts, default_pool,
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen sizeof(void *), 5);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo 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++) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen warnings = array_get_modifiable(&root->warning_rules, &count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo 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++) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainenquota_rule_parse_percentage(struct quota_root *root, struct quota_rule *rule,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "Invalid rule percentage: %lld", (long long)percentage);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen *error_r = "Default rule can't be a percentage";
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenquota_rule_recalculate_relative_rules(struct quota_rule *rule,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rule->bytes_limit = default_rule->bytes_limit *
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rule->count_limit = default_rule->count_limit *
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenvoid quota_root_recalculate_relative_rules(struct quota_root *root)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen unsigned int i, count;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rules = array_get_modifiable(&root->rules, &count);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen for (i = 0; i < count; i++) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen quota_rule_recalculate_relative_rules(&rules[i],
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen warning_rules = array_get_modifiable(&root->warning_rules, &count);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen for (i = 0; i < count; i++) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen quota_rule_recalculate_relative_rules(&warning_rules[i].rule,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenquota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen const char **error_r)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen const char **args;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen } else if (strncmp(*args, "bytes=", 6) == 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen } else if (strncmp(*args, "messages=", 9) == 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen switch (i_toupper(*p)) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* default */
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (quota_rule_parse_percentage(root, rule, limit,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_root_add_rule(struct quota_root *root, const char *rule_def,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char **error_r)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen const char *p, *mailbox_name;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <mailbox name>:<quota limits> */
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen rule = quota_root_rule_find(root, mailbox_name);
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0)
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) {
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen rule->mailbox_name = p_strdup(root->pool, mailbox_name);
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (!root->backend.v.parse_rule(root, rule, p, error_r))
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen bool allow_negative = rule != &root->default_rule;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "bytes=%lld (%u%%) messages=%lld (%u%%)", root->name,
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen rule->mailbox_name != NULL ? rule->mailbox_name : "",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen (long long)rule->bytes_limit, rule->bytes_percent,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen (long long)rule->count_limit, rule->count_percent);
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;
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 storages = array_get("a->storages, &count);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen for (i = 0; i < count; i++) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path2 = mail_storage_get_mailbox_path(storages[i], "",
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (path2 != NULL && strcmp(path, path2) == 0) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* duplicate */
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++) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenint quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen const char **error_r)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen const char *p;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen ret = quota_rule_parse_limits(root, &rule, t_strdup_until(rule_def, p),
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen warning = array_append_space(&root->warning_rules);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen "messages=%llu (%u%%) command=%s",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen (unsigned long long)warning->rule.bytes_limit,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen (unsigned long long)warning->rule.count_limit,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen warning->rule.count_percent, warning->command);
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);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo 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) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* Get the value first. This call may also update quota limits if
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen they're defined externally. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = root->backend.v.get_resource(root, name, value_r);
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)
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenint quota_set_resource(struct quota_root *root ATTR_UNUSED,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo 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,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx = i_new(struct quota_transaction_context, 1);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenstatic int quota_transaction_set_limits(struct quota_transaction_context *ctx)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen unsigned int i, count;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* find the lowest quota limits from all roots and use them */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen roots = array_get(&ctx->quota->roots, &count);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen for (i = 0; i < count; i++) {
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen /* we don't care what the current quota is */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen } else if (ret < 0) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen } else if (ret < 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenstatic void quota_warning_execute(const char *cmd)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_error("system(%s) died with signal %d", cmd, WTERMSIG(ret));
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen cmd, WIFEXITED(ret) ? WEXITSTATUS(ret) : ret);
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainenstatic void quota_warnings_execute(struct quota_transaction_context *ctx,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen unsigned int i, count;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen uint64_t bytes_current, bytes_before, bytes_limit;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen uint64_t count_current, count_before, count_limit;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen warnings = array_get_modifiable(&root->warning_rules, &count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen bytes_before = bytes_current - ctx->bytes_used;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen count_before = count_current - ctx->count_used;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen for (i = 0; i < count; i++) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if ((bytes_before < (uint64_t)warnings[i].rule.bytes_limit &&
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen bytes_current >= (uint64_t)warnings[i].rule.bytes_limit) ||
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen (count_before < (uint64_t)warnings[i].rule.count_limit &&
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen count_current >= (uint64_t)warnings[i].rule.count_limit)) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenint quota_transaction_commit(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen unsigned int i, count;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen else if (ctx->bytes_used != 0 || ctx->count_used != 0 ||
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen roots = array_get(&ctx->quota->roots, &count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen for (i = 0; i < count; i++) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (roots[i]->backend.v.update(roots[i], ctx) < 0)
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen /* execute quota warnings after all updates. this makes it
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen work correctly regardless of whether backend.get_resource()
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen returns updated values before backend.update() or not */
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen for (i = 0; i < count; i++)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenvoid quota_transaction_rollback(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = quota_test_alloc(ctx, size, 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)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_free_bytes(struct quota_transaction_context *ctx,