mail-index.c revision c53e8ee216904ffe6de4f6518d9f9f5107b7610e
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "lib.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ioloop.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "array.h"
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen#include "buffer.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "str-sanitize.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "mmap-util.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "nfs-workarounds.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "read-full.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "write-full.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "mail-index-private.h"
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include "mail-index-view-private.h"
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include "mail-index-sync-private.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "mail-transaction-log.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "mail-cache.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen#include <stdio.h>
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen#include <stddef.h>
373492be949e159fda651807b3acda2c5c077027Timo Sirainen#include <time.h>
889437fa2b6f44ffe0a8a7bcac94c00b71856767Timo Sirainen#include <sys/stat.h>
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct mail_index_module_register mail_index_module_register = { 0 };
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
373492be949e159fda651807b3acda2c5c077027Timo Sirainen struct mail_index *index;
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen index = i_new(struct mail_index, 1);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen index->dir = i_strdup(dir);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen index->prefix = i_strdup(prefix);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen index->fd = -1;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen index->extension_pool =
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen p_array_init(&index->extensions, index->extension_pool, 5);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_array_init(&index->sync_lost_handlers, 4);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_array_init(&index->module_contexts,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen I_MIN(5, mail_index_module_register.id));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen index->mode = 0600;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->gid = (gid_t)-1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->keywords_ext_id =
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_index_ext_register(index, "keywords", 128, 2, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->keywords_pool = pool_alloconly_create("keywords", 512);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_array_init(&index->keywords, 16);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->keywords_hash =
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen hash_create(default_pool, index->keywords_pool, 0,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
51fb710488efa419a2964335c30451c62b9633b1Timo Sirainen index->log = mail_transaction_log_alloc(index);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return index;
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen}
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenvoid mail_index_free(struct mail_index **_index)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct mail_index *index = *_index;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen *_index = NULL;
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen mail_index_close(index);
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen mail_transaction_log_free(&index->log);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen hash_destroy(&index->keywords_hash);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_unref(&index->extension_pool);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_unref(&index->keywords_pool);
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen array_free(&index->sync_lost_handlers);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen array_free(&index->keywords);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen array_free(&index->module_contexts);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_free(index->error);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_free(index->dir);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_free(index->prefix);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_free(index);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen}
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mode_t mode, gid_t gid)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->mode = mode & 0666;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->gid = gid;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen uint32_t default_hdr_size,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen uint16_t default_record_size,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen uint16_t default_record_align)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct mail_index_registered_ext rext;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen uint32_t ext_id;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
ba8498efbf886ca8b69fdb20c0ba2f5dba9416e3Timo Sirainen if (strcmp(name, str_sanitize(name, -1)) != 0)
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen i_panic("mail_index_ext_register(%s): Invalid name", name);
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (mail_index_ext_lookup(index, name, &ext_id))
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return ext_id;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memset(&rext, 0, sizeof(rext));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen rext.name = p_strdup(index->extension_pool, name);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen rext.index_idx = array_count(&index->extensions);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen rext.hdr_size = default_hdr_size;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext.record_size = default_record_size;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext.record_align = default_record_align;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen array_append(&index->extensions, &rext, 1);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen return rext.index_idx;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainenbool mail_index_ext_lookup(struct mail_index *index, const char *name,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen uint32_t *ext_id_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen const struct mail_index_registered_ext *extensions;
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen unsigned int i, count;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen extensions = array_get(&index->extensions, &count);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (i = 0; i < count; i++) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(extensions[i].name, name) == 0) {
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen *ext_id_r = i;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return TRUE;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen }
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen }
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen *ext_id_r = (uint32_t)-1;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return FALSE;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen}
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen uint32_t ext_id, bool call_always,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_index_expunge_handler_t *cb,
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen void *context)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct mail_index_registered_ext *rext;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen rext->expunge_handler = cb;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen rext->expunge_context = context;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext->expunge_handler_call_always = call_always;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_unregister_expunge_handler(struct mail_index *index,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen uint32_t ext_id)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct mail_index_registered_ext *rext;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen i_assert(rext->expunge_handler != NULL);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext->expunge_handler = NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen mail_index_sync_handler_t *cb,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen enum mail_index_sync_handler_type type)
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen{
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen struct mail_index_registered_ext *rext;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen i_assert(rext->sync_handler.callback == NULL);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen rext->sync_handler.callback = cb;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen rext->sync_handler.type = type;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenvoid mail_index_unregister_sync_handler(struct mail_index *index,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen uint32_t ext_id)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct mail_index_registered_ext *rext;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(rext->sync_handler.callback != NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen rext->sync_handler.callback = NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rext->sync_handler.type = 0;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_register_sync_lost_handler(struct mail_index *index,
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen mail_index_sync_lost_handler_t *cb)
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen{
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen array_append(&index->sync_lost_handlers, &cb, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen mail_index_sync_lost_handler_t *cb)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_index_sync_lost_handler_t *const *handlers;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int i, count;
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen for (i = 0; i < count; i++) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (handlers[i] == cb) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen array_delete(&index->sync_lost_handlers, i, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenbool mail_index_keyword_lookup(struct mail_index *index,
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen const char *keyword, unsigned int *idx_r)
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen{
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen void *value;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* keywords_hash keeps a name => index mapping of keywords.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen Keywords are never removed from it, so the index values are valid
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for the lifetime of the mail_index. */
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen if (hash_lookup_full(index->keywords_hash, keyword, NULL, &value)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *idx_r = POINTER_CAST_TO(value, unsigned int);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *idx_r = (unsigned int)-1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_keyword_lookup_or_create(struct mail_index *index,
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen const char *keyword,
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen unsigned int *idx_r)
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen char *keyword_dup;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(*keyword != '\0');
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (mail_index_keyword_lookup(index, keyword, idx_r))
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen *idx_r = array_count(&index->keywords);
f2df3069766c747cbf020fea5d3a4261949064b0Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen hash_insert(index->keywords_hash, keyword_dup, POINTER_CAST(*idx_r));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_append(&index->keywords, &keyword, 1);
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return &index->keywords;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainenint mail_index_try_open_only(struct mail_index *index)
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(index->fd == -1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* Note that our caller must close index->fd by itself. */
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen if (index->readonly)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen errno = EACCES;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen else {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->fd = nfs_safe_open(index->filepath, O_RDWR);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index->readonly = FALSE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (index->fd == -1 && errno == EACCES) {
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen index->fd = open(index->filepath, O_RDONLY);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen index->readonly = TRUE;
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen }
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (index->fd == -1) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (errno != ENOENT)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen return mail_index_set_syscall_error(index, "open()");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* have to create it */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return 1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic int
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainenmail_index_try_open(struct mail_index *index)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen int ret;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen i_assert(index->fd == -1);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(index))
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return 0;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen i_assert(index->map == NULL || index->map->rec_map->lock_id == 0);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen if (ret == 0) {
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen /* it's corrupted - recreate it */
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen if (index->fd != -1) {
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen if (close(index->fd) < 0)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mail_index_set_syscall_error(index, "close()");
6bd263caf006edc75205f446fa0283c6f364941bTimo Sirainen index->fd = -1;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen }
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen }
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen return ret;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen}
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainenint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen{
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen mode_t old_mask;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen const char *path;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen int fd;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen old_mask = umask(0);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen umask(old_mask);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (fd == -1)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return mail_index_file_set_syscall_error(index, path, "open()");
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (index->gid != (gid_t)-1 && fchown(fd, (uid_t)-1, index->gid) < 0) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mail_index_file_set_syscall_error(index, path, "fchown()");
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return -1;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return fd;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic int mail_index_open_files(struct mail_index *index,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen enum mail_index_open_flags flags)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen int ret;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen bool created = FALSE;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen ret = mail_transaction_log_open(index->log);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (ret == 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return 0;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* if dovecot.index exists, read it first so that we can get
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen the correct indexid and log sequence */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen (void)mail_index_try_open(index);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (index->indexid == 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* Create a new indexid for us. If we're opening index
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen into memory, index->map doesn't exist yet. */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen index->indexid = ioloop_time;
272aca0a772140d3a45a425a3fd67854ae2ccec2Timo Sirainen if (index->map != NULL)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen index->map->hdr.indexid = index->indexid;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen ret = mail_transaction_log_create(index->log);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen created = TRUE;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen }
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen if (ret >= 0) {
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen ret = index->map != NULL ? 0 : mail_index_try_open(index);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen if (ret == 0) {
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen /* doesn't exist / corrupted */
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen mail_transaction_log_close(index->log);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ret = mail_transaction_log_create(index->log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret == 0) {
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen if (index->map != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_unmap(&index->map);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index->map = mail_index_map_alloc(index);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen if (ret < 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* open/create failed, fallback to in-memory indexes */
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return -1;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (mail_index_move_to_memory(index) < 0)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return -1;
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen index->cache = created ? mail_cache_create(index) :
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen mail_cache_open_or_create(index);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen return 1;
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen}
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainenint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen enum file_lock_method lock_method)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen{
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen int ret;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
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->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;
}
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_reopen_if_changed(struct mail_index *index)
{
struct stat st1, st2;
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 (fstat(index->fd, &st1) < 0) {
if (errno != ESTALE)
return mail_index_set_syscall_error(index, "fstat()");
/* deleted/recreated, reopen */
mail_index_close_file(index);
return mail_index_try_open_only(index);
}
if (index->nfs_flush)
nfs_flush_attr_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 (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;
if (MAIL_INDEX_IS_IN_MEMORY(index))
return 0;
if (index->excl_lock_count > 0) {
/* we have index exclusively locked, nothing could
have changed. */
return 0;
}
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;
}
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;
/* 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()");
}
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