mail-cache-fields.c revision 19e8adccba16ff419f5675b1575358c2956dce83
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hash.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "file-cache.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen#include "mail-cache-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define CACHE_FIELD_IS_NEWLY_WANTED(cache, field_idx) \
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen ((cache)->field_file_map[field_idx] == (uint32_t)-1 && \
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen (cache)->fields[field_idx].used)
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainenstatic bool field_has_fixed_size(enum mail_cache_field_type type)
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen switch (type) {
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen case MAIL_CACHE_FIELD_FIXED_SIZE:
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen case MAIL_CACHE_FIELD_BITMASK:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen case MAIL_CACHE_FIELD_VARIABLE_SIZE:
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen case MAIL_CACHE_FIELD_STRING:
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen case MAIL_CACHE_FIELD_HEADER:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_FIELD_COUNT:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen i_unreached();
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen return FALSE;
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen}
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainenstatic bool field_decision_is_valid(enum mail_cache_decision_type type)
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (type & ~MAIL_CACHE_DECISION_FORCED) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_DECISION_NO:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_CACHE_DECISION_TEMP:
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen case MAIL_CACHE_DECISION_YES:
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen enum mail_cache_field_type type, unsigned int size)
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen{
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen const struct mail_cache_field *field = &cache->fields[idx].field;
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen if (field->type != type) {
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen mail_cache_set_corrupted(cache,
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen "registered field %s type changed", field->name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (field->field_size != size && field_has_fixed_size(type)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen "registered field %s size changed", field->name);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen return 0;
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen}
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_cache_field *fields,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen unsigned int fields_count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen void *orig_key, *orig_value;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen char *name;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen unsigned int new_idx;
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen unsigned int i, j;
fc40a9a002458e372ff4b9f6f4e15239520c0bcdTimo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen new_idx = cache->fields_count;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen for (i = 0; i < fields_count; i++) {
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (hash_lookup_full(cache->field_name_hash, fields[i].name,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen &orig_key, &orig_value)) {
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen i_assert(fields[i].type < MAIL_CACHE_FIELD_COUNT);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen fields[i].idx =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen POINTER_CAST_TO(orig_value, unsigned int);
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen (void)field_type_verify(cache, fields[i].idx,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen fields[i].type,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fields[i].field_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen /* check if the same header is being registered in the
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen same field array */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen for (j = 0; j < i; j++) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen if (strcasecmp(fields[i].name, fields[j].name) == 0) {
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen fields[i].idx = fields[j].idx;
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen break;
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen }
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen }
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen if (j == i)
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen fields[i].idx = new_idx++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (new_idx == cache->fields_count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen /* @UNSAFE */
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen cache->fields = i_realloc(cache->fields,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen cache->fields_count * sizeof(*cache->fields),
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen new_idx * sizeof(*cache->fields));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->field_file_map =
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen i_realloc(cache->field_file_map,
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen new_idx * sizeof(*cache->field_file_map));
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen for (i = 0; i < fields_count; i++) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int idx = fields[i].idx;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (idx < cache->fields_count)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen continue;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen /* new index - save it */
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen name = p_strdup(cache->field_pool, fields[i].name);
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen cache->fields[idx].field = fields[i];
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen cache->fields[idx].field.name = name;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen cache->field_file_map[idx] = (uint32_t)-1;
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen if (!field_has_fixed_size(cache->fields[idx].field.type))
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen cache->fields[idx].field.field_size = (unsigned int)-1;
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen hash_insert(cache->field_name_hash, name, POINTER_CAST(idx));
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen }
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen cache->fields_count = new_idx;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen}
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainenunsigned int
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen void *orig_key, *orig_value;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (hash_lookup_full(cache->field_name_hash, name,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen &orig_key, &orig_value))
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return POINTER_CAST_TO(orig_value, unsigned int);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return (unsigned int)-1;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenconst struct mail_cache_field *
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen unsigned int *count_r)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen{
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct mail_cache_field *list;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen unsigned int i;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (!cache->opened)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen (void)mail_cache_open_and_verify(cache);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen list = p_new(pool, struct mail_cache_field, cache->fields_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen list[i] = cache->fields[i].field;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen list[i].name = p_strdup(pool, list[i].name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *count_r = cache->fields_count;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return list;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int mail_cache_header_fields_get_offset(struct mail_cache *cache,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen uint32_t *offset_r, bool map)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const struct mail_cache_header_fields *field_hdr;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct mail_cache_header_fields tmp_field_hdr;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen uint32_t offset = 0, next_offset;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int next_count = 0;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen bool invalidate = FALSE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen int ret;
51078c3413b7ed4811bc725acbb1289723361ba9Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen *offset_r = 0;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return 0;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen }
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen /* find the latest header */
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen offset = 0;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen next_offset = cache->last_field_header_offset != 0 ?
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen cache->last_field_header_offset :
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen while (next_offset != 0) {
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (next_offset == offset) {
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen mail_cache_set_corrupted(cache,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen "next_offset in field header loops");
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return -1;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen }
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen offset = next_offset;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen invalidate = TRUE;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen if (cache->mmap_base != NULL) {
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen if (mail_cache_map(cache, offset,
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen sizeof(*field_hdr)) < 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen } else {
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen /* if we need to follow multiple offsets to get to
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen the last one, it's faster to just pread() the file
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen instead of going through cache */
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen ret = pread_full(cache->fd, &tmp_field_hdr,
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen sizeof(tmp_field_hdr), offset);
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen if (ret < 0) {
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen mail_cache_set_syscall_error(cache, "pread()");
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return -1;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen }
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (ret == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_cache_set_corrupted(cache,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen "next_offset points outside file");
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen field_hdr = &tmp_field_hdr;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen next_offset =
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen next_count++;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (offset == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_cache_set_corrupted(cache, "missing header fields");
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return -1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen cache->last_field_header_offset = offset;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
8b58939517a381db55670089c0984da39fc0f099Timo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (map) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (cache->file_cache != NULL && invalidate) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* if this isn't the first header in file and we hadn't
d22301419109ed4a38351715e6760011421dadecTimo Sirainen read this before, we can't trust that the cached
d22301419109ed4a38351715e6760011421dadecTimo Sirainen data is valid */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen file_cache_invalidate(cache->file_cache, offset,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen field_hdr->size);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (mail_cache_map(cache, offset, field_hdr->size) < 0)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return -1;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen *offset_r = offset;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen{
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen const struct mail_cache_header_fields *field_hdr = NULL;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen struct mail_cache_field field;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen const uint32_t *last_used, *sizes;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen const uint8_t *types, *decisions;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen const char *p, *names, *end;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen void *orig_key, *orig_value;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen unsigned int fidx, new_fields_count;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen enum mail_cache_decision_type dec;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen time_t max_drop_time;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen uint32_t offset, i;
236bedf76e31651ea9fca63fbdc25be673819526Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset, TRUE) < 0)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return -1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (offset == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* no fields - the file is empty */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return 0;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (offset + field_hdr->size > cache->mmap_length) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_cache_set_corrupted(cache,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen "field header points outside file");
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return -1;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* check the fixed size of the header. name[] has to be checked
d22301419109ed4a38351715e6760011421dadecTimo Sirainen separately */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (field_hdr->size < sizeof(*field_hdr) +
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen return -1;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen field_hdr = CONST_PTR_OFFSET(cache->data, offset);
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen new_fields_count = field_hdr->fields_count;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen if (new_fields_count != 0) {
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen cache->file_field_map =
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen i_realloc(cache->file_field_map,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cache->file_fields_count *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(unsigned int),
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen new_fields_count * sizeof(unsigned int));
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen } else {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_free_and_null(cache->file_field_map);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->file_fields_count = new_fields_count;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen sizes = CONST_PTR_OFFSET(field_hdr,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen types = CONST_PTR_OFFSET(field_hdr,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen decisions = CONST_PTR_OFFSET(field_hdr,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen names = CONST_PTR_OFFSET(field_hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* clear the old mapping */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen for (i = 0; i < cache->fields_count; i++)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen cache->field_file_map[i] = (uint32_t)-1;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen max_drop_time = cache->index->map->hdr.day_stamp == 0 ? 0 :
d22301419109ed4a38351715e6760011421dadecTimo Sirainen cache->index->map->hdr.day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen memset(&field, 0, sizeof(field));
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (p == end || *names == '\0') {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen mail_cache_set_corrupted(cache,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen "field header names corrupted");
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return -1;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
55b6e3105184ad6a2f987346380966f556300055Timo Sirainen
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen if (types[i] > MAIL_CACHE_FIELD_COUNT) {
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen mail_cache_set_corrupted(cache, "field type corrupted");
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen return -1;
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (!field_decision_is_valid(decisions[i])) {
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen mail_cache_set_corrupted(cache,
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen "field decision type corrupted");
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen return -1;
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen }
2ff23d6fb7e2ff85aa23b7f4769aeac1d0316a1bTimo Sirainen
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen if (hash_lookup_full(cache->field_name_hash, names,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen &orig_key, &orig_value)) {
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen /* already exists, see if decision can be updated */
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen fidx = POINTER_CAST_TO(orig_value, unsigned int);
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen if (!cache->fields[fidx].decision_dirty) {
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen cache->fields[fidx].field.decision =
2ff23d6fb7e2ff85aa23b7f4769aeac1d0316a1bTimo Sirainen decisions[i];
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (field_type_verify(cache, fidx,
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen types[i], sizes[i]) < 0)
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen return -1;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen } else {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen field.name = names;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen field.type = types[i];
18065635d4e79dd96eb3b3215718abd12f6a6808Timo Sirainen field.field_size = sizes[i];
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen field.decision = decisions[i];
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen mail_cache_register_fields(cache, &field, 1);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen fidx = field.idx;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (cache->field_file_map[fidx] != (uint32_t)-1) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen mail_cache_set_corrupted(cache,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen "Duplicated field in header: %s", names);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return -1;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen cache->fields[fidx].used = TRUE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->field_file_map[fidx] = i;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->file_field_map[i] = fidx;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* update last_used if it's newer than ours */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (last_used[i] > cache->fields[fidx].last_used)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->fields[fidx].last_used = last_used[i];
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen dec = cache->fields[fidx].field.decision;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if ((time_t)cache->fields[fidx].last_used < max_drop_time &&
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->fields[fidx].last_used != 0 &&
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen (dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen dec != MAIL_CACHE_DECISION_NO) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* time to drop this field. don't bother dropping
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen fields that have never been used. */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen names = p + 1;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest, bool add_new,
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen size_t offset, size_t size)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen const void *data;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen unsigned int i, field;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* copy the existing fields */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen field = cache->file_field_map[i];
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen buffer_append(dest, data, size);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (!add_new)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* copy newly wanted fields */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen buffer_append(dest, data, size);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
9fdd27b307347a06871ddab74b165122c878553cTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen bool add_new, size_t offset)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen const int *data;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen unsigned int i, field;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen uint8_t byte;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* copy the existing fields */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen field = cache->file_field_map[i];
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen byte = (uint8_t)*data;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen buffer_append(dest, &byte, 1);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (!add_new)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* copy newly wanted fields */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen for (i = 0; i < cache->fields_count; i++) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen byte = (uint8_t)*data;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen buffer_append(dest, &byte, 1);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen buffer_t *buffer;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen uint32_t i, offset, dec_offset;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen int ret = 0;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen mail_cache_header_fields_get_offset(cache, &offset, FALSE) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen copy_to_buf(cache, buffer, FALSE,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen offsetof(struct mail_cache_field_private, last_used),
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen sizeof(uint32_t));
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen offset + MAIL_CACHE_FIELD_LAST_USED());
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen if (ret == 0) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen buffer_set_used_size(buffer, 0);
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen copy_to_buf_byte(cache, buffer, FALSE,
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen offsetof(struct mail_cache_field, decision));
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen dec_offset = offset +
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count);
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen dec_offset);
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (ret == 0) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen cache->fields[i].decision_dirty = FALSE;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (ret == 0)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen cache->field_header_write_pending = FALSE;
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen return ret;
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen}
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen{
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen int ret;
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen if (cache->locked) {
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen T_BEGIN {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = mail_cache_header_fields_update_locked(cache);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen } T_END;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen return ret;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen }
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen if (mail_cache_lock(cache, NULL) <= 0)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen return -1;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen T_BEGIN {
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen ret = mail_cache_header_fields_update_locked(cache);
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen } T_END;
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen if (mail_cache_unlock(cache) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = -1;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen return ret;
e76c494ad6535d3de314cc0d3ac7a44b06e53c4bTimo Sirainen}
e76c494ad6535d3de314cc0d3ac7a44b06e53c4bTimo Sirainen
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen{
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen struct mail_cache_header_fields hdr;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen unsigned int field;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen const char *name;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen uint32_t i;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen memset(&hdr, 0, sizeof(hdr));
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen hdr.fields_count = cache->file_fields_count;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
0d73d91d1a1809f173d433023ccf97e6ec5ba629Timo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i))
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen hdr.fields_count++;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen }
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen buffer_append(dest, &hdr, sizeof(hdr));
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen /* we have to keep the field order for the existing fields. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen copy_to_buf(cache, dest, TRUE,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen offsetof(struct mail_cache_field_private, last_used),
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen sizeof(uint32_t));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen copy_to_buf(cache, dest, TRUE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offsetof(struct mail_cache_field, field_size),
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sizeof(uint32_t));
d22301419109ed4a38351715e6760011421dadecTimo Sirainen copy_to_buf_byte(cache, dest, TRUE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offsetof(struct mail_cache_field, type));
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen copy_to_buf_byte(cache, dest, TRUE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offsetof(struct mail_cache_field, decision));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen i_assert(dest->used == sizeof(hdr) +
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen (sizeof(uint32_t)*2 + 2) * hdr.fields_count);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen /* add existing fields' names */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen field = cache->file_field_map[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name = cache->fields[field].field.name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(dest, name, strlen(name)+1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* add newly wanted fields' names */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < cache->fields_count; i++) {
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if (CACHE_FIELD_IS_NEWLY_WANTED(cache, i)) {
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen name = cache->fields[i].field.name;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen buffer_append(dest, name, strlen(name)+1);
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen }
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen }
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen hdr.size = dest->used;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen buffer_write(dest, 0, &hdr, sizeof(hdr));
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if ((hdr.size & 3) != 0)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen buffer_append_zero(dest, 4 - (hdr.size & 3));
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen}
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen uint32_t *offset_r)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen{
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r, FALSE) < 0)
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen return -1;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen if (*offset_r == 0) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen *offset_r = offsetof(struct mail_cache_header,
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen field_header_offset);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen } else {
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen *offset_r += offsetof(struct mail_cache_header_fields,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen next_offset);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen }
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen return 0;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen}
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen