cydir-storage.c revision 17ad2164c747cedbf81dae1893063e71a3df0356
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "lib.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "array.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "str.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "mkdir-parents.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "index-mail.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "mail-copy.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "cydir-sync.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "cydir-storage.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include <unistd.h>
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include <dirent.h>
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include <sys/stat.h>
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#define CYDIR_LIST_CONTEXT(obj) \
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen MODULE_CONTEXT(obj, cydir_mailbox_list_module)
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenstruct cydir_mailbox_list {
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen union mailbox_list_module_context module_ctx;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen};
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenextern struct mail_storage cydir_storage;
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainenextern struct mailbox cydir_mailbox;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(cydir_mailbox_list_module,
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen &mailbox_list_module_register);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenstatic struct mail_storage *cydir_storage_alloc(void)
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen{
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen struct cydir_storage *storage;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen pool_t pool;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen pool = pool_alloconly_create("cydir storage", 512+256);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen storage = p_new(pool, struct cydir_storage, 1);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen storage->storage = cydir_storage;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen storage->storage.pool = pool;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen return &storage->storage;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen}
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenstatic void
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainencydir_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen struct mailbox_list_settings *set)
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen{
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen if (set->layout == NULL)
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen set->layout = MAILBOX_LIST_NAME_FS;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen if (set->subscription_fname == NULL)
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen}
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenstatic int create_cydir(struct mail_storage *storage, struct mailbox_list *list,
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen const char *path)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen{
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen mode_t mode;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen gid_t gid;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen mailbox_list_get_dir_permissions(list, NULL, &mode, &gid);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 &&
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen errno != EEXIST) {
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen mail_storage_set_critical(storage,
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen "mkdir(%s) failed: %m", path);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen }
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return -1;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen }
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return 0;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen}
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenstatic struct mailbox *
d97f081a3de44852197ced772e21560c108895a6Timo Sirainencydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen const char *name, struct istream *input,
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen enum mailbox_flags flags)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen{
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen struct cydir_mailbox *mbox;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen pool_t pool;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* cydir can't work without index files */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen flags &= ~MAILBOX_FLAG_NO_INDEX_FILES;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen pool = pool_alloconly_create("cydir mailbox", 1024+512);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox = p_new(pool, struct cydir_mailbox, 1);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox->ibox.box = cydir_mailbox;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox->ibox.box.pool = pool;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox->ibox.box.storage = storage;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox->ibox.box.list = list;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mbox->ibox.mail_vfuncs = &cydir_mail_vfuncs;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen index_storage_mailbox_alloc(&mbox->ibox, name, input, flags,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen CYDIR_INDEX_PREFIX);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi mail_index_set_fsync_types(mbox->ibox.index,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen MAIL_INDEX_SYNC_TYPE_APPEND |
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen mbox->storage = (struct cydir_storage *)storage;
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen return &mbox->ibox.box;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen}
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainenstatic int cydir_mailbox_open(struct mailbox *box)
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen{
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen struct stat st;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (box->input != NULL) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mail_storage_set_critical(box->storage,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen "cydir doesn't support streamed mailboxes");
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen return -1;
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen if (stat(box->path, &st) == 0) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* exists, open it */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen } else if (errno == ENOENT && strcmp(box->name, "INBOX") == 0) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* INBOX always exists, create it */
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen if (create_cydir(box->storage, box->list, box->path) < 0)
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return -1;
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen } else if (errno == ENOENT) {
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name));
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen return -1;
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen } else if (errno == EACCES) {
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen mail_storage_set_critical(box->storage, "%s",
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen mail_error_eacces_msg("stat", box->path));
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return -1;
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen } else {
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen mail_storage_set_critical(box->storage, "stat(%s) failed: %m",
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen box->path);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen return -1;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen }
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen return index_storage_mailbox_open(box);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainenstatic int
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainencydir_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
431c0aba57fba2fd6eb398acd6ef4e73b5dc1b86Timo Sirainen struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen struct mail_index_transaction *trans;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen trans = mail_index_transaction_begin(mbox->ibox.view, 0);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (update->uid_validity != 0) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen mail_index_update_header(trans,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen offsetof(struct mail_index_header, uid_validity),
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen &update->uid_validity, sizeof(update->uid_validity),
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen TRUE);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen }
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* FIXME: update next_uid, highestmodseq. guid is also missing.. */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen if (mail_index_transaction_commit(&trans) < 0) {
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen mail_storage_set_internal_error(box->storage);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen return -1;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen }
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return 0;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen}
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
static int
cydir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
bool directory)
{
const char *path;
struct stat st;
path = mailbox_list_get_path(box->list, box->name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) == 0) {
mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
"Mailbox already exists");
return -1;
}
if (create_cydir(box->storage, box->list, path) < 0)
return -1;
return directory || update == NULL ? 0 :
cydir_mailbox_update(box, update);
}
static int
cydir_delete_nonrecursive(struct mailbox_list *list, const char *path,
const char *name)
{
DIR *dir;
struct dirent *d;
string_t *full_path;
unsigned int dir_len;
bool unlinked_something = FALSE;
dir = opendir(path);
if (dir == NULL) {
if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"opendir(%s) failed: %m", path);
}
return -1;
}
full_path = t_str_new(256);
str_append(full_path, path);
str_append_c(full_path, '/');
dir_len = str_len(full_path);
errno = 0;
while ((d = readdir(dir)) != NULL) {
if (d->d_name[0] == '.') {
/* skip . and .. */
if (d->d_name[1] == '\0')
continue;
if (d->d_name[1] == '.' && d->d_name[2] == '\0')
continue;
}
str_truncate(full_path, dir_len);
str_append(full_path, d->d_name);
/* trying to unlink() a directory gives either EPERM or EISDIR
(non-POSIX). it doesn't really work anywhere in practise,
so don't bother stat()ing the file first */
if (unlink(str_c(full_path)) == 0)
unlinked_something = TRUE;
else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
mailbox_list_set_critical(list, "unlink(%s) failed: %m",
str_c(full_path));
}
}
if (closedir(dir) < 0) {
mailbox_list_set_critical(list, "closedir(%s) failed: %m",
path);
}
if (rmdir(path) == 0)
unlinked_something = TRUE;
else if (errno != ENOENT && errno != ENOTEMPTY) {
mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
return -1;
}
if (!unlinked_something) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
t_strdup_printf("Directory %s isn't empty, "
"can't delete it.", name));
return -1;
}
return 0;
}
static int
cydir_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
struct cydir_mailbox_list *mlist = CYDIR_LIST_CONTEXT(list);
struct stat st;
const char *src;
/* Make sure the indexes are closed before trying to delete the
directory that contains them. It can still fail with some NFS
implementations if indexes are opened by another session, but
that can't really be helped. */
index_storage_destroy_unrefed();
/* delete the index and control directories */
if (mlist->module_ctx.super.delete_mailbox(list, name) < 0)
return -1;
/* check if the mailbox actually exists */
src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(src, &st) != 0 && errno == ENOENT) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
return -1;
}
return cydir_delete_nonrecursive(list, src, name);
}
static void cydir_notify_changes(struct mailbox *box)
{
struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
if (box->notify_callback == NULL)
index_mailbox_check_remove_all(&mbox->ibox);
else
index_mailbox_check_add(&mbox->ibox, mbox->ibox.box.path);
}
static int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
ATTR_UNUSED,
const char *dir, const char *fname,
const char *mailbox_name ATTR_UNUSED,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
const char *mail_path;
struct stat st;
int ret = 1;
/* try to avoid stat() with these checks */
if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
type != MAILBOX_LIST_FILE_TYPE_UNKNOWN) {
/* it's a file */
*flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
return 0;
}
/* need to stat() then */
mail_path = t_strconcat(dir, "/", fname, NULL);
if (stat(mail_path, &st) == 0) {
if (!S_ISDIR(st.st_mode)) {
/* non-directory */
*flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
ret = 0;
} else if (st.st_nlink == 2) {
/* no subdirectories */
*flags |= MAILBOX_NOCHILDREN;
} else if (*ctx->list->set.maildir_name != '\0') {
/* non-default configuration: we have one directory
containing the mailboxes. if there are 3 links,
either this is a selectable mailbox without children
or non-selectable mailbox with children */
if (st.st_nlink > 3)
*flags |= MAILBOX_CHILDREN;
} else {
/* default configuration: all subdirectories are
child mailboxes. */
if (st.st_nlink > 2)
*flags |= MAILBOX_CHILDREN;
}
} else if (errno == ENOENT) {
/* doesn't exist - probably a non-existing subscribed mailbox */
*flags |= MAILBOX_NONEXISTENT;
} else {
/* non-selectable. probably either access denied, or symlink
destination not found. don't bother logging errors. */
*flags |= MAILBOX_NOSELECT;
}
return ret;
}
static void cydir_class_init(void)
{
cydir_transaction_class_init();
}
static void cydir_class_deinit(void)
{
cydir_transaction_class_deinit();
}
static void cydir_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
struct mailbox_list *list)
{
struct cydir_mailbox_list *mlist;
mlist = p_new(list->pool, struct cydir_mailbox_list, 1);
mlist->module_ctx.super = list->v;
list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
list->v.delete_mailbox = cydir_list_delete_mailbox;
MODULE_CONTEXT_SET(list, cydir_mailbox_list_module, mlist);
}
struct mail_storage cydir_storage = {
MEMBER(name) CYDIR_STORAGE_NAME,
MEMBER(class_flags) 0,
{
NULL,
cydir_class_init,
cydir_class_deinit,
cydir_storage_alloc,
NULL,
index_storage_destroy,
cydir_storage_add_list,
cydir_storage_get_list_settings,
NULL,
cydir_mailbox_alloc,
NULL
}
};
struct mailbox cydir_mailbox = {
MEMBER(name) NULL,
MEMBER(storage) NULL,
MEMBER(list) NULL,
{
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
cydir_mailbox_open,
index_storage_mailbox_close,
cydir_mailbox_create,
cydir_mailbox_update,
index_storage_get_status,
NULL,
NULL,
cydir_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
cydir_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_transaction_set_max_modseq,
index_keywords_create,
index_keywords_create_from_indexes,
index_keywords_ref,
index_keywords_unref,
index_keyword_is_valid,
index_storage_get_seq_range,
index_storage_get_uid_range,
index_storage_get_expunged_uids,
NULL,
NULL,
NULL,
index_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next_nonblock,
index_storage_search_next_update_seq,
cydir_save_alloc,
cydir_save_begin,
cydir_save_continue,
cydir_save_finish,
cydir_save_cancel,
mail_storage_copy,
index_storage_is_inconsistent
}
};