maildir-storage.c revision b28816eae22d99ba3abf0440f5368d87b69414be
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen/* Copyright (C) 2002-2006 Timo Sirainen */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define CREATE_MODE 0777 /* umask() should limit it more */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define MAILDIR_PLUSPLUS_DRIVER_NAME "maildir++"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic const char *maildirs[] = { "cur", "new", "tmp", NULL };
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int verify_inbox(struct mail_storage *storage);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic const char *strip_tail_slash(const char *path)
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainenstatic const char *strip_tail_slash_and_cut(const char *path)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmaildir_get_list_settings(struct mailbox_list_settings *list_set,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *data, enum mail_storage_flags flags)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen list_set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* we'll need to figure out the maildir location ourself.
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen It's $HOME/Maildir unless we are chrooted. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_info("maildir: /cur exists, assuming chroot");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } while (p != NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen list_set->root_dir = strip_tail_slash(list_set->root_dir);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmaildir_create(const char *data, const char *user,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (maildir_get_list_settings(&list_set, data, flags) < 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* normally the maildir is created in verify_inbox() */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage = p_new(pool, struct maildir_storage, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage->stat_dirs = getenv("MAILDIR_STAT_DIRS") != NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen storage->temp_prefix = mailbox_list_get_temp_prefix(list);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* put the temp files into tmp/ directory preferrably */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen p_strconcat(pool, "tmp/", storage->temp_prefix, NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen istorage->callbacks = p_new(pool, struct mail_storage_callbacks, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen index_storage_init(istorage, list, flags, lock_method);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void maildir_free(struct mail_storage *_storage)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct index_storage *storage = (struct index_storage *) _storage;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_info("maildir autodetect: stat(%s) failed: %m", path);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_info("maildir autodetect: %s not a directory", path);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic const char *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmaildir_get_unlink_dest(struct mail_storage *storage, const char *name)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (strcmp(mailbox_list_get_driver_name(storage->list),
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* Not maildir++ driver. Don't use this trick. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen root_dir = mailbox_list_get_path(storage->list, NULL,
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen return t_strdup_printf("%s/%c"MAILDIR_UNLINK_DIRNAME, root_dir,
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen mailbox_list_get_hierarchy_sep(storage->list));
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainenstatic int mkdir_verify(struct mail_storage *storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (errno != EEXIST && (!verify || errno != ENOENT)) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen/* create or fix maildir, ignore if it already exists */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int create_maildir(struct mail_storage *storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!verify && mkdir_verify(storage, dir, verify) < 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (mkdir_verify(storage, path, verify) < 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* small optimization. if we're verifying, we don't
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen check that the root dir actually exists unless we
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen fail here. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int create_index_dir(struct mail_storage *storage, const char *name)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen index_dir = mailbox_list_get_path(storage->list, name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mailbox_list_get_hierarchy_sep(storage->list),
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainenstatic int create_control_dir(struct mail_storage *storage, const char *name)
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen control_dir = mailbox_list_get_path(storage->list, name,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen mailbox_list_get_hierarchy_sep(storage->list),
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int verify_inbox(struct mail_storage *storage)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen path = mailbox_list_get_path(storage->list, "INBOX",
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic bool maildir_is_recent(struct index_mailbox *ibox, uint32_t uid)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)ibox;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return maildir_uidlist_is_recent(mbox->uidlist, uid);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic struct mailbox *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenmaildir_open(struct maildir_storage *storage, const char *name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen path = mailbox_list_get_path(istorage->storage.list, name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen index_dir = mailbox_list_get_path(istorage->storage.list, name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen control_dir = mailbox_list_get_path(istorage->storage.list, name,
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen /* for shared mailboxes get the create mode from the
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen permissions of dovecot-shared file. */
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen shared = stat(t_strconcat(path, "/dovecot-shared", NULL), &st) == 0;
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen pool = pool_alloconly_create("mailbox", 1024);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mbox = p_new(pool, struct maildir_mailbox, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mbox->ibox.mail_vfuncs = &maildir_mail_vfuncs;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen index_storage_mailbox_init(&mbox->ibox, index, name, flags, FALSE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mbox->control_dir = p_strdup(pool, control_dir);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (maildir_uidlist_lock(mbox->uidlist) <= 0) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainenstatic struct mailbox *
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainenmaildir_mailbox_open(struct mail_storage *_storage, const char *name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct istream *input, enum mailbox_open_flags flags)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct maildir_storage *storage = (struct maildir_storage *)_storage;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Maildir doesn't support streamed mailboxes");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!mailbox_list_is_valid_existing_name(_storage->list, name)) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* exists - make sure the required directories are also there */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (create_maildir(_storage, path, TRUE) < 0 ||
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
return NULL;
const char *path;
int fd;
const char *name,
int fd;
const char *name)
int count;
count = 0;
dest);
count++;
const char *const *names;
unsigned int i, count;
int ret;
ret = 0;
const char *name;
for (i = 0; i < count; i++) {
t_push();
t_pop();
t_pop();
return ret;
int ret;
bool found;
if (ret < 0)
int ret = 0;
return ret;
int ret;
MAILDIR_PLUSPLUS_DRIVER_NAME) == 0) {
const char *path;
t_push();
t_pop();
switch (type) {
const char *path;
t_push();
t_pop();
if (ret == 0)
return ret;
static void maildir_class_init(void)
static void maildir_class_deinit(void)