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