mail-index.c revision 06fc580f6baf83fe5bb94c64be8149d527b01a42
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2014 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "ioloop.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "eacces-error.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "hash.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "str-sanitize.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "nfs-workarounds.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "read-full.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "write-full.h"
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen#include "mail-index-alloc-cache.h"
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen#include "mail-index-private.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mail-index-view-private.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mail-index-sync-private.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mail-index-modseq.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mail-transaction-log.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "mail-cache.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <stdio.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <stddef.h>
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen#include <time.h>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include <sys/stat.h>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainenstruct mail_index_module_register mail_index_module_register = { 0 };
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainenstatic void mail_index_close_nonopened(struct mail_index *index);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index *index;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen index = i_new(struct mail_index, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen index->dir = i_strdup(dir);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen index->prefix = i_strdup(prefix);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->fd = -1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen index->extension_pool =
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen p_array_init(&index->extensions, index->extension_pool, 5);
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen i_array_init(&index->sync_lost_handlers, 4);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_array_init(&index->module_contexts,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen I_MIN(5, mail_index_module_register.id));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen index->mode = 0600;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen index->gid = (gid_t)-1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen index->lock_method = FILE_LOCK_METHOD_FCNTL;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen index->max_lock_timeout_secs = UINT_MAX;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen index->keywords_ext_id =
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen mail_index_ext_register(index, MAIL_INDEX_EXT_KEYWORDS,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen 128, 2, 1);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen index->keywords_pool = pool_alloconly_create("keywords", 512);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen i_array_init(&index->keywords, 16);
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen hash_table_create(&index->keywords_hash, index->keywords_pool, 0,
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen strcase_hash, strcasecmp);
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen index->log = mail_transaction_log_alloc(index);
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen mail_index_modseq_init(index);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return index;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenvoid mail_index_free(struct mail_index **_index)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index *index = *_index;
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen *_index = NULL;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen i_assert(index->open_count == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_free(&index->log);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen hash_table_destroy(&index->keywords_hash);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen pool_unref(&index->extension_pool);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen pool_unref(&index->keywords_pool);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen array_free(&index->sync_lost_handlers);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen array_free(&index->keywords);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen array_free(&index->module_contexts);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen i_free(index->ext_hdr_init_data);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_free(index->gid_origin);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen i_free(index->error);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen i_free(index->dir);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen i_free(index->prefix);
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen i_free(index);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_set_fsync_mode(struct mail_index *index,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen enum fsync_mode mode,
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen enum mail_index_fsync_mask mask)
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->fsync_mode = mode;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen index->fsync_mask = mask;
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen}
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mode_t mode, gid_t gid, const char *gid_origin)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->mode = mode & 0666;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen index->gid = gid;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_free(index->gid_origin);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen index->gid_origin = i_strdup(gid_origin);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenvoid mail_index_set_lock_method(struct mail_index *index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum file_lock_method lock_method,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen unsigned int max_timeout_secs)
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen{
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen index->lock_method = lock_method;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen index->max_lock_timeout_secs = max_timeout_secs;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen}
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_set_ext_init_data(struct mail_index *index, uint32_t ext_id,
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen const void *data, size_t size)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen{
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen const struct mail_index_registered_ext *rext;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_assert(index->ext_hdr_init_data == NULL ||
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen index->ext_hdr_init_id == ext_id);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen rext = array_idx(&index->extensions, ext_id);
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen i_assert(rext->hdr_size == size);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen index->ext_hdr_init_id = ext_id;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen i_free(index->ext_hdr_init_data);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->ext_hdr_init_data = i_malloc(size);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen memcpy(index->ext_hdr_init_data, data, size);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen}
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen uint32_t default_hdr_size,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen uint16_t default_record_size,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen uint16_t default_record_align)
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen{
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen struct mail_index_registered_ext rext;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen uint32_t ext_id;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (*name == '\0' || strcmp(name, str_sanitize(name, -1)) != 0)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_panic("mail_index_ext_register(%s): Invalid name", name);
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (default_record_size != 0 && default_record_align == 0) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_panic("mail_index_ext_register(%s): "
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen "Invalid record alignment", name);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (mail_index_ext_lookup(index, name, &ext_id))
4b41116563110d00330896a568eff1078c382827Timo Sirainen return ext_id;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen memset(&rext, 0, sizeof(rext));
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen rext.name = p_strdup(index->extension_pool, name);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen rext.index_idx = array_count(&index->extensions);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rext.hdr_size = default_hdr_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rext.record_size = default_record_size;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen rext.record_align = default_record_align;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen array_append(&index->extensions, &rext, 1);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen return rext.index_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
dbe64f3893616a4005c8946be75d2dc8f6823d72Timo Sirainen
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainenbool mail_index_ext_lookup(struct mail_index *index, const char *name,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *ext_id_r)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const struct mail_index_registered_ext *extensions;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen unsigned int i, count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen extensions = array_get(&index->extensions, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (strcmp(extensions[i].name, name) == 0) {
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen *ext_id_r = i;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen return TRUE;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen *ext_id_r = (uint32_t)-1;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen return FALSE;
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen}
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen uint32_t ext_id, bool call_always,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen mail_index_expunge_handler_t *cb,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen void *context)
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen{
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen struct mail_index_registered_ext *rext;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen rext->expunge_handler = cb;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen rext->expunge_context = context;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen rext->expunge_handler_call_always = call_always;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen}
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainenvoid mail_index_unregister_expunge_handler(struct mail_index *index,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uint32_t ext_id)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_registered_ext *rext;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_assert(rext->expunge_handler != NULL);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen rext->expunge_handler = NULL;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen mail_index_sync_handler_t *cb,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen enum mail_index_sync_handler_type type)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_index_registered_ext *rext;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(rext->sync_handler.callback == NULL);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen rext->sync_handler.callback = cb;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen rext->sync_handler.type = type;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen}
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainenvoid mail_index_unregister_sync_handler(struct mail_index *index,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen uint32_t ext_id)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen struct mail_index_registered_ext *rext;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen i_assert(rext->sync_handler.callback != NULL);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen rext->sync_handler.callback = NULL;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen rext->sync_handler.type = 0;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid mail_index_register_sync_lost_handler(struct mail_index *index,
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen mail_index_sync_lost_handler_t *cb)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen array_append(&index->sync_lost_handlers, &cb, 1);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainenvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen mail_index_sync_lost_handler_t *cb)
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen{
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen mail_index_sync_lost_handler_t *const *handlers;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen unsigned int i, count;
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
fcfe85637e1ee14a9fc39c41fd6ceca106301542Timo Sirainen for (i = 0; i < count; i++) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (handlers[i] == cb) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_delete(&index->sync_lost_handlers, i, 1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen}
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenbool mail_index_keyword_lookup(struct mail_index *index,
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen const char *keyword, unsigned int *idx_r)
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen{
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen char *key;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen void *value;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen /* keywords_hash keeps a name => index mapping of keywords.
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen Keywords are never removed from it, so the index values are valid
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen for the lifetime of the mail_index. */
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen if (hash_table_lookup_full(index->keywords_hash, keyword,
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen &key, &value)) {
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen *idx_r = POINTER_CAST_TO(value, unsigned int);
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen return TRUE;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen }
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen *idx_r = UINT_MAX;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen return FALSE;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_index_keyword_lookup_or_create(struct mail_index *index,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const char *keyword,
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen unsigned int *idx_r)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen char *keyword_dup;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen i_assert(*keyword != '\0');
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (mail_index_keyword_lookup(index, keyword, idx_r))
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen *idx_r = array_count(&index->keywords);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen hash_table_insert(index->keywords_hash, keyword_dup,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen POINTER_CAST(*idx_r));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen array_append(&index->keywords, &keyword, 1);
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* keep the array NULL-terminated, but the NULL itself invisible */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen array_append_zero(&index->keywords);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen array_delete(&index->keywords, array_count(&index->keywords)-1, 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return &index->keywords;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstruct mail_keywords *
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenmail_index_keywords_create(struct mail_index *index,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char *const keywords[])
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct mail_keywords *k;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int src, dest, i, count;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen count = str_array_length(keywords);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (count == 0) {
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen k = i_new(struct mail_keywords, 1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen k->index = index;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen k->refcount = 1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return k;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen /* @UNSAFE */
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen (sizeof(k->idx) * (count-1)));
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen k->index = index;
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen k->refcount = 1;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* look up the keywords from index. they're never removed from there
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen so we can permanently store indexes to them. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen for (src = dest = 0; src < count; src++) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail_index_keyword_lookup_or_create(index, keywords[src],
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen &k->idx[dest]);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* ignore if this is a duplicate */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen for (i = 0; i < src; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (k->idx[i] == k->idx[dest])
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (i == src)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen dest++;
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen }
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen k->count = dest;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return k;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstruct mail_keywords *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_keywords_create_from_indexes(struct mail_index *index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const ARRAY_TYPE(keyword_indexes)
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen *keyword_indexes)
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_keywords *k;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned int *indexes;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int src, dest, i, count;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen indexes = array_get(keyword_indexes, &count);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (count == 0) {
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k = i_new(struct mail_keywords, 1);
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k->index = index;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k->refcount = 1;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen return k;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen }
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen /* @UNSAFE */
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k = i_malloc(sizeof(struct mail_keywords) +
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen (sizeof(k->idx) * (count-1)));
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k->index = index;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen k->refcount = 1;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* copy but skip duplicates */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (src = dest = 0; src < count; src++) {
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen for (i = 0; i < src; i++) {
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen if (k->idx[i] == indexes[src])
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen break;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen }
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (i == src)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen k->idx[dest++] = indexes[src];
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen }
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen k->count = dest;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen return k;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen}
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainenvoid mail_index_keywords_ref(struct mail_keywords *keywords)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen{
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen keywords->refcount++;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainenvoid mail_index_keywords_unref(struct mail_keywords **_keywords)
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen{
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen struct mail_keywords *keywords = *_keywords;
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen i_assert(keywords->refcount > 0);
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen
1eaaa2c9003cf3fbf672d597473e3f84e70d2ee6Timo Sirainen *_keywords = NULL;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (--keywords->refcount == 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_free(keywords);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_try_open_only(struct mail_index *index)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(index->fd == -1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen /* Note that our caller must close index->fd by itself. */
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen if (index->readonly)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen errno = EACCES;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen else {
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen index->fd = nfs_safe_open(index->filepath, O_RDWR);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen index->readonly = FALSE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (index->fd == -1 && errno == EACCES) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen index->fd = open(index->filepath, O_RDONLY);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen index->readonly = TRUE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen if (index->fd == -1) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (errno != ENOENT) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen mail_index_set_syscall_error(index, "open()");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return -1;
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen }
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen /* have to create it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen return 1;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic int
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenmail_index_try_open(struct mail_index *index)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen int ret;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen i_assert(index->fd == -1);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(index))
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen return 0;
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen
e050e5c9b1688765f1fdfce9b7141f7b614383fdTimo Sirainen ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen if (ret == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* it's corrupted - recreate it */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (index->fd != -1) {
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen if (close(index->fd) < 0)
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen mail_index_set_syscall_error(index, "close()");
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen index->fd = -1;
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen }
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen }
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen return ret;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen}
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenint mail_index_create_tmp_file(struct mail_index *index,
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const char *path_prefix, const char **path_r)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen mode_t old_mask;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const char *path;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int fd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen path = *path_r = t_strconcat(path_prefix, ".tmp", NULL);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen old_mask = umask(0);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen fd = open(path, O_RDWR|O_CREAT|O_EXCL, index->mode);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen umask(old_mask);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (fd == -1 && errno == EEXIST) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* stale temp file. unlink and recreate rather than overwriting,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen just to make sure locking problems won't cause corruption */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (unlink(path) < 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_error("unlink(%s) failed: %m", path);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen return -1;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen old_mask = umask(0);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen fd = open(path, O_RDWR|O_CREAT|O_EXCL, index->mode);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen umask(old_mask);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (fd == -1) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail_index_file_set_syscall_error(index, path, "creat()");
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen return -1;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen }
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen mail_index_fchown(index, fd, path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mail_index_open_files(struct mail_index *index,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen enum mail_index_open_flags flags)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen ret = mail_transaction_log_open(index->log);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (ret == 0) {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* if dovecot.index exists, read it first so that we can get
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen the correct indexid and log sequence */
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen (void)mail_index_try_open(index);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen if (index->indexid == 0) {
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen /* Create a new indexid for us. If we're opening index
b83deefd2cf1e293373673eefb4d5cf60907978cTimo Sirainen into memory, index->map doesn't exist yet. */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen index->indexid = ioloop_time;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen index->initial_create = TRUE;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (index->map != NULL)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen index->map->hdr.indexid = index->indexid;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen ret = mail_transaction_log_create(index->log, FALSE);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (index->map != NULL) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* log creation could have changed it if someone else
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen just created it. */
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen index->map->hdr.indexid = index->indexid;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
b3b4f3875850099c9292ad74d08bb385c3988f8fTimo Sirainen index->initial_create = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
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;
}
if (index->cache == NULL)
index->cache = mail_cache_open_or_create(index);
return 1;
}
static int
mail_index_open_opened(struct mail_index *index,
enum mail_index_open_flags flags)
{
int ret;
i_assert(index->map != NULL);
if ((index->map->hdr.flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
/* index was marked corrupted. we'll probably need to
recreate the files. */
mail_index_unmap(&index->map);
mail_index_close_file(index);
mail_transaction_log_close(index->log);
if ((ret = mail_index_open_files(index, flags)) <= 0)
return ret;
}
index->open_count++;
return 1;
}
int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
{
int ret;
if (index->open_count > 0) {
if ((ret = mail_index_open_opened(index, flags)) <= 0) {
/* doesn't exist and create flag not used */
}
return ret;
}
index->filepath = MAIL_INDEX_IS_IN_MEMORY(index) ?
i_strdup("(in-memory index)") :
i_strconcat(index->dir, "/", index->prefix, NULL);
index->lock_type = F_UNLCK;
index->lock_id_counter = 2;
index->readonly = FALSE;
index->nodiskspace = FALSE;
index->index_lock_timeout = FALSE;
index->log_sync_locked = FALSE;
index->flags = flags;
index->readonly = (flags & MAIL_INDEX_OPEN_FLAG_READONLY) != 0;
if ((flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
index->fsync_mode != FSYNC_MODE_ALWAYS)
i_fatal("nfs flush requires mail_fsync=always");
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");
/* NOTE: increase open_count only after mail_index_open_files().
it's used elsewhere to check if we're doing an initial opening
of the index files */
if ((ret = mail_index_open_files(index, flags)) <= 0) {
/* doesn't exist and create flag not used */
mail_index_close_nonopened(index);
return ret;
}
index->open_count++;
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;
}
static void mail_index_close_nonopened(struct mail_index *index)
{
i_assert(!index->syncing);
i_assert(index->views == NULL);
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;
}
void mail_index_close(struct mail_index *index)
{
i_assert(index->open_count > 0);
mail_index_alloc_cache_index_closing(index);
if (--index->open_count == 0)
mail_index_close_nonopened(index);
}
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;
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;
mail_index_set_syscall_error(index, "stat()");
return -1;
}
if (fstat(index->fd, &st1) < 0) {
if (!ESTALE_FSTAT(errno)) {
mail_index_set_syscall_error(index, "fstat()");
return -1;
}
/* 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;
}
void 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);
}
}
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()");
(void)mail_transaction_log_unlink(index->log);
}
}
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()");
}
void mail_index_set_syscall_error(struct mail_index *index,
const char *function)
{
mail_index_file_set_syscall_error(index, index->filepath, function);
}
void 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;
}
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);
mail_index_set_error(index, "%s", errstr);
} else {
const char *suffix = errno != EFBIG ? "" :
" (process was started with ulimit -f limit)";
mail_index_set_error(index, "%s failed with file %s: "
"%m%s", function, filepath, suffix);
}
}
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;
}