maildir-storage.c revision 68969d3f5b70bceae90e551686b925c9dd5dc2be
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT(obj, maildir_mailbox_list_module)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(maildir_mailbox_list_module,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const char *maildir_subdirs[] = { "cur", "new", "tmp" };
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void maildir_mailbox_close(struct mailbox *box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mail_storage *maildir_storage_alloc(void)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pool = pool_alloconly_create("maildir storage", 512+256);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage = p_new(pool, struct maildir_storage, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmaildir_storage_create(struct mail_storage *_storage, struct mail_namespace *ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct maildir_storage *storage = MAILDIR_STORAGE(_storage);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->set = mail_namespace_get_driver_settings(ns, _storage);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->temp_prefix = p_strdup(_storage->pool,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (list->set.control_dir == NULL && list->set.inbox_path == NULL &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* put the temp files into tmp/ directory preferably */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->temp_prefix = p_strconcat(_storage->pool, "tmp/",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* control dir should also be writable */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _storage->temp_path_prefix = p_strconcat(_storage->pool, dir, "/",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void maildir_storage_get_list_settings(const struct mail_namespace *ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->layout = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (set->inbox_path == NULL && *set->maildir_name == '\0' &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen strcmp(set->layout, MAILBOX_LIST_NAME_FS) == 0) &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* Maildir++ INBOX is the Maildir base itself */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const char *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmaildir_storage_find_root_dir(const struct mail_namespace *ns)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we'll need to figure out the maildir location ourself.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen It's ~/Maildir unless we are chrooted. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("maildir: access(%s, rwx): failed: %m", path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("maildir: /cur exists, assuming chroot");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool maildir_storage_autodetect(const struct mail_namespace *ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("maildir autodetect: stat(%s) failed: %m", path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("maildir autodetect: %s not a directory", path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmkdir_verify(struct mailbox *box, const char *dir, bool verify)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mkdir_parents_chgrp(dir, perm->dir_create_mode,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Mailbox already exists");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Mailbox was deleted while it was being created");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (box->list->ns->type == MAIL_NAMESPACE_TYPE_SHARED) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* shared namespace, don't log permission errors */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int maildir_check_tmp(struct mail_storage *storage, const char *dir)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int interval = storage->set->mail_temp_scan_interval;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* if tmp/ directory exists, we need to clean it up once in a while */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* disabled */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (st.st_atime > st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* the directory should be empty. we won't do anything
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen until ctime changes. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (st.st_atime < ioloop_time - (time_t)interval) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* time to scan */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* create or fix maildir, ignore if it already exists */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int create_maildir_subdirs(struct mailbox *box, bool verify)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path = t_strconcat(box_path, "/", maildir_subdirs[i], NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* try to create all of the directories in case one
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen of them doesn't exist */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void maildir_lock_touch_timeout(struct maildir_mailbox *mbox)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)maildir_uidlist_lock_touch(mbox->uidlist);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenstatic struct mailbox *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmaildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen pool = pool_alloconly_create("maildir mailbox", 1024*3);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mbox = p_new(pool, struct maildir_mailbox, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mbox->maildir_list_index_ext_id = (uint32_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int maildir_mailbox_open_existing(struct mailbox *box)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct maildir_mailbox *mbox = MAILDIR_MAILBOX(box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (maildir_uidlist_lock(mbox->uidlist) <= 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mbox->keep_lock_to = timeout_add(MAILDIR_LOCK_TOUCH_SECS * 1000,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (index_storage_mailbox_open(box, FALSE) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_ext_register(mbox->box.index, "maildir",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool maildir_storage_is_readonly(struct mailbox *box)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct maildir_mailbox *mbox = MAILDIR_MAILBOX(box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* return read-only only if there are no private flags
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (that are stored in index files) */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmaildir_mailbox_exists(struct mailbox *box, bool auto_boxes ATTR_UNUSED,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return index_storage_mailbox_exists_full(box, "cur", existence_r);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int maildir_mailbox_open(struct mailbox *box)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* begin by checking if tmp/ directory exists and if it should be
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cleaned up. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = maildir_check_tmp(box->storage, box_path);
const char *path;
&path);
if (ret < 0)
path);
int ret = 0;
FALSE);
if (ret == 0)
if (locked)
return ret;
const char *path;
int fd;
bool directory)
int ret;
return ret;
ret = 0;
return ret;
const char *name)
const char *path;
&path2) ||
NULL,
NULL,
NULL,