mail-cache-fields.c revision a817fdcc43aedf423e2134091d5f83f91d64bcc9
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "lib.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "buffer.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "hash.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "file-cache.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include "write-full.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "mail-cache-private.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include <stddef.h>
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#define CACHE_HDR_PREFETCH 1024
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_cache_field *fields,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int fields_count)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void *orig_key, *orig_value;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int new_idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_idx = cache->fields_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < fields_count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (hash_lookup_full(cache->field_name_hash, fields[i].name,
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen &orig_key, &orig_value)) {
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen fields[i].idx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen POINTER_CAST_TO(orig_value, unsigned int);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen continue;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fields[i].idx = new_idx++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (new_idx == cache->fields_count)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* @UNSAFE */
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen cache->fields = i_realloc(cache->fields,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen cache->fields_count * sizeof(*cache->fields),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_idx * sizeof(*cache->fields));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->field_file_map =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_realloc(cache->field_file_map,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
d22301419109ed4a38351715e6760011421dadecTimo Sirainen new_idx * sizeof(*cache->field_file_map));
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen for (i = 0; i < fields_count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx = fields[i].idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (idx < cache->fields_count)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen continue;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* new index - save it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields[idx].field = fields[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields[idx].field.name =
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen p_strdup(cache->field_pool, fields[i].name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (cache->fields[idx].field.type) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case MAIL_CACHE_FIELD_BITMASK:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case MAIL_CACHE_FIELD_STRING:
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen case MAIL_CACHE_FIELD_HEADER:
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen cache->fields[idx].field.field_size = (unsigned int)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen hash_insert(cache->field_name_hash,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (char *)cache->fields[idx].field.name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen POINTER_CAST(idx));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields_count = new_idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenunsigned int
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void *orig_key, *orig_value;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (hash_lookup_full(cache->field_name_hash, name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &orig_key, &orig_value))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return POINTER_CAST_TO(orig_value, unsigned int);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return (unsigned int)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst struct mail_cache_field *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int *count_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_cache_field *list;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen unsigned int i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen list = p_new(pool, struct mail_cache_field, cache->fields_count);
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen list[i] = cache->fields[i].field;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen list[i].name = p_strdup(pool, list[i].name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *count_r = cache->fields_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return list;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainenstatic int mail_cache_header_fields_get_offset(struct mail_cache *cache,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen uint32_t *offset_r)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_cache_header_fields *field_hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t offset, next_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *offset_r = 0;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen return 0;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen }
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen /* find the latest header */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen offset = 0;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen next_offset =
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen while (next_offset != 0) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (next_offset == offset) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mail_cache_set_corrupted(cache,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen "next_offset in field header loops");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen }
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen offset = next_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (cache->file_cache != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we can't trust that the cached data is valid */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(*field_hdr) +
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen CACHE_HDR_PREFETCH);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_cache_map(cache, offset,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(*field_hdr) + CACHE_HDR_PREFETCH) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen next_offset =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen *offset_r = offset;
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_cache_header_fields *field_hdr = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_cache_field field;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen const uint32_t *last_used, *sizes;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const uint8_t *types, *decisions;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *p, *names, *end;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void *orig_key, *orig_value;
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen uint32_t offset, i;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset) < 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (offset == 0) {
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen /* no fields - the file is empty */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (offset + field_hdr->size > cache->mmap_length) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mail_cache_set_corrupted(cache,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "field header points outside file");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* check the fixed size of the header. name[] has to be checked
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen separately */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (field_hdr->size > sizeof(*field_hdr) + CACHE_HDR_PREFETCH) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (cache->file_cache != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we can't trust that the cached data is valid */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(*field_hdr) +
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen CACHE_HDR_PREFETCH);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_cache_map(cache, offset, field_hdr->size) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen cache->file_field_map =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_realloc(cache->file_field_map,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->file_fields_count * sizeof(unsigned int),
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen field_hdr->fields_count * sizeof(unsigned int));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen cache->file_fields_count = field_hdr->fields_count;
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen types = CONST_PTR_OFFSET(field_hdr,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen names = CONST_PTR_OFFSET(field_hdr,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* clear the old mapping */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (i = 0; i < cache->fields_count; i++)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen cache->field_file_map[i] = (uint32_t)-1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen memset(&field, 0, sizeof(field));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (p == end || *names == '\0') {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mail_cache_set_corrupted(cache,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "field header names corrupted");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (hash_lookup_full(cache->field_name_hash, names,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &orig_key, &orig_value)) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* already exists, see if decision can be updated */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen field.idx = POINTER_CAST_TO(orig_value, unsigned int);
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen if (!cache->fields[field.idx].decision_dirty) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields[field.idx].field.decision =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen decisions[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (cache->fields[field.idx].field.type != types[i]) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mail_cache_set_corrupted(cache,
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen "registered field type changed");
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return -1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen field.name = names;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen field.type = types[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen field.field_size = sizes[i];
d22301419109ed4a38351715e6760011421dadecTimo Sirainen field.decision = decisions[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_cache_register_fields(cache, &field, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (cache->field_file_map[field.idx] != (uint32_t)-1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_cache_set_corrupted(cache,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Duplicated field in header: %s", names);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->field_file_map[field.idx] = i;
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen cache->file_field_map[i] = field.idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* update last_used if it's newer than ours */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (last_used[i] > cache->fields[field.idx].last_used)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields[field.idx].last_used = last_used[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen names = p + 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 0;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen}
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen size_t offset, size_t size)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const void *data;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen unsigned int i, field;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen field = cache->file_field_map[i];
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append(dest, data, size);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (cache->field_file_map[i] != (uint32_t)-1)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen continue;
ddb018bc886680f462463b2c87f983fdedbf6cf0Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen buffer_append(dest, data, size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen size_t offset)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen const int *data;
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen unsigned int i, field;
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen uint8_t byte;
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen field = cache->file_field_map[i];
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen byte = (uint8_t)*data;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(dest, &byte, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (cache->field_file_map[i] != (uint32_t)-1)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen continue;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen byte = (uint8_t)*data;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(dest, &byte, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_t *buffer;
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen uint32_t i, offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t_push();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen copy_to_buf(cache, buffer,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen offsetof(struct mail_cache_field_private, last_used),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(uint32_t));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = mail_cache_write(cache, buffer->data,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sizeof(uint32_t) * cache->file_fields_count,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret == 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_set_used_size(buffer, 0);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen copy_to_buf_byte(cache, buffer,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen offsetof(struct mail_cache_field, decision));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen ret = mail_cache_write(cache, buffer->data,
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen sizeof(uint8_t) * cache->file_fields_count, offset +
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ret == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->fields[i].decision_dirty = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t_pop();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen cache->field_header_write_pending = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen int ret;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen if (cache->locked)
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen return mail_cache_header_fields_update_locked(cache);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (mail_cache_lock(cache) <= 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_cache_unlock(cache) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
void mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
{
struct mail_cache_header_fields hdr;
unsigned int field;
const char *name;
uint32_t i;
memset(&hdr, 0, sizeof(hdr));
hdr.fields_count = cache->fields_count;
buffer_append(dest, &hdr, sizeof(hdr));
/* we have to keep the field order for the existing fields. */
copy_to_buf(cache, dest,
offsetof(struct mail_cache_field_private, last_used),
sizeof(uint32_t));
copy_to_buf(cache, dest, offsetof(struct mail_cache_field, field_size),
sizeof(uint32_t));
copy_to_buf_byte(cache, dest, offsetof(struct mail_cache_field, type));
copy_to_buf_byte(cache, dest,
offsetof(struct mail_cache_field, decision));
i_assert(buffer_get_used_size(dest) == sizeof(hdr) +
(sizeof(uint32_t)*2 + 2) * hdr.fields_count);
for (i = 0; i < cache->file_fields_count; i++) {
field = cache->file_field_map[i];
name = cache->fields[field].field.name;
buffer_append(dest, name, strlen(name)+1);
}
for (i = 0; i < cache->fields_count; i++) {
if (cache->field_file_map[i] != (uint32_t)-1)
continue;
name = cache->fields[i].field.name;
buffer_append(dest, name, strlen(name)+1);
}
hdr.size = buffer_get_used_size(dest);
buffer_write(dest, 0, &hdr, sizeof(hdr));
if ((hdr.size & 3) != 0)
buffer_append_zero(dest, 4 - (hdr.size & 3));
}
int mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
uint32_t *offset_r)
{
if (mail_cache_header_fields_get_offset(cache, offset_r) < 0)
return -1;
if (*offset_r == 0) {
*offset_r = offsetof(struct mail_cache_header,
field_header_offset);
} else {
*offset_r += offsetof(struct mail_cache_header_fields,
next_offset);
}
return 0;
}