mail-cache-fields.c revision a16d9a651aaa36a308f1aaae87e73e143fdff887
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "ioloop.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hash.h"
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen#include "file-cache.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "read-full.h"
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "mail-cache-private.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define CACHE_FIELD_IS_NEWLY_WANTED(cache, field_idx) \
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen ((cache)->field_file_map[field_idx] == (uint32_t)-1 && \
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen (cache)->fields[field_idx].used)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainenstatic bool field_has_fixed_size(enum mail_cache_field_type type)
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi{
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen switch (type) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_BITMASK:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen case MAIL_CACHE_FIELD_STRING:
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen case MAIL_CACHE_FIELD_HEADER:
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen return FALSE;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen case MAIL_CACHE_FIELD_COUNT:
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool field_decision_is_valid(enum mail_cache_decision_type type)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen switch (type & ~MAIL_CACHE_DECISION_FORCED) {
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen case MAIL_CACHE_DECISION_NO:
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen case MAIL_CACHE_DECISION_TEMP:
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen case MAIL_CACHE_DECISION_YES:
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen return TRUE;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen default:
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen return FALSE;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainenstatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen enum mail_cache_field_type type, unsigned int size)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen const struct mail_cache_field *field = &cache->fields[idx].field;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen if (field->type != type) {
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen mail_cache_set_corrupted(cache,
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen "registered field %s type changed", field->name);
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return -1;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen }
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen if (field->field_size != size && field_has_fixed_size(type)) {
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen mail_cache_set_corrupted(cache,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen "registered field %s size changed", field->name);
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen return -1;
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen }
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen return 0;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen}
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenstatic void
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenmail_cache_field_update(struct mail_cache *cache,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen const struct mail_cache_field *newfield)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_field_private *orig;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_assert(newfield->type < MAIL_CACHE_FIELD_COUNT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen orig = &cache->fields[newfield->idx];
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if ((newfield->decision & MAIL_CACHE_DECISION_FORCED) != 0 ||
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen newfield->decision > orig->field.decision) {
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen orig->field.decision = newfield->decision;
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen orig->decision_dirty = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (orig->field.last_used < newfield->last_used) {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen orig->field.last_used = newfield->last_used;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen orig->decision_dirty = TRUE;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen }
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen if (orig->decision_dirty)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen cache->field_header_write_pending = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen (void)field_type_verify(cache, newfield->idx,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen newfield->type, newfield->field_size);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_field *fields,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int fields_count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen void *value;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen unsigned int new_idx;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen unsigned int i, j;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen new_idx = cache->fields_count;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen for (i = 0; i < fields_count; i++) {
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash,
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen fields[i].name, &name, &value)) {
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen fields[i].idx = POINTER_CAST_TO(value, unsigned int);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen mail_cache_field_update(cache, &fields[i]);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen continue;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen }
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainen /* check if the same header is being registered in the
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainen same field array */
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainen for (j = 0; j < i; j++) {
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen if (strcasecmp(fields[i].name, fields[j].name) == 0) {
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen fields[i].idx = fields[j].idx;
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen break;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen }
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen }
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (j == i)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen fields[i].idx = new_idx++;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen }
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (new_idx == cache->fields_count)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen return;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen /* @UNSAFE */
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen cache->fields = i_realloc(cache->fields,
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen cache->fields_count * sizeof(*cache->fields),
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen new_idx * sizeof(*cache->fields));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen cache->field_file_map =
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen i_realloc(cache->field_file_map,
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen new_idx * sizeof(*cache->field_file_map));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen for (i = 0; i < fields_count; i++) {
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen unsigned int idx = fields[i].idx;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (idx < cache->fields_count)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen continue;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen /* new index - save it */
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen name = p_strdup(cache->field_pool, fields[i].name);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen cache->fields[idx].field = fields[i];
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen cache->fields[idx].field.name = name;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen cache->fields[idx].field.last_used = fields[i].last_used;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (!field_has_fixed_size(cache->fields[idx].field.type))
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen cache->fields[idx].field.field_size = UINT_MAX;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen hash_table_insert(cache->field_name_hash, name,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen POINTER_CAST(idx));
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen cache->fields_count = new_idx;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen}
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainenunsigned int
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen{
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen char *key;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen void *value;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen if (hash_table_lookup_full(cache->field_name_hash, name, &key, &value))
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return POINTER_CAST_TO(value, unsigned int);
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen else
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return UINT_MAX;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen}
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenconst struct mail_cache_field *
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenmail_cache_register_get_field(struct mail_cache *cache, unsigned int field_idx)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen i_assert(field_idx < cache->fields_count);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return &cache->fields[field_idx].field;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenconst struct mail_cache_field *
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen unsigned int *count_r)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen struct mail_cache_field *list;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen unsigned int i;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (!cache->opened)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen (void)mail_cache_open_and_verify(cache);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen list = cache->fields_count == 0 ? NULL :
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen p_new(pool, struct mail_cache_field, cache->fields_count);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen list[i] = cache->fields[i].field;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen list[i].name = p_strdup(pool, list[i].name);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen *count_r = cache->fields_count;
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen return list;
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen}
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainenstatic int
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainenmail_cache_header_fields_get_offset(struct mail_cache *cache,
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen uint32_t *offset_r,
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen const struct mail_cache_header_fields **field_hdr_r)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen const struct mail_cache_header_fields *field_hdr;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct mail_cache_header_fields tmp_field_hdr;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch const void *data;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen uint32_t offset = 0, next_offset, field_hdr_size;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen unsigned int next_count = 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen int ret;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *offset_r = 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (field_hdr_r != NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen *field_hdr_r = NULL;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return 0;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen /* find the latest header */
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen offset = 0;
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen next_offset = cache->last_field_header_offset != 0 ?
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen cache->last_field_header_offset :
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen while (next_offset != 0) {
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen if (next_offset == offset) {
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen mail_cache_set_corrupted(cache,
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen "next_offset in field header loops");
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen return -1;
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen }
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen offset = next_offset;
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (cache->mmap_base != NULL || cache->map_with_read) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen ret = mail_cache_map(cache, offset, sizeof(*field_hdr),
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen &data);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (ret <= 0) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (ret < 0)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return -1;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen mail_cache_set_corrupted(cache,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen "header field next_offset points outside file");
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return -1;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen field_hdr = data;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen } else {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* if we need to follow multiple offsets to get to
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen the last one, it's faster to just pread() the file
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen instead of going through cache */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen ret = pread_full(cache->fd, &tmp_field_hdr,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen sizeof(tmp_field_hdr), offset);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ret < 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_cache_set_syscall_error(cache, "pread()");
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen return -1;
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen }
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen if (ret == 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_cache_set_corrupted(cache,
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen "header field next_offset points outside file");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen }
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen field_hdr = &tmp_field_hdr;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen next_offset =
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen next_count++;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (offset == 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen mail_cache_set_corrupted(cache, "missing header fields");
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen cache->last_field_header_offset = offset;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (field_hdr_r != NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* detect corrupted size later */
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen field_hdr_size = I_MAX(field_hdr->size, sizeof(*field_hdr));
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (cache->file_cache != NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* invalidate the cache fields area to make sure we
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen get the latest cache decisions/last_used fields */
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen field_hdr_size);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (cache->read_buf != NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen buffer_set_used_size(cache->read_buf, 0);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen ret = mail_cache_map(cache, offset, field_hdr_size, &data);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (ret < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (ret == 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen mail_cache_set_corrupted(cache,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "header field size outside file");
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen *field_hdr_r = data;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen *offset_r = offset;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen{
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen const struct mail_cache_header_fields *field_hdr;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen struct mail_cache_field field;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen const uint32_t *last_used, *sizes;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen const uint8_t *types, *decisions;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen const char *p, *names, *end;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen char *orig_key;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen void *orig_value;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen unsigned int fidx, new_fields_count;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen enum mail_cache_decision_type dec;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen time_t max_drop_time;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen uint32_t offset, i;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset, &field_hdr) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (offset == 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* no fields - the file is empty */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return 0;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* check the fixed size of the header. name[] has to be checked
6825360d446542046757b06064282301c4c6b27cTimo Sirainen separately */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen new_fields_count = field_hdr->fields_count;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (new_fields_count != 0) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen cache->file_field_map =
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_realloc(cache->file_field_map,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen cache->file_fields_count *
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sizeof(unsigned int),
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen new_fields_count * sizeof(unsigned int));
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen } else {
6825360d446542046757b06064282301c4c6b27cTimo Sirainen i_free_and_null(cache->file_field_map);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen }
6825360d446542046757b06064282301c4c6b27cTimo Sirainen cache->file_fields_count = new_fields_count;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
6825360d446542046757b06064282301c4c6b27cTimo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
6825360d446542046757b06064282301c4c6b27cTimo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
6825360d446542046757b06064282301c4c6b27cTimo Sirainen types = CONST_PTR_OFFSET(field_hdr,
6825360d446542046757b06064282301c4c6b27cTimo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
6825360d446542046757b06064282301c4c6b27cTimo Sirainen names = CONST_PTR_OFFSET(field_hdr,
6825360d446542046757b06064282301c4c6b27cTimo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* clear the old mapping */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < cache->fields_count; i++)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen cache->field_file_map[i] = (uint32_t)-1;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen max_drop_time = cache->index->map->hdr.day_stamp == 0 ? 0 :
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen cache->index->map->hdr.day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen memset(&field, 0, sizeof(field));
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (p == end || *names == '\0') {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen mail_cache_set_corrupted(cache,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen "field header names corrupted");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (types[i] > MAIL_CACHE_FIELD_COUNT) {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen mail_cache_set_corrupted(cache, "field type corrupted");
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return -1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen }
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (!field_decision_is_valid(decisions[i])) {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen mail_cache_set_corrupted(cache,
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen "field decision type corrupted");
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return -1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen }
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash, names,
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen &orig_key, &orig_value)) {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen /* already exists, see if decision can be updated */
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen fidx = POINTER_CAST_TO(orig_value, unsigned int);
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (!cache->fields[fidx].decision_dirty) {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen cache->fields[fidx].field.decision =
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen decisions[i];
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen }
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (field_type_verify(cache, fidx,
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen types[i], sizes[i]) < 0)
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return -1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen } else {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen field.name = names;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen field.type = types[i];
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen field.field_size = sizes[i];
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen field.decision = decisions[i];
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen mail_cache_register_fields(cache, &field, 1);
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen fidx = field.idx;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen }
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen if (cache->field_file_map[fidx] != (uint32_t)-1) {
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen mail_cache_set_corrupted(cache,
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen "Duplicated field in header: %s", names);
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return -1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen }
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen cache->fields[fidx].used = TRUE;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen cache->field_file_map[fidx] = i;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen cache->file_field_map[i] = fidx;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* update last_used if it's newer than ours */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if ((time_t)last_used[i] > cache->fields[fidx].field.last_used)
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen cache->fields[fidx].field.last_used = last_used[i];
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen dec = cache->fields[fidx].field.decision;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (cache->fields[fidx].field.last_used < max_drop_time &&
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen cache->fields[fidx].field.last_used != 0 &&
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen (dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen dec != MAIL_CACHE_DECISION_NO) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* time to drop this field. don't bother dropping
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen fields that have never been used. */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen names = p + 1;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen return 0;
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen}
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest, bool add_new,
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen size_t offset, size_t size)
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen{
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen const void *data;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen unsigned int i, field;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* copy the existing fields */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen field = cache->file_field_map[i];
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen buffer_append(dest, data, size);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (!add_new)
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen return;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* copy newly wanted fields */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen buffer_append(dest, data, size);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen}
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen bool add_new, size_t offset)
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen{
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen const int *data;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen unsigned int i, field;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen uint8_t byte;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* copy the existing fields */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen field = cache->file_field_map[i];
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen byte = (uint8_t)*data;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen buffer_append(dest, &byte, 1);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen if (!add_new)
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen return;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen /* copy newly wanted fields */
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen byte = (uint8_t)*data;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen buffer_append(dest, &byte, 1);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen{
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen buffer_t *buffer;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen uint32_t i, offset, dec_offset;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen int ret = 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset, FALSE) < 0)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen copy_to_buf(cache, buffer, FALSE,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen offsetof(struct mail_cache_field, last_used),
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen sizeof(uint32_t));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (ret == 0) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen buffer_set_used_size(buffer, 0);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen copy_to_buf_byte(cache, buffer, FALSE,
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen offsetof(struct mail_cache_field, decision));
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen dec_offset = offset +
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen dec_offset);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen if (ret == 0) {
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen cache->fields[i].decision_dirty = FALSE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (ret == 0)
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen cache->field_header_write_pending = FALSE;
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (cache->locked) {
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen T_BEGIN {
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen } T_END;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return ret;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen }
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen if (mail_cache_lock(cache, FALSE) <= 0)
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen return -1;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen T_BEGIN {
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen ret = mail_cache_header_fields_update_locked(cache);
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen } T_END;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen if (mail_cache_unlock(cache) < 0)
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen ret = -1;
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen return ret;
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen}
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_header_fields hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int field;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *name;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen uint32_t i;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(&hdr, 0, sizeof(hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr.fields_count = cache->file_fields_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr.fields_count++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen buffer_append(dest, &hdr, sizeof(hdr));
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* we have to keep the field order for the existing fields. */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen copy_to_buf(cache, dest, TRUE,
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen offsetof(struct mail_cache_field, last_used),
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen sizeof(uint32_t));
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen copy_to_buf(cache, dest, TRUE,
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen offsetof(struct mail_cache_field, field_size),
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen sizeof(uint32_t));
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen copy_to_buf_byte(cache, dest, TRUE,
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen offsetof(struct mail_cache_field, type));
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen copy_to_buf_byte(cache, dest, TRUE,
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen offsetof(struct mail_cache_field, decision));
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen i_assert(dest->used == sizeof(hdr) +
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen (sizeof(uint32_t)*2 + 2) * hdr.fields_count);
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen /* add existing fields' names */
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen field = cache->file_field_map[i];
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen name = cache->fields[field].field.name;
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen buffer_append(dest, name, strlen(name)+1);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* add newly wanted fields' names */
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen name = cache->fields[i].field.name;
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen buffer_append(dest, name, strlen(name)+1);
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen }
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen }
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen hdr.size = dest->used;
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen buffer_write(dest, 0, &hdr, sizeof(hdr));
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if ((hdr.size & 3) != 0)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen buffer_append_zero(dest, 4 - (hdr.size & 3));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen uint32_t *offset_r)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r, FALSE) < 0)
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return -1;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen if (*offset_r == 0) {
e4b242684975b4d3702ca79bfd56452fe139a2bfTimo Sirainen *offset_r = offsetof(struct mail_cache_header,
e4b242684975b4d3702ca79bfd56452fe139a2bfTimo Sirainen field_header_offset);
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen } else {
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen *offset_r += offsetof(struct mail_cache_header_fields,
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen next_offset);
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen }
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen return 0;
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen}
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen