mail-index-map.c revision d0ab5936be1cd971007fc2241e0be120c442cb84
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void mail_index_map_init_extbufs(struct mail_index_map *map,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sizeof(struct mail_index_ext) + sizeof(uint32_t))
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen pool_alloconly_create(MEMPOOL_GROWING"map extensions",
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* try to use the existing pool's size for initial_count so
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen we don't grow it unneededly */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen size = p_get_max_easy_alloc_size(map->extension_pool);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen p_array_init(&map->extensions, map->extension_pool, initial_count);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainenbool mail_index_map_lookup_ext(struct mail_index_map *map, const char *name,
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen unsigned int i, size;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen extensions = array_get(&map->extensions, &size);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen for (i = 0; i < size; i++) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenunsigned int mail_index_map_ext_hdr_offset(unsigned int name_len)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen size_t size = sizeof(struct mail_index_ext_header) + name_len;
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenmail_index_map_register_ext(struct mail_index_map *map,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen i_assert(!mail_index_map_lookup_ext(map, name, NULL));
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen ext->name = p_strdup(map->extension_pool, name);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen ext->index_idx = mail_index_ext_register(map->index, name,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* Update index ext_id -> map ext_id mapping. Fill non-used
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen ext_ids with (uint32_t)-1 */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen while (array_count(&map->ext_id_map) < ext->index_idx)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen array_append(&map->ext_id_map, &empty_idx, 1);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenint mail_index_map_ext_get_next(struct mail_index_map *map,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen unsigned int *offset_p,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen const struct mail_index_ext_header **ext_hdr_r,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen const char **name_r)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* Extension header contains:
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen - struct mail_index_ext_header
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen - name (not 0-terminated)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen - 64bit alignment padding
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen - extension header contents
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen - 64bit alignment padding
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen if (offset + sizeof(*ext_hdr) >= map->hdr.header_size)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen offset += mail_index_map_ext_hdr_offset(ext_hdr->name_size);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen *name_r = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(*name_r, str_sanitize(*name_r, -1)) != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* we allow only plain ASCII names, so this extension
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen is most likely broken */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* finally make sure that the hdr_size is small enough.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen do this last so that we could return a usable name. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint mail_index_map_ext_hdr_check(const struct mail_index_header *hdr,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen (ext_hdr->record_align == 0 && ext_hdr->record_size != 0)) {
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen if (ext_hdr->record_offset + ext_hdr->record_size > hdr->record_size) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen *error_r = t_strdup_printf("Record field points "
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen "outside record size (%u+%u > %u)",
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen (ext_hdr->record_offset % ext_hdr->record_align) != 0) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen *error_r = t_strdup_printf("Record field alignment %u "
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* if we get here from extension introduction, record_offset=0 and
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen hdr->record_size hasn't been updated yet */
861f53be0cc2fa5665f3c107a7576e2a53bb2eb0Timo Sirainen (hdr->record_size % ext_hdr->record_align) != 0) {
b4ddb5b3c3722620a8fef387dd8c47bb411a5643Timo Sirainen *error_r = t_strdup_printf("Record size not aligned by %u "
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen "as required by extension",
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen if (ext_hdr->hdr_size > MAIL_INDEX_EXT_HEADER_MAX_SIZE) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen *error_r = t_strdup_printf("Headersize too large (%u)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int mail_index_map_parse_extensions(struct mail_index_map *map)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* extension headers always start from 64bit offsets, so if base header
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doesn't happen to be 64bit aligned we'll skip some bytes */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
2efe19d9045768d985a3bd549cff12f65ba40cc8Timo Sirainen if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* nothing to do, skip allocatations and all */
2efe19d9045768d985a3bd549cff12f65ba40cc8Timo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < old_count; i++)
5b4d189a01d248458496068f838128f1bafdcf2eTimo Sirainen for (i = 0; offset < map->hdr.header_size; i++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "Header extension #%d (%s) goes outside header",
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen "Broken extension #%d (%s): %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (mail_index_map_lookup_ext(map, name, NULL)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "Duplicate header extension %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_map_register_ext(map, name, ext_offset, ext_hdr);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainenint mail_index_map_parse_keywords(struct mail_index_map *map)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, name_area_end_offset, old_count;
8dd76854cc680053986142d5f5e823f637447929Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &idx)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Extension header contains:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen - struct mail_index_keyword_header
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen - struct mail_index_keyword_header_rec * keywords_count
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen - const char names[] * keywords_count
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(ext->hdr_offset < map->hdr.header_size);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
412b772c337428b72149605c1410524c2353e5d4Timo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* Keywords can only be added into same mapping. Removing requires a
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen new mapping (recreating the index file) */
f9f77e06a148fd0816004e0e1b0f585307148a7dTimo Sirainen /* nothing changed */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* make sure the header is valid */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "Keywords removed unexpectedly",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "keywords_count larger than header size",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
7ee226c2a66aa4dce7f13e8b17687db285c981bdTimo Sirainen for (i = 0; i < kw_hdr->keywords_count; i++) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (kw_rec[i].name_offset > name_area_end_offset) {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "name_offset points outside allocated header",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "Keyword header doesn't end with NUL",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* create file -> index mapping */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
const unsigned int *old_idx;
unsigned int kw_idx;
unsigned int kw_idx;
#ifndef WORDS_BIGENDIAN
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
sizeof(struct mail_index_record));
int ret;
pos = 0;
if (ret > 0)
return ret;
const void *buf;
pos);
if (ret > 0) {
extra = 0;
extra);
if (ret < 0) {
if (ret == 0) {
unsigned int *lock_id)
unsigned int i, count;
int ret;
for (i = 0; i < count; i++)
ret = 0;
*lock_id = 0;
if (ret <= 0) {
if (ret == 0) {
return ret;
#ifndef WORDS_BIGENDIAN
unsigned int lock_id;
if (ret <= 0) {
if (ret < 0)
if (use_mmap) {
if (ret == 0) {
ret = 0;
ret = 0;
} T_END;
if (ret < 0) {
ret = 0;
if (ret <= 0) {
int ret;
ret = 0;
if (ret == 0) {
TRUE);
return ret;
unsigned int i, count;
for (i = 0; i < count; i++) {
i_unreached();
unsigned int record_size)
static struct mail_index_record_map *
return rec_map;
unsigned int i, count;
for (i = 0; i < count; i++) {
return mem_map;
return FALSE;