mailbox-list-fs.c revision e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2006-2012 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);
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo 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 char fs_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_get_path(struct mailbox_list *_list, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum mailbox_list_path_type type, const char **path_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct mailbox_list_settings *set = &_list->set;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* return root directories */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return mailbox_list_set_get_root_path(set, type, path_r) ? 1 : 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(mailbox_list_is_valid_name(_list, name, &error));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_try_get_absolute_path(_list, &name)) {
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", set->root_dir,
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", set->alt_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", set->control_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", set->index_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", set->index_pvt_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* don't use inbox_path */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if (strcmp(name, "INBOX") == 0 && set->inbox_path != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* If INBOX is a file, index and control directories are
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen located in root directory. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((_list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0 ||
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = t_strdup_printf("%s/%s%s", root_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = t_strdup_printf("%s/%s%s/%s", root_dir,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic const char *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_get_temp_prefix(struct mailbox_list *_list, bool global)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return global ? GLOBAL_TEMP_PREFIX : list->temp_prefix;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenstatic const char *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_join_refpattern(struct mailbox_list *_list ATTR_UNUSED,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* pattern overrides reference */
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen /* merge reference and pattern */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic int fs_list_set_subscribed(struct mailbox_list *_list,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen struct fs_mailbox_list *list = (struct fs_mailbox_list *)_list;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen path = t_strconcat(_list->set.control_dir != NULL ?
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return subsfile_set_subscribed(_list, path, list->temp_prefix,
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainenstatic const char *mailbox_list_fs_get_trash_dir(struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen root_dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return t_strdup_printf("%s/"MAILBOX_LIST_FS_TRASH_DIR_NAME, root_dir);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenfs_list_delete_maildir(struct mailbox_list *list, const char *name)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen trash_dir = mailbox_list_fs_get_trash_dir(list);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen ret = mailbox_list_delete_maildir_via_trash(list, name,
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen /* try to delete the parent directory */
a574952c01611899b8ecf81434dbbb3345f27518Timo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX,
a3fbf5236d3daec08f191e569cdc4758809cb05fTimo Sirainen return mailbox_list_delete_mailbox_nonrecursive(list, name, path,
a3fbf5236d3daec08f191e569cdc4758809cb05fTimo Sirainenstatic int fs_list_delete_mailbox(struct mailbox_list *list, const char *name)
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen ret = mailbox_list_delete_mailbox_file(list, name, path);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if (ret == 0 || (list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) != 0)
a574952c01611899b8ecf81434dbbb3345f27518Timo Sirainenstatic int fs_list_rmdir(struct mailbox_list *list, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_DIR,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int fs_list_delete_dir(struct mailbox_list *list, const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *path, *child_name, *child_path, *p;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if (errno == ENOTEMPTY || errno == EEXIST) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* mbox workaround: if only .imap/ directory is preventing the
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen deletion, remove it */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen child_name = t_strdup_printf("%s%cchild", name, sep);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen strncmp(path, child_path, strlen(path)) == 0) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* drop the "/child" part out. */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (rmdir(t_strdup_until(child_path, p)) == 0) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* try again */
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "Mailbox has children, delete them first");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int rename_dir(struct mailbox_list *oldlist, const char *oldname,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_list *newlist, const char *newname,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum mailbox_list_path_type type, bool rmdir_parent)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *oldpath, *newpath, *p, *oldparent, *newparent;
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen if (mailbox_list_get_path(oldlist, oldname, type, &oldpath) <= 0 ||
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen mailbox_list_get_path(newlist, newname, type, &newpath) <= 0)
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen oldparent = p == NULL ? "/" : t_strdup_until(oldpath, p);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen newparent = p == NULL ? "/" : t_strdup_until(newpath, p);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (strcmp(oldparent, newparent) != 0 && stat(oldpath, &st) == 0) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen /* make sure the newparent exists */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen mailbox_list_get_root_permissions(newlist, &perm);
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen if (mkdir_parents_chgrp(newparent, perm.dir_create_mode,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (mailbox_list_set_error_from_errno(oldlist))
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen mailbox_list_set_critical(oldlist, "rename(%s, %s) failed: %m",
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (rmdir_parent && (p = strrchr(oldpath, '/')) != NULL) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* avoid leaving empty directories lying around */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen mailbox_list_delete_until_root(oldlist, oldpath, type);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic int fs_list_rename_mailbox(struct mailbox_list *oldlist,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen const char *oldvname, *oldpath, *newpath, *alt_newpath, *root_path, *p;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen struct mailbox_permissions old_perm, new_perm;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen oldvname = mailbox_list_get_vname(oldlist, oldname);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (mailbox_list_get_storage(&oldlist, oldvname, &oldstorage) < 0)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (mailbox_list_get_path(newlist, newname, MAILBOX_LIST_PATH_TYPE_ALT_DIR,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen root_path = mailbox_list_get_root_forced(oldlist, MAILBOX_LIST_PATH_TYPE_MAILBOX);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* most likely INBOX */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen t_strdup_printf("Renaming %s isn't supported.",
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen mailbox_list_get_permissions(oldlist, oldname, &old_perm);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen mailbox_list_get_permissions(newlist, newname, &new_perm);
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen /* if we're renaming under another mailbox, require its permissions
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen to be same as ours. */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (strchr(newname, mailbox_list_get_hierarchy_sep(newlist)) != NULL &&
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen (new_perm.file_create_mode != old_perm.file_create_mode ||
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen new_perm.dir_create_mode != old_perm.dir_create_mode ||
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen new_perm.file_create_gid != old_perm.file_create_gid)) {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen "Renaming not supported across conflicting "
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen "directory permissions");
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* create the hierarchy */
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (mkdir_parents_chgrp(p, new_perm.dir_create_mode,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (mailbox_list_set_error_from_errno(oldlist))
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen "mkdir_parents(%s) failed: %m", p);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* first check that the destination mailbox doesn't exist.
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen this is racy, but we need to be atomic and there's hardly any
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen possibility that someone actually tries to rename two mailboxes
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen to same new one */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen "Target mailbox already exists");
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen "Target mailbox doesn't allow inferior mailboxes");
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen } else if (errno != ENOENT && errno != EACCES) {
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen mailbox_list_set_critical(oldlist, "lstat(%s) failed: %m",
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* race condition or a directory left there lying around?
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen safest to just report error. */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_EXISTS,
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen "Target mailbox already exists");
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen mailbox_list_set_critical(oldlist, "stat(%s) failed: %m",
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTFOUND,
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen } else if (!mailbox_list_set_error_from_errno(oldlist)) {
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen "rename(%s, %s) failed: %m", oldpath, newpath);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen (void)rename_dir(oldlist, oldname, newlist, newname,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen MAILBOX_LIST_PATH_TYPE_ALT_DIR, rmdir_parent);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen (void)rename_dir(oldlist, oldname, newlist, newname,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL, rmdir_parent);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen (void)rename_dir(oldlist, oldname, newlist, newname,