mail-index-sync-keywords.c revision a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const char *keyword_name, unsigned int *idx_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const unsigned int *idx_map;
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen if (array_is_created(&map->keyword_idx_map) &&
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen mail_index_keyword_lookup(ctx->view->index, keyword_name,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* FIXME: slow. maybe create index -> file mapping as well */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen idx_map = array_get(&map->keyword_idx_map, &count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < count; i++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenkeywords_get_header_buf(struct mail_index_map *map,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int new_count, unsigned int *keywords_count_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t *rec_offset_r, size_t *name_offset_root_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
d1c2f6dd39ebb7f6b220ae2afda1162ba72ab43bTimo Sirainen i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *keywords_count_r = new_kw_hdr.keywords_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainenstatic void keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_create_static_hard(pool_datastack_create(),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u = buffer_append_space_unsafe(ext_intro_buf, sizeof(*u));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* since we aren't properly aligned anyway,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen reserve one extra byte for future */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(ext_intro_buf, "keywords", u->name_size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const char *keyword_name, unsigned int *keyword_idx_r)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen size_t keyword_len, rec_offset, name_offset, name_offset_root;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if we crash in the middle of writing the header, the
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen keywords are more or less corrupted. avoid that by
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen making sure the header is updated atomically. */
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx))
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* update existing header */
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* create new / replace broken header */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* add the keyword */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buffer_write(buf, name_offset_root, keyword_name, keyword_len);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ext == NULL || buf->used > ext->hdr_size ||
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* if we need to grow the buffer, add some padding */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* map may have changed */
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx))
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen buffer_copy(map->hdr_copy_buf, ext->hdr_offset, buf, 0, buf->used);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_panic("Keyword update corrupted keywords header");
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_assert(*keyword_idx_r / CHAR_BIT < ext->record_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenkeywords_update_records(struct mail_index_sync_map_ctx *ctx,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int keyword_idx, enum modify_type type,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen if (!mail_index_lookup_seq_range(view, uid1, uid2, &seq1, &seq2))
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_index_modseq_update_keyword(ctx->modseq_ctx, keyword_idx,
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen i_assert(data_offset >= sizeof(struct mail_index_record));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_keyword_update *rec)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen keyword_name = t_strndup(rec + 1, rec->name_size);
8870854fbd44602a2d2174177c305f3570401a09Timo Sirainen "Trying to use empty keyword");
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (!keyword_lookup(ctx, keyword_name, &keyword_idx))
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen keywords_header_add(ctx, keyword_name, &keyword_idx);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* if the keyword wasn't found, the "keywords" extension was created.
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if it was found, the record size should already be correct, but
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen in case it isn't just fix it ourself. */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (!mail_index_map_lookup_ext(view->map, "keywords", &ext_map_idx))
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext = array_idx(&view->map->extensions, ext_map_idx);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (keyword_idx / CHAR_BIT >= ext->record_size) {
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* nothing to do */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* grow the record size */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen keywords_ext_register(ctx, ext_map_idx, ext->reset_id,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (!mail_index_map_lookup_ext(view->map, "keywords",
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext = array_idx(&view->map->extensions, ext_map_idx);
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen ret = keywords_update_records(ctx, ext, keyword_idx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_transaction_keyword_reset *r)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_transaction_keyword_reset *end;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx)) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* nothing to do */
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (; r != end; r++) {
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen if (!mail_index_lookup_seq_range(ctx->view, r->uid1, r->uid2,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);