mail-cache-fields.c revision 6e235046e1d8e9d89fc948f5c623676c20421a28
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2004-2007 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hash.h"
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen#include "file-cache.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "mmap-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-cache-private.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen#define CACHE_FIELD_IS_NEWLY_WANTED(cache, field_idx) \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((cache)->field_file_map[field_idx] == (uint32_t)-1 && \
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen (cache)->fields[field_idx].used)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic bool field_has_fixed_size(enum mail_cache_field_type type)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen switch (type) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen case MAIL_CACHE_FIELD_BITMASK:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_STRING:
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen case MAIL_CACHE_FIELD_HEADER:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_COUNT:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return FALSE;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen}
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainenstatic bool field_decision_is_valid(enum mail_cache_decision_type type)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (type & ~MAIL_CACHE_DECISION_FORCED) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_DECISION_NO:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case MAIL_CACHE_DECISION_TEMP:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case MAIL_CACHE_DECISION_YES:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen}
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_cache_field_type type, unsigned int size)
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen{
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen const struct mail_cache_field *field = &cache->fields[idx].field;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen if (field->type != type) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen mail_cache_set_corrupted(cache,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "registered field %s type changed", field->name);
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen return -1;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (field->field_size != size && field_has_fixed_size(type)) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_cache_set_corrupted(cache,
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen "registered field %s size changed", field->name);
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return 0;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen}
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_cache_field *fields,
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen unsigned int fields_count)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen void *orig_key, *orig_value;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen char *name;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen unsigned int new_idx;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen unsigned int i, j;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen new_idx = cache->fields_count;
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen for (i = 0; i < fields_count; i++) {
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen if (hash_lookup_full(cache->field_name_hash, fields[i].name,
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen &orig_key, &orig_value)) {
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen i_assert(fields[i].type < MAIL_CACHE_FIELD_COUNT);
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen fields[i].idx =
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen POINTER_CAST_TO(orig_value, unsigned int);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen (void)field_type_verify(cache, fields[i].idx,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen fields[i].type,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen fields[i].field_size);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen continue;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
aff3354de83df9d683587e27461697193ff36591Timo Sirainen
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen /* check if the same header is being registered in the
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen same field array */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (j = 0; j < i; j++) {
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen if (strcasecmp(fields[i].name, fields[j].name) == 0) {
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen fields[i].idx = fields[j].idx;
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen break;
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen }
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (j == i)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen fields[i].idx = new_idx++;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (new_idx == cache->fields_count)
6a7f64562ddd0dd2fec755ec4e9c9afde8e85cf1Timo Sirainen return;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields = i_realloc(cache->fields,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->fields_count * sizeof(*cache->fields),
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen new_idx * sizeof(*cache->fields));
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen cache->field_file_map =
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_realloc(cache->field_file_map,
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen new_idx * sizeof(*cache->field_file_map));
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen for (i = 0; i < fields_count; i++) {
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen unsigned int idx = fields[i].idx;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (idx < cache->fields_count)
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen continue;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen /* new index - save it */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen name = p_strdup(cache->field_pool, fields[i].name);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->fields[idx].field = fields[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields[idx].field.name = name;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen if (!field_has_fixed_size(cache->fields[idx].field.type))
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen cache->fields[idx].field.field_size = (unsigned int)-1;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen hash_insert(cache->field_name_hash, name, POINTER_CAST(idx));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->fields_count = new_idx;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenunsigned int
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen{
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen void *orig_key, *orig_value;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen if (hash_lookup_full(cache->field_name_hash, name,
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen &orig_key, &orig_value))
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen return POINTER_CAST_TO(orig_value, unsigned int);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen else
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return (unsigned int)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenconst struct mail_cache_field *
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int *count_r)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_field *list;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int i;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen if (!cache->opened)
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen (void)mail_cache_open_and_verify(cache);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen list = p_new(pool, struct mail_cache_field, cache->fields_count);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen list[i] = cache->fields[i].field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen list[i].name = p_strdup(pool, list[i].name);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *count_r = cache->fields_count;
02166e32bcda5d0018ae1a2a38614126ab5c6025Timo Sirainen return list;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int mail_cache_header_fields_get_offset(struct mail_cache *cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t *offset_r, bool map)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct mail_cache_header_fields *field_hdr;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_header_fields tmp_field_hdr;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t offset = 0, next_offset;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int next_count = 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *offset_r = 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* find the latest header */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen offset = 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen next_offset = cache->last_field_header_offset != 0 ?
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->last_field_header_offset :
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while (next_offset != 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (next_offset == offset) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "next_offset in field header loops");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen offset = next_offset;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (cache->mmap_base != NULL) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_map(cache, offset,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen sizeof(*field_hdr)) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen } else {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* if we need to follow multiple offsets to get to
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen the last one, it's faster to just pread() the file
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen instead of going through cache */
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen ret = pread_full(cache->fd, &tmp_field_hdr,
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen sizeof(tmp_field_hdr), offset);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret < 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_syscall_error(cache, "pread()");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret == 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "next_offset points outside file");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_hdr = &tmp_field_hdr;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen next_offset =
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen next_count++;
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (offset == 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache, "missing header fields");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen cache->last_field_header_offset = offset;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (map) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (cache->file_cache != NULL) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* we can't trust that the cached data is valid */
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_hdr->size);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_map(cache, offset, field_hdr->size) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *offset_r = offset;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct mail_cache_header_fields *field_hdr = NULL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_field field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const uint32_t *last_used, *sizes;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const uint8_t *types, *decisions;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const char *p, *names, *end;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen void *orig_key, *orig_value;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int new_fields_count;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen time_t max_drop_time;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t offset, i;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset, TRUE) < 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (offset == 0) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* no fields - the file is empty */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (offset + field_hdr->size > cache->mmap_length) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_set_corrupted(cache,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen "field header points outside file");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* check the fixed size of the header. name[] has to be checked
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen separately */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen new_fields_count = field_hdr->fields_count;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (new_fields_count != 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->file_field_map =
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i_realloc(cache->file_field_map,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->file_fields_count *
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen sizeof(unsigned int),
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen new_fields_count * sizeof(unsigned int));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_free_and_null(cache->file_field_map);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->file_fields_count = new_fields_count;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen types = CONST_PTR_OFFSET(field_hdr,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen names = CONST_PTR_OFFSET(field_hdr,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* clear the old mapping */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < cache->fields_count; i++)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->field_file_map[i] = (uint32_t)-1;
f65602dff8a85170176ddaa790db6df56006d132Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen max_drop_time = cache->index->map->hdr.day_stamp -
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen MAIL_CACHE_FIELD_DROP_SECS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen memset(&field, 0, sizeof(field));
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen if (p == end || *names == '\0') {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_cache_set_corrupted(cache,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen "field header names corrupted");
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return -1;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (types[i] > MAIL_CACHE_FIELD_COUNT) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache, "field type corrupted");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!field_decision_is_valid(decisions[i])) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen "field decision type corrupted");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen if (hash_lookup_full(cache->field_name_hash, names,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen &orig_key, &orig_value)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* already exists, see if decision can be updated */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen field.idx = POINTER_CAST_TO(orig_value, unsigned int);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!cache->fields[field.idx].decision_dirty) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->fields[field.idx].field.decision =
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen decisions[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field_type_verify(cache, field.idx,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen types[i], sizes[i]) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen } else {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field.name = names;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field.type = types[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field.field_size = sizes[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field.decision = decisions[i];
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen mail_cache_register_fields(cache, &field, 1);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen }
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen if (cache->field_file_map[field.idx] != (uint32_t)-1) {
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen mail_cache_set_corrupted(cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Duplicated field in header: %s", names);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->fields[field.idx].used = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen cache->field_file_map[field.idx] = i;
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen cache->file_field_map[i] = field.idx;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen /* update last_used if it's newer than ours */
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen if (last_used[i] > cache->fields[field.idx].last_used)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen cache->fields[field.idx].last_used = last_used[i];
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (cache->fields[field.idx].last_used < max_drop_time) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* time to drop this field */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen names = p + 1;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest, bool add_new,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t offset, size_t size)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const void *data;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int i, field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* copy the existing fields */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen field = cache->file_field_map[i];
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(dest, data, size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!add_new)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* copy newly wanted fields */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_append(dest, data, size);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen bool add_new, size_t offset)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const int *data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, field;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen uint8_t byte;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* copy the existing fields */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field = cache->file_field_map[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen byte = (uint8_t)*data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buffer_append(dest, &byte, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!add_new)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* copy newly wanted fields */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen byte = (uint8_t)*data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(dest, &byte, 1);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buffer_t *buffer;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen uint32_t i, offset, dec_offset;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset, FALSE) < 0)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return -1;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen t_push();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen copy_to_buf(cache, buffer, FALSE,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen offsetof(struct mail_cache_field_private, last_used),
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen sizeof(uint32_t));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret == 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_set_used_size(buffer, 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen copy_to_buf_byte(cache, buffer, FALSE,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen offsetof(struct mail_cache_field, decision));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen dec_offset = offset +
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen dec_offset);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret == 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen cache->fields[i].decision_dirty = FALSE;
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ret == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cache->field_header_write_pending = FALSE;
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen return ret;
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen}
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen{
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen int ret;
0beb5d6c661ee68130a954ed0f31a34c19195fb7Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (cache->locked)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen return mail_cache_header_fields_update_locked(cache);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mail_cache_lock(cache, NULL) <= 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_unlock(cache) < 0)
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen ret = -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_header_fields hdr;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int field;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const char *name;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t i;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen memset(&hdr, 0, sizeof(hdr));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen hdr.fields_count = cache->file_fields_count;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i))
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen hdr.fields_count++;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_append(dest, &hdr, sizeof(hdr));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* we have to keep the field order for the existing fields. */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen copy_to_buf(cache, dest, TRUE,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen offsetof(struct mail_cache_field_private, last_used),
84004c37192dc91a8dcc9f213ca2cfa22b4f40e4Timo Sirainen sizeof(uint32_t));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen copy_to_buf(cache, dest, TRUE,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen offsetof(struct mail_cache_field, field_size),
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen sizeof(uint32_t));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen copy_to_buf_byte(cache, dest, TRUE,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen offsetof(struct mail_cache_field, type));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen copy_to_buf_byte(cache, dest, TRUE,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen offsetof(struct mail_cache_field, decision));
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i_assert(dest->used == sizeof(hdr) +
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen (sizeof(uint32_t)*2 + 2) * hdr.fields_count);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* add existing fields' names */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen field = cache->file_field_map[i];
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen name = cache->fields[field].field.name;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buffer_append(dest, name, strlen(name)+1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* add newly wanted fields' names */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen name = cache->fields[i].field.name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(dest, name, strlen(name)+1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr.size = dest->used;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_write(dest, 0, &hdr, sizeof(hdr));
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if ((hdr.size & 3) != 0)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buffer_append_zero(dest, 4 - (hdr.size & 3));
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen}
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t *offset_r)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r, FALSE) < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (*offset_r == 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen *offset_r = offsetof(struct mail_cache_header,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen field_header_offset);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen *offset_r += offsetof(struct mail_cache_header_fields,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen next_offset);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen