cydir-storage.c revision ad24d1a93178a4d9aec3d0ce73455d8fb50edbe1
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen MODULE_CONTEXT(obj, cydir_mailbox_list_module)
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(cydir_mailbox_list_module,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct mail_storage *cydir_storage_alloc(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create("cydir storage", 512+256);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen storage = p_new(pool, struct cydir_storage, 1);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainencydir_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic int create_cydir(struct mail_storage *storage, struct mail_namespace *ns,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_get_dir_permissions(ns->list, NULL, &mode, &gid);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic struct mailbox *
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainencydir_open(struct mail_storage *storage, struct mailbox_list *list,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen const char *name, enum mailbox_open_flags flags)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index = index_storage_alloc(list, name, flags, CYDIR_INDEX_PREFIX);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_set_fsync_types(index, MAIL_INDEX_SYNC_TYPE_APPEND |
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create("cydir mailbox", 1024+512);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen mbox->storage = (struct cydir_storage *)storage;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic struct mailbox *
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainencydir_mailbox_open(struct mail_storage *storage, struct mailbox_list *list,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "cydir doesn't support streamed mailboxes");
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen /* cydir can't work without index files */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return cydir_open(storage, list, name, flags);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* INBOX always exists, create it */
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (create_cydir(storage, list->ns, path) < 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return cydir_open(storage, list, "INBOX", flags);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen mail_storage_set_critical(storage, "stat(%s) failed: %m",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainencydir_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen "Mailbox already exists");
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainencydir_delete_nonrecursive(struct mailbox_list *list, const char *path,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int dir_len;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen if (!mailbox_list_set_error_from_errno(list)) {
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen /* skip . and .. */
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen if (d->d_name[1] == '.' && d->d_name[2] == '\0')
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* trying to unlink() a directory gives either EPERM or EISDIR
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen (non-POSIX). it doesn't really work anywhere in practise,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk so don't bother stat()ing the file first */
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen mailbox_list_set_critical(list, "unlink(%s) failed: %m",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_list_set_critical(list, "closedir(%s) failed: %m",
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen else if (errno != ENOENT && errno != ENOTEMPTY) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainencydir_list_delete_mailbox(struct mailbox_list *list, const char *name)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct cydir_mailbox_list *mlist = CYDIR_LIST_CONTEXT(list);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *src;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* Make sure the indexes are closed before trying to delete the
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen directory that contains them. It can still fail with some NFS
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen implementations if indexes are opened by another session, but
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen that can't really be helped. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* delete the index and control directories */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (mlist->module_ctx.super.delete_mailbox(list, name) < 0)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* check if the mailbox actually exists */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return cydir_delete_nonrecursive(list, src, name);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic void cydir_notify_changes(struct mailbox *box)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen index_mailbox_check_add(&mbox->ibox, mbox->path);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* try to avoid stat() with these checks */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* it's a file */
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* need to stat() then */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen mail_path = t_strconcat(dir, "/", fname, NULL);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* non-directory */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* no subdirectories */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen } else if (*ctx->list->set.maildir_name != '\0') {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* non-default configuration: we have one directory
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen containing the mailboxes. if there are 3 links,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen either this is a selectable mailbox without children
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen or non-selectable mailbox with children */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* default configuration: all subdirectories are
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen child mailboxes. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* doesn't exist - probably a non-existing subscribed mailbox */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* non-selectable. probably either access denied, or symlink
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen destination not found. don't bother logging errors. */
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainenstatic void cydir_class_init(void)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic void cydir_class_deinit(void)
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainenstatic void cydir_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen mlist = p_new(list->pool, struct cydir_mailbox_list, 1);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen list->v.delete_mailbox = cydir_list_delete_mailbox;