mailbox-list-fs.c revision 10a2e8716e9040908fb60fcda56b5315ea4c1312
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "hostpid.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mkdir-parents.h"
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen#include "mailbox-log.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "subscription-file.h"
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen#include "mail-storage.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "mailbox-list-delete.h"
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen#include "mailbox-list-fs.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <stdio.h>
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include <unistd.h>
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include <sys/stat.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define GLOBAL_TEMP_PREFIX ".temp."
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenextern struct mailbox_list fs_mailbox_list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct mailbox_list *fs_list_alloc(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct fs_mailbox_list *list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_t pool;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create("fs list", 2048);
4c1deab456fe8877bf025d11843167ac1f36327aTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list = p_new(pool, struct fs_mailbox_list, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list->list = fs_mailbox_list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list->list.pool = pool;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list->temp_prefix = p_strconcat(pool, GLOBAL_TEMP_PREFIX,
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen my_hostname, ".", my_pid, ".", NULL);
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen return &list->list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void fs_list_deinit(struct mailbox_list *_list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool_unref(&list->list.pool);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool fs_list_is_valid_common(const char *name, size_t *len_r)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen *len_r = strlen(name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (name[0] == '\0' || name[*len_r-1] == '/')
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return FALSE;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_is_valid_common_nonfs(struct mailbox_list *list, const char *name)
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen bool ret, allow_internal_dirs;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* make sure it's not absolute path */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*name == '/' || *name == '~')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen /* make sure the mailbox name doesn't contain any foolishness:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "../" could give access outside the mailbox directory.
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen "./" and "//" could fool ACL checks. */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen allow_internal_dirs = list->v.is_internal_name == NULL ||
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen *list->set.maildir_name != '\0';
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen T_BEGIN {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *const *names;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen names = t_strsplit(name, "/");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (; *names != NULL; names++) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *n = *names;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*n == '\0')
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen break; /* // */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*n == '.') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (n[1] == '\0')
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen break; /* ./ */
72ba6a8227bfdf02282d7e4f4c49194af5c354ddTimo Sirainen if (n[1] == '.' && n[2] == '\0')
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen break; /* ../ */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*list->set.maildir_name != '\0' &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen strcmp(list->set.maildir_name, n) == 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* don't allow maildir_name to be used as part
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen of the mailbox name */
72ba6a8227bfdf02282d7e4f4c49194af5c354ddTimo Sirainen break;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!allow_internal_dirs &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list->v.is_internal_name(list, n))
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen break;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = *names == NULL;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen } T_END;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic bool
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_is_valid_pattern(struct mailbox_list *list, const char *pattern)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return fs_list_is_valid_common_nonfs(list, pattern);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic bool
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_is_valid_existing_name(struct mailbox_list *list, const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t len;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (!fs_list_is_valid_common(name, &len))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return FALSE;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return fs_list_is_valid_common_nonfs(list, name);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen}
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic bool
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenfs_is_valid_create_name(struct mailbox_list *list, const char *name)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen{
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen size_t len;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (!fs_list_is_valid_common(name, &len))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return FALSE;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (len > FS_MAX_CREATE_MAILBOX_NAME_LENGTH)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return FALSE;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
7fa561fecd106f0e3f58315db2402f7ba83c4226Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_name_is_too_large(name, '/'))
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen return FALSE;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return fs_list_is_valid_common_nonfs(list, name);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen}
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic const char *
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_list_get_path(struct mailbox_list *_list, const char *name,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen enum mailbox_list_path_type type)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const struct mailbox_list_settings *set = &_list->set;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *root_dir;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (name == NULL) {
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen /* return root directories */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return mailbox_list_get_root_path(set, type);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen i_assert(mailbox_list_is_valid_pattern(_list, name));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_try_get_absolute_path(_list, &name))
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return name;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen root_dir = set->root_dir;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen switch (type) {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen case MAILBOX_LIST_PATH_TYPE_DIR:
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (*set->maildir_name != '\0')
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return t_strdup_printf("%s/%s%s", set->root_dir,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen set->mailbox_dir_name, name);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen break;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (set->alt_dir == NULL)
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return NULL;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if (*set->maildir_name != '\0')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return t_strdup_printf("%s/%s%s", set->alt_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen set->mailbox_dir_name, name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen root_dir = set->alt_dir;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case MAILBOX_LIST_PATH_TYPE_MAILBOX:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (set->alt_dir == NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen root_dir = set->alt_dir;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case MAILBOX_LIST_PATH_TYPE_CONTROL:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (set->control_dir != NULL)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return t_strdup_printf("%s/%s%s", set->control_dir,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen set->mailbox_dir_name, name);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen break;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen case MAILBOX_LIST_PATH_TYPE_INDEX:
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (set->index_dir != NULL) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*set->index_dir == '\0')
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return "";
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return t_strdup_printf("%s/%s%s", set->index_dir,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen set->mailbox_dir_name, name);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen }
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen break;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (type == MAILBOX_LIST_PATH_TYPE_ALT_DIR ||
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen type == MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX) {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* don't use inbox_path */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen } else if (strcmp(name, "INBOX") == 0 && set->inbox_path != NULL) {
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen /* If INBOX is a file, index and control directories are
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen located in root directory. */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if ((_list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0 ||
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen type == MAILBOX_LIST_PATH_TYPE_MAILBOX ||
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen type == MAILBOX_LIST_PATH_TYPE_DIR)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return set->inbox_path;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (*set->maildir_name == '\0') {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return t_strdup_printf("%s/%s%s", root_dir,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen set->mailbox_dir_name, name);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen } else {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return t_strdup_printf("%s/%s%s/%s", root_dir,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen set->mailbox_dir_name, name,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen set->maildir_name);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen }
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen}
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainenstatic int
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenfs_list_get_mailbox_name_status(struct mailbox_list *_list, const char *name,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen enum mailbox_name_status *status)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen{
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen struct stat st;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *path, *dir_path;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen enum mailbox_info_flags flags;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (strcmp(name, "INBOX") == 0 &&
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen *status = MAILBOX_NAME_EXISTS_MAILBOX;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen return 0;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen }
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen path = mailbox_list_get_path(_list, name,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (stat(path, &st) == 0) {
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (*_list->set.maildir_name != '\0' ||
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen _list->v.is_internal_name == NULL || !S_ISDIR(st.st_mode)) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen *status = MAILBOX_NAME_EXISTS_MAILBOX;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* check if mailbox is selectable */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (mailbox_list_mailbox(_list, name, &flags) < 0)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen return -1;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if ((flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen *status = MAILBOX_NAME_EXISTS_MAILBOX;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen else
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen *status = MAILBOX_NAME_EXISTS_DIR;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen return 0;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (errno == ENOENT) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* see if the directory exists */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen dir_path = mailbox_list_get_path(_list, name,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen if (strcmp(path, dir_path) != 0 && stat(dir_path, &st) == 0) {
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen *status = MAILBOX_NAME_EXISTS_DIR;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen return 0;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen errno = ENOENT;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (!mailbox_list_is_valid_create_name(_list, name)) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen *status = MAILBOX_NAME_INVALID;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return 0;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (ENOTFOUND(errno) || errno == EACCES) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen *status = MAILBOX_NAME_VALID;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (errno == ENOTDIR) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen *status = MAILBOX_NAME_NOINFERIORS;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return 0;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen } else {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mailbox_list_set_critical(_list, "stat(%s) failed: %m", path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return -1;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen }
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen}
1e4623e33bc4e37e61fcdc1e24e22327e49e303aTimo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenstatic const char *
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenfs_list_get_temp_prefix(struct mailbox_list *_list, bool global)
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen{
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return global ? GLOBAL_TEMP_PREFIX : list->temp_prefix;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic const char *
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_list_join_refpattern(struct mailbox_list *_list ATTR_UNUSED,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *ref, const char *pattern)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen{
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (*pattern == '/' || *pattern == '~') {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* pattern overrides reference */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen } else if (*ref != '\0') {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* merge reference and pattern */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen pattern = t_strconcat(ref, pattern, NULL);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return pattern;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen}
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenstatic int fs_list_set_subscribed(struct mailbox_list *_list,
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen const char *name, bool set)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen{
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen const char *path;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen path = t_strconcat(_list->set.control_dir != NULL ?
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen _list->set.control_dir : _list->set.root_dir,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "/", _list->set.subscription_fname, NULL);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return subsfile_set_subscribed(_list, path, list->temp_prefix,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen name, set);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen}
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainenstatic int mailbox_is_selectable(struct mailbox_list *list, const char *name)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen enum mailbox_info_flags flags;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (mailbox_list_mailbox(list, name, &flags) < 0)
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen return -1;
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen return (flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0 ? 1 : 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen}
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainenstatic int
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainenfs_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen bool directory)
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen{
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen const char *path, *gid_origin, *p;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mode_t mode;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen gid_t gid;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen bool create_parent_dir;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen int ret;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen path = mailbox_list_get_path(list, name,
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen directory ? MAILBOX_LIST_PATH_TYPE_DIR :
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen create_parent_dir = !directory &&
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (create_parent_dir) {
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* we only need to make sure that the parent directory exists */
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen p = strrchr(path, '/');
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (p == NULL)
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen return 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen path = t_strdup_until(path, p);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen }
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen mailbox_list_get_dir_permissions(list, NULL, &mode,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen &gid, &gid_origin);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return 0;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen else if (errno == EEXIST) {
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen if (create_parent_dir)
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen return 0;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (!directory && *list->set.mailbox_dir_name == '\0') {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if ((ret = mailbox_is_selectable(list, name)) <= 0)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return ret;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen "Mailbox already exists");
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen } else if (errno == ENOTDIR) {
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen "Mailbox doesn't allow inferior mailboxes");
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen } else if (!mailbox_list_set_error_from_errno(list)) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_critical(list, "mkdir(%s) failed: %m", path);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return -1;
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic const char *mailbox_list_fs_get_trash_dir(struct mailbox_list *list)
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *root_dir;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen root_dir = mailbox_list_get_path(list, NULL,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return t_strdup_printf("%s/"MAILBOX_LIST_FS_TRASH_DIR_NAME, root_dir);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_delete_mailbox(struct mailbox_list *list, const char *name)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *path, *trash_dir;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen int ret = 0;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_delete_mailbox_file(list, name) < 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return -1;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = 1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (*list->set.maildir_name != '\0' &&
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen *list->set.mailbox_dir_name != '\0' && ret == 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen trash_dir = mailbox_list_fs_get_trash_dir(list);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen ret = mailbox_list_delete_maildir_via_trash(list, name,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen trash_dir);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (ret < 0)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* try to delete the parent directory */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen path = mailbox_list_get_path(list, name,
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen if (rmdir(path) < 0 && errno != ENOENT &&
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen errno != ENOTEMPTY && errno != EEXIST) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m",
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen path);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen if (ret == 0) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen bool rmdir_path = *list->set.maildir_name != '\0';
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen path = mailbox_list_get_path(list, name,
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mailbox_list_delete_mailbox_nonrecursive(list, name, path,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen rmdir_path) < 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen mailbox_list_delete_finish(list, name);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen return 0;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen}
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_rmdir(struct mailbox_list *list, const char *name,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *path)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen uint8_t dir_sha128[MAIL_GUID_128_SIZE];
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (rmdir(path) < 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_name_get_sha128(name, dir_sha128);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_DIR,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen dir_sha128);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return 0;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_delete_dir(struct mailbox_list *list, const char *name)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *path, *child_name, *child_path, *p;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (fs_list_rmdir(list, name, path) == 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return 0;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (errno == ENOENT) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen } else if (errno == ENOTEMPTY || errno == EEXIST) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* mbox workaround: if only .imap/ directory is preventing the
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen deletion, remove it */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen child_name = t_strdup_printf("%s%cchild", name,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen list->ns->real_sep);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen child_path = mailbox_list_get_path(list, child_name,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (strncmp(path, child_path, strlen(path)) == 0) {
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen /* drop the "/child" part out. */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen p = strrchr(child_path, '/');
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (rmdir(t_strdup_until(child_path, p)) == 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* try again */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (fs_list_rmdir(list, name, path) == 0)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return 0;
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen }
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "Mailbox has children, delete them first");
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen } else {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int rename_dir(struct mailbox_list *oldlist, const char *oldname,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct mailbox_list *newlist, const char *newname,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen enum mailbox_list_path_type type, bool rmdir_parent)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainen const char *oldpath, *newpath, *p;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen oldpath = mailbox_list_get_path(oldlist, oldname, type);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen newpath = mailbox_list_get_path(newlist, newname, type);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (strcmp(oldpath, newpath) == 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return 0;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen oldpath, newpath);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return -1;
48ca4c43ebca6fa3eee217bd4439cba5b5376dd4Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (rmdir_parent && (p = strrchr(oldpath, '/')) != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen oldpath = t_strdup_until(oldpath, p);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (rmdir(oldpath) < 0 && errno != ENOENT &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen errno != ENOTEMPTY && errno != EEXIST) {
77c462c3a415536f9c87028ee34546ee96fd1445Timo Sirainen mailbox_list_set_critical(oldlist,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen "rmdir(%s) failed: %m", oldpath);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* avoid leaving empty directories lying around */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen mailbox_list_delete_until_root(oldlist, oldpath, type);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic int fs_list_rename_mailbox(struct mailbox_list *oldlist,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen const char *oldname,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_list *newlist,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *newname, bool rename_children)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen struct mail_storage *oldstorage;
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen const char *oldpath, *newpath, *alt_newpath, *root_path;
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen const char *p, *origin;
8854395cdd21ca521b37ce669f3acb8445792b20Timo Sirainen enum mailbox_list_path_type path_type, alt_path_type;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct stat st;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mode_t mode;
gid_t gid;
bool rmdir_parent = FALSE;
if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
return -1;
if (rename_children) {
path_type = MAILBOX_LIST_PATH_TYPE_DIR;
alt_path_type = MAILBOX_LIST_PATH_TYPE_ALT_DIR;
} else if (mail_storage_is_mailbox_file(oldstorage) ||
*oldlist->set.maildir_name != '\0') {
path_type = MAILBOX_LIST_PATH_TYPE_MAILBOX;
alt_path_type = MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX;
} else {
/* we can't do this, our children would get renamed with us */
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Can't rename mailbox without its children.");
return -1;
}
oldpath = mailbox_list_get_path(oldlist, oldname, path_type);
newpath = mailbox_list_get_path(newlist, newname, path_type);
alt_newpath = mailbox_list_get_path(newlist, newname, alt_path_type);
root_path = mailbox_list_get_path(oldlist, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(oldpath, root_path) == 0) {
/* most likely INBOX */
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
t_strdup_printf("Renaming %s isn't supported.",
oldname));
return -1;
}
/* create the hierarchy */
p = strrchr(newpath, '/');
if (p != NULL) {
mailbox_list_get_dir_permissions(newlist, NULL, &mode,
&gid, &origin);
p = t_strdup_until(newpath, p);
if (mkdir_parents_chgrp(p, mode, gid, origin) < 0 &&
errno != EEXIST) {
if (mailbox_list_set_error_from_errno(oldlist))
return -1;
mailbox_list_set_critical(oldlist,
"mkdir_parents(%s) failed: %m", p);
return -1;
}
}
/* first check that the destination mailbox doesn't exist.
this is racy, but we need to be atomic and there's hardly any
possibility that someone actually tries to rename two mailboxes
to same new one */
if (lstat(newpath, &st) == 0) {
mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
"Target mailbox already exists");
return -1;
} else if (errno == ENOTDIR) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Target mailbox doesn't allow inferior mailboxes");
return -1;
} else if (errno != ENOENT && errno != EACCES) {
mailbox_list_set_critical(oldlist, "lstat(%s) failed: %m",
newpath);
return -1;
}
if (alt_newpath != NULL) {
if (stat(alt_newpath, &st) == 0) {
/* race condition or a directory left there lying around?
safest to just report error. */
mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
"Target mailbox already exists");
return -1;
} else if (errno != ENOENT) {
mailbox_list_set_critical(oldlist, "stat(%s) failed: %m",
alt_newpath);
return -1;
}
}
if (rename(oldpath, newpath) < 0) {
if (ENOTFOUND(errno)) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
} else if (!mailbox_list_set_error_from_errno(oldlist)) {
mailbox_list_set_critical(oldlist,
"rename(%s, %s) failed: %m", oldpath, newpath);
}
return -1;
}
if (!rename_children) {
/* if there are no child mailboxes, get rid of the mailbox
directory entirely. */
oldpath = mailbox_list_get_path(oldlist, oldname,
MAILBOX_LIST_PATH_TYPE_DIR);
if (rmdir(oldpath) == 0)
rmdir_parent = TRUE;
else if (errno != ENOENT &&
errno != ENOTEMPTY && errno != EEXIST) {
mailbox_list_set_critical(oldlist,
"rmdir(%s) failed: %m", oldpath);
}
}
if (alt_newpath != NULL) {
(void)rename_dir(oldlist, oldname, newlist, newname,
alt_path_type, rmdir_parent);
}
(void)rename_dir(oldlist, oldname, newlist, newname,
MAILBOX_LIST_PATH_TYPE_CONTROL, rmdir_parent);
(void)rename_dir(oldlist, oldname, newlist, newname,
MAILBOX_LIST_PATH_TYPE_INDEX, rmdir_parent);
return 0;
}
struct mailbox_list fs_mailbox_list = {
.name = MAILBOX_LIST_NAME_FS,
.hierarchy_sep = '/',
.props = 0,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
{
fs_list_alloc,
fs_list_deinit,
NULL,
fs_is_valid_pattern,
fs_is_valid_existing_name,
fs_is_valid_create_name,
fs_list_get_path,
fs_list_get_mailbox_name_status,
fs_list_get_temp_prefix,
fs_list_join_refpattern,
fs_list_iter_init,
fs_list_iter_next,
fs_list_iter_deinit,
fs_list_get_mailbox_flags,
NULL,
fs_list_set_subscribed,
fs_list_create_mailbox_dir,
fs_list_delete_mailbox,
fs_list_delete_dir,
fs_list_rename_mailbox
}
};