mail-cache-fields.c revision dbd9604da561399cc6255289d5b6f6f662ab2d00
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hash.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "file-cache.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "mail-cache-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define CACHE_HDR_PREFETCH 1024
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo 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{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen void *orig_key, *orig_value;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen unsigned int new_idx;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen size_t i;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen new_idx = cache->fields_count;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen for (i = 0; i < fields_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hash_lookup_full(cache->field_name_hash, fields[i].name,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &orig_key, &orig_value)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fields[i].idx =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen POINTER_CAST_TO(orig_value, unsigned int);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fields[i].idx = new_idx++;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen }
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (new_idx == cache->fields_count)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* @UNSAFE */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen cache->fields = i_realloc(cache->fields,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields_count * sizeof(*cache->fields),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_idx * sizeof(*cache->fields));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->field_file_map =
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_realloc(cache->field_file_map,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen new_idx * sizeof(*cache->field_file_map));
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < fields_count; i++) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int idx = fields[i].idx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (idx < cache->fields_count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* new index - save it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields[idx].field = fields[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields[idx].field.name =
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen p_strdup(cache->field_pool, fields[i].name);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen switch (cache->fields[idx].field.type) {
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen case MAIL_CACHE_FIELD_BITMASK:
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen case MAIL_CACHE_FIELD_STRING:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_HEADER:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->fields[idx].field.field_size = (unsigned int)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hash_insert(cache->field_name_hash,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen (char *)cache->fields[idx].field.name,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen POINTER_CAST(idx));
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen cache->fields_count = new_idx;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen}
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainenunsigned int
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen void *orig_key, *orig_value;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (hash_lookup_full(cache->field_name_hash, name,
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen &orig_key, &orig_value))
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return POINTER_CAST_TO(orig_value, unsigned int);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen else
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return (unsigned int)-1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenstatic int mail_cache_header_fields_get_offset(struct mail_cache *cache,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen uint32_t *offset_r)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen const struct mail_cache_header_fields *field_hdr;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen uint32_t offset, next_offset;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen *offset_r = 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen /* find the latest header */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen offset = 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen next_offset =
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen while (next_offset != 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (next_offset == offset) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_cache_set_corrupted(cache,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "next_offset in field header loops");
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen offset = next_offset;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen if (cache->file_cache != NULL) {
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen /* we can't trust that the cached data is valid */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen sizeof(*field_hdr) +
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen CACHE_HDR_PREFETCH);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (mail_cache_map(cache, offset,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen sizeof(*field_hdr) + CACHE_HDR_PREFETCH) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen next_offset =
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen *offset_r = offset;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return 0;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen const struct mail_cache_header_fields *field_hdr = NULL;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen struct mail_cache_field field;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen const uint32_t *last_used, *sizes;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen const uint8_t *types, *decisions;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen const char *p, *names, *end;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen void *orig_key, *orig_value;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen uint32_t offset, i;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (offset == 0) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen /* no fields - the file is empty */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (offset + field_hdr->size > cache->mmap_length) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen mail_cache_set_corrupted(cache,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "field header points outside file");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen }
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen /* check the fixed size of the header. name[] has to be checked
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen separately */
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (field_hdr->size > sizeof(*field_hdr) + CACHE_HDR_PREFETCH) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (cache->file_cache != NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* we can't trust that the cached data is valid */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen sizeof(*field_hdr) +
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen CACHE_HDR_PREFETCH);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (mail_cache_map(cache, offset, field_hdr->size) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen cache->file_field_map =
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_realloc(cache->file_field_map,
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen cache->file_fields_count * sizeof(unsigned int),
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen field_hdr->fields_count * sizeof(unsigned int));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen cache->file_fields_count = field_hdr->fields_count;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen types = CONST_PTR_OFFSET(field_hdr,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen names = CONST_PTR_OFFSET(field_hdr,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* clear the old mapping */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen for (i = 0; i < cache->fields_count; i++)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen cache->field_file_map[i] = (uint32_t)-1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen memset(&field, 0, sizeof(field));
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (p == end || *names == '\0') {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen mail_cache_set_corrupted(cache,
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen "field header names corrupted");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return -1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (hash_lookup_full(cache->field_name_hash, names,
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen &orig_key, &orig_value)) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* already exists, see if decision can be updated */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen field.idx = POINTER_CAST_TO(orig_value, unsigned int);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (!cache->fields[field.idx].decision_dirty) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen cache->fields[field.idx].field.decision =
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen decisions[i];
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (cache->fields[field.idx].field.type != types[i]) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen mail_cache_set_corrupted(cache,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen "registered field type changed");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return -1;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen } else {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen field.name = names;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen field.type = types[i];
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen field.field_size = sizes[i];
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen field.decision = decisions[i];
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mail_cache_register_fields(cache, &field, 1);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (cache->field_file_map[field.idx] != (uint32_t)-1) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mail_cache_set_corrupted(cache,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen "Duplicated field in header: %s", names);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return -1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen }
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen cache->field_file_map[field.idx] = i;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen cache->file_field_map[i] = field.idx;
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* update last_used if it's newer than ours */
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (last_used[i] > cache->fields[field.idx].last_used)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen cache->fields[field.idx].last_used = last_used[i];
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen names = p + 1;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return 0;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest,
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen size_t offset, size_t size)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
ab286a8b58306eb8d22fc18342b6c199fd428e1eTimo Sirainen const void *data;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen unsigned int i, field;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen field = cache->file_field_map[i];
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(dest, data, size);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (cache->field_file_map[i] != (uint32_t)-1)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen continue;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen buffer_append(dest, data, size);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen size_t offset)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const int *data;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen unsigned int i, field;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen uint8_t byte;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen field = cache->file_field_map[i];
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen byte = (uint8_t)*data;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen buffer_append(dest, &byte, 1);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (cache->field_file_map[i] != (uint32_t)-1)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen continue;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen byte = (uint8_t)*data;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_append(dest, &byte, 1);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen buffer_t *buffer;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen uint32_t i, offset;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen int ret = 0;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset) < 0)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen t_push();
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen copy_to_buf(cache, buffer,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen offsetof(struct mail_cache_field_private, last_used),
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen sizeof(uint32_t));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen ret = mail_cache_write(cache, buffer->data,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen sizeof(uint32_t) * cache->file_fields_count,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ret == 0) {
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen buffer_set_used_size(buffer, 0);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen copy_to_buf_byte(cache, buffer,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen offsetof(struct mail_cache_field, decision));
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen ret = mail_cache_write(cache, buffer->data,
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen sizeof(uint8_t) * cache->file_fields_count, offset +
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count));
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen if (ret == 0) {
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen cache->fields[i].decision_dirty = FALSE;
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen }
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen }
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen t_pop();
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen if (ret == 0)
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen cache->field_header_write_pending = FALSE;
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen return ret;
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen}
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen{
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen int ret;
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen if (cache->locked)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return mail_cache_header_fields_update_locked(cache);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (mail_cache_lock(cache) <= 0)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ret = mail_cache_header_fields_update_locked(cache);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen mail_cache_unlock(cache);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return ret;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_cache_header_fields hdr;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int field;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const char *name;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint32_t i;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen memset(&hdr, 0, sizeof(hdr));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr.fields_count = cache->fields_count;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_append(dest, &hdr, sizeof(hdr));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* we have to keep the field order for the existing fields. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen copy_to_buf(cache, dest,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen offsetof(struct mail_cache_field_private, last_used),
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sizeof(uint32_t));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen copy_to_buf(cache, dest, offsetof(struct mail_cache_field, field_size),
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sizeof(uint32_t));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen copy_to_buf_byte(cache, dest, offsetof(struct mail_cache_field, type));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen copy_to_buf_byte(cache, dest,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen offsetof(struct mail_cache_field, decision));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(buffer_get_used_size(dest) == sizeof(hdr) +
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (sizeof(uint32_t)*2 + 2) * hdr.fields_count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen field = cache->file_field_map[i];
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen name = cache->fields[field].field.name;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_append(dest, name, strlen(name)+1);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (cache->field_file_map[i] != (uint32_t)-1)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen continue;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name = cache->fields[i].field.name;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(dest, name, strlen(name)+1);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr.size = buffer_get_used_size(dest);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_write(dest, 0, &hdr, sizeof(hdr));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((hdr.size & 3) != 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_append(dest, null4, 4 - (hdr.size & 3));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t *offset_r)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r) < 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (*offset_r == 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *offset_r = offsetof(struct mail_cache_header,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen field_header_offset);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *offset_r += offsetof(struct mail_cache_header_fields,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen next_offset);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen