index-storage.c revision b83deefd2cf1e293373673eefb4d5cf60907978c
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastruct index_storage_module index_storage_module =
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina MODULE_CONTEXT_INIT(&mail_storage_module_register);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinaint index_list_create_missing_index_dir(struct mailbox_list *list,
d3c82d0170d6d7407549afdadd08aa7e11aeb9a2Pavel Březina const char *root_dir, *index_dir, *parent_dir, *p, *origin;
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina unsigned int n = 0;
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina if (*index_dir == '\0' || strcmp(index_dir, root_dir) == 0)
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina mailbox_list_get_dir_permissions(list, name, &mode, &gid, &origin);
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina while (mkdir_chgrp(index_dir, mode, gid, origin) < 0) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (errno != ENOENT || p == NULL || ++n == 2) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* create the parent directory first */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastatic struct mail_index *
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaindex_storage_alloc(struct mailbox_list *list, const char *name,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_path = mailbox_list_get_path(list, name,
afdc0179af0ad8ddbedd67422193ef02dcd2bf84Lukas Slebodnik index_dir = (flags & MAILBOX_FLAG_NO_INDEX_FILES) != 0 ? "" :
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_INDEX);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return mail_index_alloc_cache_get(mailbox_path, index_dir, prefix);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastatic void set_cache_decisions(const char *set, const char *fields,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina const char *const *arr;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek for (arr = t_strsplit_spaces(fields, " ,"); *arr != NULL; arr++) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek for (i = 0; i < MAIL_INDEX_CACHE_FIELD_COUNT; i++) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek i_error("%s: Invalid cache field name '%s', ignoring ",
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekstatic void index_cache_register_defaults(struct mailbox *box)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina const struct mail_storage_settings *set = box->storage->set;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina set_cache_decisions("mail_never_cache_fields",
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->cache_fields = i_malloc(sizeof(global_cache_fields));
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina memcpy(ibox->cache_fields, global_cache_fields,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_cache_register_fields(cache, ibox->cache_fields,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavoid index_storage_lock_notify(struct mailbox *box,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina const char *str;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina /* if notify type changes, print the message immediately */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (ibox->last_notify_type == MAILBOX_LOCK_NOTIFY_NONE ||
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (ibox->last_notify_type == MAILBOX_LOCK_NOTIFY_NONE &&
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina notify_type == MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina /* first override notification, show it */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (now < ibox->next_lock_notify || secs_left < 15)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->next_lock_notify = now + LOCK_NOTIFY_INTERVAL;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina str = t_strdup_printf("Mailbox is locked, will abort in "
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina notify_no(box, str, storage->callback_context);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina str = t_strdup_printf("Stale mailbox lock file detected, "
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina notify_ok(box, str, storage->callback_context);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavoid index_storage_lock_notify_reset(struct mailbox *box)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinaint index_storage_mailbox_open(struct mailbox *box, bool move_to_memory)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->index_flags &= ~MAIL_INDEX_OPEN_FLAG_CREATE;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina "Couldn't create index file");
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (index_list_create_missing_index_dir(box->list, box->name) < 0) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_storage_set_internal_error(box->storage);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ret = mail_index_open(box->index, index_flags, lock_method);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (mail_index_move_to_memory(box->index) < 0) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina /* try opening once more. it should be created
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina directly into memory now. */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina box->cache = mail_index_get_cache(box->index);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ibox->keyword_names = mail_index_get_keywords(box->index);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_index_ext_register(box->index, "hdr-vsize",
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina sizeof(struct index_vsize_header), 0,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if ((box->flags & MAILBOX_FLAG_OPEN_DELETED) == 0) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvoid index_storage_mailbox_alloc(struct mailbox *box, const char *name,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek const char *path;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_namespace_get_vname(box->list->ns, vname, name);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek box->vname = p_strdup(box->pool, str_c(vname));
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek p_array_init(&box->search_results, box->pool, 16);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek ibox = p_new(box->pool, struct index_mailbox_context, 1);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek ibox->index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_storage_settings_to_index_flags(box->storage->set);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek MODULE_CONTEXT_SET(box, index_storage_module, ibox);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek box->index = index_storage_alloc(box->list, name, flags, index_prefix);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina (box->list->ns->flags & NAMESPACE_FLAG_INBOX) != 0;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_index_set_permissions(box->index, box->file_create_mode,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekint index_storage_mailbox_enable(struct mailbox *box,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if ((feature & MAILBOX_FEATURE_CONDSTORE) != 0) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek box->enabled_features |= MAILBOX_FEATURE_CONDSTORE;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvoid index_storage_mailbox_close(struct mailbox *box)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvoid index_storage_mailbox_free(struct mailbox *box)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvoid index_storage_mailbox_update_cache_fields(struct mailbox *box,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek const char *const *field_names = update->cache_fields;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ARRAY_DEFINE(new_fields, struct mail_cache_field);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina unsigned int i, j, old_count;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina old_fields = mail_cache_register_get_list(box->cache,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* There shouldn't be many fields, so don't worry about O(n^2). */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* see if it's an existing field */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek for (j = 0; j < old_count; j++) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if (strcmp(field_names[i], old_fields[j].name) == 0)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek } else if (strncmp(field_names[i], "hdr.", 4) == 0) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* new header */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina /* new unknown field. we can't do anything about
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina this since we don't know its type */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekint index_storage_mailbox_update(struct mailbox *box,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek index_storage_mailbox_update_cache_fields(box, update);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* make sure we get the latest index info */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* UIDVALIDITY change requires index to be reset */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek offsetof(struct mail_index_header, uid_validity),
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_index_modseq_get_highest(view) < update->min_highest_modseq) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if ((ret = mail_index_transaction_commit(&trans)) < 0)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_storage_set_internal_error(box->storage);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaint index_storage_mailbox_delete_dir(struct mailbox *box, bool mailbox_deleted)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (mailbox_list_delete_dir(box->list, box->name) == 0)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina (void)mailbox_list_get_last_error(box->list, &error);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (error != MAIL_ERROR_NOTFOUND || !mailbox_deleted) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_storage_copy_list_error(box->storage, box->list);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* failed directory deletion, but mailbox deletion succeeded.
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina this was probably maildir++, which internally deleted the
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina directory as well. add changelog record about that too. */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_name_get_sha128(box->name, dir_sha128);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_DIR,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaint index_storage_mailbox_delete(struct mailbox *box)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* \noselect mailbox, try deleting only the directory */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return index_storage_mailbox_delete_dir(box, FALSE);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (mailbox_mark_index_deleted(box, TRUE) < 0)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* Make sure the indexes are closed before trying to delete the
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina directory that contains them. It can still fail with some NFS
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina implementations if indexes are opened by another session, but
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina that can't really be helped. */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (box->list->v.delete_mailbox(box->list, box->name) < 0) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_storage_copy_list_error(box->storage, box->list);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_MAILBOX,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return index_storage_mailbox_delete_dir(box, TRUE);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaint index_storage_mailbox_rename(struct mailbox *src, struct mailbox *dest,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (src->list->v.rename_mailbox(src->list, src->name,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_storage_copy_list_error(src->storage, src->list);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* we'll track mailbox names, instead of GUIDs. We may be renaming a
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina non-selectable mailbox (directory), which doesn't even have a GUID */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mailbox_list_add_change(src->list, MAILBOX_LOG_RECORD_RENAME, guid);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinabool index_storage_is_readonly(struct mailbox *box)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if ((box->flags & MAILBOX_FLAG_READONLY) != 0)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* return read-only only if there are no private flags
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina (that are stored in index files) */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinabool index_storage_allow_new_keywords(struct mailbox *box)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* FIXME: return FALSE if we're full */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinabool index_storage_is_inconsistent(struct mailbox *box)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return mail_index_view_is_inconsistent(box->view);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinabool index_keyword_is_valid(struct mailbox *box, const char *keyword,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina const char **error_r)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina unsigned int i, idx;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* if it already exists, skip validity checks */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (mail_index_keyword_lookup(box->index, keyword, &idx))
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* these are IMAP-specific restrictions, but for now IMAP is all we
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina care about */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (IS_ATOM_SPECIAL((unsigned char)keyword[i])) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (i > box->storage->set->mail_max_keyword_length) {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaindex_keywords_create_skip(struct mailbox *box,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina const char *const keywords[])
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (mailbox_keyword_is_valid(box, *keywords, &error))
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina (void)array_append_space(&valid_keywords); /* NULL-terminate */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return mail_index_keywords_create(box->index, keywords);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaint index_keywords_create(struct mailbox *box, const char *const keywords[],
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina struct mail_keywords **keywords_r, bool skip_invalid)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina unsigned int i;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (mailbox_keyword_is_valid(box, keywords[i], &error))
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* found invalid keywords, do this the slow way */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina *keywords_r = index_keywords_create_skip(box, keywords);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina *keywords_r = mail_index_keywords_create(box->index, keywords);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinaindex_keywords_create_from_indexes(struct mailbox *_box,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return mail_index_keywords_create_from_indexes(_box->index, idx);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinavoid index_keywords_ref(struct mail_keywords *keywords)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinavoid index_keywords_unref(struct mail_keywords *keywords)