mail-cache-fields.c revision df6478c4cf605bd81b3891c148b84c14eb6c4035
8900b9eb2514c07047541833286428572493a9fdStéphane Graber/* Copyright (C) 2004 Timo Sirainen */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "lib.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "buffer.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "hash.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "file-cache.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "write-full.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include "mail-cache-private.h"
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#include <stddef.h>
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi#define CACHE_HDR_PREFETCH 1024
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic bool field_has_fixed_size(enum mail_cache_field_type type)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi switch (type) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_FIELD_FIXED_SIZE:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_FIELD_BITMASK:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return TRUE;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_FIELD_VARIABLE_SIZE:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_FIELD_STRING:
a5ba96715d4ef264c43d4f187251de491ba198c0KATOH Yasufumi case MAIL_CACHE_FIELD_HEADER:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return FALSE;
8900b9eb2514c07047541833286428572493a9fdStéphane Graber
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_FIELD_COUNT:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi break;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
faefa7f8584a7d1567df2e6f1f9240a28a6466abStéphane Graber i_unreached();
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return FALSE;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic bool field_decision_is_valid(enum mail_cache_decision_type type)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi switch (type & ~MAIL_CACHE_DECISION_FORCED) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_DECISION_NO:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_DECISION_TEMP:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi case MAIL_CACHE_DECISION_YES:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return TRUE;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi default:
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return FALSE;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi enum mail_cache_field_type type, unsigned int size)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const struct mail_cache_field *field = &cache->fields[idx].field;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
6127da6b3f5815028bee187ac98840cd94313841KATOH Yasufumi if (field->type != type) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "registered field %s type changed", field->name);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (field->field_size != size && field_has_fixed_size(type)) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "registered field %s size changed", field->name);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumivoid mail_cache_register_fields(struct mail_cache *cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi struct mail_cache_field *fields,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int fields_count)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi void *orig_key, *orig_value;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi char *name;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int new_idx;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int i, j;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi new_idx = cache->fields_count;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (i = 0; i < fields_count; i++) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (hash_lookup_full(cache->field_name_hash, fields[i].name,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi &orig_key, &orig_value)) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi i_assert(fields[i].type < MAIL_CACHE_FIELD_COUNT);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi fields[i].idx =
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi POINTER_CAST_TO(orig_value, unsigned int);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi (void)field_type_verify(cache, fields[i].idx,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi fields[i].type,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi fields[i].field_size);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi continue;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* check if the same header is being registered in the
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi same field array */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (j = 0; j < i; j++) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (strcasecmp(fields[i].name, fields[j].name) == 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi fields[i].idx = fields[j].idx;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi break;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (j == i)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi fields[i].idx = new_idx++;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (new_idx == cache->fields_count)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* @UNSAFE */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields = i_realloc(cache->fields,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields_count * sizeof(*cache->fields),
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi new_idx * sizeof(*cache->fields));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->field_file_map =
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi i_realloc(cache->field_file_map,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields_count * sizeof(*cache->field_file_map),
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi new_idx * sizeof(*cache->field_file_map));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (i = 0; i < fields_count; i++) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int idx = fields[i].idx;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (idx < cache->fields_count)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi continue;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* new index - save it */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi name = p_strdup(cache->field_pool, fields[i].name);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields[idx].field = fields[i];
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields[idx].field.name = name;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->field_file_map[idx] = (uint32_t)-1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (!field_has_fixed_size(cache->fields[idx].field.type))
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields[idx].field.field_size = (unsigned int)-1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi hash_insert(cache->field_name_hash, name, POINTER_CAST(idx));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->fields_count = new_idx;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumiunsigned int
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumimail_cache_register_lookup(struct mail_cache *cache, const char *name)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi void *orig_key, *orig_value;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (hash_lookup_full(cache->field_name_hash, name,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi &orig_key, &orig_value))
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return POINTER_CAST_TO(orig_value, unsigned int);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi else
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return (unsigned int)-1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumiconst struct mail_cache_field *
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumimail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int *count_r)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi struct mail_cache_field *list;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi unsigned int i;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi list = p_new(pool, struct mail_cache_field, cache->fields_count);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (i = 0; i < cache->fields_count; i++) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi list[i] = cache->fields[i].field;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi list[i].name = p_strdup(pool, list[i].name);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi *count_r = cache->fields_count;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return list;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumistatic int mail_cache_header_fields_get_offset(struct mail_cache *cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi uint32_t *offset_r)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const struct mail_cache_header_fields *field_hdr;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi uint32_t offset, next_offset;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (MAIL_CACHE_IS_UNUSABLE(cache)) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi *offset_r = 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* find the latest header */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi offset = 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi next_offset =
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_index_offset_to_uint32(cache->hdr->field_header_offset);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi while (next_offset != 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (next_offset == offset) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "next_offset in field header loops");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi offset = next_offset;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (cache->file_cache != NULL) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* we can't trust that the cached data is valid */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi file_cache_invalidate(cache->file_cache, offset,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizeof(*field_hdr) +
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi CACHE_HDR_PREFETCH);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (mail_cache_map(cache, offset,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizeof(*field_hdr) + CACHE_HDR_PREFETCH) < 0)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi field_hdr = CONST_PTR_OFFSET(cache->data, offset);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi next_offset =
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_index_offset_to_uint32(field_hdr->next_offset);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi *offset_r = offset;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi}
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumiint mail_cache_header_fields_read(struct mail_cache *cache)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi{
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const struct mail_cache_header_fields *field_hdr = NULL;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi struct mail_cache_field field;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const uint32_t *last_used, *sizes;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const uint8_t *types, *decisions;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi const char *p, *names, *end;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi void *orig_key, *orig_value;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi uint32_t offset, i;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (mail_cache_header_fields_get_offset(cache, &offset) < 0)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (offset == 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* no fields - the file is empty */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return 0;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi field_hdr = CONST_PTR_OFFSET(cache->data, offset);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (offset + field_hdr->size > cache->mmap_length) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "field header points outside file");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* check the fixed size of the header. name[] has to be checked
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi separately */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (field_hdr->size < sizeof(*field_hdr) +
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache, "invalid field header size");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (field_hdr->size > sizeof(*field_hdr) + CACHE_HDR_PREFETCH) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (cache->file_cache != NULL) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* we can't trust that the cached data is valid */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi file_cache_invalidate(cache->file_cache, offset,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizeof(*field_hdr) +
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi CACHE_HDR_PREFETCH);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (mail_cache_map(cache, offset, field_hdr->size) < 0)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi field_hdr = CONST_PTR_OFFSET(cache->data, offset);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (field_hdr->fields_count != 0) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->file_field_map =
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi i_realloc(cache->file_field_map,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->file_fields_count *
8900b9eb2514c07047541833286428572493a9fdStéphane Graber sizeof(unsigned int),
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi field_hdr->fields_count *
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizeof(unsigned int));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi } else {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi i_free_and_null(cache->file_field_map);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->file_fields_count = field_hdr->fields_count;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi sizes = CONST_PTR_OFFSET(field_hdr,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi types = CONST_PTR_OFFSET(field_hdr,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi decisions = CONST_PTR_OFFSET(field_hdr,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi names = CONST_PTR_OFFSET(field_hdr,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi /* clear the old mapping */
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (i = 0; i < cache->fields_count; i++)
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi cache->field_file_map[i] = (uint32_t)-1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi memset(&field, 0, sizeof(field));
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (i = 0; i < field_hdr->fields_count; i++) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi for (p = names; p != end && *p != '\0'; p++) ;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (p == end || *names == '\0') {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache,
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi "field header names corrupted");
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi return -1;
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi }
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi if (types[i] > MAIL_CACHE_FIELD_COUNT) {
57da8c32f85c0255efa61ee32e260068afdaa565KATOH Yasufumi mail_cache_set_corrupted(cache, "field type corrupted");
return -1;
}
if (!field_decision_is_valid(decisions[i])) {
mail_cache_set_corrupted(cache,
"field decision type corrupted");
return -1;
}
if (hash_lookup_full(cache->field_name_hash, names,
&orig_key, &orig_value)) {
/* already exists, see if decision can be updated */
field.idx = POINTER_CAST_TO(orig_value, unsigned int);
if (!cache->fields[field.idx].decision_dirty) {
cache->fields[field.idx].field.decision =
decisions[i];
}
if (field_type_verify(cache, field.idx,
types[i], sizes[i]) < 0)
return -1;
} else {
field.name = names;
field.type = types[i];
field.field_size = sizes[i];
field.decision = decisions[i];
mail_cache_register_fields(cache, &field, 1);
}
if (cache->field_file_map[field.idx] != (uint32_t)-1) {
mail_cache_set_corrupted(cache,
"Duplicated field in header: %s", names);
return -1;
}
cache->field_file_map[field.idx] = i;
cache->file_field_map[i] = field.idx;
/* update last_used if it's newer than ours */
if (last_used[i] > cache->fields[field.idx].last_used)
cache->fields[field.idx].last_used = last_used[i];
names = p + 1;
}
return 0;
}
static void copy_to_buf(struct mail_cache *cache, buffer_t *dest,
size_t offset, size_t size)
{
const void *data;
unsigned int i, field;
for (i = 0; i < cache->file_fields_count; i++) {
field = cache->file_field_map[i];
data = CONST_PTR_OFFSET(&cache->fields[field], offset);
buffer_append(dest, data, size);
}
for (i = 0; i < cache->fields_count; i++) {
if (cache->field_file_map[i] != (uint32_t)-1)
continue;
data = CONST_PTR_OFFSET(&cache->fields[i], offset);
buffer_append(dest, data, size);
}
}
static void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
size_t offset)
{
const int *data;
unsigned int i, field;
uint8_t byte;
for (i = 0; i < cache->file_fields_count; i++) {
field = cache->file_field_map[i];
data = CONST_PTR_OFFSET(&cache->fields[field], offset);
byte = (uint8_t)*data;
buffer_append(dest, &byte, 1);
}
for (i = 0; i < cache->fields_count; i++) {
if (cache->field_file_map[i] != (uint32_t)-1)
continue;
data = CONST_PTR_OFFSET(&cache->fields[i], offset);
byte = (uint8_t)*data;
buffer_append(dest, &byte, 1);
}
}
static int mail_cache_header_fields_update_locked(struct mail_cache *cache)
{
buffer_t *buffer;
uint32_t i, offset;
int ret = 0;
if (mail_cache_header_fields_read(cache) < 0 ||
mail_cache_header_fields_get_offset(cache, &offset) < 0)
return -1;
t_push();
buffer = buffer_create_dynamic(pool_datastack_create(), 256);
copy_to_buf(cache, buffer,
offsetof(struct mail_cache_field_private, last_used),
sizeof(uint32_t));
ret = mail_cache_write(cache, buffer->data,
sizeof(uint32_t) * cache->file_fields_count,
offset + MAIL_CACHE_FIELD_LAST_USED());
if (ret == 0) {
buffer_set_used_size(buffer, 0);
copy_to_buf_byte(cache, buffer,
offsetof(struct mail_cache_field, decision));
ret = mail_cache_write(cache, buffer->data,
sizeof(uint8_t) * cache->file_fields_count, offset +
MAIL_CACHE_FIELD_DECISION(cache->file_fields_count));
if (ret == 0) {
for (i = 0; i < cache->file_fields_count; i++)
cache->fields[i].decision_dirty = FALSE;
}
}
t_pop();
if (ret == 0)
cache->field_header_write_pending = FALSE;
return ret;
}
int mail_cache_header_fields_update(struct mail_cache *cache)
{
int ret;
if (cache->locked)
return mail_cache_header_fields_update_locked(cache);
if (mail_cache_lock(cache, NULL) <= 0)
return -1;
ret = mail_cache_header_fields_update_locked(cache);
if (mail_cache_unlock(cache) < 0)
ret = -1;
return ret;
}
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;
}