mailbox-list-fs.c revision 10a2e8716e9040908fb60fcda56b5315ea4c1312
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct mailbox_list *fs_list_alloc(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create("fs list", 2048);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list = p_new(pool, struct fs_mailbox_list, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list->temp_prefix = p_strconcat(pool, GLOBAL_TEMP_PREFIX,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void fs_list_deinit(struct mailbox_list *_list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool fs_list_is_valid_common(const char *name, size_t *len_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_is_valid_common_nonfs(struct mailbox_list *list, const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* make sure it's not absolute path */
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 ||
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *const *names;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *n = *names;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*n == '\0')
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen break; /* // */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (*n == '.') {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen break; /* ./ */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen break; /* ../ */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* don't allow maildir_name to be used as part
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen of the mailbox name */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_is_valid_pattern(struct mailbox_list *list, const char *pattern)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return fs_list_is_valid_common_nonfs(list, pattern);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_is_valid_existing_name(struct mailbox_list *list, const char *name)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return fs_list_is_valid_common_nonfs(list, name);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenfs_is_valid_create_name(struct mailbox_list *list, const char *name)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (list->mail_set->mail_full_filesystem_access)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_name_is_too_large(name, '/'))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return fs_list_is_valid_common_nonfs(list, name);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic const char *
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_list_get_path(struct mailbox_list *_list, const char *name,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const struct mailbox_list_settings *set = &_list->set;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen /* return root directories */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen i_assert(mailbox_list_is_valid_pattern(_list, name));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_try_get_absolute_path(_list, &name))
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return t_strdup_printf("%s/%s%s", set->root_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return t_strdup_printf("%s/%s%s", set->alt_dir,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return t_strdup_printf("%s/%s%s", set->control_dir,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return t_strdup_printf("%s/%s%s", set->index_dir,
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 ||
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return t_strdup_printf("%s/%s%s/%s", root_dir,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenfs_list_get_mailbox_name_status(struct mailbox_list *_list, const char *name,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen _list->v.is_internal_name == NULL || !S_ISDIR(st.st_mode)) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* check if mailbox is selectable */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (mailbox_list_mailbox(_list, name, &flags) < 0)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if ((flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* see if the directory exists */
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen if (strcmp(path, dir_path) != 0 && stat(dir_path, &st) == 0) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (!mailbox_list_is_valid_create_name(_list, name)) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mailbox_list_set_critical(_list, "stat(%s) failed: %m", path);
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenstatic const char *
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenfs_list_get_temp_prefix(struct mailbox_list *_list, bool global)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return global ? GLOBAL_TEMP_PREFIX : list->temp_prefix;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenstatic const char *
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenfs_list_join_refpattern(struct mailbox_list *_list ATTR_UNUSED,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* pattern overrides reference */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* merge reference and pattern */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenstatic int fs_list_set_subscribed(struct mailbox_list *_list,
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen path = t_strconcat(_list->set.control_dir != NULL ?
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return subsfile_set_subscribed(_list, path, list->temp_prefix,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainenstatic int mailbox_is_selectable(struct mailbox_list *list, const char *name)
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (mailbox_list_mailbox(list, name, &flags) < 0)
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen return (flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0 ? 1 : 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainenfs_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* we only need to make sure that the parent directory exists */
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen mailbox_list_get_dir_permissions(list, NULL, &mode,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (!directory && *list->set.mailbox_dir_name == '\0') {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if ((ret = mailbox_is_selectable(list, name)) <= 0)
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen "Mailbox already exists");
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);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic const char *mailbox_list_fs_get_trash_dir(struct mailbox_list *list)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return t_strdup_printf("%s/"MAILBOX_LIST_FS_TRASH_DIR_NAME, root_dir);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_delete_mailbox(struct mailbox_list *list, const char *name)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_delete_mailbox_file(list, 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,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* try to delete the parent directory */
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m",
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen bool rmdir_path = *list->set.maildir_name != '\0';
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (mailbox_list_delete_mailbox_nonrecursive(list, name, path,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_rmdir(struct mailbox_list *list, const char *name,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_DIR,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int fs_list_delete_dir(struct mailbox_list *list, const char *name)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *path, *child_name, *child_path, *p;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
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 child_path = mailbox_list_get_path(list, child_name,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (strncmp(path, child_path, strlen(path)) == 0) {
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen /* drop the "/child" part out. */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (rmdir(t_strdup_until(child_path, p)) == 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* try again */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "Mailbox has children, delete them first");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
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)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen oldpath = mailbox_list_get_path(oldlist, oldname, type);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen newpath = mailbox_list_get_path(newlist, newname, type);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (rmdir_parent && (p = strrchr(oldpath, '/')) != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* avoid leaving empty directories lying around */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen mailbox_list_delete_until_root(oldlist, oldpath, type);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic int fs_list_rename_mailbox(struct mailbox_list *oldlist,
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;
if (rename_children) {
oldname));
if (p != NULL) {
newpath);
if (!rename_children) {
.props = 0,
NULL,
NULL,