cydir-storage.c revision 6bc5fed79741503437c6d46d9f282b66bd029c6b
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch MODULE_CONTEXT(obj, cydir_mailbox_list_module)
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschstatic MODULE_CONTEXT_DEFINE_INIT(cydir_mailbox_list_module,
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschstatic struct mail_storage *cydir_storage_alloc(void)
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch pool = pool_alloconly_create("cydir storage", 512+256);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch storage = p_new(pool, struct cydir_storage, 1);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschcydir_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch set->dir_guid_fname = CYDIR_DIR_GUID_FILE_NAME;
1e653c7406ec0b062c0bacfdf2e7568a3f860500Stephan Boschstatic int create_cydir(struct mail_storage *storage, struct mailbox_list *list,
1e653c7406ec0b062c0bacfdf2e7568a3f860500Stephan Bosch mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch if (mkdir_parents_chgrp(path, mode, gid, origin) < 0 &&
1e653c7406ec0b062c0bacfdf2e7568a3f860500Stephan Bosch if (!mail_storage_set_error_from_errno(storage)) {
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschstatic struct mailbox *
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschcydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody /* cydir can't work without index files */
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody pool = pool_alloconly_create("cydir mailbox", 1024+512);
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody mbox->ibox.save_commit_pre = cydir_transaction_save_commit_pre;
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody mbox->ibox.save_commit_post = cydir_transaction_save_commit_post;
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody mbox->ibox.save_rollback = cydir_transaction_save_rollback;
bf3dbfd29e4d65f485b963bb5598b653e65b5f82Phil Carmody index_storage_mailbox_alloc(&mbox->ibox, name, input, flags,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch mbox->storage = (struct cydir_storage *)storage;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschstatic int cydir_mailbox_open(struct mailbox *box)
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch "cydir doesn't support streamed mailboxes");
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* exists, open it */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch } else if (errno == ENOENT && strcmp(box->name, "INBOX") == 0) {
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* INBOX always exists, create it */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch if (create_cydir(box->storage, box->list, box->path) < 0)
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch mail_storage_set_critical(box->storage, "stat(%s) failed: %m",
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschcydir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch path = mailbox_list_get_path(box->list, box->name,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch "Mailbox already exists");
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch if (create_cydir(box->storage, box->list, path) < 0)
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschcydir_delete_nonrecursive(struct mailbox_list *list, const char *path,
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch unsigned int dir_len;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch if (!mailbox_list_set_error_from_errno(list)) {
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* skip . and .. */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch if (d->d_name[1] == '.' && d->d_name[2] == '\0')
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* trying to unlink() a directory gives either EPERM or EISDIR
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch (non-POSIX). it doesn't really work anywhere in practise,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch so don't bother stat()ing the file first */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch mailbox_list_set_critical(list, "unlink(%s) failed: %m",
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch mailbox_list_set_critical(list, "closedir(%s) failed: %m",
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch else if (errno != ENOENT && errno != ENOTEMPTY) {
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschcydir_list_delete_mailbox(struct mailbox_list *list, const char *name)
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch struct cydir_mailbox_list *mlist = CYDIR_LIST_CONTEXT(list);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch const char *src;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* Make sure the indexes are closed before trying to delete the
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch directory that contains them. It can still fail with some NFS
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch implementations if indexes are opened by another session, but
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch that can't really be helped. */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* delete the index and control directories */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch if (mlist->module_ctx.super.delete_mailbox(list, name) < 0)
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* check if the mailbox actually exists */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch return cydir_delete_nonrecursive(list, src, name);
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Boschstatic void cydir_notify_changes(struct mailbox *box)
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch index_mailbox_check_add(&mbox->ibox, mbox->ibox.box.path);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* try to avoid stat() with these checks */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* it's a file */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* need to stat() then */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch mail_path = t_strconcat(dir, "/", fname, NULL);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* non-directory */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* no subdirectories */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch } else if (*ctx->list->set.maildir_name != '\0') {
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* non-default configuration: we have one directory
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch containing the mailboxes. if there are 3 links,
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch either this is a selectable mailbox without children
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch or non-selectable mailbox with children */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* default configuration: all subdirectories are
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch child mailboxes. */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch /* doesn't exist - probably a non-existing subscribed mailbox */
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch /* non-selectable. probably either access denied, or symlink
5394bed8aaef2a6c1c870a34a23a7824e1f370bbStephan Bosch destination not found. don't bother logging errors. */
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschstatic void cydir_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
29ba46818861793cc016013ce2c30e3f3d2a7d11Timo Sirainen mlist = p_new(list->pool, struct cydir_mailbox_list, 1);
1e653c7406ec0b062c0bacfdf2e7568a3f860500Stephan Bosch list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
1e653c7406ec0b062c0bacfdf2e7568a3f860500Stephan Bosch list->v.delete_mailbox = cydir_list_delete_mailbox;