mail-index-sync-keywords.c revision 02752bc8d64df8cd361f464e55422f7b3f2f143e
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozekkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *keyword_name, unsigned int *idx_r)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher const unsigned int *idx_map;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (array_is_created(&map->keyword_idx_map) &&
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_keyword_lookup(ctx->view->index, keyword_name,
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher /* FIXME: slow. maybe create index -> file mapping as well */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher idx_map = array_get(&map->keyword_idx_map, &count);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek for (i = 0; i < count; i++) {
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekkeywords_get_header_buf(struct mail_index_map *map,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int new_count, unsigned int *keywords_count_r,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t *rec_offset_r, size_t *name_offset_root_r,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct mail_index_keyword_header *kw_hdr;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct mail_index_keyword_header_rec *kw_rec;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct mail_index_keyword_header new_kw_hdr;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek name = (const char *)(kw_rec + kw_hdr->keywords_count);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *keywords_count_r = new_kw_hdr.keywords_count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buf = buffer_create_dynamic(pool_datastack_create(), 512);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekstatic void keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned char ext_intro_data[sizeof(*u) +
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_create_data(&ext_intro_buf, ext_intro_data,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan u = buffer_append_space_unsafe(&ext_intro_buf, sizeof(*u));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek /* since we aren't properly aligned anyway,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek reserve one extra byte for future */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan u->name_size = strlen(MAIL_INDEX_EXT_KEYWORDS);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_append(&ext_intro_buf, MAIL_INDEX_EXT_KEYWORDS,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_panic("Keyword extension growing failed");
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *keyword_name, unsigned int *keyword_idx_r)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct mail_index_keyword_header_rec kw_rec;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher size_t keyword_len, rec_offset, name_offset, name_offset_root;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* if we crash in the middle of writing the header, the
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher keywords are more or less corrupted. avoid that by
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan making sure the header is updated atomically. */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher map = mail_index_sync_get_atomic_map(ctx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* update existing header */
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher ext = array_idx(&map->extensions, ext_map_idx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* create new / replace broken header */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buf = buffer_create_dynamic(pool_datastack_create(), 512);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* add the keyword */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_write(buf, name_offset_root, keyword_name, keyword_len);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_append_zero(buf, 4 - (buf->used % 4));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (ext == NULL || buf->used > ext->hdr_size ||
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* if we need to grow the buffer, add some padding */
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek /* map may have changed */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ext = array_idx(&map->extensions, ext_map_idx);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan buffer_copy(map->hdr_copy_buf, ext->hdr_offset, buf, 0, buf->used);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (mail_index_map_parse_keywords(map) < 0)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher i_panic("Keyword update corrupted keywords header");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(*keyword_idx_r / CHAR_BIT < ext->record_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivankeywords_update_records(struct mail_index_sync_map_ctx *ctx,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan unsigned int keyword_idx, enum modify_type type,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (!mail_index_lookup_seq_range(view, uid1, uid2, &seq1, &seq2))
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_sync_write_seq_update(ctx, seq1, seq2);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_modseq_update_keyword(ctx->modseq_ctx, keyword_idx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(data_offset >= sizeof(struct mail_index_record));
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_update *rec)
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek keyword_name = t_strndup(rec + 1, rec->name_size);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek "Trying to use empty keyword");
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (!keyword_lookup(ctx, keyword_name, &keyword_idx))
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek keywords_header_add(ctx, keyword_name, &keyword_idx);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* if the keyword wasn't found, the "keywords" extension was created.
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if it was found, the record size should already be correct, but
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek in case it isn't just fix it ourself. */
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek if (!mail_index_map_lookup_ext(view->map, MAIL_INDEX_EXT_KEYWORDS,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek ext = array_idx(&view->map->extensions, ext_map_idx);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (keyword_idx / CHAR_BIT >= ext->record_size) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek /* nothing to do */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* grow the record size */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek keywords_ext_register(ctx, ext_map_idx, ext->reset_id,
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek ext = array_idx(&view->map->extensions, ext_map_idx);
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek ret = keywords_update_records(ctx, ext, keyword_idx,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_reset *r)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_reset *end;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* nothing to do */
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek ext = array_idx(&map->extensions, ext_map_idx);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek for (; r != end; r++) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_index_lookup_seq_range(ctx->view, r->uid1, r->uid2,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_index_sync_write_seq_update(ctx, seq1, seq2);