mail-index.c revision 036626b19f14bef582f96e556913ae91b1d67881
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "buffer.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "eacces-error.h"
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen#include "hash.h"
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen#include "str-sanitize.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "mmap-util.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "nfs-workarounds.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "read-full.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "write-full.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "mail-index-alloc-cache.h"
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#include "mail-index-private.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mail-index-view-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-index-sync-private.h"
daf029d2a627daa39d05507140f385162828172eTimo Sirainen#include "mail-index-modseq.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-transaction-log.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-cache.h"
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <stdio.h>
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen#include <stddef.h>
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include <time.h>
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include <sys/stat.h>
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstruct mail_index_module_register mail_index_module_register = { 0 };
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_index *index;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen index = i_new(struct mail_index, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->dir = i_strdup(dir);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen index->prefix = i_strdup(prefix);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->fd = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->extension_pool =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen p_array_init(&index->extensions, index->extension_pool, 5);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_array_init(&index->sync_lost_handlers, 4);
daf029d2a627daa39d05507140f385162828172eTimo Sirainen i_array_init(&index->module_contexts,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen I_MIN(5, mail_index_module_register.id));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->mode = 0600;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen index->gid = (gid_t)-1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->lock_method = FILE_LOCK_METHOD_FCNTL;
daf029d2a627daa39d05507140f385162828172eTimo Sirainen index->max_lock_timeout_secs = -1U;
daf029d2a627daa39d05507140f385162828172eTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->keywords_ext_id =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_ext_register(index, MAIL_INDEX_EXT_KEYWORDS,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen 128, 2, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->keywords_pool = pool_alloconly_create("keywords", 512);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_array_init(&index->keywords, 16);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->keywords_hash =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hash_table_create(default_pool, index->keywords_pool, 0,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->log = mail_transaction_log_alloc(index);
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen mail_index_modseq_init(index);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return index;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid mail_index_free(struct mail_index **_index)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail_index *index = *_index;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *_index = NULL;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen i_assert(index->open_count == 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_transaction_log_free(&index->log);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hash_table_destroy(&index->keywords_hash);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pool_unref(&index->extension_pool);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pool_unref(&index->keywords_pool);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen array_free(&index->sync_lost_handlers);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_free(&index->keywords);
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen array_free(&index->module_contexts);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(index->gid_origin);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_free(index->error);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_free(index->dir);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_free(index->prefix);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen i_free(index);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid mail_index_set_fsync_types(struct mail_index *index,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enum mail_index_sync_type fsync_mask)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->fsync_mask = fsync_mask;
35df1dd606c5ef21068ab4fe4be305859d4fad4bTimo Sirainen}
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen mode_t mode, gid_t gid, const char *gid_origin)
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->mode = mode & 0666;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index->gid = gid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen i_free(index->gid_origin);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen index->gid_origin = i_strdup(gid_origin);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid mail_index_set_lock_method(struct mail_index *index,
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen enum file_lock_method lock_method,
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen unsigned int max_timeout_secs)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen index->lock_method = lock_method;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen index->max_lock_timeout_secs = max_timeout_secs;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t default_hdr_size,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint16_t default_record_size,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen uint16_t default_record_align)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mail_index_registered_ext rext;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen uint32_t ext_id;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (*name == '\0' || strcmp(name, str_sanitize(name, -1)) != 0)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_panic("mail_index_ext_register(%s): Invalid name", name);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (default_record_size != 0 && default_record_align == 0) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_panic("mail_index_ext_register(%s): "
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen "Invalid record alignment", name);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen if (mail_index_ext_lookup(index, name, &ext_id))
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen return ext_id;
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen memset(&rext, 0, sizeof(rext));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen rext.name = p_strdup(index->extension_pool, name);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen rext.index_idx = array_count(&index->extensions);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen rext.hdr_size = default_hdr_size;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen rext.record_size = default_record_size;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen rext.record_align = default_record_align;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen array_append(&index->extensions, &rext, 1);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return rext.index_idx;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenbool mail_index_ext_lookup(struct mail_index *index, const char *name,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen uint32_t *ext_id_r)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen const struct mail_index_registered_ext *extensions;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen unsigned int i, count;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen extensions = array_get(&index->extensions, &count);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen for (i = 0; i < count; i++) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (strcmp(extensions[i].name, name) == 0) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *ext_id_r = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return TRUE;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen *ext_id_r = (uint32_t)-1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return FALSE;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen uint32_t ext_id, bool call_always,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen mail_index_expunge_handler_t *cb,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen void *context)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct mail_index_registered_ext *rext;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen rext->expunge_handler = cb;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext->expunge_context = context;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen rext->expunge_handler_call_always = call_always;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_unregister_expunge_handler(struct mail_index *index,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t ext_id)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen struct mail_index_registered_ext *rext;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen i_assert(rext->expunge_handler != NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext->expunge_handler = NULL;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_sync_handler_t *cb,
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen enum mail_index_sync_handler_type type)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen struct mail_index_registered_ext *rext;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(rext->sync_handler.callback == NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext->sync_handler.callback = cb;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rext->sync_handler.type = type;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_unregister_sync_handler(struct mail_index *index,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t ext_id)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen struct mail_index_registered_ext *rext;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen i_assert(rext->sync_handler.callback != NULL);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen rext->sync_handler.callback = NULL;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen rext->sync_handler.type = 0;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenvoid mail_index_register_sync_lost_handler(struct mail_index *index,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen mail_index_sync_lost_handler_t *cb)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen array_append(&index->sync_lost_handlers, &cb, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_sync_lost_handler_t *cb)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_sync_lost_handler_t *const *handlers;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int i, count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = 0; i < count; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (handlers[i] == cb) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_delete(&index->sync_lost_handlers, i, 1);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen break;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool mail_index_keyword_lookup(struct mail_index *index,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen const char *keyword, unsigned int *idx_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void *value;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen /* keywords_hash keeps a name => index mapping of keywords.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Keywords are never removed from it, so the index values are valid
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for the lifetime of the mail_index. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (hash_table_lookup_full(index->keywords_hash, keyword,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen NULL, &value)) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *idx_r = POINTER_CAST_TO(value, unsigned int);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *idx_r = (unsigned int)-1;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen return FALSE;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainenvoid mail_index_keyword_lookup_or_create(struct mail_index *index,
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen const char *keyword,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int *idx_r)
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen{
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen char *keyword_dup;
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen i_assert(*keyword != '\0');
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (mail_index_keyword_lookup(index, keyword, idx_r))
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *idx_r = array_count(&index->keywords);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen hash_table_insert(index->keywords_hash,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen keyword_dup, POINTER_CAST(*idx_r));
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen array_append(&index->keywords, &keyword, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainenconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen return &index->keywords;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen}
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainenstruct mail_keywords *
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainenmail_index_keywords_create(struct mail_index *index,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen const char *const keywords[])
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen struct mail_keywords *k;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen unsigned int src, dest, i, count;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen count = str_array_length(keywords);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (count == 0) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k = i_new(struct mail_keywords, 1);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->index = index;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->refcount = 1;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return k;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* @UNSAFE */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen (sizeof(k->idx) * (count-1)));
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->index = index;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->refcount = 1;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* look up the keywords from index. they're never removed from there
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen so we can permanently store indexes to them. */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen for (src = dest = 0; src < count; src++) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen mail_index_keyword_lookup_or_create(index, keywords[src],
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen &k->idx[dest]);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* ignore if this is a duplicate */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen for (i = 0; i < src; i++) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (k->idx[i] == k->idx[dest])
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen break;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (i == src)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen dest++;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->count = dest;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return k;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenstruct mail_keywords *
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenmail_index_keywords_create_from_indexes(struct mail_index *index,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen const ARRAY_TYPE(keyword_indexes)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen *keyword_indexes)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_keywords *k;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const unsigned int *indexes;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned int src, dest, i, count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen indexes = array_get(keyword_indexes, &count);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (count == 0) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k = i_new(struct mail_keywords, 1);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->index = index;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen k->refcount = 1;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return k;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen /* @UNSAFE */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen (sizeof(k->idx) * (count-1)));
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen k->index = index;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen k->refcount = 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* copy but skip duplicates */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (src = dest = 0; src < count; src++) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < src; i++) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (k->idx[i] == indexes[src])
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen break;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (i == src)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen k->idx[dest++] = indexes[src];
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen k->count = dest;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return k;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid mail_index_keywords_ref(struct mail_keywords *keywords)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen keywords->refcount++;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid mail_index_keywords_unref(struct mail_keywords **_keywords)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mail_keywords *keywords = *_keywords;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(keywords->refcount > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen *_keywords = NULL;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (--keywords->refcount == 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_free(keywords);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint mail_index_try_open_only(struct mail_index *index)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(index->fd == -1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* Note that our caller must close index->fd by itself. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (index->readonly)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen errno = EACCES;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen else {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index->fd = nfs_safe_open(index->filepath, O_RDWR);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index->readonly = FALSE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (index->fd == -1 && errno == EACCES) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index->fd = open(index->filepath, O_RDONLY);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index->readonly = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (index->fd == -1) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (errno != ENOENT)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return mail_index_set_syscall_error(index, "open()");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to create it */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic int
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenmail_index_try_open(struct mail_index *index)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(index->fd == -1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(index))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(index->map == NULL || index->map->rec_map->lock_id == 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ret == 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* it's corrupted - recreate it */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (index->fd != -1) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (close(index->fd) < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_set_syscall_error(index, "close()");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen index->fd = -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mode_t old_mask;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const char *path;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int fd;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen old_mask = umask(0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen umask(old_mask);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (fd == -1) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_file_set_syscall_error(index, path, "creat()");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_fchown(index, fd, path);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return fd;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic int mail_index_open_files(struct mail_index *index,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen enum mail_index_open_flags flags)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen bool created = FALSE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ret = mail_transaction_log_open(index->log);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ret == 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* if dovecot.index exists, read it first so that we can get
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen the correct indexid and log sequence */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (void)mail_index_try_open(index);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen 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);
if (index->map != NULL) {
/* log creation could have changed it if someone else
just created it. */
index->map->hdr.indexid = index->indexid;
}
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)
{
int ret;
if (index->open_count > 0) {
i_assert(index->map != NULL);
index->open_count++;
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->flags = flags;
index->readonly = (flags & MAIL_INDEX_OPEN_FLAG_READONLY) != 0;
if ((flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
(flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) != 0)
i_fatal("nfs flush requires fsync_disable=no");
if ((flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
(flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0)
i_fatal("nfs flush requires mmap_disable=yes");
index->open_count++;
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);
mail_index_alloc_cache_index_opened(index);
return 1;
}
int mail_index_open_or_create(struct mail_index *index,
enum mail_index_open_flags flags)
{
int ret;
flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
ret = mail_index_open(index, flags);
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)
{
i_assert(index->open_count > 0);
if (--index->open_count > 0)
return;
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;
}
int mail_index_unlink(struct mail_index *index)
{
const char *path;
int last_errno = 0;
if (MAIL_INDEX_IS_IN_MEMORY(index) || index->readonly)
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->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0);
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->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0)
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->flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0)
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 (!index->readonly) {
if (unlink(index->filepath) < 0 &&
errno != ENOENT && errno != ESTALE)
mail_index_set_syscall_error(index, "unlink()");
}
}
bool mail_index_is_deleted(struct mail_index *index)
{
return index->index_delete_requested || index->index_deleted;
}
int mail_index_get_modification_time(struct mail_index *index, time_t *mtime_r)
{
struct stat st;
if (mail_transaction_log_get_mtime(index->log, mtime_r) < 0)
return -1;
if (*mtime_r == 0) {
if (stat(index->filepath, &st) < 0) {
mail_index_set_syscall_error(index, "stat()");
return -1;
}
*mtime_r = st.st_mtime;
}
return 0;
}
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 != EPERM)
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->flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) == 0)
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)
{
const char *errstr;
i_assert(filepath != NULL);
i_assert(function != NULL);
if (ENOSPACE(errno)) {
index->nodiskspace = TRUE;
if ((index->flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) == 0)
return -1;
}
if (errno == EACCES) {
function = t_strcut(function, '(');
if (strcmp(function, "creat") == 0 ||
strncmp(function, "file_dotlock_", 13) == 0)
errstr = eacces_error_get_creating(function, filepath);
else
errstr = eacces_error_get(function, filepath);
return mail_index_set_error(index, "%s", errstr);
} 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;
}