set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
}
-static int create_cydir(struct mail_storage *storage, struct mailbox_list *list,
- const char *path)
-{
- const char *origin;
- mode_t mode;
- gid_t gid;
-
- mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin);
- if (mkdir_parents_chgrp(path, mode, gid, origin) < 0 &&
- errno != EEXIST) {
- if (!mail_storage_set_error_from_errno(storage)) {
- mail_storage_set_critical(storage,
- "mkdir(%s) failed: %m", path);
- }
- return -1;
- }
- return 0;
-}
-
static struct mailbox *
cydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
const char *name, struct istream *input,
/* exists, open it */
} else if (errno == ENOENT && strcmp(box->name, "INBOX") == 0) {
/* INBOX always exists, create it */
- if (create_cydir(box->storage, box->list, box->path) < 0)
+ if (box->list->v.create_mailbox_dir(box->list,
+ box->name, FALSE) < 0)
return -1;
} else if (errno == ENOENT) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
cydir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
- const char *path;
- struct stat st;
-
- path = mailbox_list_get_path(box->list, box->name,
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
- if (stat(path, &st) == 0) {
- mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- return -1;
- }
-
- if (create_cydir(box->storage, box->list, path) < 0)
- return -1;
+ if (directory &&
+ (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
+ return 0;
- return directory || update == NULL ? 0 :
+ return update == NULL ? 0 :
index_storage_mailbox_update(box, update);
}
int dbox_mailbox_create(struct mailbox *box,
const struct mailbox_update *update, bool directory)
{
- const char *path, *alt_path, *origin;
- struct stat st;
-
- path = mailbox_list_get_path(box->list, box->name,
- directory ? MAILBOX_LIST_PATH_TYPE_DIR :
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
- if (stat(path, &st) == 0) {
- mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- return -1;
- }
+ struct dbox_storage *storage = (struct dbox_storage *)box->storage;
- if (directory) {
- mode_t mode;
- gid_t gid;
+ if (directory &&
+ (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
+ return 0;
- mailbox_list_get_dir_permissions(box->list, NULL, &mode,
- &gid, &origin);
- if (mkdir_parents_chgrp(path, mode, gid, origin) == 0)
- return 0;
- else if (errno == EEXIST) {
- mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- } else if (!mail_storage_set_error_from_errno(box->storage)) {
- mail_storage_set_critical(box->storage,
- "mkdir(%s) failed: %m", path);
- }
+ if (index_storage_mailbox_open(box) < 0)
return -1;
- }
-
- /* make sure the alt path doesn't exist yet. it shouldn't (except with
- race conditions with RENAME/DELETE), but if something crashed and
- left it lying around we don't want to start overwriting files in
- it. */
- alt_path = dbox_get_alt_path(box->list, path);
- if (alt_path != NULL && stat(alt_path, &st) == 0) {
- mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
+ if (storage->v.mailbox_create_indexes(box, update) < 0)
return -1;
- }
-
- return dbox_mailbox_create_indexes(box, update);
+ return 0;
}
int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx ATTR_UNUSED,
{
struct mailbox *box = &ibox->box;
const char *path;
- gid_t dir_gid;
- const char *origin, *dir_origin;
string_t *vname;
if (name != NULL) {
ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
ibox->index = index_storage_alloc(box->list, name, flags, index_prefix);
- if (box->file_create_mode == 0) {
- mailbox_list_get_permissions(box->list, name,
- &box->file_create_mode,
- &box->file_create_gid, &origin);
- box->file_create_gid_origin = p_strdup(box->pool, origin);
- mailbox_list_get_dir_permissions(box->list, name,
- &box->dir_create_mode,
- &dir_gid, &dir_origin);
- mail_index_set_permissions(ibox->index,
- box->file_create_mode,
- box->file_create_gid, origin);
- }
+ if (box->file_create_mode == 0)
+ mailbox_refresh_permissions(box);
+ mail_index_set_permissions(ibox->index, box->file_create_mode,
+ box->file_create_gid,
+ box->file_create_gid_origin);
}
int index_storage_mailbox_enable(struct mailbox *box,
#include <unistd.h>
#include <sys/stat.h>
-#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
-
#define MAILDIR_LIST_CONTEXT(obj) \
MODULE_CONTEXT(obj, maildir_mailbox_list_module)
}
/* create or fix maildir, ignore if it already exists */
-static int
-create_maildir(struct mail_storage *storage, struct mail_namespace *ns,
- const char *dir, mode_t mode, gid_t gid, const char *gid_origin,
- bool verify)
+static int create_maildir(struct mailbox *box, bool verify)
{
const char *path;
unsigned int i;
int ret;
if (!verify) {
- ret = maildir_check_tmp(storage, dir);
+ ret = maildir_check_tmp(box->storage, box->path);
if (ret > 0) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(box->storage,
MAIL_ERROR_EXISTS, "Mailbox already exists");
return -1;
}
}
for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
- path = t_strconcat(dir, "/", maildir_subdirs[i], NULL);
- if (mkdir_verify(storage, ns, path, mode, gid,
- gid_origin, verify) < 0)
+ path = t_strconcat(box->path, "/", maildir_subdirs[i], NULL);
+ if (mkdir_verify(box->storage, box->list->ns, path,
+ box->dir_create_mode, box->file_create_gid,
+ box->file_create_gid_origin, verify) < 0)
return -1;
}
return 0;
(void)maildir_uidlist_lock_touch(mbox->uidlist);
}
-static mode_t get_dir_mode(mode_t mode)
-{
- /* add the execute bit if either read or write bit is set */
- if ((mode & 0600) != 0) mode |= 0100;
- if ((mode & 0060) != 0) mode |= 0010;
- if ((mode & 0006) != 0) mode |= 0001;
- return mode;
-}
-
static struct mailbox *
maildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
const char *name, struct istream *input,
struct stat st;
const char *shared_path;
- /* for shared mailboxes get the create mode from the
- permissions of dovecot-shared file. */
shared_path = t_strconcat(box->path, "/dovecot-shared", NULL);
- if (stat(shared_path, &st) == 0) {
- if ((st.st_mode & S_ISGID) != 0 ||
- (st.st_mode & 0060) == 0) {
- /* Ignore GID */
- st.st_gid = (gid_t)-1;
- }
- mail_index_set_permissions(mbox->ibox.index,
- st.st_mode & 0666, st.st_gid,
- shared_path);
-
- box->file_create_mode = st.st_mode & 0666;
- box->dir_create_mode = get_dir_mode(st.st_mode & 0666);
- box->file_create_gid = st.st_gid;
- mbox->ibox.box.file_create_gid_origin =
- p_strdup(box->pool, shared_path);
+ if (stat(shared_path, &st) == 0)
box->private_flags_mask = MAIL_SEEN;
- }
if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) {
if (maildir_uidlist_lock(mbox->uidlist) <= 0)
static int maildir_mailbox_open(struct mailbox *box)
{
struct stat st;
- const char *gid_origin;
- mode_t mode;
- gid_t gid;
int ret;
bool inbox;
/* tmp/ directory doesn't exist. does the maildir? */
if (inbox || (*box->name != '\0' && stat(box->path, &st) == 0)) {
/* yes, we'll need to create the missing dirs */
- mailbox_list_get_dir_permissions(box->list, box->name,
- &mode, &gid, &gid_origin);
- if (create_maildir(box->storage, box->list->ns, box->path,
- mode, gid, gid_origin, TRUE) < 0)
+ if (create_maildir(box, TRUE) < 0)
return -1;
return maildir_mailbox_open_existing(box);
}
}
-static int
-maildir_create_shared(struct mail_storage *storage, struct mail_namespace *ns,
- const char *dir, mode_t mode, gid_t gid,
- const char *gid_origin)
+static int maildir_create_shared(struct mailbox *box)
{
const char *path;
mode_t old_mask;
int fd;
- /* add the execute bit if either read or write bit is set */
- if ((mode & 0600) != 0) mode |= 0100;
- if ((mode & 0060) != 0) mode |= 0010;
- if ((mode & 0006) != 0) mode |= 0001;
-
- if (create_maildir(storage, ns, dir, mode, gid, gid_origin, FALSE) < 0)
- return -1;
-
- old_mask = umask(0777 ^ mode);
- path = t_strconcat(dir, "/dovecot-shared", NULL);
- fd = open(path, O_WRONLY | O_CREAT, mode & 0666);
+ old_mask = umask(0);
+ path = t_strconcat(box->path, "/dovecot-shared", NULL);
+ fd = open(path, O_WRONLY | O_CREAT, box->file_create_mode);
umask(old_mask);
if (fd == -1) {
- mail_storage_set_critical(storage, "open(%s) failed: %m", path);
+ mail_storage_set_critical(box->storage, "open(%s) failed: %m",
+ path);
return -1;
}
- if (fchown(fd, (uid_t)-1, gid) < 0) {
+ if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) {
if (errno == EPERM) {
- mail_storage_set_critical(storage, "%s",
+ mail_storage_set_critical(box->storage, "%s",
eperm_error_get_chgrp("fchown", path,
- gid, gid_origin));
+ box->file_create_gid,
+ box->file_create_gid_origin));
} else {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(box->storage,
"fchown(%s) failed: %m", path);
}
}
maildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
+ const char *root_dir, *shared_path;
struct stat st;
- const char *path, *root_dir, *shared_path, *gid_origin;
- mode_t old_mask;
- int fd;
- path = mailbox_list_get_path(box->list, box->name,
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
+ if (directory &&
+ (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
+ return 0;
+
+ if (create_maildir(box, FALSE) < 0)
+ return -1;
+
+ /* if dovecot-shared exists in the root dir, copy it to newly
+ created mailboxes */
root_dir = mailbox_list_get_path(box->list, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
-
- /* if dovecot-shared exists in the root dir, create the mailbox using
- its permissions and gid, and copy the dovecot-shared inside it. */
shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
if (stat(shared_path, &st) == 0) {
- gid_origin = shared_path;
- if (maildir_create_shared(box->storage, box->list->ns, path,
- st.st_mode & 0666, st.st_gid,
- gid_origin) < 0)
- return -1;
- } else {
- mailbox_list_get_dir_permissions(box->list, NULL, &st.st_mode,
- &st.st_gid, &gid_origin);
- if (create_maildir(box->storage, box->list->ns, path,
- st.st_mode, st.st_gid, gid_origin,
- FALSE) < 0)
+ if (maildir_create_shared(box) < 0)
return -1;
}
- /* Maildir++ spec wants that maildirfolder named file is created for
- all subfolders. */
- path = t_strconcat(path, "/" MAILDIR_SUBFOLDER_FILENAME, NULL);
- old_mask = umask(0777 ^ (st.st_mode & 0666));
- fd = open(path, O_CREAT | O_WRONLY, 0666);
- umask(old_mask);
- if (fd != -1) {
- /* if dovecot-shared exists, use the same group */
- if (st.st_gid == (gid_t)-1) {
- /* doesn't exist */
- } else if (fchown(fd, (uid_t)-1, st.st_gid) == 0) {
- /* ok */
- } else if (errno == EPERM) {
- mail_storage_set_critical(box->storage, "%s",
- eperm_error_get_chgrp("fchown", path,
- st.st_gid, gid_origin));
- } else {
- mail_storage_set_critical(box->storage,
- "fchown(%s) failed: %m", path);
- }
- (void)close(fd);
- } else if (errno == ENOENT) {
- mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
- "Mailbox was deleted while it was being created");
- return -1;
- } else {
- mail_storage_set_critical(box->storage,
- "open(%s, O_CREAT) failed: %m", path);
- }
- return directory || update == NULL ? 0 :
- maildir_mailbox_update(box, update);
+ return update == NULL ? 0 : maildir_mailbox_update(box, update);
}
static void
mbox_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
- struct mail_storage *storage = box->storage;
- const char *path, *p, *origin;
- struct stat st;
- mode_t mode;
- gid_t gid;
- int fd;
+ int fd, ret;
- /* make sure it doesn't exist already */
- path = mailbox_list_get_path(box->list, box->name,
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
- if (stat(path, &st) == 0) {
- mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- return -1;
- }
+ if (directory &&
+ (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
+ return 0;
- if (errno != ENOENT) {
- if (errno == ENOTDIR) {
- mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
- "Mailbox doesn't allow inferior mailboxes");
- } else if (!mail_storage_set_error_from_errno(storage)) {
- mail_storage_set_critical(storage,
- "stat() failed for mbox file %s: %m", path);
+ /* create the mbox file */
+ ret = mailbox_create_fd(box, box->path, O_RDWR | O_CREAT | O_EXCL, &fd);
+ if (ret <= 0) {
+ if (ret == 0) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
+ "Mailbox already exists");
}
return -1;
}
-
- /* create the hierarchy if needed */
- p = directory ? path + strlen(path) : strrchr(path, '/');
- if (p != NULL) {
- p = t_strdup_until(path, p);
- mailbox_list_get_dir_permissions(box->list, NULL, &mode, &gid,
- &origin);
- if (mkdir_parents_chgrp(p, mode, gid, origin) < 0 &&
- errno != EEXIST) {
- if (!mail_storage_set_error_from_errno(storage)) {
- mail_storage_set_critical(storage,
- "mkdir_parents(%s) failed: %m", p);
- }
- return -1;
- }
-
- if (directory) {
- /* wanted to create only the directory */
- return 0;
- }
- }
-
- /* create the mailbox file */
- fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
- if (fd != -1) {
- (void)close(fd);
- return update == NULL ? 0 : mbox_mailbox_update(box, update);
- }
-
- if (errno == EEXIST) {
- /* mailbox was just created between stat() and open() call.. */
- mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- } else if (!mail_storage_set_error_from_errno(storage)) {
- mail_storage_set_critical(storage,
- "Can't create mailbox %s: %m", box->name);
- }
- return -1;
+ (void)close(fd);
+ return update == NULL ? 0 : mbox_mailbox_update(box, update);
}
static void mbox_mailbox_close(struct mailbox *box)
shared_storage_get_namespace(&ns, &name) < 0) {
switch (type) {
case MAILBOX_LIST_PATH_TYPE_DIR:
+ case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
case MAILBOX_LIST_PATH_TYPE_MAILBOX:
+ case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
case MAILBOX_LIST_PATH_TYPE_CONTROL:
break;
case MAILBOX_LIST_PATH_TYPE_INDEX:
return ret;
}
+static int
+shared_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
+ bool directory)
+{
+ struct mail_namespace *ns = list->ns;
+ int ret;
+
+ if (shared_storage_get_namespace(&ns, &name) < 0)
+ return -1;
+ ret = ns->list->v.create_mailbox_dir(ns->list, name, directory);
+ if (ret < 0)
+ shared_list_copy_error(list, ns);
+ return ret;
+}
+
static int
shared_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
shared_list_iter_deinit,
NULL,
shared_list_set_subscribed,
+ shared_list_create_mailbox_dir,
shared_list_delete_mailbox,
shared_list_delete_dir,
shared_list_rename_mailbox,
enum mailbox_list_path_type type)
{
const struct mailbox_list_settings *set = &_list->set;
- const char *path;
+ const char *path, *root_dir;
if (name == NULL) {
/* return root directories */
switch (type) {
case MAILBOX_LIST_PATH_TYPE_DIR:
return set->root_dir;
+ case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
+ return _list->set.alt_dir;
case MAILBOX_LIST_PATH_TYPE_MAILBOX:
path = t_strconcat(set->root_dir, "/",
set->mailbox_dir_name, NULL);
return t_strndup(path, strlen(path)-1);
+ case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
+ path = t_strconcat(set->alt_dir, "/",
+ set->mailbox_dir_name, NULL);
+ return t_strndup(path, strlen(path)-1);
case MAILBOX_LIST_PATH_TYPE_CONTROL:
return set->control_dir != NULL ?
set->control_dir : set->root_dir;
if (mailbox_list_try_get_absolute_path(_list, &name))
return name;
+ root_dir = set->root_dir;
switch (type) {
case MAILBOX_LIST_PATH_TYPE_DIR:
if (*set->maildir_name != '\0')
return t_strdup_printf("%s/%s%s", set->root_dir,
set->mailbox_dir_name, name);
break;
+ case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
+ if (*set->maildir_name != '\0')
+ return t_strdup_printf("%s/%s%s", set->alt_dir,
+ set->mailbox_dir_name, name);
+ break;
case MAILBOX_LIST_PATH_TYPE_MAILBOX:
break;
+ case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
+ if (set->alt_dir == NULL)
+ return NULL;
+ root_dir = set->alt_dir;
+ break;
case MAILBOX_LIST_PATH_TYPE_CONTROL:
if (set->control_dir != NULL)
return t_strdup_printf("%s/%s%s", set->control_dir,
break;
}
- /* If INBOX is a file, index and control directories are located
- in root directory. */
- if (strcmp(name, "INBOX") == 0 && set->inbox_path != NULL &&
- ((_list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0 ||
- type == MAILBOX_LIST_PATH_TYPE_MAILBOX ||
- type == MAILBOX_LIST_PATH_TYPE_DIR))
- return set->inbox_path;
+ if (type == MAILBOX_LIST_PATH_TYPE_ALT_DIR ||
+ type == MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX) {
+ /* don't use inbox_path */
+ } else if (strcmp(name, "INBOX") == 0 && set->inbox_path != NULL) {
+ /* If INBOX is a file, index and control directories are
+ located in root directory. */
+ if ((_list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0 ||
+ type == MAILBOX_LIST_PATH_TYPE_MAILBOX ||
+ type == MAILBOX_LIST_PATH_TYPE_DIR)
+ return set->inbox_path;
+ }
if (*set->maildir_name == '\0') {
- return t_strdup_printf("%s/%s%s", set->root_dir,
+ return t_strdup_printf("%s/%s%s", root_dir,
set->mailbox_dir_name, name);
} else {
- return t_strdup_printf("%s/%s%s/%s", set->root_dir,
+ return t_strdup_printf("%s/%s%s/%s", root_dir,
set->mailbox_dir_name, name,
set->maildir_name);
}
name, set);
}
+static int
+fs_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
+ bool directory)
+{
+ const char *path, *alt_path, *gid_origin, *p;
+ struct stat st;
+ mode_t mode;
+ gid_t gid;
+ bool create_parent_dir;
+
+ /* make sure the alt path doesn't exist yet. it shouldn't (except with
+ race conditions with RENAME/DELETE), but if something crashed and
+ left it lying around we don't want to start overwriting files in
+ it. */
+ if (!directory) {
+ alt_path = mailbox_list_get_path(list, name,
+ MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX);
+ if (alt_path != NULL && stat(alt_path, &st) == 0) {
+ mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
+ "Mailbox already exists");
+ return -1;
+ }
+ }
+
+ path = mailbox_list_get_path(list, name,
+ directory ? MAILBOX_LIST_PATH_TYPE_DIR :
+ MAILBOX_LIST_PATH_TYPE_MAILBOX);
+ create_parent_dir = !directory &&
+ (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
+ if (create_parent_dir) {
+ /* we only need to make sure that the parent directory exists */
+ p = strrchr(path, '/');
+ if (p == NULL)
+ return 0;
+ path = t_strdup_until(path, p);
+ }
+
+ mailbox_list_get_dir_permissions(list, NULL, &mode,
+ &gid, &gid_origin);
+ if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0)
+ return 0;
+ else if (errno == EEXIST) {
+ if (create_parent_dir)
+ return 0;
+ mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
+ "Mailbox already exists");
+ } else if (errno == ENOTDIR) {
+ mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+ "Mailbox doesn't allow inferior mailboxes");
+ } else if (!mailbox_list_set_error_from_errno(list)) {
+ mailbox_list_set_critical(list, "mkdir(%s) failed: %m", path);
+ }
+ return -1;
+}
+
static int fs_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
/* let the backend handle the rest */
fs_list_iter_deinit,
NULL,
fs_list_set_subscribed,
+ fs_list_create_mailbox_dir,
fs_list_delete_mailbox,
fs_list_delete_dir,
fs_list_rename_mailbox,
#include "lib.h"
#include "array.h"
#include "hostpid.h"
+#include "eacces-error.h"
+#include "mkdir-parents.h"
#include "subscription-file.h"
#include "mailbox-list-maildir.h"
#include <stdio.h>
#include <sys/stat.h>
+#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
#define MAILDIR_GLOBAL_TEMP_PREFIX "temp."
#define IMAPDIR_GLOBAL_TEMP_PREFIX ".temp."
maildir_list_get_path(struct mailbox_list *_list, const char *name,
enum mailbox_list_path_type type)
{
+ const char *root_dir;
+
if (name == NULL) {
/* return root directories */
switch (type) {
case MAILBOX_LIST_PATH_TYPE_DIR:
case MAILBOX_LIST_PATH_TYPE_MAILBOX:
return _list->set.root_dir;
+ case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
+ case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
+ return _list->set.alt_dir;
case MAILBOX_LIST_PATH_TYPE_CONTROL:
return _list->set.control_dir != NULL ?
_list->set.control_dir : _list->set.root_dir;
(*name == '/' || *name == '~'))
return maildir_list_get_absolute_path(_list, name);
+ root_dir = _list->set.root_dir;
switch (type) {
case MAILBOX_LIST_PATH_TYPE_DIR:
case MAILBOX_LIST_PATH_TYPE_MAILBOX:
break;
+ case MAILBOX_LIST_PATH_TYPE_ALT_DIR:
+ case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX:
+ if (_list->set.alt_dir == NULL)
+ return NULL;
+ root_dir = _list->set.alt_dir;
+ break;
case MAILBOX_LIST_PATH_TYPE_CONTROL:
if (_list->set.control_dir != NULL) {
return maildir_list_get_dirname_path(_list,
break;
}
- if (strcmp(name, "INBOX") == 0 && _list->set.inbox_path != NULL)
+ if (type == MAILBOX_LIST_PATH_TYPE_ALT_DIR ||
+ type == MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX) {
+ /* don't use inbox_path */
+ } else if (strcmp(name, "INBOX") == 0 && _list->set.inbox_path != NULL)
return _list->set.inbox_path;
- return maildir_list_get_dirname_path(_list, _list->set.root_dir, name);
+ return maildir_list_get_dirname_path(_list, root_dir, name);
}
static int
return ret;
}
+static int
+maildir_list_create_maildirfolder_file(struct mailbox_list *list,
+ const char *dir)
+{
+ const char *path, *gid_origin;
+ mode_t mode, old_mask;
+ gid_t gid;
+ int fd;
+
+ /* Maildir++ spec wants that maildirfolder named file is created for
+ all subfolders. */
+ mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin);
+
+ path = t_strconcat(dir, "/" MAILDIR_SUBFOLDER_FILENAME, NULL);
+ old_mask = umask(0);
+ fd = open(path, O_CREAT | O_WRONLY, mode);
+ umask(old_mask);
+ if (fd != -1) {
+ /* ok */
+ } else if (errno == ENOENT) {
+ mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+ "Mailbox was deleted while it was being created");
+ return -1;
+ } else {
+ mailbox_list_set_critical(list,
+ "open(%s, O_CREAT) failed: %m", path);
+ return -1;
+ }
+
+ if (gid != (gid_t)-1) {
+ if (fchown(fd, (uid_t)-1, gid) == 0) {
+ /* ok */
+ } else if (errno == EPERM) {
+ mailbox_list_set_critical(list, "%s",
+ eperm_error_get_chgrp("fchown", path,
+ gid, gid_origin));
+ } else {
+ mailbox_list_set_critical(list,
+ "fchown(%s) failed: %m", path);
+ }
+ }
+ (void)close(fd);
+ return 0;
+}
+
+static int
+maildir_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
+ bool directory ATTR_UNUSED)
+{
+ const char *path, *gid_origin, *p;
+ mode_t mode;
+ gid_t gid;
+ bool create_parent_dir;
+
+ path = mailbox_list_get_path(list, name,
+ MAILBOX_LIST_PATH_TYPE_MAILBOX);
+ create_parent_dir = !directory &&
+ (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
+ if (create_parent_dir) {
+ /* we only need to make sure that the parent directory exists */
+ p = strrchr(path, '/');
+ if (p == NULL)
+ return 0;
+ path = t_strdup_until(path, p);
+ }
+
+ mailbox_list_get_dir_permissions(list, NULL, &mode,
+ &gid, &gid_origin);
+ if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0) {
+ /* ok */
+ } else if (errno == EEXIST) {
+ if (!create_parent_dir) {
+ mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
+ "Mailbox already exists");
+ return -1;
+ }
+ } else if (mailbox_list_set_error_from_errno(list)) {
+ return -1;
+ } else {
+ mailbox_list_set_critical(list, "mkdir(%s) failed: %m", path);
+ return -1;
+ }
+ return create_parent_dir ? 0 :
+ maildir_list_create_maildirfolder_file(list, path);
+}
+
static int
maildir_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
struct mailbox_list maildir_mailbox_list = {
.name = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS,
.hierarchy_sep = '.',
- .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME,
+ .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
+ MAILBOX_LIST_PROP_NO_NOSELECT,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
{
maildir_list_iter_deinit,
NULL,
maildir_list_set_subscribed,
+ maildir_list_create_mailbox_dir,
maildir_list_delete_mailbox,
maildir_list_delete_dir,
maildir_list_rename_mailbox,
struct mailbox_list imapdir_mailbox_list = {
.name = MAILBOX_LIST_NAME_IMAPDIR,
.hierarchy_sep = '.',
- .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME,
+ .props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
+ MAILBOX_LIST_PROP_NO_NOSELECT,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
{
maildir_list_iter_deinit,
NULL,
maildir_list_set_subscribed,
+ maildir_list_create_mailbox_dir,
maildir_list_delete_mailbox,
maildir_list_delete_dir,
maildir_list_rename_mailbox,
int mail_set_aborted(struct mail *mail);
void mail_set_expunged(struct mail *mail);
void mailbox_set_deleted(struct mailbox *box);
+void mailbox_refresh_permissions(struct mailbox *box);
+
+/* Returns -1 if error, 0 if failed with EEXIST, 1 if ok */
+int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
+ int *fd_r);
#endif
#include "ioloop.h"
#include "array.h"
#include "llist.h"
+#include "eacces-error.h"
#include "mkdir-parents.h"
#include "var-expand.h"
#include "mail-index-private.h"
return -1;
}
+ if (box->list->v.create_mailbox_dir(box->list, box->name,
+ directory) < 0) {
+ const char *str;
+ enum mail_error error;
+
+ str = mailbox_list_get_last_error(box->list, &error);
+ mail_storage_set_error(box->storage, error, str);
+ return -1;
+ }
+ mailbox_refresh_permissions(box);
+
return box->v.create(box, update, directory);
}
"Mailbox was deleted under us");
box->mailbox_deleted = TRUE;
}
+
+void mailbox_refresh_permissions(struct mailbox *box)
+{
+ const char *origin, *dir_origin;
+ gid_t dir_gid;
+
+ if (box->input != NULL) {
+ box->file_create_mode = 0600;
+ box->dir_create_mode = 0700;
+ box->file_create_gid = (gid_t)-1;
+ box->file_create_gid_origin = "defaults";
+ return;
+ }
+
+ mailbox_list_get_permissions(box->list, box->name,
+ &box->file_create_mode,
+ &box->file_create_gid, &origin);
+
+ box->file_create_gid_origin = p_strdup(box->pool, origin);
+ mailbox_list_get_dir_permissions(box->list, box->name,
+ &box->dir_create_mode,
+ &dir_gid, &dir_origin);
+}
+
+int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
+ int *fd_r)
+{
+ mode_t old_mask;
+ int fd;
+
+ i_assert(box->file_create_mode != 0);
+ i_assert((flags & O_CREAT) != 0);
+
+ *fd_r = -1;
+
+ old_mask = umask(0);
+ fd = open(path, flags, box->file_create_mode);
+ umask(old_mask);
+
+ if (fd != -1) {
+ /* ok */
+ } else if (errno == EEXIST) {
+ /* O_EXCL used, caller will handle this error */
+ return 0;
+ } else if (errno == ENOENT) {
+ mailbox_set_deleted(box);
+ return -1;
+ } else if (mail_storage_set_error_from_errno(box->storage)) {
+ return -1;
+ } else {
+ mail_storage_set_critical(box->storage,
+ "open(%s, O_CREAT) failed: %m", path);
+ return -1;
+ }
+
+ if (box->file_create_gid != (gid_t)-1) {
+ if (fchown(fd, (uid_t)-1, box->file_create_gid) == 0) {
+ /* ok */
+ } else if (errno == EPERM) {
+ mail_storage_set_critical(box->storage, "%s",
+ eperm_error_get_chgrp("fchown", path,
+ box->file_create_gid,
+ box->file_create_gid_origin));
+ } else {
+ mail_storage_set_critical(box->storage,
+ "fchown(%s) failed: %m", path);
+ }
+ }
+ *fd_r = fd;
+ return 1;
+}
int (*set_subscribed)(struct mailbox_list *list,
const char *name, bool set);
+ int (*create_mailbox_dir)(struct mailbox_list *list, const char *name,
+ bool directory);
int (*delete_mailbox)(struct mailbox_list *list, const char *name);
int (*delete_dir)(struct mailbox_list *list, const char *name);
int (*rename_mailbox)(struct mailbox_list *oldlist, const char *oldname,
enum mailbox_list_properties {
/* maildir_name must always be empty */
- MAILBOX_LIST_PROP_NO_MAILDIR_NAME = 0x01
+ MAILBOX_LIST_PROP_NO_MAILDIR_NAME = 0x01,
+ /* no support for \noselect directories, only mailboxes */
+ MAILBOX_LIST_PROP_NO_NOSELECT = 0x02
};
enum mailbox_list_flags {
enum mailbox_list_path_type {
/* Return directory's path (eg. ~/dbox/INBOX) */
MAILBOX_LIST_PATH_TYPE_DIR,
+ MAILBOX_LIST_PATH_TYPE_ALT_DIR,
/* Return mailbox path (eg. ~/dbox/INBOX/dbox-Mails) */
MAILBOX_LIST_PATH_TYPE_MAILBOX,
+ MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX,
/* Return control directory */
MAILBOX_LIST_PATH_TYPE_CONTROL,
/* Return index file directory */
return 0;
}
+static int
+acl_mailbox_list_create_dir(struct mailbox_list *list, const char *name,
+ bool directory)
+{
+ struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list);
+ int ret;
+
+ /* we're looking up CREATE permission from our parent's rights */
+ ret = acl_mailbox_list_have_right(list, name, TRUE,
+ ACL_STORAGE_RIGHT_CREATE, NULL);
+ if (ret <= 0) {
+ if (ret < 0)
+ return -1;
+ /* Note that if user didn't have LOOKUP permission to parent
+ mailbox, this may reveal the mailbox's existence to user.
+ Can't help it. */
+ mailbox_list_set_error(list, MAIL_ERROR_PERM,
+ MAIL_ERRSTR_NO_PERMISSION);
+ return -1;
+ }
+ return alist->module_ctx.super.
+ create_mailbox_dir(list, name, directory);
+}
+
static int
acl_mailbox_list_delete(struct mailbox_list *list, const char *name)
{
list->v.iter_next = acl_mailbox_list_iter_next;
list->v.iter_deinit = acl_mailbox_list_iter_deinit;
list->v.get_mailbox_name_status = acl_get_mailbox_name_status;
+ list->v.create_mailbox_dir = acl_mailbox_list_create_dir;
list->v.delete_mailbox = acl_mailbox_list_delete;
list->v.rename_mailbox = acl_mailbox_list_rename;
acl_object_list_deinit(&iter);
acl_object_deinit(&parent_aclobj);
}
+
static int
acl_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
struct acl_mailbox *abox = ACL_CONTEXT(box);
- int ret;
- /* we're looking up CREATE permission from our parent's rights */
- ret = acl_mailbox_list_have_right(box->list, box->name, TRUE,
- ACL_STORAGE_RIGHT_CREATE, NULL);
- if (ret <= 0) {
- if (ret < 0)
- return -1;
- /* Note that if user didn't have LOOKUP permission to parent
- mailbox, this may reveal the mailbox's existence to user.
- Can't help it. */
- mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
- MAIL_ERRSTR_NO_PERMISSION);
- return -1;
- }
+ /* we already checked permissions in list.mailbox_create_dir(). */
if (abox->module_ctx.super.create(box, update, directory) < 0)
return -1;