mail-index-sync-ext.c revision 5f5870385cff47efd2f58e7892f251cf13761528
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "lib.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "array.h"
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#include "buffer.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mail-index-view-private.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mail-index-sync-private.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mail-index-modseq.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mail-transaction-log.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid mail_index_sync_init_expunge_handlers(struct mail_index_sync_map_ctx *ctx)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_registered_ext *rext;
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen const uint32_t *id_map;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen void **contexts;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen struct mail_index_expunge_handler eh;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int ext_count, id_map_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int rext_count, context_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t idx_ext_id, map_ext_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!array_is_created(&ctx->view->map->extensions))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(&eh, 0, sizeof(eh));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (array_is_created(&ctx->expunge_handlers))
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen array_clear(&ctx->expunge_handlers);
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_array_init(&ctx->expunge_handlers, 64);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen rext = array_get(&ctx->view->index->extensions, &rext_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_get(&ctx->view->map->extensions, &ext_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen id_map = array_get(&ctx->view->map->ext_id_map, &id_map_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen contexts = array_get_modifiable(&ctx->extra_contexts, &context_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_assert(context_count >= rext_count);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen for (idx_ext_id = 0; idx_ext_id < rext_count; idx_ext_id++) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen map_ext_id = idx_ext_id >= id_map_count ? (uint32_t)-1 :
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen id_map[idx_ext_id];
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (rext[idx_ext_id].expunge_handler == NULL ||
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen (map_ext_id == (uint32_t)-1 &&
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen !rext[idx_ext_id].expunge_handler_call_always))
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen continue;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen eh.handler = rext[idx_ext_id].expunge_handler;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen eh.context = rext[idx_ext_id].expunge_context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen eh.sync_context = &contexts[idx_ext_id];
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen eh.record_offset = map_ext_id == (uint32_t)-1 ? 0 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext[map_ext_id].record_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append(&ctx->expunge_handlers, &eh, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->expunge_handlers_set = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->expunge_handlers_used = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_index_sync_deinit_expunge_handlers(struct mail_index_sync_map_ctx *ctx)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen const struct mail_index_expunge_handler *eh;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (!array_is_created(&ctx->expunge_handlers))
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen array_foreach(&ctx->expunge_handlers, eh) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (eh->sync_context != NULL) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen eh->handler(ctx, 0, NULL, eh->sync_context,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen eh->context);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_free(&ctx->expunge_handlers);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenvoid mail_index_sync_init_handlers(struct mail_index_sync_map_ctx *ctx)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen unsigned int count;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (!array_is_created(&ctx->view->map->extensions))
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* set space for extra contexts */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen count = array_count(&ctx->view->index->extensions);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_assert(count > 0);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen if (!array_is_created(&ctx->extra_contexts))
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen i_array_init(&ctx->extra_contexts, count);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* make sure the extra_contexts contains everything */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen (void)array_idx_modifiable(&ctx->extra_contexts, count - 1);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* we need to update the expunge handler list in case they had
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen already been called */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen ctx->expunge_handlers_set = FALSE;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen}
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainenvoid mail_index_sync_deinit_handlers(struct mail_index_sync_map_ctx *ctx)
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen{
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen const struct mail_index_registered_ext *rext;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen void **extra_contexts;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen unsigned int i, rext_count, context_count;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (!array_is_created(&ctx->extra_contexts))
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rext = array_get(&ctx->view->index->extensions, &rext_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen extra_contexts =
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_get_modifiable(&ctx->extra_contexts, &context_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_assert(context_count <= rext_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen for (i = 0; i < context_count; i++) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (extra_contexts[i] != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rext[i].sync_handler.callback(ctx, 0, NULL, NULL,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &extra_contexts[i]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_free(&ctx->extra_contexts);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic struct mail_index_ext_header *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenget_ext_header(struct mail_index_map *map, const struct mail_index_ext *ext)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_ext_header *ext_hdr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void *hdr_base;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* do some kludgy jumping to get to it. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr_base = buffer_get_modifiable_data(map->hdr_copy_buf, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr = PTR_OFFSET(hdr_base, ext->ext_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(memcmp((char *)(ext_hdr + 1),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->name, strlen(ext->name)) == 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ext_hdr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mail_index_ext_align_cmp(const void *p1, const void *p2)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_ext *const *e1 = p1, *const *e2 = p2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return (int)(*e2)->record_align - (int)(*e1)->record_align;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void sync_ext_reorder(struct mail_index_map *map, uint32_t ext_map_idx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint16_t old_ext_size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_ext *ext, **sorted;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_ext_header *ext_hdr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint16_t *old_offsets, *copy_sizes, min_align, max_align;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t offset, new_record_size, rec_idx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const void *src;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_t *new_buffer;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t new_buffer_size;
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map) && map->refcount == 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen ext = array_get_modifiable(&map->extensions, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ext_map_idx < count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* @UNSAFE */
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen old_offsets = t_new(uint16_t, count);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen copy_sizes = t_new(uint16_t, count);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen sorted = t_new(struct mail_index_ext *, count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++) {
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen old_offsets[i] = ext[i].record_offset;
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen copy_sizes[i] = ext[i].record_size;
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen ext[i].record_offset = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sorted[i] = &ext[i];
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen }
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen qsort(sorted, count, sizeof(struct mail_index_ext *),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_ext_align_cmp);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen if (copy_sizes[ext_map_idx] > old_ext_size) {
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* we are growing the extension record. remember this
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen so we don't write extra data while copying the record */
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen copy_sizes[ext_map_idx] = old_ext_size;
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen }
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* we simply try to use the extensions with largest alignment
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen requirement first. FIXME: if the extension sizes don't match
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen alignment, this may not give the minimal layout. */
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen offset = sizeof(struct mail_index_record);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen max_align = sizeof(uint32_t);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen for (;;) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen min_align = (uint16_t)-1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++) {
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen if (sorted[i]->record_align > max_align)
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen max_align = sorted[i]->record_align;
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen if (sorted[i]->record_offset == 0 &&
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen sorted[i]->record_size > 0) {
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen if ((offset % sorted[i]->record_align) == 0)
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen break;
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen if (sorted[i]->record_align < min_align)
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen min_align = sorted[i]->record_align;
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i == count) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (min_align == (uint16_t)-1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* all done */
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen break;
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen }
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen /* we have to leave space here */
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen i_assert(min_align > 1 && min_align < (uint16_t)-1);
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen offset += min_align - (offset % min_align);
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen } else {
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen sorted[i]->record_offset = offset;
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen offset += sorted[i]->record_size;
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen }
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(offset < (uint16_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((offset % max_align) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* keep record size divisible with maximum alignment */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen offset += max_align - (offset % max_align);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen new_record_size = offset;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen /* copy the records to new buffer */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen new_buffer_size = map->rec_map->records_count * new_record_size;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen new_buffer = buffer_create_dynamic(default_pool, new_buffer_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen src = map->rec_map->records;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen offset = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (rec_idx = 0; rec_idx < map->rec_map->records_count; rec_idx++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* write the base record */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_write(new_buffer, offset, src,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sizeof(struct mail_index_record));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* write extensions */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_write(new_buffer, offset + ext[i].record_offset,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen CONST_PTR_OFFSET(src, old_offsets[i]),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen copy_sizes[i]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen src = CONST_PTR_OFFSET(src, map->hdr.record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen offset += new_record_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (new_buffer->used != new_buffer_size) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we didn't fully write the last record */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen size_t space = new_buffer_size - new_buffer->used;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen i_assert(space < new_record_size);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen buffer_append_zero(new_buffer, space);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen }
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen buffer_free(&map->rec_map->buffer);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen map->rec_map->buffer = new_buffer;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen map->rec_map->records =
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen buffer_get_modifiable_data(map->rec_map->buffer, NULL);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen map->hdr.record_size = new_record_size;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen /* update record offsets in headers */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen for (i = 0; i < count; i++) {
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen ext_hdr = get_ext_header(map, &ext[i]);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen ext_hdr->record_offset = ext[i].record_offset;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainenstatic void
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainensync_ext_resize(const struct mail_transaction_ext_intro *u,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t ext_map_idx, struct mail_index_sync_map_ctx *ctx,
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen bool no_shrink)
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen{
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen struct mail_index_map *map = ctx->view->map;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen struct mail_index_ext *ext;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen struct mail_index_ext_header *ext_hdr;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen uint32_t old_size, new_size, old_record_size;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen bool modified = FALSE, reorder = FALSE;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen ext = array_idx_modifiable(&map->extensions, ext_map_idx);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen old_size = MAIL_INDEX_HEADER_SIZE_ALIGN(ext->hdr_size);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen new_size = MAIL_INDEX_HEADER_SIZE_ALIGN(u->hdr_size);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen if (new_size < old_size) {
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen /* header shrank */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (no_shrink)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen new_size = old_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen else {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen buffer_delete(map->hdr_copy_buf,
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->hdr_offset + new_size,
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen old_size - new_size);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->hdr_size = u->hdr_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen modified = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen } else if (new_size > old_size) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* header grown */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen buffer_insert_zero(map->hdr_copy_buf,
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->hdr_offset + old_size,
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen new_size - old_size);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->hdr_size = u->hdr_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen modified = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (ext->record_align < u->record_align ||
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen (ext->record_align > u->record_align && !no_shrink)) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->record_align = u->record_align;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen modified = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen reorder = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen old_record_size = ext->record_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (ext->record_size < u->record_size ||
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen (ext->record_size > u->record_size && !no_shrink)) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext->record_size = u->record_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen modified = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen reorder = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (modified) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_assert((map->hdr_copy_buf->used % sizeof(uint64_t)) == 0);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen map->hdr.header_size = map->hdr_copy_buf->used;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen map->write_base_header = map->write_ext_header = TRUE;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr = get_ext_header(map, ext);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr->reset_id = ext->reset_id;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr->hdr_size = ext->hdr_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr->record_offset = ext->record_offset;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr->record_size = ext->record_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext_hdr->record_align = ext->record_align;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen } else {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_assert(map->hdr_base == map->hdr_copy_buf->data);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (new_size != old_size) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* move all hdr_offset of all extensions after this one */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen unsigned int i, count = array_count(&map->extensions);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ssize_t diff = (ssize_t)new_size - (ssize_t)old_size;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext = array_idx_modifiable(&map->extensions, 0);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen for (i = ext_map_idx + 1; i < count; i++) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext[i].ext_offset += diff;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ext[i].hdr_offset += diff;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen }
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen if (reorder) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_ext_reorder(map, ext_map_idx, old_record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (modified) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* header size changed. recreate index file. */
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen (void)mail_index_sync_get_atomic_map(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainen}
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainen
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainenstatic bool
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainenmail_index_sync_ext_unknown_complain(struct mail_index_sync_map_ctx *ctx,
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen uint32_t ext_map_idx)
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned char *p;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ext_map_idx >= 1024) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* don't try to track too high values */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ctx->unknown_extensions == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->unknown_extensions =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_create_dynamic(default_pool, ext_map_idx + 8);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen p = buffer_get_space_unsafe(ctx->unknown_extensions, ext_map_idx, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*p != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we've already complained once */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *p = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_index_sync_ext_init_new(struct mail_index_sync_map_ctx *ctx,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen const char *name,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen const struct mail_index_ext_header *ext_hdr,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t *ext_map_idx_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen struct mail_index_map *map;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen const struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_t *hdr_buf;
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen uint32_t ext_map_idx;
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen /* be sure to get a unique mapping before we modify the extensions,
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen otherwise other map users will see the new extension but not the
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen data records that sync_ext_reorder() adds. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr_buf = map->hdr_copy_buf;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(hdr_buf->used == map->hdr.header_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (MAIL_INDEX_HEADER_SIZE_ALIGN(hdr_buf->used) != hdr_buf->used) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we need to add padding between base header and extensions */
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen buffer_append_zero(hdr_buf,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_INDEX_HEADER_SIZE_ALIGN(hdr_buf->used) -
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr_buf->used);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* register record offset initially using zero,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_ext_reorder() will fix it. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_map_idx = mail_index_map_register_ext(map, name, hdr_buf->used,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* <ext_hdr> <name> [padding] [header data] */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ext_hdr->name_size == strlen(name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(hdr_buf, ext_hdr, sizeof(*ext_hdr));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(hdr_buf, name, ext_hdr->name_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* header must begin and end in correct alignment */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append_zero(hdr_buf,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_INDEX_HEADER_SIZE_ALIGN(hdr_buf->used) - hdr_buf->used +
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_INDEX_HEADER_SIZE_ALIGN(ext->hdr_size));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(hdr_buf->used ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->hdr_offset + MAIL_INDEX_HEADER_SIZE_ALIGN(ext->hdr_size));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert((hdr_buf->used % sizeof(uint64_t)) == 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map->hdr.header_size = hdr_buf->used;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen map->hdr_base = hdr_buf->data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_init_handlers(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_ext_reorder(map, ext_map_idx, 0);
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen i_assert(ext->record_offset != 0 || ext->record_size == 0);
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen *ext_map_idx_r = ext_map_idx;
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen}
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainenvoid mail_index_sync_ext_init(struct mail_index_sync_map_ctx *ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *name, bool fix_size,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t *ext_map_idx_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_map *map = ctx->view->map;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen const struct mail_index_registered_ext *rext;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen struct mail_index_ext_header ext_hdr;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen struct mail_transaction_ext_intro u;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen uint32_t ext_id;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen if (!mail_index_ext_lookup(ctx->view->index, name, &ext_id))
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen i_unreached();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rext = array_idx(&ctx->view->index->extensions, ext_id);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_map_lookup_ext(map, name, ext_map_idx_r)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!fix_size)
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen return;
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen /* make sure it's the expected size */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen memset(&u, 0, sizeof(u));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen u.hdr_size = rext->hdr_size;
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen u.record_size = rext->record_size;
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen u.record_align = rext->record_align;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_ext_resize(&u, *ext_map_idx_r, ctx, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(&ext_hdr, 0, sizeof(ext_hdr));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr.name_size = strlen(name);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ext_hdr.hdr_size = rext->hdr_size;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ext_hdr.record_size = rext->record_size;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ext_hdr.record_align = rext->record_align;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_index_sync_ext_init_new(ctx, name, &ext_hdr,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ext_map_idx_r);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenint mail_index_sync_ext_intro(struct mail_index_sync_map_ctx *ctx,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen const struct mail_transaction_ext_intro *u)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen struct mail_index_map *map = ctx->view->map;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen struct mail_index_ext_header ext_hdr;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen const struct mail_index_ext *ext;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen const char *name, *error;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen uint32_t ext_map_idx;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen bool no_shrink;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* default to ignoring the following extension updates in case this
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen intro is corrupted */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_map_idx = (uint32_t)-2;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ctx->cur_ext_ignore = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (u->ext_id != (uint32_t)-1 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (!array_is_created(&map->extensions) ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen u->ext_id >= array_count(&map->extensions))) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_index_sync_ext_unknown_complain(ctx, u->ext_id))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen "Extension introduction for unknown id %u", u->ext_id);
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen return -1;
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen }
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen if (u->ext_id == (uint32_t)-1 && u->name_size == 0) {
e4427a13680e8b7db98fb7eb9ef2e5f788e84212Timo Sirainen mail_index_sync_set_corrupted(ctx,
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen "Extension introduction without id or name");
e4427a13680e8b7db98fb7eb9ef2e5f788e84212Timo Sirainen return -1;
e4427a13680e8b7db98fb7eb9ef2e5f788e84212Timo Sirainen }
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen if (u->ext_id != (uint32_t)-1) {
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen name = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_map_idx = u->ext_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen name = t_strndup(u + 1, u->name_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_index_map_lookup_ext(map, name, &ext_map_idx))
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen ext_map_idx = (uint32_t)-1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ext_map_idx == (uint32_t)-1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen name = ext->name;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(name != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!ctx->internal_update &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen strcmp(name, MAIL_INDEX_EXT_KEYWORDS) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Keyword extension is handled internally by the keyword
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen code. Any attempt to modify them directly could cause
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen assert-crashes later, so prevent them immediately. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension introduction for keywords");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(&ext_hdr, 0, sizeof(ext_hdr));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr.name_size = strlen(name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr.reset_id = u->reset_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr.hdr_size = u->hdr_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr.record_size = u->record_size;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ext_hdr.record_align = u->record_align;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen no_shrink = (u->flags & MAIL_TRANSACTION_EXT_INTRO_FLAG_NO_SHRINK) != 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* make sure the header looks valid before doing anything with it */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (mail_index_map_ext_hdr_check(&map->hdr, &ext_hdr,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen name, &error) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Broken extension introduction: %s", error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ext != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* exists already */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (u->reset_id == ext->reset_id) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* check if we need to resize anything */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_ext_resize(u, ext_map_idx, ctx, no_shrink);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_ignore = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* extension was reset and this transaction hadn't
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen yet seen it. ignore this update (except for
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen resets). */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_ignore = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_map_idx = ext_map_idx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_ext_init_new(ctx, name, &ext_hdr, &ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_ignore = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->cur_ext_map_idx = ctx->internal_update ?
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (uint32_t)-1 : ext_map_idx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void mail_index_sync_ext_clear(struct mail_index_view *view,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_map *map,
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen struct mail_index_ext *ext)
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_record *rec;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(buffer_get_space_unsafe(map->hdr_copy_buf, ext->hdr_offset,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->hdr_size), 0, ext->hdr_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < view->map->rec_map->records_count; i++) {
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, i);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(PTR_OFFSET(rec, ext->record_offset), 0,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map->rec_map->write_seq_first = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map->rec_map->write_seq_last = view->map->rec_map->records_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mail_index_sync_ext_reset(struct mail_index_sync_map_ctx *ctx,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen const struct mail_transaction_ext_reset *u)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_map *map;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_ext_header *ext_hdr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ctx->cur_ext_map_idx == (uint32_t)-1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension reset without intro prefix");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ctx->cur_ext_map_idx == (uint32_t)-2 && ctx->cur_ext_ignore) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* previous extension intro was broken */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* since we're resetting the extension, don't check cur_ext_ignore */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* a new index file will be created, so the old data won't be
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen accidentally used by other processes. */
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx_modifiable(&map->extensions, ctx->cur_ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->reset_id = u->new_reset_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!u->preserve_data)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_ext_clear(ctx->view, map, ext);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr = get_ext_header(map, ext);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext_hdr->reset_id = u->new_reset_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mail_index_sync_ext_hdr_update(struct mail_index_sync_map_ctx *ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t offset, uint32_t size,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const void *data)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_map *map = ctx->view->map;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ctx->cur_ext_map_idx == (uint32_t)-1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension header update without intro prefix");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ctx->cur_ext_ignore)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx(&map->extensions, ctx->cur_ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (offset + size > ext->hdr_size) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension header update points outside header size");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_write(map->hdr_copy_buf, ext->hdr_offset + offset, data, size);
a3dcda4b01461c7690c655a013ec12851cdb78d4Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
a3dcda4b01461c7690c655a013ec12851cdb78d4Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ext->index_idx == ctx->view->index->modseq_ext_id)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_modseq_hdr_update(ctx->modseq_ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen map->write_ext_header = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_index_sync_ext_rec_update(struct mail_index_sync_map_ctx *ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_transaction_ext_rec_update *u)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
5fc02738b38ac2b0c21db0854d7a5ad452b1177fTimo Sirainen struct mail_index_view *view = ctx->view;
5fc02738b38ac2b0c21db0854d7a5ad452b1177fTimo Sirainen struct mail_index_record *rec;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_registered_ext *rext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void *old_data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t seq;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ctx->cur_ext_map_idx != (uint32_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(!ctx->cur_ext_ignore);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (u->uid == 0 || u->uid >= view->map->hdr.next_uid) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension record update for invalid uid=%u", u->uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_index_lookup_seq(view, u->uid, &seq))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx(&view->map->extensions, ctx->cur_ext_map_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ext->record_offset + ext->record_size <=
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen view->map->hdr.record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_data = PTR_OFFSET(rec, ext->record_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rext = array_idx(&view->index->extensions, ext->index_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* call sync handlers only when its registered type matches with
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen current synchronization type (index/view) */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((rext->sync_handler.type & ctx->type) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void **extra_context =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_idx_modifiable(&ctx->extra_contexts,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext->index_idx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = rext->sync_handler.callback(ctx, seq, old_data, u + 1,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen extra_context);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen if (ret <= 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_write_seq_update(ctx, seq, seq);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* @UNSAFE */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen memcpy(old_data, u + 1, ext->record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmail_index_sync_ext_atomic_inc(struct mail_index_sync_map_ctx *ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_transaction_ext_atomic_inc *u)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_view *view = ctx->view;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_record *rec;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_ext *ext;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t seq;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint64_t min_value, max_value, orig_num;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ctx->cur_ext_map_idx != (uint32_t)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(!ctx->cur_ext_ignore);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (u->uid == 0 || u->uid >= view->map->hdr.next_uid) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension record inc for invalid uid=%u", u->uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen if (!mail_index_lookup_seq(view, u->uid, &seq))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ext = array_idx(&view->map->extensions, ctx->cur_ext_map_idx);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen i_assert(ext->record_offset + ext->record_size <=
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen view->map->hdr.record_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen data = PTR_OFFSET(rec, ext->record_offset);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen min_value = u->diff >= 0 ? 0 : (uint64_t)(-(int64_t)u->diff);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen max_value = ext->record_size == 8 ? (uint64_t)-1 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ((uint64_t)1 << (ext->record_size*8)) - 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (u->diff <= 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* skip */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen } else if (max_value >= (uint32_t)u->diff) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen max_value -= u->diff;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen } else {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen mail_index_sync_set_corrupted(ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Extension record inc diff=%d larger than max value=%u "
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen "(uid=%u)", u->diff, (unsigned int)max_value, u->uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (ext->record_size) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 1: {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint8_t *num = data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen orig_num = *num;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (orig_num >= min_value && orig_num <= max_value)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *num += u->diff;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen case 2: {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint16_t *num = data;
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen orig_num = *num;
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen if (orig_num >= min_value && orig_num <= max_value)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *num += u->diff;
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 4: {
uint32_t *num = data;
orig_num = *num;
if (orig_num >= min_value && orig_num <= max_value)
*num += u->diff;
break;
}
case 8: {
uint64_t *num = data;
orig_num = *num;
if (orig_num >= min_value && orig_num <= max_value)
*num += u->diff;
break;
}
default:
mail_index_sync_set_corrupted(ctx,
"Extension record inc with invalid size=%u",
ext->record_size);
return -1;
}
if (orig_num < min_value) {
mail_index_sync_set_corrupted(ctx,
"Extension record inc drops number below zero "
"(uid=%u, diff=%d, orig=%llu)",
u->uid, u->diff, (unsigned long long)orig_num);
return -1;
} else if (orig_num > max_value) {
mail_index_sync_set_corrupted(ctx,
"Extension record inc overflows number "
"(uid=%u, diff=%d, orig=%llu)",
u->uid, u->diff, (unsigned long long)orig_num);
return -1;
}
mail_index_sync_write_seq_update(ctx, seq, seq);
return 1;
}