cydir-storage.c revision f81f4bc282cd1944cec187bae89c0701a416ed2a
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen/* Copyright (C) 2007 Timo Sirainen */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen MODULE_CONTEXT(obj, cydir_mailbox_list_module)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(cydir_mailbox_list_module,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_list_delete_mailbox(struct mailbox_list *list, const char *name);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_get_list_settings(struct mailbox_list_settings *list_set,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *data, enum mail_storage_flags flags)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *p;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen list_set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* we won't do any guessing for this format. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* <root dir> [:INDEX=<dir>] */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } while (p != NULL);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* strip trailing '/' */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen list_set->root_dir = t_strndup(list_set->root_dir, len-1);
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen pool = pool_alloconly_create("cydir storage", 512+256);
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen storage = p_new(pool, struct cydir_storage, 1);
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainenstatic int cydir_create(struct mail_storage *_storage, const char *data)
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen struct cydir_storage *storage = (struct cydir_storage *)_storage;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen if (cydir_get_list_settings(&list_set, data, _storage->flags) < 0)
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen list_set.mail_storage_flags = &_storage->flags;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen list_set.lock_method = &_storage->lock_method;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen if ((_storage->flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (mkdir_parents(list_set.root_dir, CREATE_MODE) < 0 &&
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_error("mkdir_parents(%s) failed: %m", list_set.root_dir);
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen storage->list_module_ctx.super = _storage->list->v;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen _storage->list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen _storage->list->v.delete_mailbox = cydir_list_delete_mailbox;
0a3b01714dadf97dcc7439ad4eeba690ab044966Timo Sirainen MODULE_CONTEXT_SET_FULL(_storage->list, cydir_mailbox_list_module,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int create_cydir(struct mail_storage *storage, const char *path)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int create_index_dir(struct mail_storage *storage, const char *name)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen index_dir = mailbox_list_get_path(storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (mkdir_parents(index_dir, CREATE_MODE) < 0 && errno != EEXIST) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic struct mailbox *
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_open(struct cydir_storage *storage, const char *name,
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen struct mail_storage *_storage = &storage->storage;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen index_dir = mailbox_list_get_path(_storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen index = index_storage_alloc(index_dir, path, CYDIR_INDEX_PREFIX);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen pool = pool_alloconly_create("cydir mailbox", 1024+512);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic struct mailbox *
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_mailbox_open(struct mail_storage *_storage, const char *name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct istream *input, enum mailbox_open_flags flags)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct cydir_storage *storage = (struct cydir_storage *)_storage;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "cydir doesn't support streamed mailboxes");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int cydir_mailbox_create(struct mail_storage *_storage,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_storage_set_error(_storage, "Mailbox already exists");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_delete_nonrecursive(struct mailbox_list *list, const char *path,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen unsigned int dir_len;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* skip . and .. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (d->d_name[1] == '.' && d->d_name[2] == '\0')
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* trying to unlink() a directory gives either EPERM or EISDIR
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (non-POSIX). it doesn't really work anywhere in practise,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen so don't bother stat()ing the file first */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "unlink_directory(%s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mailbox_list_set_critical(list, "closedir(%s) failed: %m",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen else if (errno != ENOENT && errno != ENOTEMPTY) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "Directory %s isn't empty, can't delete it.", name));
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainencydir_list_delete_mailbox(struct mailbox_list *list, const char *name)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct cydir_storage *storage = CYDIR_LIST_CONTEXT(list);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *src;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* Make sure the indexes are closed before trying to delete the
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen directory that contains them. It can still fail with some NFS
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen implementations if indexes are opened by another session, but
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen that can't really be helped. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* delete the index and control directories */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (storage->list_module_ctx.super.delete_mailbox(list, name) < 0)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* check if the mailbox actually exists */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return cydir_delete_nonrecursive(list, src, name);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int cydir_storage_close(struct mailbox *box)
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainenstatic void cydir_notify_changes(struct mailbox *box)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen index_mailbox_check_add(&mbox->ibox, mbox->path);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* try to avoid stat() with these checks */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (ctx->flags & MAILBOX_LIST_ITER_FAST_FLAGS) != 0) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* it's a file */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* need to stat() then */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen mail_path = t_strconcat(dir, "/", fname, NULL);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* non-directory */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* non-selectable, but may contain subdirs */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void cydir_class_init(void)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void cydir_class_deinit(void)