quota.c revision 4c7e360ab67642c08f82c709445ea45aa170632d
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2005-2015 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "hash.h"
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen#include "str.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen#include "write-full.h"
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen#include "eacces-error.h"
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen#include "wildcard-match.h"
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen#include "dict.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mailbox-list-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-private.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "quota-fs.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#include <stdlib.h>
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen#include <sys/wait.h>
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
cb2b5a7d6e7e651191bf9ee1eda94a6e207288b0Timo Sirainen#define DEFAULT_QUOTA_EXCEEDED_MSG \
cb2b5a7d6e7e651191bf9ee1eda94a6e207288b0Timo Sirainen "Quota exceeded (mailbox for user is full)"
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen#define QUOTA_LIMIT_SET_PATH DICT_PATH_PRIVATE"quota/limit/"
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};
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
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen unsigned int i;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen for (i = 0; i < N_ELEMENTS(quota_backends); i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen if (strcmp(quota_backends[i]->name, name) == 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return quota_backends[i];
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen return NULL;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int quota_root_add_rules(struct mail_user *user, const char *root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *rule_name, *rule, *error;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strconcat(root_name, "_rule", NULL);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 2;; i++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule = mail_user_plugin_getenv(user, rule_name);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (rule == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (quota_root_add_rule(root_set, rule, &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid rule %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen rule, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strdup_printf("%s_rule%d", root_name, i);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenquota_root_add_warning_rules(struct mail_user *user, const char *root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *rule_name, *rule, *error;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strconcat(root_name, "_warning", NULL);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 2;; i++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule = mail_user_plugin_getenv(user, rule_name);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (rule == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (quota_root_add_warning_rule(root_set, rule, &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid warning rule: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen rule);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strdup_printf("%s_warning%d", root_name, i);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainenstatic int
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainenquota_root_parse_set(struct mail_user *user, const char *root_name,
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen struct quota_root_settings *root_set,
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen const char **error_r)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen{
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen const char *name, *value;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen name = t_strconcat(root_name, "_set", NULL);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen value = mail_user_plugin_getenv(user, name);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (value == NULL)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return 0;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (strncmp(value, "dict:", 5) != 0) {
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen *error_r = t_strdup_printf("%s supports only dict backend", name);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen }
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen root_set->limit_set = p_strdup(root_set->set->pool, value+5);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return 0;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen}
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_settings_init(struct quota_settings *quota_set, const char *root_def,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings **set_r,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root_settings *root_set;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen const struct quota_backend *backend;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *p, *args, *backend_name;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo 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);
d9b8c65d0a0ffc709ba7d23c449dbf2f46b10674Timo Sirainen if (backend == NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Unknown quota backend: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen backend_name);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
d9b8c65d0a0ffc709ba7d23c449dbf2f46b10674Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set = p_new(quota_set->pool, struct quota_root_settings, 1);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->set = quota_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->backend = backend;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (args != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* save root's name */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = strchr(args, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name = p_strdup(quota_set->pool, args);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name =
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_strdup_until(quota_set->pool, args, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p + 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name = "";
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->args = p_strdup(quota_set->pool, args);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota_set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Quota root: name=%s backend=%s args=%s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk root_set->name, backend_name, args == NULL ? "" : args);
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen }
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_array_init(&root_set->rules, quota_set->pool, 4);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_array_init(&root_set->warning_rules, quota_set->pool, 4);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_append(&quota_set->root_sets, &root_set, 1);
4316355ca8b7698516272520a972291378698140Timo Sirainen *set_r = root_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_add(struct quota_settings *quota_set, struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *env, const char *root_name, const char **error_r)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen const char *set_name, *value;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_settings_init(quota_set, env, &root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen root_set->set_name = p_strdup(quota_set->pool, root_name);
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add_rules(user, root_name, root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (quota_root_parse_set(user, root_name, root_set, error_r) < 0)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen set_name = t_strconcat(root_name, "_grace", NULL);
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen value = mail_user_plugin_getenv(user, set_name);
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen if (quota_root_parse_grace(root_set, value, error_r) < 0) {
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen *error_r = t_strdup_printf("Invalid %s value '%s': %s",
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen set_name, value, *error_r);
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen return -1;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenint quota_user_read_settings(struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings **set_r,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings *quota_set;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen char root_name[5 + MAX_INT_STRLEN + 1];
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *env, *error;
4316355ca8b7698516272520a972291378698140Timo Sirainen unsigned int i;
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_t pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen pool = pool_alloconly_create("quota settings", 2048);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set = p_new(pool, struct quota_settings, 1);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->pool = pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->test_alloc = quota_default_test_alloc;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->debug = user->mail_debug;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->quota_exceeded_msg =
4316355ca8b7698516272520a972291378698140Timo Sirainen mail_user_plugin_getenv(user, "quota_exceeded_message");
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_set->quota_exceeded_msg == NULL)
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen p_array_init(&quota_set->root_sets, pool, 4);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_strocpy(root_name, "quota", sizeof(root_name)) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
4316355ca8b7698516272520a972291378698140Timo Sirainen for (i = 2;; i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen env = mail_user_plugin_getenv(user, root_name);
3cfc375f0d939c346b9b0e6f0ac78b9bc367dd95Timo Sirainen if (env == NULL || *env == '\0')
4316355ca8b7698516272520a972291378698140Timo Sirainen break;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add(quota_set, user, env, root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid quota root %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root_name, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_snprintf(root_name, sizeof(root_name), "quota%d", i) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen if (array_count(&quota_set->root_sets) == 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
b8a4aab1f117f6760184ad50b1af41ba810b51f9Timo Sirainen
b8a4aab1f117f6760184ad50b1af41ba810b51f9Timo Sirainen quota_set->initialized = TRUE;
4316355ca8b7698516272520a972291378698140Timo Sirainen *set_r = quota_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 1;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenvoid quota_settings_deinit(struct quota_settings **_quota_set)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings *quota_set = *_quota_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen *_quota_set = NULL;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&quota_set->pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic void quota_root_deinit(struct quota_root *root)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_t pool = root->pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (root->limit_set_dict != NULL)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen dict_deinit(&root->limit_set_dict);
4316355ca8b7698516272520a972291378698140Timo Sirainen root->backend.v.deinit(root);
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_init(struct quota_root_settings *root_set, struct quota *quota,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root **root_r, const char **error_r)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *root;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *const *tmp;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root = root_set->backend->v.alloc();
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen root->resource_ret = -1;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->pool = pool_alloconly_create("quota root", 512);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->set = root_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->quota = quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->backend = *root_set->backend;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen root->bytes_limit = root_set->default_rule.bytes_limit;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen root->count_limit = root_set->default_rule.count_limit;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_create(&root->quota_module_contexts, root->pool,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen sizeof(void *), 10);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (root->backend.v.init != NULL) {
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen if (root->backend.v.init(root, root_set->args, error_r) < 0) {
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen *error_r = t_strdup_printf("%s quota init failed: %s",
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen root->backend.name, *error_r);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen } else if (root_set->args != NULL) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen tmp = t_strsplit_spaces(root_set->args, " ");
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen for (; *tmp != NULL; tmp++) {
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen if (strcmp(*tmp, "noenforcing") == 0)
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen root->no_enforcing = TRUE;
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainen else if (strcmp(*tmp, "hidden") == 0)
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainen root->hidden = TRUE;
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen else if (strcmp(*tmp, "ignoreunlimited") == 0)
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen root->disable_unlimited_tracking = TRUE;
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen else
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen break;
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen }
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen if (*tmp != NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf(
4316355ca8b7698516272520a972291378698140Timo Sirainen "Unknown parameter for backend %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root->backend.name, *tmp);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen if (root_set->default_rule.bytes_limit == 0 &&
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen root_set->default_rule.count_limit == 0 &&
4316355ca8b7698516272520a972291378698140Timo Sirainen root->disable_unlimited_tracking) {
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_root_deinit(root);
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen *root_r = root;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 1;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenint quota_init(struct quota_settings *quota_set, struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota **quota_r, const char **error_r)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *root;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root_settings *const *root_sets;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *error;
4316355ca8b7698516272520a972291378698140Timo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota = i_new(struct quota, 1);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota->user = user;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota->set = quota_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen i_array_init(&quota->roots, 8);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_sets = array_get(&quota_set->root_sets, &count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_array_init(&quota->namespaces, count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen ret = quota_root_init(root_sets[i], quota, &root, &error);
4316355ca8b7698516272520a972291378698140Timo Sirainen if (ret < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Quota root %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root_sets[i]->name, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_deinit(&quota);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen if (ret > 0)
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen array_append(&quota->roots, &root, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen *quota_r = quota;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenvoid quota_deinit(struct quota **_quota)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota = *_quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *const *roots;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen unsigned int i, count;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen roots = array_get(&quota->roots, &count);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen for (i = 0; i < count; i++)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota_root_deinit(roots[i]);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen /* deinit quota roots before setting quser->quota=NULL */
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen *_quota = NULL;
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_free(&quota->roots);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_free(&quota->namespaces);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen i_free(quota);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainenstatic int quota_root_get_rule_limits(struct quota_root *root,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen const char *mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen uint64_t *bytes_limit_r,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen uint64_t *count_limit_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rule;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int64_t bytes_limit, count_limit;
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen bool enabled;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (!root->set->force_default_rule) {
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen if (root->backend.v.init_limits != NULL) {
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen if (root->backend.v.init_limits(root) < 0)
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen return -1;
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen }
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen }
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen bytes_limit = root->bytes_limit;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen count_limit = root->count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen /* if default rule limits are 0, user has unlimited quota.
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen ignore any specific quota rules */
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen enabled = bytes_limit != 0 || count_limit != 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen (void)mail_namespace_find_unalias(root->quota->user->namespaces,
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen &mailbox_name);
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen rule = enabled ? quota_root_rule_find(root->set, mailbox_name) : NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (rule != NULL) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (!rule->ignore) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen bytes_limit += rule->bytes_limit;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen count_limit += rule->count_limit;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen } else {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen bytes_limit = 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen count_limit = 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
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;
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen return enabled ? 1 : 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainenstatic bool
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainenquota_is_duplicate_namespace(struct quota *quota, struct mail_namespace *ns)
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen{
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen struct mail_namespace *const *namespaces;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen unsigned int i, count;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen const char *path, *path2;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen if (!mailbox_list_get_root_path(ns->list,
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX, &path))
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return TRUE;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen namespaces = array_get(&quota->namespaces, &count);
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen for (i = 0; i < count; i++) {
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen if (mailbox_list_get_root_path(namespaces[i]->list,
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX, &path2) &&
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen strcmp(path, path2) == 0) {
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen /* duplicate path */
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return TRUE;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen /* this is inbox=yes namespace, but the earlier one
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen that had the same location was inbox=no. we need to
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen include the INBOX also in quota calculations, so we
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen can't just ignore this namespace. but since we've
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen already called backend's namespace_added(), we can't
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen just remove it either. so just mark the old one as
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen unwanted namespace.
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen an alternative would be to do a bit larger change so
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen namespaces wouldn't be added until
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen mail_namespaces_created() hook is called */
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen i_assert(quota->unwanted_ns == NULL);
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen quota->unwanted_ns = namespaces[i];
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return FALSE;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen }
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen }
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return FALSE;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen}
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid quota_add_user_namespace(struct quota *quota, struct mail_namespace *ns)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_backend **backends;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, j, count;
ccd44abfe14f51cc1f6d8c0ec1aa6dc31242e2d3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* first check if there already exists a namespace with the exact same
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path. we don't want to count them twice. */
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen if (quota_is_duplicate_namespace(quota, ns))
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append(&quota->namespaces, &ns, 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++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (backends[i]->v.namespace_added != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen backends[i]->v.namespace_added(quota, ns);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid quota_remove_user_namespace(struct mail_namespace *ns)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *const *namespaces;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota = ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(ns->user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota == NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* no quota for this namespace */
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen namespaces = array_get(&quota->namespaces, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (namespaces[i] == ns) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_delete(&quota->namespaces, i, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root_iter *
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenquota_root_iter_init(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root_iter *iter;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter = i_new(struct quota_root_iter, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen iter->quota = box->list->ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->user);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->box = box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return iter;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenbool quota_root_is_namespace_visible(struct quota_root *root,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *ns)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen{
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen struct mailbox_list *list = ns->list;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen struct mail_storage *storage;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen /* this check works as long as there is only one storage per list */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0)
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen return FALSE;
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen if (root->quota->unwanted_ns == ns)
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen return FALSE;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen
766115d2b2e6dbcf59f90d3b3866851cf6f740feTimo Sirainen if (root->ns_prefix != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (root->ns != ns)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ns->owner == NULL)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen }
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return TRUE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen}
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainenstatic bool
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainenquota_root_is_visible(struct quota_root *root, struct mailbox *box,
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen bool enforce)
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen{
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (root->no_enforcing && enforce) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen /* we don't want to include this root in quota enforcing */
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!quota_root_is_namespace_visible(root, box->list->ns))
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (array_count(&root->quota->roots) == 1) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen /* a single quota root: don't bother checking further */
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return TRUE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return root->backend.v.match_box == NULL ? TRUE :
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen root->backend.v.match_box(root, box);
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen}
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo 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++) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[iter->i], iter->box, FALSE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen ret = roots[iter->i]->resource_ret;
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen if (ret == -1) {
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen ret = quota_get_resource(roots[iter->i], "",
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen &value, &limit);
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen }
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 }
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen roots[iter->i]->resource_ret = ret;
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
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct quota_root *quota_root_lookup(struct mail_user *user, const char *name)
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota = quota_get_mail_user_quota(user);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (strcmp(roots[i]->set->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{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return root->set->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
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainenbool quota_root_is_hidden(struct quota_root *root)
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainen{
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainen return root->hidden;
3f7583189249a28892cd5bd69e15681c7a8a619bTimo Sirainen}
3f7583189249a28892cd5bd69e15681c7a8a619bTimo 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
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);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret <= 0)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return ret;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (quota_root_get_rule_limits(root, mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit, &count_limit) < 0)
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen
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
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (kilobytes) {
e265563be2031bc1f9b4ef15888e31a94a344e5eTimo Sirainen *value_r = (*value_r + 1023) / 1024;
e265563be2031bc1f9b4ef15888e31a94a344e5eTimo Sirainen *limit_r = (*limit_r + 1023) / 1024;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return *limit_r == 0 ? 0 : 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainenint quota_set_resource(struct quota_root *root, const char *name,
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen uint64_t value, const char **error_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen struct dict_transaction_context *trans;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen const char *key;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (root->set->limit_set == NULL) {
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen *error_r = MAIL_ERRSTR_NO_PERMISSION;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen }
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (strcasecmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen key = "storage";
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen else if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen key = "bytes";
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen else if (strcasecmp(name, QUOTA_NAME_MESSAGES) == 0)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen key = "messages";
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen else {
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen *error_r = t_strdup_printf("Unsupported resource name: %s", name);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen }
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (root->limit_set_dict == NULL) {
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen struct dict_settings set;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen memset(&set, 0, sizeof(set));
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.username = root->quota->user->username;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.base_dir = root->quota->user->set->base_dir;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen if (mail_user_get_home(root->quota->user, &set.home_dir) <= 0)
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.home_dir = NULL;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen if (dict_init_full(root->set->limit_set, &set,
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen &root->limit_set_dict, error_r) < 0)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen }
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen trans = dict_transaction_begin(root->limit_set_dict);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen key = t_strdup_printf(QUOTA_LIMIT_SET_PATH"%s", key);
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen dict_set(trans, key, dec2str(value));
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen if (dict_transaction_commit(&trans) < 0) {
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen *error_r = "Internal quota limit update error";
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return -1;
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen }
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_transaction_context *ctx;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx = i_new(struct quota_transaction_context, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->quota = box->list->ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->user);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen i_assert(ctx->quota != NULL);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->box = box;
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen ctx->bytes_ceil = (uint64_t)-1;
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen ctx->bytes_ceil2 = (uint64_t)-1;
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen ctx->count_ceil = (uint64_t)-1;
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen
10ccd0e45768923d69be459e87ef6cd2574cec60Timo Sirainen if (box->storage->user->dsyncing) {
10ccd0e45768923d69be459e87ef6cd2574cec60Timo Sirainen /* ignore quota for dsync */
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen ctx->limits_set = TRUE;
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ctx;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenstatic int quota_transaction_set_limits(struct quota_transaction_context *ctx)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen struct quota_root *const *roots;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen const char *mailbox_name;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen unsigned int i, count;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen uint64_t bytes_limit, count_limit, current, limit, diff;
50ecf65993bff429af04deef6c832deb019c76a5Timo Sirainen bool use_grace;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen int ret;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ctx->limits_set = TRUE;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen mailbox_name = mailbox_get_vname(ctx->box);
e66cd209fcab4817d2234d0121b404925dc60034Timo Sirainen /* use quota_grace only for LDA/LMTP */
50ecf65993bff429af04deef6c832deb019c76a5Timo Sirainen use_grace = (ctx->box->flags & MAILBOX_FLAG_POST_SESSION) != 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
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++) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen continue;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (quota_root_get_rule_limits(roots[i], mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &count_limit) < 0) {
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen ctx->failed = TRUE;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (bytes_limit > 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen QUOTA_NAME_STORAGE_BYTES,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen &current, &limit);
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (ret > 0) {
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen if (limit <= current) {
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen /* over quota */
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_ceil = 0;
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen ctx->bytes_ceil2 = 0;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = current - limit;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->bytes_over < diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_over = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen } else {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = limit - current;
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen if (ctx->bytes_ceil2 > diff)
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen ctx->bytes_ceil2 = diff;
50ecf65993bff429af04deef6c832deb019c76a5Timo Sirainen diff += !use_grace ? 0 :
a2f5f69de816fd9680ded4d1150e103f5dcda1beTimo Sirainen roots[i]->set->last_mail_max_extra_bytes;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->bytes_ceil > diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_ceil = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen } else if (ret < 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ctx->failed = TRUE;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen return -1;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (count_limit > 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen QUOTA_NAME_MESSAGES,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen &current, &limit);
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (ret > 0) {
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen if (limit <= current) {
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen /* over quota */
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_ceil = 0;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = current - limit;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->count_over < diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_over = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen } else {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = limit - current;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->count_ceil > diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_ceil = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen } else if (ret < 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ctx->failed = TRUE;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen return -1;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen}
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainenstatic void quota_warning_execute(struct quota_root *root, const char *cmd,
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen const char *last_arg)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen const char *socket_path, *const *args;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen string_t *str;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen int fd;
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainen
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainen if (root->quota->set->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("quota: Executing warning: %s", cmd);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
4f68fa8a117642e2c134a29d8e35569bce6c3158Timo Sirainen args = t_strsplit_spaces(cmd, " ");
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (last_arg != NULL) {
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen unsigned int count = str_array_length(args);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen const char **new_args = t_new(const char *, count + 2);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen memcpy(new_args, args, sizeof(const char *) * count);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen new_args[count] = last_arg;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen args = new_args;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path = args[0];
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen args++;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (*socket_path != '/') {
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path = t_strconcat(root->quota->user->set->base_dir, "/",
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path, NULL);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if ((fd = net_connect_unix_with_retries(socket_path, 1000)) < 0) {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen if (errno == EACCES) {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen i_error("quota: %s",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen eacces_error_get("net_connect_unix",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen socket_path));
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen } else {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen i_error("quota: net_connect_unix(%s) failed: %m",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen socket_path);
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str = t_str_new(1024);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen str_append(str, "VERSION\tscript\t3\t0\nnoreply\n");
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen for (; *args != NULL; args++) {
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append(str, *args);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append_c(str, '\n');
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append_c(str, '\n');
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen net_set_nonblock(fd, FALSE);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0)
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen i_error("write(%s) failed: %m", socket_path);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (close(fd) < 0)
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen i_error("close(%s) failed: %m", socket_path);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainenstatic void quota_warnings_execute(struct quota_transaction_context *ctx,
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen struct quota_root *root)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_warning_rule *warnings;
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
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen warnings = array_get_modifiable(&root->set->warning_rules, &count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (count == 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen &bytes_current, &bytes_limit) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen &count_current, &count_limit) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
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++) {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen if (quota_warning_match(&warnings[i],
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen bytes_before, bytes_current,
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen count_before, count_current)) {
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen quota_warning_execute(root, warnings[i].command, NULL);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen break;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenint quota_transaction_commit(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen struct quota_rule *rule;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_root *const *roots;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen unsigned int i, count;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen const char *mailbox_name;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen int ret = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *_ctx = NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (ctx->failed)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen ret = -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen else if (ctx->bytes_used != 0 || ctx->count_used != 0 ||
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen ctx->recalculate) T_BEGIN {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct quota_root *) warn_roots;
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen mailbox_name = mailbox_get_vname(ctx->box);
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen (void)mail_namespace_find_unalias(
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen ctx->box->storage->user->namespaces, &mailbox_name);
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen roots = array_get(&ctx->quota->roots, &count);
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen t_array_init(&warn_roots, count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen for (i = 0; i < count; i++) {
89adb28d8f041e8c0b9c5156f089bb2f8f478ee3Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, FALSE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = quota_root_rule_find(roots[i]->set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen mailbox_name);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (rule != NULL && rule->ignore) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* mailbox not included in quota */
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen continue;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (roots[i]->backend.v.update(roots[i], ctx) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen ret = -1;
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen else if (!ctx->sync_transaction)
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen array_append(&warn_roots, &roots[i], 1);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen /* execute quota warnings after all updates. this makes it
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen work correctly regardless of whether backend.get_resource()
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen returns updated values before backend.update() or not.
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen warnings aren't executed when dsync bring the user over,
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen because the user probably already got the warning on the
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen other replica. */
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen array_foreach(&warn_roots, roots)
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen quota_warnings_execute(ctx, *roots);
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen } T_END;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_free(ctx);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return ret;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainenstatic void
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainenquota_over_flag_check_root(struct mail_user *user, struct quota_root *root)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen{
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen const char *name, *flag_mask, *overquota_value, *overquota_script;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen const char *const *resources;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen unsigned int i;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen uint64_t value, limit;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen bool overquota_flag, cur_overquota = FALSE;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen int ret;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen name = t_strconcat(root->set->set_name, "_over_script", NULL);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen overquota_script = mail_user_plugin_getenv(user, name);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (overquota_script == NULL)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen return;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen /* e.g.: quota_over_flag_value=TRUE or quota_over_flag_value=* */
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen name = t_strconcat(root->set->set_name, "_over_flag_value", NULL);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen flag_mask = mail_user_plugin_getenv(user, name);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (flag_mask == NULL)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen return;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen /* compare quota_over_flag's value to quota_over_flag_value and
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen save the result. */
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen name = t_strconcat(root->set->set_name, "_over_flag", NULL);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen overquota_value = mail_user_plugin_getenv(user, name);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen overquota_flag = overquota_value != NULL &&
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen overquota_value[0] != '\0' &&
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen wildcard_match_icase(overquota_value, flag_mask);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen resources = quota_root_get_resources(root);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen for (i = 0; resources[i] != NULL; i++) {
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen ret = quota_get_resource(root, "", resources[i], &value, &limit);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (ret < 0) {
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen /* can't reliably verify this */
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen if (root->quota->set->debug) {
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen i_debug("quota: Quota %s lookup failed - can't verify quota_over_flag",
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen resources[i]);
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen }
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen return;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen }
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen if (root->quota->set->debug) {
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen i_debug("quota: quota_over_flag check: %s ret=%d value=%llu limit=%llu",
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen resources[i], ret,
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen (unsigned long long)value,
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen (unsigned long long)limit);
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen }
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (ret > 0 && value > limit)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen cur_overquota = TRUE;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen }
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen if (root->quota->set->debug) {
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen i_debug("quota: quota_over_flag=%d(%s) vs currently overquota=%d",
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen overquota_flag, overquota_value != NULL ? "(null)" : overquota_value,
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen cur_overquota);
9871c4b8a06fc26de2101b825fedd7c80e8195b3Timo Sirainen }
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen if (cur_overquota != overquota_flag)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen quota_warning_execute(root, overquota_script, overquota_value);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen}
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainenvoid quota_over_flag_check(struct mail_user *user, struct quota *quota)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen{
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen struct quota_root *const *roots;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen unsigned int i, count;
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen roots = array_get(&quota->roots, &count);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen for (i = 0; i < count; i++)
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen quota_over_flag_check_root(user, roots[i]);
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen}
666286d8ecc6c450b2232dcc628f79454215acfcTimo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenvoid quota_transaction_rollback(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *_ctx = NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_free(ctx);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail *mail, bool *too_large_r)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen uoff_t size;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen int ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = quota_test_alloc(ctx, size, 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{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (ctx->failed)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (!ctx->limits_set) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (quota_transaction_set_limits(ctx) < 0)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen /* this is a virtual function mainly for trash plugin and similar,
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen which may automatically delete mails to stay under quota. */
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return ctx->quota->set->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;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen int ret;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = FALSE;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen if (!quota_transaction_is_over(ctx, size))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 1;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen /* limit reached. only thing left to do now is to set too_large_r. */
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
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen ret = quota_root_get_rule_limits(roots[i],
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen mailbox_get_vname(ctx->box),
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit, &count_limit);
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (ret < 0)
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if size is bigger than any limit, then
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it is bigger than the lowest limit */
4c7e360ab67642c08f82c709445ea45aa170632dTimo Sirainen if (bytes_limit > 0 && size > bytes_limit) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo 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
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->bytes_used += size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen ctx->bytes_ceil = ctx->bytes_ceil2;
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
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) < 0)
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}