mail-index.c revision 4a09c57f1c66b4a8880bcc12b567bb42c3549f52
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#include "ioloop.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "array.h"
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen#include "buffer.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "eacces-error.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "hash.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "str-sanitize.h"
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen#include "mmap-util.h"
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen#include "nfs-workarounds.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "read-full.h"
18565c69efcd7db003dbf27cf625ed822e889fb1Timo Sirainen#include "write-full.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-index-private.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-index-view-private.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-index-sync-private.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-index-modseq.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-transaction-log.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include "mail-cache.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <stdio.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <stddef.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <time.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <sys/stat.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenstruct mail_index_module_register mail_index_module_register = { 0 };
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen{
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct mail_index *index;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen index = i_new(struct mail_index, 1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen index->dir = i_strdup(dir);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen index->prefix = i_strdup(prefix);
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen index->fd = -1;
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index->extension_pool =
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen p_array_init(&index->extensions, index->extension_pool, 5);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_array_init(&index->sync_lost_handlers, 4);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen i_array_init(&index->module_contexts,
4b41116563110d00330896a568eff1078c382827Timo Sirainen I_MIN(5, mail_index_module_register.id));
4b41116563110d00330896a568eff1078c382827Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen index->mode = 0600;
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen index->gid = (gid_t)-1;
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen index->keywords_ext_id =
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_index_ext_register(index, MAIL_INDEX_EXT_KEYWORDS,
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen 128, 2, 1);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen index->keywords_pool = pool_alloconly_create("keywords", 512);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen i_array_init(&index->keywords, 16);
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen index->keywords_hash =
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen hash_table_create(default_pool, index->keywords_pool, 0,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen index->log = mail_transaction_log_alloc(index);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen mail_index_modseq_init(index);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen return index;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mail_index_free(struct mail_index **_index)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct mail_index *index = *_index;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen *_index = NULL;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen mail_index_close(index);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen mail_transaction_log_free(&index->log);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen hash_table_destroy(&index->keywords_hash);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen pool_unref(&index->extension_pool);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen pool_unref(&index->keywords_pool);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen array_free(&index->sync_lost_handlers);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen array_free(&index->keywords);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen array_free(&index->module_contexts);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i_free(index->gid_origin);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i_free(index->error);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i_free(index->dir);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i_free(index->prefix);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen i_free(index);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen}
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mail_index_set_fsync_types(struct mail_index *index,
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen enum mail_index_sync_type fsync_mask)
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen index->fsync_mask = fsync_mask;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen mode_t mode, gid_t gid, const char *gid_origin)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen index->mode = mode & 0666;
4b41116563110d00330896a568eff1078c382827Timo Sirainen index->gid = gid;
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen i_free(index->gid_origin);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen index->gid_origin = i_strdup(gid_origin);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen uint32_t default_hdr_size,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen uint16_t default_record_size,
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen uint16_t default_record_align)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct mail_index_registered_ext rext;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen uint32_t ext_id;
4b41116563110d00330896a568eff1078c382827Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (*name == '\0' || strcmp(name, str_sanitize(name, -1)) != 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_panic("mail_index_ext_register(%s): Invalid name", name);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (default_record_size != 0 && default_record_align == 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_panic("mail_index_ext_register(%s): "
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen "Invalid record alignment", name);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_index_ext_lookup(index, name, &ext_id))
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return ext_id;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen memset(&rext, 0, sizeof(rext));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen rext.name = p_strdup(index->extension_pool, name);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen rext.index_idx = array_count(&index->extensions);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen rext.hdr_size = default_hdr_size;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen rext.record_size = default_record_size;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen rext.record_align = default_record_align;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen array_append(&index->extensions, &rext, 1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return rext.index_idx;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenbool mail_index_ext_lookup(struct mail_index *index, const char *name,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen uint32_t *ext_id_r)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const struct mail_index_registered_ext *extensions;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen unsigned int i, count;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen extensions = array_get(&index->extensions, &count);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen for (i = 0; i < count; i++) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (strcmp(extensions[i].name, name) == 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *ext_id_r = i;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return TRUE;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen *ext_id_r = (uint32_t)-1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return FALSE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen uint32_t ext_id, bool call_always,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen mail_index_expunge_handler_t *cb,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen void *context)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct mail_index_registered_ext *rext;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen rext->expunge_handler = cb;
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen rext->expunge_context = context;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen rext->expunge_handler_call_always = call_always;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen}
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainenvoid mail_index_unregister_expunge_handler(struct mail_index *index,
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen uint32_t ext_id)
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct mail_index_registered_ext *rext;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen i_assert(rext->expunge_handler != NULL);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen rext->expunge_handler = NULL;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_index_sync_handler_t *cb,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen enum mail_index_sync_handler_type type)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct mail_index_registered_ext *rext;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
4b41116563110d00330896a568eff1078c382827Timo Sirainen i_assert(rext->sync_handler.callback == NULL);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen rext->sync_handler.callback = cb;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen rext->sync_handler.type = type;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
ee3e01f75b1db691bf20dd4e2558965421b8f937Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenvoid mail_index_unregister_sync_handler(struct mail_index *index,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen uint32_t ext_id)
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen{
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct mail_index_registered_ext *rext;
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_assert(rext->sync_handler.callback != NULL);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen rext->sync_handler.callback = NULL;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen rext->sync_handler.type = 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainenvoid mail_index_register_sync_lost_handler(struct mail_index *index,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen mail_index_sync_lost_handler_t *cb)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen array_append(&index->sync_lost_handlers, &cb, 1);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen}
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_index_sync_lost_handler_t *cb)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mail_index_sync_lost_handler_t *const *handlers;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen unsigned int i, count;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen for (i = 0; i < count; i++) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (handlers[i] == cb) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen array_delete(&index->sync_lost_handlers, i, 1);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen break;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen }
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen}
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenbool mail_index_keyword_lookup(struct mail_index *index,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen const char *keyword, unsigned int *idx_r)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen{
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen void *value;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* keywords_hash keeps a name => index mapping of keywords.
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen Keywords are never removed from it, so the index values are valid
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen for the lifetime of the mail_index. */
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen if (hash_table_lookup_full(index->keywords_hash, keyword,
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen NULL, &value)) {
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen *idx_r = POINTER_CAST_TO(value, unsigned int);
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen return TRUE;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen }
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen *idx_r = (unsigned int)-1;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen return FALSE;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen}
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainenvoid mail_index_keyword_lookup_or_create(struct mail_index *index,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen const char *keyword,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen unsigned int *idx_r)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen char *keyword_dup;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen i_assert(*keyword != '\0');
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen if (mail_index_keyword_lookup(index, keyword, idx_r))
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen return;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen *idx_r = array_count(&index->keywords);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen hash_table_insert(index->keywords_hash,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen keyword_dup, POINTER_CAST(*idx_r));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen array_append(&index->keywords, &keyword, 1);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen}
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainenconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen return &index->keywords;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen}
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainenstruct mail_keywords *
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainenmail_index_keywords_create(struct mail_index *index,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen const char *const keywords[])
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen{
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen struct mail_keywords *k;
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen unsigned int src, dest, i, count;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen count = str_array_length(keywords);
a1808be0774cbcb28fec45341aabf803ec44bae5Timo Sirainen if (count == 0) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen k = i_new(struct mail_keywords, 1);
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen k->index = index;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen k->refcount = 1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return k;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* @UNSAFE */
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen (sizeof(k->idx) * (count-1)));
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen k->index = index;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen k->refcount = 1;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* look up the keywords from index. they're never removed from there
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen so we can permanently store indexes to them. */
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen for (src = dest = 0; src < count; src++) {
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen mail_index_keyword_lookup_or_create(index, keywords[src],
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen &k->idx[dest]);
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen /* ignore if this is a duplicate */
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen for (i = 0; i < src; i++) {
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (k->idx[i] == k->idx[dest])
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen break;
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen }
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen if (i == src)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen dest++;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen }
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen k->count = dest;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return k;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainenstruct mail_keywords *
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenmail_index_keywords_create_from_indexes(struct mail_index *index,
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen const ARRAY_TYPE(keyword_indexes)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen *keyword_indexes)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct mail_keywords *k;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const unsigned int *indexes;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen unsigned int src, dest, i, count;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen indexes = array_get(keyword_indexes, &count);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (count == 0) {
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen k = i_new(struct mail_keywords, 1);
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen k->index = index;
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen k->refcount = 1;
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen return k;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* @UNSAFE */
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen (sizeof(k->idx) * (count-1)));
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen k->index = index;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen k->refcount = 1;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* copy but skip duplicates */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen for (src = dest = 0; src < count; src++) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen for (i = 0; i < src; i++) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (k->idx[i] == indexes[src])
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen break;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (i == src)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen k->idx[dest++] = indexes[src];
8f017a40470ef2f4b530000d947a8bce44350a5eTimo Sirainen }
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen k->count = dest;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen return k;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenvoid mail_index_keywords_ref(struct mail_keywords *keywords)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen keywords->refcount++;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenvoid mail_index_keywords_unref(struct mail_keywords **_keywords)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct mail_keywords *keywords = *_keywords;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen i_assert(keywords->refcount > 0);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen *_keywords = NULL;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (--keywords->refcount == 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_free(keywords);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenint mail_index_try_open_only(struct mail_index *index)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen i_assert(index->fd == -1);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* Note that our caller must close index->fd by itself. */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index->readonly)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen errno = EACCES;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen else {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen index->fd = nfs_safe_open(index->filepath, O_RDWR);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen index->readonly = FALSE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index->fd == -1 && errno == EACCES) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen index->fd = open(index->filepath, O_RDONLY);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen index->readonly = TRUE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index->fd == -1) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (errno != ENOENT)
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen return mail_index_set_syscall_error(index, "open()");
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* have to create it */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainenstatic int
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenmail_index_try_open(struct mail_index *index)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen int ret;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_assert(index->fd == -1);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(index))
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen i_assert(index->map == NULL || index->map->rec_map->lock_id == 0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ret == 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* it's corrupted - recreate it */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (index->fd != -1) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (close(index->fd) < 0)
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen mail_index_set_syscall_error(index, "close()");
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen index->fd = -1;
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen }
01404d41657a104c5ea1c12bb87f9c321e9c1ac4Timo Sirainen }
01404d41657a104c5ea1c12bb87f9c321e9c1ac4Timo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
int mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
{
mode_t old_mask;
const char *path;
int fd;
i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
old_mask = umask(0);
fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
umask(old_mask);
if (fd == -1)
return mail_index_file_set_syscall_error(index, path, "open()");
mail_index_fchown(index, fd, path);
return fd;
}
static int mail_index_open_files(struct mail_index *index,
enum mail_index_open_flags flags)
{
int ret;
bool created = FALSE;
ret = mail_transaction_log_open(index->log);
if (ret == 0) {
if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
return 0;
/* if dovecot.index exists, read it first so that we can get
the correct indexid and log sequence */
(void)mail_index_try_open(index);
if (index->indexid == 0) {
/* Create a new indexid for us. If we're opening index
into memory, index->map doesn't exist yet. */
index->indexid = ioloop_time;
index->initial_create = TRUE;
if (index->map != NULL)
index->map->hdr.indexid = index->indexid;
}
ret = mail_transaction_log_create(index->log, FALSE);
index->initial_create = FALSE;
created = TRUE;
}
if (ret >= 0) {
ret = index->map != NULL ? 1 : mail_index_try_open(index);
if (ret == 0) {
/* corrupted */
mail_transaction_log_close(index->log);
ret = mail_transaction_log_create(index->log, TRUE);
if (ret == 0) {
if (index->map != NULL)
mail_index_unmap(&index->map);
index->map = mail_index_map_alloc(index);
}
}
}
if (ret < 0) {
/* open/create failed, fallback to in-memory indexes */
if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
return -1;
if (mail_index_move_to_memory(index) < 0)
return -1;
}
index->cache = created ? mail_cache_create(index) :
mail_cache_open_or_create(index);
return 1;
}
int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags,
enum file_lock_method lock_method)
{
int ret;
if (index->opened) {
if (index->map != NULL &&
(index->map->hdr.flags &
MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
/* corrupted, reopen files */
mail_index_close(index);
} else {
i_assert(index->map != NULL);
return 1;
}
}
index->filepath = MAIL_INDEX_IS_IN_MEMORY(index) ?
i_strdup("(in-memory index)") :
i_strconcat(index->dir, "/", index->prefix, NULL);
index->shared_lock_count = 0;
index->excl_lock_count = 0;
index->lock_type = F_UNLCK;
index->lock_id_counter = 2;
index->readonly = FALSE;
index->nodiskspace = FALSE;
index->index_lock_timeout = FALSE;
index->log_locked = FALSE;
index->mmap_disable = (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0;
index->use_excl_dotlocks =
(flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
index->fsync_disable =
(flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) != 0;
index->nfs_flush = (flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
index->readonly = (flags & MAIL_INDEX_OPEN_FLAG_READONLY) != 0;
index->keep_backups = (flags & MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS) != 0;
index->never_in_memory =
(flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0;
index->lock_method = lock_method;
if (index->nfs_flush && index->fsync_disable)
i_fatal("nfs flush requires fsync_disable=no");
if (index->nfs_flush && !index->mmap_disable)
i_fatal("nfs flush requires mmap_disable=yes");
if ((ret = mail_index_open_files(index, flags)) <= 0) {
/* doesn't exist and create flag not used */
mail_index_close(index);
return ret;
}
i_assert(index->map != NULL);
index->opened = TRUE;
return 1;
}
int mail_index_open_or_create(struct mail_index *index,
enum mail_index_open_flags flags,
enum file_lock_method lock_method)
{
int ret;
flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
ret = mail_index_open(index, flags, lock_method);
i_assert(ret != 0);
return ret < 0 ? -1 : 0;
}
void mail_index_close_file(struct mail_index *index)
{
if (index->file_lock != NULL)
file_lock_free(&index->file_lock);
if (index->fd != -1) {
if (close(index->fd) < 0)
mail_index_set_syscall_error(index, "close()");
index->fd = -1;
}
index->lock_id_counter += 2;
index->lock_type = F_UNLCK;
index->shared_lock_count = 0;
index->excl_lock_count = 0;
}
void mail_index_close(struct mail_index *index)
{
if (index->map != NULL)
mail_index_unmap(&index->map);
mail_index_close_file(index);
mail_transaction_log_close(index->log);
if (index->cache != NULL)
mail_cache_free(&index->cache);
i_free_and_null(index->filepath);
index->indexid = 0;
index->opened = FALSE;
}
int mail_index_unlink(struct mail_index *index)
{
const char *path;
int last_errno = 0;
if (MAIL_INDEX_IS_IN_MEMORY(index))
return 0;
/* main index */
if (unlink(index->filepath) < 0 && errno != ENOENT)
last_errno = errno;
/* logs */
path = t_strconcat(index->filepath, MAIL_TRANSACTION_LOG_SUFFIX, NULL);
if (unlink(path) < 0 && errno != ENOENT)
last_errno = errno;
path = t_strconcat(index->filepath,
MAIL_TRANSACTION_LOG_SUFFIX".2", NULL);
if (unlink(path) < 0 && errno != ENOENT)
last_errno = errno;
/* cache */
path = t_strconcat(index->filepath, MAIL_CACHE_FILE_SUFFIX, NULL);
if (unlink(path) < 0 && errno != ENOENT)
last_errno = errno;
if (last_errno == 0)
return 0;
else {
errno = last_errno;
return -1;
}
}
int mail_index_reopen_if_changed(struct mail_index *index)
{
struct stat st1, st2;
i_assert(index->shared_lock_count == 0 || !index->nfs_flush);
i_assert(index->excl_lock_count == 0);
if (MAIL_INDEX_IS_IN_MEMORY(index))
return 0;
if (index->fd == -1)
return mail_index_try_open_only(index);
if (index->nfs_flush)
nfs_flush_file_handle_cache(index->filepath);
if (nfs_safe_stat(index->filepath, &st2) < 0) {
if (errno == ENOENT)
return 0;
return mail_index_set_syscall_error(index, "stat()");
}
if (fstat(index->fd, &st1) < 0) {
if (errno != ESTALE)
return mail_index_set_syscall_error(index, "fstat()");
/* deleted/recreated, reopen */
} else if (st1.st_ino == st2.st_ino &&
CMP_DEV_T(st1.st_dev, st2.st_dev)) {
/* the same file */
return 1;
}
/* new file, new locks. the old fd can keep its locks, they don't
matter anymore as no-one's going to modify the file. */
mail_index_close_file(index);
return mail_index_try_open_only(index);
}
int mail_index_refresh(struct mail_index *index)
{
int ret;
ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
return ret <= 0 ? -1 : 0;
}
struct mail_cache *mail_index_get_cache(struct mail_index *index)
{
return index->cache;
}
int mail_index_set_error(struct mail_index *index, const char *fmt, ...)
{
va_list va;
i_free(index->error);
if (fmt == NULL)
index->error = NULL;
else {
va_start(va, fmt);
index->error = i_strdup_vprintf(fmt, va);
va_end(va);
i_error("%s", index->error);
}
return -1;
}
bool mail_index_is_in_memory(struct mail_index *index)
{
return MAIL_INDEX_IS_IN_MEMORY(index);
}
int mail_index_move_to_memory(struct mail_index *index)
{
struct mail_index_map *map;
if (MAIL_INDEX_IS_IN_MEMORY(index))
return index->map == NULL ? -1 : 0;
if (index->never_in_memory)
return -1;
/* set the index as being into memory */
i_free_and_null(index->dir);
i_free(index->filepath);
index->filepath = i_strdup("(in-memory index)");
if (index->map == NULL) {
/* index was never even opened. just mark it as being in
memory and let the caller re-open the index. */
i_assert(index->fd == -1);
return -1;
}
/* move index map to memory */
if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
map = mail_index_map_clone(index->map);
mail_index_unmap(&index->map);
index->map = map;
}
if (index->log != NULL) {
/* move transaction log to memory */
mail_transaction_log_move_to_memory(index->log);
}
if (index->file_lock != NULL)
file_lock_free(&index->file_lock);
if (index->fd != -1) {
if (close(index->fd) < 0)
mail_index_set_syscall_error(index, "close()");
index->fd = -1;
}
return 0;
}
void mail_index_mark_corrupted(struct mail_index *index)
{
index->indexid = 0;
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()");
}
void mail_index_fchown(struct mail_index *index, int fd, const char *path)
{
mode_t mode;
if (index->gid == (gid_t)-1) {
/* no gid changing */
return;
} else if (fchown(fd, (uid_t)-1, index->gid) == 0) {
/* success */
return;
} if ((index->mode & 0060) >> 3 == (index->mode & 0006)) {
/* group and world permissions are the same, so group doesn't
really matter. ignore silently. */
return;
}
if (errno != EACCES)
mail_index_file_set_syscall_error(index, path, "fchown()");
else {
mail_index_set_error(index, "%s",
eperm_error_get_chgrp("fchown", path, index->gid,
index->gid_origin));
}
/* continue, but change permissions so that only the common
subset of group and world is used. this makes sure no one
gets any extra permissions. */
mode = ((index->mode & 0060) >> 3) & (index->mode & 0006);
mode |= (mode << 3) | (index->mode & 0600);
if (fchmod(fd, mode) < 0)
mail_index_file_set_syscall_error(index, path, "fchmod()");
}
int mail_index_set_syscall_error(struct mail_index *index,
const char *function)
{
i_assert(function != NULL);
if (ENOSPACE(errno)) {
index->nodiskspace = TRUE;
if (!index->never_in_memory)
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;
if (!index->never_in_memory)
return -1;
}
if (errno == EACCES) {
return mail_index_set_error(index, "%s",
eacces_error_get(t_strcut(function, '('), filepath));
} else {
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;
}