mail-cache-fields.c revision a16d9a651aaa36a308f1aaae87e73e143fdff887
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define CACHE_FIELD_IS_NEWLY_WANTED(cache, field_idx) \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ((cache)->field_file_map[field_idx] == (uint32_t)-1 && \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool field_has_fixed_size(enum mail_cache_field_type type)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenstatic bool field_decision_is_valid(enum mail_cache_decision_type type)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int field_type_verify(struct mail_cache *cache, unsigned int idx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_cache_field_type type, unsigned int size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_cache_field *field = &cache->fields[idx].field;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "registered field %s type changed", field->name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (field->field_size != size && field_has_fixed_size(type)) {
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen "registered field %s size changed", field->name);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainenmail_cache_field_update(struct mail_cache *cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(newfield->type < MAIL_CACHE_FIELD_COUNT);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((newfield->decision & MAIL_CACHE_DECISION_FORCED) != 0 ||
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (orig->field.last_used < newfield->last_used) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid mail_cache_register_fields(struct mail_cache *cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int new_idx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, j;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < fields_count; i++) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (hash_table_lookup_full(cache->field_name_hash,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fields[i].idx = POINTER_CAST_TO(value, unsigned int);
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen /* check if the same header is being registered in the
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen same field array */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen for (j = 0; j < i; j++) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (strcasecmp(fields[i].name, fields[j].name) == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* @UNSAFE */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->fields_count * sizeof(*cache->field_file_map),
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen for (i = 0; i < fields_count; i++) {
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen /* new index - save it */
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen name = p_strdup(cache->field_pool, fields[i].name);
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen cache->fields[idx].field.last_used = fields[i].last_used;
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen if (!field_has_fixed_size(cache->fields[idx].field.type))
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen cache->fields[idx].field.field_size = UINT_MAX;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hash_table_insert(cache->field_name_hash, name,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_cache_register_lookup(struct mail_cache *cache, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash, name, &key, &value))
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_cache_register_get_field(struct mail_cache *cache, unsigned int field_idx)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int *count_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen p_new(pool, struct mail_cache_field, cache->fields_count);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmail_cache_header_fields_get_offset(struct mail_cache *cache,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const struct mail_cache_header_fields **field_hdr_r)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen const struct mail_cache_header_fields *field_hdr;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen struct mail_cache_header_fields tmp_field_hdr;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen uint32_t offset = 0, next_offset, field_hdr_size;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen unsigned int next_count = 0;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen /* find the latest header */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen next_offset = cache->last_field_header_offset != 0 ?
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen mail_index_offset_to_uint32(cache->hdr->field_header_offset);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen while (next_offset != 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen "next_offset in field header loops");
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (cache->mmap_base != NULL || cache->map_with_read) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen ret = mail_cache_map(cache, offset, sizeof(*field_hdr),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "header field next_offset points outside file");
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* if we need to follow multiple offsets to get to
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen the last one, it's faster to just pread() the file
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen instead of going through cache */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_syscall_error(cache, "pread()");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "header field next_offset points outside file");
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_index_offset_to_uint32(field_hdr->next_offset);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen mail_cache_set_corrupted(cache, "missing header fields");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* detect corrupted size later */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen field_hdr_size = I_MAX(field_hdr->size, sizeof(*field_hdr));
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* invalidate the cache fields area to make sure we
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen get the latest cache decisions/last_used fields */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file_cache_invalidate(cache->file_cache, offset,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen ret = mail_cache_map(cache, offset, field_hdr_size, &data);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen "header field size outside file");
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenint mail_cache_header_fields_read(struct mail_cache *cache)
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const struct mail_cache_header_fields *field_hdr;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (mail_cache_header_fields_get_offset(cache, &offset, &field_hdr) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no fields - the file is empty */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* check the fixed size of the header. name[] has to be checked
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen separately */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen field_hdr->fields_count * (sizeof(uint32_t)*2 + 1 + 2)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_set_corrupted(cache, "invalid field header size");
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen sizeof(unsigned int),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen new_fields_count * sizeof(unsigned int));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen last_used = CONST_PTR_OFFSET(field_hdr, MAIL_CACHE_FIELD_LAST_USED());
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAIL_CACHE_FIELD_SIZE(field_hdr->fields_count));
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen MAIL_CACHE_FIELD_TYPE(field_hdr->fields_count));
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen MAIL_CACHE_FIELD_DECISION(field_hdr->fields_count));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen MAIL_CACHE_FIELD_NAMES(field_hdr->fields_count));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen end = CONST_PTR_OFFSET(field_hdr, field_hdr->size);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen /* clear the old mapping */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen max_drop_time = cache->index->map->hdr.day_stamp == 0 ? 0 :
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen cache->index->map->hdr.day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen for (i = 0; i < field_hdr->fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (p = names; p != end && *p != '\0'; p++) ;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "field header names corrupted");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_cache_set_corrupted(cache, "field type corrupted");
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen "field decision type corrupted");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (hash_table_lookup_full(cache->field_name_hash, names,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already exists, see if decision can be updated */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fidx = POINTER_CAST_TO(orig_value, unsigned int);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (cache->field_file_map[fidx] != (uint32_t)-1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* update last_used if it's newer than ours */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((time_t)last_used[i] > cache->fields[fidx].field.last_used)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cache->fields[fidx].field.last_used = last_used[i];
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (cache->fields[fidx].field.last_used < max_drop_time &&
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* time to drop this field. don't bother dropping
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen fields that have never been used. */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainenstatic void copy_to_buf(struct mail_cache *cache, buffer_t *dest, bool add_new,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen unsigned int i, field;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen /* copy the existing fields */
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy newly wanted fields */
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void copy_to_buf_byte(struct mail_cache *cache, buffer_t *dest,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, field;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy the existing fields */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[field], offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* copy newly wanted fields */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = CONST_PTR_OFFSET(&cache->fields[i], offset);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic int mail_cache_header_fields_update_locked(struct mail_cache *cache)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_cache_header_fields_read(cache) < 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_cache_header_fields_get_offset(cache, &offset, FALSE) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_CACHE_FIELD_DECISION(cache->file_fields_count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = mail_cache_write(cache, buffer->data, buffer->used,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < cache->file_fields_count; i++)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenint mail_cache_header_fields_update(struct mail_cache *cache)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen ret = mail_cache_header_fields_update_locked(cache);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenvoid mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen unsigned int field;
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* we have to keep the field order for the existing fields. */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen offsetof(struct mail_cache_field, field_size),
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen /* add existing fields' names */
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen for (i = 0; i < cache->file_fields_count; i++) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen /* add newly wanted fields' names */
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainenint mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_cache_header_fields_get_offset(cache, offset_r, FALSE) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *offset_r = offsetof(struct mail_cache_header,