mail-index.c revision 947ad4dfcc7c5c07263a5cf2493fdefc9e12d4c3
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek/* Copyright (C) 2003-2004 Timo Sirainen */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "lib.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "ioloop.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "array.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "buffer.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "hash.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mmap-util.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "nfs-workarounds.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "read-full.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "write-full.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mail-index-private.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mail-index-view-private.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mail-index-sync-private.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mail-transaction-log.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include "mail-cache.h"
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include <stdio.h>
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include <stddef.h>
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include <time.h>
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#include <sys/stat.h>
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstruct mail_index_module_register mail_index_module_register = { 0 };
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index *index;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index = i_new(struct mail_index, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->dir = i_strdup(dir);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->prefix = i_strdup(prefix);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->fd = -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->extension_pool =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek p_array_init(&index->extensions, index->extension_pool, 5);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_array_init(&index->sync_lost_handlers, 4);
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek i_array_init(&index->module_contexts,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek I_MIN(5, mail_index_module_register.id));
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->mode = 0600;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->gid = (gid_t)-1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->keywords_ext_id =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_ext_register(index, "keywords", 128, 2, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->keywords_pool = pool_alloconly_create("keywords", 512);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_array_init(&index->keywords, 16);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->keywords_hash =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek hash_create(default_pool, index->keywords_pool, 0,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek strcase_hash, (hash_cmp_callback_t *)strcasecmp);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->log = mail_transaction_log_alloc(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return index;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_free(struct mail_index **_index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index *index = *_index;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek *_index = NULL;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_close(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_transaction_log_free(&index->log);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek hash_destroy(index->keywords_hash);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek pool_unref(index->extension_pool);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek pool_unref(index->keywords_pool);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_free(&index->sync_lost_handlers);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_free(&index->keywords);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_free(&index->module_contexts);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_free(index->error);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_free(index->dir);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_free(index->prefix);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_free(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_set_permissions(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mode_t mode, gid_t gid)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->mode = mode & 0666;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->gid = gid;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint32_t default_hdr_size,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint16_t default_record_size,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint16_t default_record_align)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const struct mail_index_registered_ext *extensions;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index_registered_ext rext;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek unsigned int i, ext_count;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek extensions = array_get(&index->extensions, &ext_count);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* see if it's already there */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (i = 0; i < ext_count; i++) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (strcmp(extensions[i].name, name) == 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return i;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek memset(&rext, 0, sizeof(rext));
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext.name = p_strdup(index->extension_pool, name);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext.index_idx = ext_count;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext.hdr_size = default_hdr_size;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext.record_size = default_record_size;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext.record_align = default_record_align;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_append(&index->extensions, &rext, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return ext_count;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_register_expunge_handler(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint32_t ext_id, bool call_always,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_expunge_handler_t *cb,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek void *context)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index_registered_ext *rext;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext = array_idx_modifiable(&index->extensions, ext_id);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->expunge_handler = cb;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->expunge_context = context;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->expunge_handler_call_always = call_always;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_unregister_expunge_handler(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint32_t ext_id)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index_registered_ext *rext;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext = array_idx_modifiable(&index->extensions, ext_id);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(rext->expunge_handler != NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->expunge_handler = NULL;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_sync_handler_t *cb,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek enum mail_index_sync_handler_type type)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index_registered_ext *rext;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext = array_idx_modifiable(&index->extensions, ext_id);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(rext->sync_handler.callback == NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->sync_handler.callback = cb;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->sync_handler.type = type;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_unregister_sync_handler(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek uint32_t ext_id)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index_registered_ext *rext;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext = array_idx_modifiable(&index->extensions, ext_id);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(rext->sync_handler.callback != NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->sync_handler.callback = NULL;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek rext->sync_handler.type = 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_register_sync_lost_handler(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_sync_lost_handler_t *cb)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_append(&index->sync_lost_handlers, &cb, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_sync_lost_handler_t *cb)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_sync_lost_handler_t *const *handlers;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek unsigned int i, count;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek handlers = array_get(&index->sync_lost_handlers, &count);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (i = 0; i < count; i++) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (handlers[i] == cb) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_delete(&index->sync_lost_handlers, i, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek break;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekbool mail_index_keyword_lookup(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const char *keyword, bool autocreate,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek unsigned int *idx_r)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek char *keyword_dup;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek void *value;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* keywords_hash keeps a name => index mapping of keywords.
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek Keywords are never removed from it, so the index values are valid
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for the lifetime of the mail_index. */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (hash_lookup_full(index->keywords_hash, keyword, NULL, &value)) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek *idx_r = POINTER_CAST_TO(value, unsigned int);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return TRUE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (!autocreate) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek *idx_r = (unsigned int)-1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return FALSE;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
84ae0c4345baf1a589a237bfd132acdaf7a56738Jakub Hrozek *idx_r = array_count(&index->keywords);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech hash_insert(index->keywords_hash, keyword_dup, POINTER_CAST(*idx_r));
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_append(&index->keywords, &keyword, 1);
84ae0c4345baf1a589a237bfd132acdaf7a56738Jakub Hrozek return TRUE;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_map_parse_keywords(struct mail_index_map *map)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct mail_index *index = map->index;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik const struct mail_index_ext *ext;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik const struct mail_index_keyword_header *kw_hdr;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik const struct mail_index_keyword_header_rec *kw_rec;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik const char *name;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik unsigned int i, name_area_end_offset, old_count;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik uint32_t ext_id;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik map->keywords_read = TRUE;
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik ext_id = mail_index_map_lookup_ext(map, "keywords");
a263309322cf8fff15d21207a4eee5f301e3ad2eLukas Slebodnik if (ext_id == (uint32_t)-1) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (array_is_created(&map->keyword_idx_map))
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_clear(&map->keyword_idx_map);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek }
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek ext = array_idx(&map->extensions, ext_id);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Extension header contains:
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek - struct mail_index_keyword_header
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek - struct mail_index_keyword_header_rec * keywords_count
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek - const char names[] * keywords_count
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(ext->hdr_offset < map->hdr.header_size);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek kw_rec = (const void *)(kw_hdr + 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek name = (const char *)(kw_rec + kw_hdr->keywords_count);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_count(&map->keyword_idx_map);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Keywords can only be added into same mapping. Removing requires a
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek new mapping (recreating the index file) */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (kw_hdr->keywords_count == old_count) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* nothing changed */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek /* make sure the header is valid */
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek if (kw_hdr->keywords_count < old_count) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_error(index, "Corrupted index file %s: "
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek "Keywords removed unexpectedly",
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_error(index, "Corrupted index file %s: "
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek "keywords_count larger than header size",
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (i = 0; i < kw_hdr->keywords_count; i++) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (kw_rec[i].name_offset > name_area_end_offset) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_error(index, "Corrupted index file %s: "
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek "name_offset points outside allocated header",
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (name[name_area_end_offset-1] != '\0') {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_error(index, "Corrupted index file %s: "
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech "Keyword header doesn't end with NUL",
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* create file -> index mapping */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (!array_is_created(&map->keyword_idx_map))
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#ifdef DEBUG
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Check that existing headers are still the same. It's behind DEBUG
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek since it's pretty useless waste of CPU normally. */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const char *keyword = name + kw_rec[i].name_offset;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const unsigned int *old_idx;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek unsigned int idx;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek old_idx = array_idx(&map->keyword_idx_map, i);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (!mail_index_keyword_lookup(index, keyword, FALSE, &idx) ||
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek idx != *old_idx) {
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek mail_index_set_error(index, "Corrupted index file %s: "
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek "Keywords changed unexpectedly",
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek#endif
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Register the newly seen keywords */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i = array_count(&map->keyword_idx_map);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (; i < kw_hdr->keywords_count; i++) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const char *keyword = name + kw_rec[i].name_offset;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek unsigned int idx;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (void)mail_index_keyword_lookup(index, keyword, TRUE, &idx);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek array_append(&map->keyword_idx_map, &idx, 1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Make sure all the keywords are in index->keywords. It's quick to do
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if nothing has changed. */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (void)mail_index_map_parse_keywords(index->map);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return &index->keywords;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_try_open_only(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->fd == -1);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* Note that our caller must close index->fd by itself. */
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek index->fd = nfs_safe_open(index->filepath, O_RDWR);
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek index->readonly = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->fd == -1 && errno == EACCES) {
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik index->fd = open(index->filepath, O_RDONLY);
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik index->readonly = TRUE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->fd == -1) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (errno != ENOENT)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_set_syscall_error(index, "open()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* have to create it */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstatic int
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekmail_index_try_open(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek int ret;
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->fd == -1);
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (MAIL_INDEX_IS_IN_MEMORY(index))
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->map == NULL || index->map->lock_id == 0);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (ret == 0) {
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek /* it's corrupted - recreate it */
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek if (index->fd != -1) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (close(index->fd) < 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_syscall_error(index, "close()");
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik index->fd = -1;
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return ret;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mode_t old_mask;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek const char *path;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek int fd;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek old_mask = umask(0);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek umask(old_mask);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (fd == -1)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_file_set_syscall_error(index, path, "open()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->gid != (gid_t)-1 && fchown(fd, (uid_t)-1, index->gid) < 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_file_set_syscall_error(index, path, "fchown()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek return fd;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstatic bool mail_index_open_files(struct mail_index *index,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek enum mail_index_open_flags flags)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek int ret;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek bool created = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = mail_transaction_log_open(index->log);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (ret == 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* if dovecot.index exists, read it first so that we can get
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek the correct indexid and log sequence */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (void)mail_index_try_open(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->indexid == 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* create a new indexid for us */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->indexid = ioloop_time;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek ret = mail_transaction_log_create(index->log);
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek created = TRUE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (ret >= 0) {
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik ret = index->map != NULL ? 0 : mail_index_try_open(index);
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik if (ret == 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* doesn't exist / corrupted */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->map = mail_index_map_alloc(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (ret < 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* open/create failed, fallback to in-memory indexes */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (mail_index_move_to_memory(index) < 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->cache = created ? mail_cache_create(index) :
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_cache_open_or_create(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return TRUE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags,
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek enum file_lock_method lock_method)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik int i = 0, ret = 1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->opened) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->map != NULL &&
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (index->map->hdr.flags &
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* corrupted, reopen files */
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek mail_index_close(index);
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek } else {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->map != NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 1;
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->filepath = MAIL_INDEX_IS_IN_MEMORY(index) ?
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_strdup("(in-memory index)") :
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_strconcat(index->dir, "/", index->prefix, NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek for (;;) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->shared_lock_count = 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->excl_lock_count = 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->lock_type = F_UNLCK;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->lock_id_counter = 2;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->readonly = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->nodiskspace = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->index_lock_timeout = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->log_locked = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->mmap_disable =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0;
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik index->use_excl_dotlocks =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->fsync_disable =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) != 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->nfs_flush =
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek (flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->lock_method = lock_method;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek if (index->nfs_flush && index->fsync_disable)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_fatal("nfs flush requires fsync_disable=no");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->nfs_flush && !index->mmap_disable)
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik i_fatal("nfs flush requires mmap_disable=yes");
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(!index->opened);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (!mail_index_open_files(index, flags)) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* doesn't exist and create flag not used */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek break;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->map != NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->opened = TRUE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->fsck) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->fsck = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = mail_index_fsck(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (ret == 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* completely broken, reopen */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (i++ < 3) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_close(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek continue;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* too many tries */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek break;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek if (ret <= 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_close(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(ret <= 0 || index->map != NULL);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return ret;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstatic void mail_index_close_file(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->file_lock != NULL)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek file_lock_free(&index->file_lock);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->fd != -1) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (close(index->fd) < 0)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_set_syscall_error(index, "close()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->fd = -1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->lock_type == F_RDLCK)
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek index->lock_type = F_UNLCK;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek index->lock_id_counter += 2;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->shared_lock_count = 0;
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik}
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekvoid mail_index_close(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->map != NULL)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_unmap(&index->map);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_close_file(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_transaction_log_close(index->log);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->cache != NULL)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_cache_free(&index->cache);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_free_and_null(index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->indexid = 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->opened = FALSE;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_reopen_if_changed(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek struct stat st1, st2;
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek i_assert(index->excl_lock_count == 0);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (MAIL_INDEX_IS_IN_MEMORY(index))
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek if (index->fd == -1)
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek return mail_index_try_open_only(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik if (fstat(index->fd, &st1) < 0) {
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik if (errno != ESTALE)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_set_syscall_error(index, "fstat()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* deleted/recreated, reopen */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_try_open_only(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (index->nfs_flush)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek nfs_flush_attr_cache(index->filepath);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (nfs_safe_stat(index->filepath, &st2) < 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (errno == ENOENT)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_set_syscall_error(index, "stat()");
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (st1.st_ino == st2.st_ino && CMP_DEV_T(st1.st_dev, st2.st_dev)) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* the same file */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 1;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik /* new file, new locks. the old fd can keep its locks, they don't
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek matter anymore as no-one's going to modify the file. */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek mail_index_close_file(index);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return mail_index_try_open_only(index);
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek}
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_refresh(struct mail_index *index)
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik{
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik int ret;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (MAIL_INDEX_IS_IN_MEMORY(index))
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
a949dfb6b03c70896e6ab3c7a10781e8ecbaadc2Lukas Slebodnik if (index->excl_lock_count > 0) {
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek /* we have index exclusively locked, nothing could
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek have changed. */
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek }
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return ret <= 0 ? -1 : 0;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekstruct mail_cache *mail_index_get_cache(struct mail_index *index)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek return index->cache;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek}
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozekint mail_index_set_error(struct mail_index *index, const char *fmt, ...)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek{
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek va_list va;
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek
bae42db17f223e9ba7fa239d899414877d9d8eafJakub Hrozek i_free(index->error);
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek if (fmt == NULL)
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek index->error = NULL;
b8946a5dbde01a87465de707092716349a35248bJakub Hrozek else {
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech va_start(va, fmt);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech index->error = i_strdup_vprintf(fmt, va);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech va_end(va);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
84ae0c4345baf1a589a237bfd132acdaf7a56738Jakub Hrozek i_error("%s", index->error);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech return -1;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech}
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čechint mail_index_move_to_memory(struct mail_index *index)
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech{
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech struct mail_index_map *map;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech if (MAIL_INDEX_IS_IN_MEMORY(index))
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech return index->map == NULL ? -1 : 0;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech /* set the index as being into memory */
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech i_free_and_null(index->dir);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech i_free(index->filepath);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech index->filepath = i_strdup("(in-memory index)");
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech if (index->map == NULL) {
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech /* index was never even opened. just mark it as being in
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech memory and let the caller re-open the index. */
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech i_assert(index->fd == -1);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech return -1;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech /* move index map to memory */
84ae0c4345baf1a589a237bfd132acdaf7a56738Jakub Hrozek if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech map = mail_index_map_clone(index->map);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech mail_index_unmap(&index->map);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech index->map = map;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech if (index->log != NULL) {
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech /* move transaction log to memory */
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech mail_transaction_log_move_to_memory(index->log);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech }
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech if (index->file_lock != NULL)
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech file_lock_free(&index->file_lock);
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech /* close the index file. */
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech if (close(index->fd) < 0)
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech mail_index_set_syscall_error(index, "close()");
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech index->fd = -1;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech return 0;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech}
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
57a924e71230ea360b19a88e0d5818cf01017161Petr Čechvoid mail_index_mark_corrupted(struct mail_index *index)
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech{
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech index->indexid = 0;
57a924e71230ea360b19a88e0d5818cf01017161Petr Čech
index->map->hdr.flags |= MAIL_INDEX_HDR_FLAG_CORRUPTED;
if (unlink(index->filepath) < 0 && errno != ENOENT && errno != ESTALE)
mail_index_set_syscall_error(index, "unlink()");
}
int mail_index_set_syscall_error(struct mail_index *index,
const char *function)
{
i_assert(function != NULL);
if (ENOSPACE(errno)) {
index->nodiskspace = TRUE;
return -1;
}
return mail_index_set_error(index, "%s failed with index file %s: %m",
function, index->filepath);
}
int mail_index_file_set_syscall_error(struct mail_index *index,
const char *filepath,
const char *function)
{
i_assert(filepath != NULL);
i_assert(function != NULL);
if (ENOSPACE(errno)) {
index->nodiskspace = TRUE;
return -1;
}
return mail_index_set_error(index, "%s failed with file %s: %m",
function, filepath);
}
const char *mail_index_get_error_message(struct mail_index *index)
{
return index->error;
}
void mail_index_reset_error(struct mail_index *index)
{
if (index->error != NULL) {
i_free(index->error);
index->error = NULL;
}
index->nodiskspace = FALSE;
index->index_lock_timeout = FALSE;
}
#ifdef WORDS_BIGENDIAN
/* FIXME: Unfortunately these functions were originally written to use
endian-specific code and we can't avoid that without breaking backwards
compatibility. When we do break it, just select one of these. */
uint32_t mail_index_uint32_to_offset(uint32_t offset)
{
i_assert(offset < 0x40000000);
i_assert((offset & 3) == 0);
offset >>= 2;
return 0x00000080 | ((offset & 0x0000007f)) |
0x00008000 | ((offset & 0x00003f80) >> 7 << 8) |
0x00800000 | ((offset & 0x001fc000) >> 14 << 16) |
0x80000000 | ((offset & 0x0fe00000) >> 21 << 24);
}
uint32_t mail_index_offset_to_uint32(uint32_t offset)
{
if ((offset & 0x80808080) != 0x80808080)
return 0;
return (((offset & 0x0000007f)) |
((offset & 0x00007f00) >> 8 << 7) |
((offset & 0x007f0000) >> 16 << 14) |
((offset & 0x7f000000) >> 24 << 21)) << 2;
}
#else
uint32_t mail_index_uint32_to_offset(uint32_t offset)
{
i_assert(offset < 0x40000000);
i_assert((offset & 3) == 0);
offset >>= 2;
return 0x80000000 | ((offset & 0x0000007f) << 24) |
0x00800000 | ((offset & 0x00003f80) >> 7 << 16) |
0x00008000 | ((offset & 0x001fc000) >> 14 << 8) |
0x00000080 | ((offset & 0x0fe00000) >> 21);
}
uint32_t mail_index_offset_to_uint32(uint32_t offset)
{
if ((offset & 0x80808080) != 0x80808080)
return 0;
return (((offset & 0x0000007f) << 21) |
((offset & 0x00007f00) >> 8 << 14) |
((offset & 0x007f0000) >> 16 << 7) |
((offset & 0x7f000000) >> 24)) << 2;
}
#endif