mail-cache-fields.c revision a16d9a651aaa36a308f1aaae87e73e143fdff887
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "buffer.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "hash.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "file-cache.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "read-full.h"
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include "write-full.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mmap-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-cache-private.h"
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stddef.h>
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define CACHE_FIELD_IS_NEWLY_WANTED(cache, field_idx) \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ((cache)->field_file_map[field_idx] == (uint32_t)-1 && \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (cache)->fields[field_idx].used)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool field_has_fixed_size(enum mail_cache_field_type type)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen switch (type) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_BITMASK:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_STRING:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_HEADER:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case MAIL_CACHE_FIELD_COUNT:
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen break;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_unreached();
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return FALSE;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenstatic bool field_decision_is_valid(enum mail_cache_decision_type type)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen{
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen switch (type & ~MAIL_CACHE_DECISION_FORCED) {
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen case MAIL_CACHE_DECISION_NO:
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen case MAIL_CACHE_DECISION_TEMP:
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen case MAIL_CACHE_DECISION_YES:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen default:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_cache_field_type type, unsigned int size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_cache_field *field = &cache->fields[idx].field;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen if (field->type != type) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_corrupted(cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "registered field %s type changed", field->name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (field->field_size != size && field_has_fixed_size(type)) {
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen mail_cache_set_corrupted(cache,
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen "registered field %s size changed", field->name);
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen return -1;
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen }
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen return 0;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen}
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainenstatic void
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainenmail_cache_field_update(struct mail_cache *cache,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen const struct mail_cache_field *newfield)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen{
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen struct mail_cache_field_private *orig;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(newfield->type < MAIL_CACHE_FIELD_COUNT);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen orig = &cache->fields[newfield->idx];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((newfield->decision & MAIL_CACHE_DECISION_FORCED) != 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen newfield->decision > orig->field.decision) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen orig->field.decision = newfield->decision;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen orig->decision_dirty = TRUE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (orig->field.last_used < newfield->last_used) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen orig->field.last_used = newfield->last_used;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen orig->decision_dirty = TRUE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (orig->decision_dirty)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen cache->field_header_write_pending = TRUE;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)field_type_verify(cache, newfield->idx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen newfield->type, newfield->field_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_cache_field *fields,
7fe37c2b0e4cd2a39896ab16e47eb418a59e3934Timo Sirainen unsigned int fields_count)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen char *name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen void *value;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int new_idx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, j;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen new_idx = cache->fields_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < fields_count; i++) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (hash_table_lookup_full(cache->field_name_hash,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen fields[i].name, &name, &value)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fields[i].idx = POINTER_CAST_TO(value, unsigned int);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_field_update(cache, &fields[i]);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen continue;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen /* check if the same header is being registered in the
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen same field array */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen for (j = 0; j < i; j++) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (strcasecmp(fields[i].name, fields[j].name) == 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen fields[i].idx = fields[j].idx;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen break;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if (j == i)
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen fields[i].idx = new_idx++;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen }
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if (new_idx == cache->fields_count)
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen return;
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* @UNSAFE */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields = i_realloc(cache->fields,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields_count * sizeof(*cache->fields),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen new_idx * sizeof(*cache->fields));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->field_file_map =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_realloc(cache->field_file_map,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen new_idx * sizeof(*cache->field_file_map));
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen for (i = 0; i < fields_count; i++) {
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen unsigned int idx = fields[i].idx;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (idx < cache->fields_count)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen continue;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen /* new index - save it */
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen name = p_strdup(cache->field_pool, fields[i].name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields[idx].field = fields[i];
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen cache->fields[idx].field.name = name;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen cache->fields[idx].field.last_used = fields[i].last_used;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen if (!field_has_fixed_size(cache->fields[idx].field.type))
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen cache->fields[idx].field.field_size = UINT_MAX;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hash_table_insert(cache->field_name_hash, name,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen POINTER_CAST(idx));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen cache->fields_count = new_idx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainenunsigned int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen{
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen char *key;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen void *value;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash, name, &key, &value))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return POINTER_CAST_TO(value, unsigned int);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return UINT_MAX;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenconst struct mail_cache_field *
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_cache_register_get_field(struct mail_cache *cache, unsigned int field_idx)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen{
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen i_assert(field_idx < cache->fields_count);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return &cache->fields[field_idx].field;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst struct mail_cache_field *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int *count_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_cache_field *list;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!cache->opened)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)mail_cache_open_and_verify(cache);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen list = cache->fields_count == 0 ? NULL :
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen p_new(pool, struct mail_cache_field, cache->fields_count);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen list[i] = cache->fields[i].field;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen list[i].name = p_strdup(pool, list[i].name);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen *count_r = cache->fields_count;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return list;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen}
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenstatic int
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_cache_header_fields_get_offset(struct mail_cache *cache,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen uint32_t *offset_r,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const struct mail_cache_header_fields **field_hdr_r)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen{
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const struct mail_cache_header_fields *field_hdr;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen struct mail_cache_header_fields tmp_field_hdr;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const void *data;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen uint32_t offset = 0, next_offset, field_hdr_size;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen unsigned int next_count = 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen int ret;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen *offset_r = 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (field_hdr_r != NULL)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen *field_hdr_r = NULL;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen return 0;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen }
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* find the latest header */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen offset = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_offset = cache->last_field_header_offset != 0 ?
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->last_field_header_offset :
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen while (next_offset != 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (next_offset == offset) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_cache_set_corrupted(cache,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen "next_offset in field header loops");
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return -1;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen offset = next_offset;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (cache->mmap_base != NULL || cache->map_with_read) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen ret = mail_cache_map(cache, offset, sizeof(*field_hdr),
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen &data);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen if (ret <= 0) {
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen if (ret < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_corrupted(cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "header field next_offset points outside file");
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen return -1;
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen }
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen field_hdr = data;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen } else {
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* if we need to follow multiple offsets to get to
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen the last one, it's faster to just pread() the file
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen instead of going through cache */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = pread_full(cache->fd, &tmp_field_hdr,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sizeof(tmp_field_hdr), offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_syscall_error(cache, "pread()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_set_corrupted(cache,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "header field next_offset points outside file");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen field_hdr = &tmp_field_hdr;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen next_offset =
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen next_count++;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (offset == 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_cache_set_corrupted(cache, "missing header fields");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->last_field_header_offset = offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (field_hdr_r != NULL) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* detect corrupted size later */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen field_hdr_size = I_MAX(field_hdr->size, sizeof(*field_hdr));
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (cache->file_cache != NULL) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* invalidate the cache fields area to make sure we
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen get the latest cache decisions/last_used fields */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen field_hdr_size);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (cache->read_buf != NULL)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen buffer_set_used_size(cache->read_buf, 0);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen ret = mail_cache_map(cache, offset, field_hdr_size, &data);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (ret < 0)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return -1;
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen if (ret == 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_cache_set_corrupted(cache,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen "header field size outside file");
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen return -1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen *field_hdr_r = data;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *offset_r = offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen{
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const struct mail_cache_header_fields *field_hdr;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen struct mail_cache_field field;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const uint32_t *last_used, *sizes;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen const uint8_t *types, *decisions;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen const char *p, *names, *end;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen char *orig_key;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen void *orig_value;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen unsigned int fidx, new_fields_count;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen enum mail_cache_decision_type dec;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen time_t max_drop_time;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen uint32_t offset, i;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset, &field_hdr) < 0)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen return -1;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (offset == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no fields - the file is empty */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* check the fixed size of the header. name[] has to be checked
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen separately */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen }
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen new_fields_count = field_hdr->fields_count;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (new_fields_count != 0) {
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen cache->file_field_map =
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen i_realloc(cache->file_field_map,
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen cache->file_fields_count *
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen sizeof(unsigned int),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen new_fields_count * sizeof(unsigned int));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free_and_null(cache->file_field_map);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->file_fields_count = new_fields_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen types = CONST_PTR_OFFSET(field_hdr,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen names = CONST_PTR_OFFSET(field_hdr,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen /* clear the old mapping */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen for (i = 0; i < cache->fields_count; i++)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen cache->field_file_map[i] = (uint32_t)-1;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen max_drop_time = cache->index->map->hdr.day_stamp == 0 ? 0 :
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen cache->index->map->hdr.day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen memset(&field, 0, sizeof(field));
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (p == end || *names == '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_set_corrupted(cache,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "field header names corrupted");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (types[i] > MAIL_CACHE_FIELD_COUNT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_set_corrupted(cache, "field type corrupted");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!field_decision_is_valid(decisions[i])) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_set_corrupted(cache,
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen "field decision type corrupted");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash, names,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen &orig_key, &orig_value)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already exists, see if decision can be updated */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fidx = POINTER_CAST_TO(orig_value, unsigned int);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!cache->fields[fidx].decision_dirty) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->fields[fidx].field.decision =
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen decisions[i];
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen }
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen if (field_type_verify(cache, fidx,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen types[i], sizes[i]) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen field.name = names;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen field.type = types[i];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen field.field_size = sizes[i];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen field.decision = decisions[i];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_register_fields(cache, &field, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fidx = field.idx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (cache->field_file_map[fidx] != (uint32_t)-1) {
cbcba924a745c938260fd39cb284175b75f8eaf2Timo Sirainen mail_cache_set_corrupted(cache,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Duplicated field in header: %s", names);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->fields[fidx].used = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->field_file_map[fidx] = i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->file_field_map[i] = fidx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* update last_used if it's newer than ours */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((time_t)last_used[i] > cache->fields[fidx].field.last_used)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->fields[fidx].field.last_used = last_used[i];
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dec = cache->fields[fidx].field.decision;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (cache->fields[fidx].field.last_used < max_drop_time &&
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen cache->fields[fidx].field.last_used != 0 &&
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen (dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen dec != MAIL_CACHE_DECISION_NO) {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* time to drop this field. don't bother dropping
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen fields that have never been used. */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen names = p + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest, bool add_new,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t offset, size_t size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const void *data;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen unsigned int i, field;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen /* copy the existing fields */
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen field = cache->file_field_map[i];
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(dest, data, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!add_new)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy newly wanted fields */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen buffer_append(dest, data, size);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen }
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool add_new, size_t offset)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const int *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, field;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint8_t byte;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy the existing fields */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen field = cache->file_field_map[i];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen byte = (uint8_t)*data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(dest, &byte, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!add_new)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy newly wanted fields */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen byte = (uint8_t)*data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(dest, &byte, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen buffer_t *buffer;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint32_t i, offset, dec_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset, FALSE) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen copy_to_buf(cache, buffer, FALSE,
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen offsetof(struct mail_cache_field, last_used),
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen sizeof(uint32_t));
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen if (ret == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_set_used_size(buffer, 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen copy_to_buf_byte(cache, buffer, FALSE,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen offsetof(struct mail_cache_field, decision));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dec_offset = offset +
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dec_offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields[i].decision_dirty = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (ret == 0)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen cache->field_header_write_pending = FALSE;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return ret;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen}
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen{
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen int ret;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (cache->locked) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen T_BEGIN {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen } T_END;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return ret;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen }
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mail_cache_lock(cache, FALSE) <= 0)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen return -1;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen T_BEGIN {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen } T_END;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (mail_cache_unlock(cache) < 0)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen ret = -1;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen return ret;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen}
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen struct mail_cache_header_fields hdr;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen unsigned int field;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const char *name;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen uint32_t i;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen memset(&hdr, 0, sizeof(hdr));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen hdr.fields_count = cache->file_fields_count;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i))
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen hdr.fields_count++;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen buffer_append(dest, &hdr, sizeof(hdr));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* we have to keep the field order for the existing fields. */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen copy_to_buf(cache, dest, TRUE,
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen offsetof(struct mail_cache_field, last_used),
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen sizeof(uint32_t));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen copy_to_buf(cache, dest, TRUE,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen offsetof(struct mail_cache_field, field_size),
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen sizeof(uint32_t));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen copy_to_buf_byte(cache, dest, TRUE,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen offsetof(struct mail_cache_field, type));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen copy_to_buf_byte(cache, dest, TRUE,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen offsetof(struct mail_cache_field, decision));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_assert(dest->used == sizeof(hdr) +
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen (sizeof(uint32_t)*2 + 2) * hdr.fields_count);
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* add existing fields' names */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen field = cache->file_field_map[i];
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen name = cache->fields[field].field.name;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen buffer_append(dest, name, strlen(name)+1);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen }
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen /* add newly wanted fields' names */
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen name = cache->fields[i].field.name;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(dest, name, strlen(name)+1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr.size = dest->used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_write(dest, 0, &hdr, sizeof(hdr));
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if ((hdr.size & 3) != 0)
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen buffer_append_zero(dest, 4 - (hdr.size & 3));
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen}
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen uint32_t *offset_r)
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r, FALSE) < 0)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen return -1;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*offset_r == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *offset_r = offsetof(struct mail_cache_header,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen field_header_offset);
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen } else {
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen *offset_r += offsetof(struct mail_cache_header_fields,
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen next_offset);
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen }
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen return 0;
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen}
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen