bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_maildir;
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainenstatic struct dotlock_settings dotlock_settings = {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildir_sum_dir(const char *dir, uint64_t *total_bytes,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi uint64_t *total_count, const char **error_r)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen const char *p;
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi *error_r = t_strdup_printf("opendir(%s) failed: %m", dir);
b83f52b3ac3736d7f509db7ba80360d89f8a776dTimo Sirainen (dp->d_name[1] == '\0' || dp->d_name[1] == '.'))
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* ,S=nnnn[:,] */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* not in expected format, fallback to stat() */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen } else if (errno != ENOENT && errno != ESTALE) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi *error_r = t_strdup_printf("closedir(%s) failed: %m", dir);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmaildir_list_init(struct maildir_quota_root *root, struct mailbox_list *list)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic bool maildir_set_next_path(struct maildir_list_context *ctx)
17ec7fd70556e1811c758449d6fa29fa52f2c410Martti Rannanjärvi storage_name = mailbox_list_get_storage_name(
17ec7fd70556e1811c758449d6fa29fa52f2c410Martti Rannanjärvi if (mailbox_list_get_path(ctx->list, storage_name,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic const char *
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildir_list_next(struct maildir_list_context *ctx, time_t *mtime_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ctx->info = mailbox_list_iter_next(ctx->iter);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = quota_root_rule_find(ctx->root->root.set,
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* mailbox not included in quota */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* ignore if the directory got lost, stale or if it was
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen actually a file and not a directory */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (errno != ENOENT && errno != ESTALE && errno != ENOTDIR) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_error("stat(%s) failed: %m", str_c(ctx->path));
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvistatic int maildir_list_deinit(struct maildir_list_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int ret = mailbox_list_iter_deinit(&ctx->iter);
bf20e0e1aa622d73df3ea763a14f5db38f40ea7bMartti Rannanjärvi "Listing mailboxes failed: %s",
bf20e0e1aa622d73df3ea763a14f5db38f40ea7bMartti Rannanjärvi mailbox_list_get_last_internal_error(ctx->list, NULL));
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenmaildirs_check_have_changed(struct maildir_quota_root *root,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi struct mail_namespace *ns, time_t latest_mtime,
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen while (maildir_list_next(ctx, &mtime) != NULL) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildir_list_deinit(ctx, error_r) < 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_write(struct maildir_quota_root *root, const char *path)
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen /* figure out what permissions we should use for maildirsize.
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen use the inbox namespace's permissions if possible. */
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen perm.file_create_mode = 0600; perm.dir_create_mode = 0700;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen namespaces = array_get(&root->root.quota->namespaces, &count);
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen for (i = 0; i < count; i++) {
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen if ((namespaces[i]->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen mailbox_list_get_root_permissions(namespaces[i]->list,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dotlock_settings.use_excl_lock = set->dotlock_use_excl;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dotlock_settings.nfs_flush = set->mail_nfs_storage;
52ec61a8d49986fa140639d371f75ac078c47be5Timo Sirainen fd = safe_mkstemp_hostpid_group(temp_path, perm.file_create_mode,
cb07373a0afd4b0635e10a6757bd22e46dc9cf61Timo Sirainen /* the control directory doesn't exist yet? create it */
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (mkdir_parents_chgrp(dir, perm.dir_create_mode,
b76bc28de1c65b7ed6b19c7873b294d3742f5d57Timo Sirainen /* if we have no limits, write 0S instead of an empty line */
b76bc28de1c65b7ed6b19c7873b294d3742f5d57Timo Sirainen if (_root->bytes_limit != 0 || _root->count_limit == 0) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, "%"PRId64"S", _root->bytes_limit);
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, "%"PRIu64"C", _root->count_limit);
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, "\n%"PRIu64" %"PRIu64"\n",
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0) {
52ec61a8d49986fa140639d371f75ac078c47be5Timo Sirainen i_error("write_full(%s) failed: %m", str_c(temp_path));
52ec61a8d49986fa140639d371f75ac078c47be5Timo Sirainen i_error("rename(%s, %s) failed: %m", str_c(temp_path), path);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void maildirsize_recalculate_init(struct maildir_quota_root *root)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int maildirsize_recalculate_namespace(struct maildir_quota_root *root,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen while ((dir = maildir_list_next(ctx, &mtime)) != NULL) {
17ec7fd70556e1811c758449d6fa29fa52f2c410Martti Rannanjärvi if (maildir_sum_dir(dir, &root->total_bytes,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildir_list_deinit(ctx, error_r) < 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic void maildirsize_rebuild_later(struct maildir_quota_root *root)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* FIXME: can't unlink(), because the limits would be lost. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_error("unlink(%s) failed: %m", root->maildirsize_path);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int maildirsize_recalculate_finish(struct maildir_quota_root *root,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* maildir didn't change, we can write the maildirsize file */
948dccd80c13b2b62e6c0c4599404495154c892eTimo Sirainen if ((ret = maildirsize_write(root, root->maildirsize_path)) < 0)
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvistatic int maildirsize_recalculate(struct maildir_quota_root *root,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* count mails from all namespaces */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen namespaces = array_get(&root->root.quota->namespaces, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!quota_root_is_namespace_visible(&root->root, namespaces[i]))
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirsize_recalculate_namespace(root, namespaces[i], error_r) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* check if any of the directories have changed */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!quota_root_is_namespace_visible(&root->root,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ret = maildirs_check_have_changed(root, namespaces[i],
948dccd80c13b2b62e6c0c4599404495154c892eTimo Sirainen return maildirsize_recalculate_finish(root, ret, error_r);
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenmaildir_parse_limit(const char *str, uint64_t *bytes_r, uint64_t *count_r)
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* 0 values mean unlimited */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen for (limit = t_strsplit(str, ","); *limit != NULL; limit++) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_parse_ullong(*limit, &value, &pos) < 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen switch (pos[0]) {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainenstatic int maildirsize_parse(struct maildir_quota_root *root,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint64_t message_bytes_limit, message_count_limit;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen /* first line contains the limits */
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen (void)maildir_parse_limit(lines[0], &message_bytes_limit,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* truncate too high limits to signed 64bit int range */
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen if (root->root.bytes_limit == (int64_t)message_bytes_limit &&
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen root->root.count_limit == (int64_t)message_count_limit) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* limits haven't changed */
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen } else if (root->root.set->force_default_rule) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen /* we know the limits and they've changed.
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen the file must be rewritten. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* we're using limits from the file. */
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen quota_root_recalculate_relative_rules(root->root.set,
ba3f68dfb8475299f43125c3e86985a713013c5dTimo Sirainen /* no quota lines. rebuild it. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* rest of the lines contains <bytes> <count> diffs */
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen for (lines++; *lines != NULL; lines++, line_count++) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (sscanf(*lines, "%lld %d", &bytes_diff, &count_diff) != 2)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* corrupted */
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen if ((total_bytes > _root->bytes_limit && _root->bytes_limit != 0) ||
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen (total_count > _root->count_limit && _root->count_limit != 0)) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* we're over quota. don't trust these values if the file
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen contains more than the initial summary line, or if the file
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen is older than 15 minutes. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen st.st_mtime < ioloop_time - MAILDIRSIZE_STALE_SECS)
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvistatic int maildirsize_open(struct maildir_quota_root *root,
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd_path(&root->fd, root->maildirsize_path);
0223007c8a72339fe40a732710203afb82f108a6Timo Sirainen root->fd = nfs_safe_open(root->maildirsize_path, O_RDWR | O_APPEND);
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi "open(%s) failed: %m", root->maildirsize_path);
7be291ff7fcb7d10a5f96db00282a40287b471c5Timo Sirainenstatic bool maildirsize_has_changed(struct maildir_quota_root *root)
7be291ff7fcb7d10a5f96db00282a40287b471c5Timo Sirainen nfs_flush_file_handle_cache(root->maildirsize_path);
7be291ff7fcb7d10a5f96db00282a40287b471c5Timo Sirainen nfs_flush_attr_cache_unlocked(root->maildirsize_path);
ed22384e18b005c6a518478c515e7bfdb9e110eeTimo Sirainen return root->last_size != st2.st_size || st1.st_ino != st2.st_ino ||
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvistatic int maildirsize_read(struct maildir_quota_root *root, bool *retry,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if ((ret = maildirsize_open(root, error_r)) <= 0)
4c5272b168b4d71a95a08d48cc5b29cd7b27f193Timo Sirainen /* @UNSAFE */
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen while ((ret = read(root->fd, buf + size, sizeof(buf)-1 - size)) != 0) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi "read(%s) failed: %m", root->maildirsize_path);
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen /* we'll need to recalculate the quota */
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen /* try to use the file even if we ran into some error. if we don't have
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen forced limits, we'll need to read the header to get them */
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen /* skip the last line if there's no LF at the end. Remove the last LF
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen so we don't get one empty line in the strsplit. */
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen while (size > 0 && buf[size-1] != '\n') size--;
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen /* the read failed and there's no usable header, fail. */
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen /* If there are any NUL bytes, the file is broken. */
0563ad5c7f179554623682f6fd7b98596901b49fTimo Sirainen for (i = 0; i < size; i++) {
37f5e4f22d8f0d6aeca6536fba84b396c2196364Timo Sirainen maildirsize_parse(root, root->fd, t_strsplit(buf, "\n")) > 0 &&
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* broken file / need recalculation */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenstatic bool maildirquota_limits_init(struct maildir_quota_root *root)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
282142061c85f892e52154e81b9f8d4393b3b0c3Timo Sirainen strcmp(storage->name, MAILDIR_STORAGE_NAME) != 0) {
282142061c85f892e52154e81b9f8d4393b3b0c3Timo Sirainen /* non-maildir namespace, skip */
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen i_warning("quota: Namespace '%s' is not Maildir, "
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen "skipping for Maildir++ quota",
79ce5b0d2f911f858fbc3f259f09a8dce00d3dc6Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_CONTROL,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvistatic int maildirquota_read_limits(struct maildir_quota_root *root,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi ret = maildirsize_read(root, &retry, error_r);
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvimaildirquota_refresh(struct maildir_quota_root *root, bool *recalculated_r,
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi ret = maildirquota_read_limits(root, error_r);
9f018a85c93145e789ea5365718cfc6dd954a913Timo Sirainen root->root.set->default_rule.bytes_limit == 0 &&
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->root.set->default_rule.count_limit == 0) {
2d71e0ea3006576961b47d91d564d31771676624Timo Sirainen /* no quota */
53101f0e1e998d9bf718689fdb1363c5f0a07b0fTimo Sirainen /* explicitly specified 0 as quota. keep the quota
53101f0e1e998d9bf718689fdb1363c5f0a07b0fTimo Sirainen updated even if it's not enforced. */
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi ret = maildirsize_recalculate(root, error_r);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic int maildirsize_update(struct maildir_quota_root *root,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* We rely on O_APPEND working in here. That isn't NFS-safe, but it
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen isn't necessarily that bad because the file is recreated once in
a8fcd55e88550ebb905249825bdb1eec7b9667ffTimo Sirainen a while, and sooner if corruption causes calculations to go
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen over quota. This is also how Maildir++ spec specifies it should be
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen if (write_full(root->fd, str, strlen(str)) < 0) {
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* deleted/replaced already, ignore */
15093714cd8484c0b7781e00de5ab6f991c558dcTimo Sirainen /* close the file to force a flush with NFS */
15093714cd8484c0b7781e00de5ab6f991c558dcTimo Sirainen i_error("close(%s) failed: %m", root->maildirsize_path);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_root *maildir_quota_alloc(void)
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainenstatic int maildir_quota_init(struct quota_root *_root, const char *args,
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen const char **error_r)
5ee92077753dae191aafca24da44f4f78e7f545cSergey Kitov return quota_root_default_init(_root, args, error_r);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic void maildir_quota_deinit(struct quota_root *_root)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenmaildir_quota_parse_rule(struct quota_root_settings *root_set ATTR_UNUSED,
5a8f244ec97d99fef45e86a0aa24b8f63b219616Timo Sirainen } else if (!maildir_parse_limit(str, &bytes, &count)) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi "quota-maildir: Invalid Maildir++ quota rule \"%s\"",
e83a11eb1dc0dea31754396e1d07c5205d810104Martti Rannanjärvistatic int maildir_quota_init_limits(struct quota_root *_root,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirquota_read_limits(root, &error) < 0) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi "quota-maildir: Failed to read limits: %s", error);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmaildir_quota_root_namespace_added(struct quota_root *_root,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmaildir_quota_namespace_added(struct quota *quota, struct mail_namespace *ns)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get_modifiable("a->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen if (roots[i]->backend.name == quota_backend_maildir.name &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen maildir_quota_root_namespace_added(roots[i], ns);
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic const char *const *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenmaildir_quota_root_get_resources(struct quota_root *root ATTR_UNUSED)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenmaildir_quota_get_resource(struct quota_root *_root, const char *name,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirquota_refresh(root, &recalculated, &error) < 0) {
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi *error_r = t_strdup_printf("Failed to get %s: %s", name, error);
5a001dd0848310e9ed6622442329ff346b189257Timo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0) {
5a001dd0848310e9ed6622442329ff346b189257Timo Sirainen } else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0) {
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = QUOTA_UNKNOWN_RESOURCE_ERROR_STRING;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_UNKNOWN_RESOURCE;
12aae0081cbdf86bfb330ab087a3824466234255Timo Sirainen struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
e394583a7c1121599799a35f205bf237f6a1ee04Timo Sirainen /* no limits */
63af428111bdf1975b06da83f98d072210514a36Timo Sirainen /* even though we don't really care about the limits in here ourself,
63af428111bdf1975b06da83f98d072210514a36Timo Sirainen we do want to make sure the header gets updated if the limits have
63af428111bdf1975b06da83f98d072210514a36Timo Sirainen changed. also this makes sure the maildirsize file is created if
63af428111bdf1975b06da83f98d072210514a36Timo Sirainen it doesn't exist. */
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirquota_refresh(root, &recalculated, &error) < 0) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi "quota-maildir: Could not update storage usage data: %s",
12aae0081cbdf86bfb330ab087a3824466234255Timo Sirainen /* quota was just recalculated and it already contains the changes
12aae0081cbdf86bfb330ab087a3824466234255Timo Sirainen we wanted to do. */
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirsize_recalculate(root, &error) < 0)
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi } else if (ctx->recalculate != QUOTA_RECALCULATE_DONT) {
6d1372638a3e4a0a70b25bf1a52ab826a36cd729Martti Rannanjärvi if (maildirsize_recalculate(root, &error) < 0)
46c6ebbfafc684c8e97287c9755f9ce5bc002952Timo Sirainen } else if (maildirsize_update(root, ctx->count_used, ctx->bytes_used) < 0) {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .init_limits = maildir_quota_init_limits,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .namespace_added = maildir_quota_namespace_added,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resources = maildir_quota_root_get_resources,