mail-index-map.c revision 3675a7e9bd3775ba13fe8bc93915902513a0f1a4
97a9a944b5887e91042b019776c41d5dd74557aferikabele/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
97a9a944b5887e91042b019776c41d5dd74557aferikabele
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd#include "lib.h"
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd#include "array.h"
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd#include "str-sanitize.h"
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive#include "nfs-workarounds.h"
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive#include "mmap-util.h"
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive#include "read-full.h"
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#include "mail-index-private.h"
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc#include "mail-index-sync-private.h"
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#include "mail-transaction-log-private.h"
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowenstatic void mail_index_map_init_extbufs(struct mail_index_map *map,
2e545ce2450a9953665f701bb05350f0d3f26275nd unsigned int initial_count)
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen{
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen#define EXTENSION_NAME_APPROX_LEN 20
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#define EXT_GLOBAL_ALLOC_SIZE \
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#define EXT_PER_ALLOC_SIZE \
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen (EXTENSION_NAME_APPROX_LEN + \
3f08db06526d6901aa08c110b5bc7dde6bc39905nd sizeof(struct mail_index_ext) + sizeof(uint32_t))
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd size_t size;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (map->extension_pool == NULL) {
3f08db06526d6901aa08c110b5bc7dde6bc39905nd size = EXT_GLOBAL_ALLOC_SIZE +
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd initial_count * EXT_PER_ALLOC_SIZE;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd map->extension_pool =
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd pool_alloconly_create("map extensions",
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung nearest_power(size));
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd } else {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd p_clear(map->extension_pool);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* try to use the existing pool's size for initial_count so
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd we don't grow it unneededly */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd size = p_get_max_easy_alloc_size(map->extension_pool);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf EXT_PER_ALLOC_SIZE;
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive p_array_init(&map->extensions, map->extension_pool, initial_count);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndbool mail_index_map_lookup_ext(struct mail_index_map *map, const char *name,
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri uint32_t *idx_r)
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri{
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri const struct mail_index_ext *extensions;
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri unsigned int i, size;
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri if (array_is_created(&map->extensions)) {
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri extensions = array_get(&map->extensions, &size);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd for (i = 0; i < size; i++) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (strcmp(extensions[i].name, name) == 0) {
117c1f888a14e73cdd821dc6c23eb0411144a41cnd if (idx_r != NULL)
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess *idx_r = i;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return TRUE;
0844fff26cb7719e0f0a368d88544156ed6374b6sf }
117c1f888a14e73cdd821dc6c23eb0411144a41cnd }
117c1f888a14e73cdd821dc6c23eb0411144a41cnd }
117c1f888a14e73cdd821dc6c23eb0411144a41cnd return FALSE;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd}
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cndunsigned int mail_index_map_ext_hdr_offset(unsigned int name_len)
3bfe5718442b1bc7401a4d513762858997bcf708sf{
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton size_t size = sizeof(struct mail_index_ext_header) + name_len;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd return MAIL_INDEX_HEADER_SIZE_ALIGN(size);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen}
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jortonuint32_t
c57fa68c99b9e13aeafaf473e4feefaff590edb2jortonmail_index_map_register_ext(struct mail_index_map *map,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton const char *name, uint32_t ext_offset,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton const struct mail_index_ext_header *ext_hdr)
817a2329f22ff84555a29b23248894b999a7336fjim{
817a2329f22ff84555a29b23248894b999a7336fjim struct mail_index_ext *ext;
817a2329f22ff84555a29b23248894b999a7336fjim uint32_t idx, empty_idx = (uint32_t)-1;
0237f43ab925775250e266e479d0a337ff374a4btakashi
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand if (!array_is_created(&map->extensions)) {
117c1f888a14e73cdd821dc6c23eb0411144a41cnd mail_index_map_init_extbufs(map, 5);
117c1f888a14e73cdd821dc6c23eb0411144a41cnd idx = 0;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd } else {
117c1f888a14e73cdd821dc6c23eb0411144a41cnd idx = array_count(&map->extensions);
117c1f888a14e73cdd821dc6c23eb0411144a41cnd }
0844fff26cb7719e0f0a368d88544156ed6374b6sf i_assert(!mail_index_map_lookup_ext(map, name, NULL));
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext = array_append_space(&map->extensions);
52ea316008e2581c8113441c9c341e5c65225f6anilgun ext->name = p_strdup(map->extension_pool, name);
52ea316008e2581c8113441c9c341e5c65225f6anilgun ext->ext_offset = ext_offset;
3304e0a95f408fa1e70f0d4e575444fdca0699fekbrand ext->hdr_offset = ext_offset +
117c1f888a14e73cdd821dc6c23eb0411144a41cnd mail_index_map_ext_hdr_offset(strlen(name));
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext->hdr_size = ext_hdr->hdr_size;
0844fff26cb7719e0f0a368d88544156ed6374b6sf ext->record_offset = ext_hdr->record_offset;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext->record_size = ext_hdr->record_size;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext->record_align = ext_hdr->record_align;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext->reset_id = ext_hdr->reset_id;
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext->index_idx = mail_index_ext_register(map->index, name,
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext_hdr->hdr_size,
4a3f85b165e7ece75cfbdb5e0c5d272edd036c32rpluem ext_hdr->record_size,
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext_hdr->record_align);
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cnd /* Update index ext_id -> map ext_id mapping. Fill non-used
117c1f888a14e73cdd821dc6c23eb0411144a41cnd ext_ids with (uint32_t)-1 */
9cb641b95a976f28161ff3eb5dc71105a8f75ddeminfrin while (array_count(&map->ext_id_map) < ext->index_idx)
9995029b732e29b6957f746bbeed2c2547273150rjung array_append(&map->ext_id_map, &empty_idx, 1);
5238f0f8774d14ac2a433e1ae85d4db5814a56c8sf array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
5238f0f8774d14ac2a433e1ae85d4db5814a56c8sf return idx;
cb89c9a75694a1cde836412059863a69d1349addkbrand}
cb89c9a75694a1cde836412059863a69d1349addkbrand
cb89c9a75694a1cde836412059863a69d1349addkbrandint mail_index_map_ext_get_next(struct mail_index_map *map,
cb89c9a75694a1cde836412059863a69d1349addkbrand unsigned int *offset_p,
cb89c9a75694a1cde836412059863a69d1349addkbrand const struct mail_index_ext_header **ext_hdr_r,
cb89c9a75694a1cde836412059863a69d1349addkbrand const char **name_r)
cb89c9a75694a1cde836412059863a69d1349addkbrand{
cb89c9a75694a1cde836412059863a69d1349addkbrand const struct mail_index_ext_header *ext_hdr;
cb89c9a75694a1cde836412059863a69d1349addkbrand unsigned int offset, name_offset;
19e58a269fe969b87c28465ee4914f3ae637e264jim
0e30a2297a821567cc54f5ea334692e1edb17866jorton offset = *offset_p;
cb89c9a75694a1cde836412059863a69d1349addkbrand *name_r = "";
117c1f888a14e73cdd821dc6c23eb0411144a41cnd
117c1f888a14e73cdd821dc6c23eb0411144a41cnd /* Extension header contains:
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd - struct mail_index_ext_header
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeri - name (not 0-terminated)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd - 64bit alignment padding
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar - extension header contents
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar - 64bit alignment padding
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar name_offset = offset + sizeof(*ext_hdr);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (offset + sizeof(*ext_hdr) >= map->hdr.header_size)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar offset += mail_index_map_ext_hdr_offset(ext_hdr->name_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (offset > map->hdr.header_size)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *name_r = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_hdr->name_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (strcmp(*name_r, str_sanitize(*name_r, -1)) != 0) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* we allow only plain ASCII names, so this extension
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar is most likely broken */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *name_r = "";
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* finally make sure that the hdr_size is small enough.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar do this last so that we could return a usable name. */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (offset > map->hdr.header_size)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *offset_p = offset;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *ext_hdr_r = ext_hdr;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarint mail_index_map_ext_hdr_check(const struct mail_index_header *hdr,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const struct mail_index_ext_header *ext_hdr,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *name, const char **error_r)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar (ext_hdr->record_align == 0 && ext_hdr->record_size != 0)) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *error_r = "Invalid field values";
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (*name == '\0') {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *error_r = "Broken name";
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (ext_hdr->record_offset + ext_hdr->record_size > hdr->record_size) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *error_r = t_strdup_printf("Record field points "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "outside record size (%u+%u > %u)",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_hdr->record_offset,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_hdr->record_size,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar hdr->record_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (ext_hdr->record_size > 0 &&
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar (hdr->record_size % ext_hdr->record_align) != 0)) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar *error_r = t_strdup_printf("Record field alignmentation %u "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "not used", ext_hdr->record_align);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic int mail_index_map_parse_extensions(struct mail_index_map *map)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar struct mail_index *index = map->index;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const struct mail_index_ext_header *ext_hdr;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar unsigned int i, old_count, offset;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *name, *error;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar uint32_t ext_id, ext_offset;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* extension headers always start from 64bit offsets, so if base header
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar doesn't happen to be 64bit aligned we'll skip some bytes */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* nothing to do, skip allocatations and all */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar old_count = array_count(&index->extensions);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_map_init_extbufs(map, old_count + 5);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_id = (uint32_t)-1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar for (i = 0; i < old_count; i++)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar array_append(&map->ext_id_map, &ext_id, 1);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar for (i = 0; offset < map->hdr.header_size; i++) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext_offset = offset;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar t_push();
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (mail_index_map_ext_get_next(map, &offset,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar &ext_hdr, &name) < 0) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Header extension #%d (%s) goes outside header",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath, i, name);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar t_pop();
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar name, &error) < 0) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Broken extension #%d (%s): %s",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath, i, name, error);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar t_pop();
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (mail_index_map_lookup_ext(map, name, NULL)) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Duplicate header extension %s",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath, name);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar t_pop();
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_map_register_ext(map, name, ext_offset, ext_hdr);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar t_pop();
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar}
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarint mail_index_map_parse_keywords(struct mail_index_map *map)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar{
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar struct mail_index *index = map->index;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const struct mail_index_ext *ext;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const struct mail_index_keyword_header *kw_hdr;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const struct mail_index_keyword_header_rec *kw_rec;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *name;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar unsigned int i, name_area_end_offset, old_count;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar uint32_t idx;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (!mail_index_map_lookup_ext(map, "keywords", &idx)) {
aaed4ebc116f5862aff2610a809a9a9e9a28f50ecoar if (array_is_created(&map->keyword_idx_map))
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar array_clear(&map->keyword_idx_map);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ext = array_idx(&map->extensions, idx);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Extension header contains:
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar - struct mail_index_keyword_header
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar - struct mail_index_keyword_header_rec * keywords_count
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar - const char names[] * keywords_count
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar i_assert(ext->hdr_offset < map->hdr.header_size);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar kw_rec = (const void *)(kw_hdr + 1);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar name = (const char *)(kw_rec + kw_hdr->keywords_count);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar array_count(&map->keyword_idx_map);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Keywords can only be added into same mapping. Removing requires a
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar new mapping (recreating the index file) */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (kw_hdr->keywords_count == old_count) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* nothing changed */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return 0;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* make sure the header is valid */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (kw_hdr->keywords_count < old_count) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Keywords removed unexpectedly",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "keywords_count larger than header size",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar for (i = 0; i < kw_hdr->keywords_count; i++) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (kw_rec[i].name_offset > name_area_end_offset) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "name_offset points outside allocated header",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (name[name_area_end_offset-1] != '\0') {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar mail_index_set_error(index, "Corrupted index file %s: "
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Keyword header doesn't end with NUL",
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar index->filepath);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return -1;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar }
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* create file -> index mapping */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (!array_is_created(&map->keyword_idx_map))
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar#ifdef DEBUG
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Check that existing headers are still the same. It's behind DEBUG
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar since it's pretty useless waste of CPU normally. */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *keyword = name + kw_rec[i].name_offset;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd const unsigned int *old_idx;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd unsigned int idx;
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd old_idx = array_idx(&map->keyword_idx_map, i);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (!mail_index_keyword_lookup(index, keyword, &idx) ||
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd idx != *old_idx) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_set_error(index, "Corrupted index file %s: "
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd "Keywords changed unexpectedly",
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd index->filepath);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#endif
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Register the newly seen keywords */
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf i = array_count(&map->keyword_idx_map);
97a9a944b5887e91042b019776c41d5dd74557aferikabele for (; i < kw_hdr->keywords_count; i++) {
4aa603e6448b99f9371397d439795c91a93637eand const char *keyword = name + kw_rec[i].name_offset;
e487d6c09669296f94a5190cc34586a98e624a00nd unsigned int idx;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (*keyword == '\0') {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_set_error(index, "Corrupted index file %s: "
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd "Empty keyword name in header",
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd index->filepath);
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf return -1;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_keyword_lookup_or_create(index, keyword, &idx);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd array_append(&map->keyword_idx_map, &idx, 1);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return 0;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic bool mail_index_check_header_compat(struct mail_index *index,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const struct mail_index_header *hdr,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive uoff_t file_size)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive enum mail_index_header_compat_flags compat_flags = 0;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#ifndef WORDS_BIGENDIAN
06ba4a61654b3763ad65f52283832ebf058fdf1cslive compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
943058dd6ec8f21d88204c1f2dc67bf86b1d2e5arbowen#endif
4aa603e6448b99f9371397d439795c91a93637eand
e487d6c09669296f94a5190cc34586a98e624a00nd if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* major version change - handle silently(?) */
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return FALSE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess /* we've already complained about it */
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf return FALSE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->compat_flags != compat_flags) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess /* architecture change */
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_index_set_error(index, "Rebuilding index file %s: "
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess "CPU architecture changed",
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess index->filepath);
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return FALSE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess hdr->header_size < hdr->base_header_size) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_index_set_error(index, "Corrupted index file %s: "
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess "Corrupted header sizes (base %u, full %u)",
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess index->filepath, hdr->base_header_size,
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess hdr->header_size);
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return FALSE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->header_size > file_size) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_index_set_error(index, "Corrupted index file %s: "
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess "Corrupted header size (%u > %"PRIuUOFF_T")",
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess index->filepath, hdr->header_size,
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess file_size);
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return FALSE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->indexid != index->indexid) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (index->indexid != 0) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_index_set_error(index, "Index file %s: "
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess "indexid changed: %u -> %u",
4aa603e6448b99f9371397d439795c91a93637eand index->filepath, index->indexid,
e487d6c09669296f94a5190cc34586a98e624a00nd hdr->indexid);
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess index->indexid = hdr->indexid;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_transaction_log_indexid_changed(index->log);
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess }
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf return TRUE;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess}
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkessint mail_index_map_check_header(struct mail_index_map *map)
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess{
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess struct mail_index *index = map->index;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess const struct mail_index_header *hdr = &map->hdr;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1))
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess return -1;
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess /* following some extra checks that only take a bit of CPU */
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->record_size < sizeof(struct mail_index_record)) {
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess mail_index_set_error(index, "Corrupted index file %s: "
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess "record_size too small: %u < %"PRIuSIZE_T,
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess index->filepath, hdr->record_size,
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess sizeof(struct mail_index_record));
943058dd6ec8f21d88204c1f2dc67bf86b1d2e5arbowen return -1;
4aa603e6448b99f9371397d439795c91a93637eand }
e487d6c09669296f94a5190cc34586a98e624a00nd
281c0b44de97d9942428ff51bc2be0e8e61ed87bkess if (hdr->uid_validity == 0 && hdr->next_uid != 1)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->next_uid == 0)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->messages_count > map->rec_map->records_count)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->seen_messages_count > hdr->messages_count ||
0844fff26cb7719e0f0a368d88544156ed6374b6sf hdr->deleted_messages_count > hdr->messages_count)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->minor_version == 0) {
0844fff26cb7719e0f0a368d88544156ed6374b6sf /* upgrade silently from v1.0 */
0844fff26cb7719e0f0a368d88544156ed6374b6sf map->hdr.minor_version = MAIL_INDEX_MINOR_VERSION;
0844fff26cb7719e0f0a368d88544156ed6374b6sf map->hdr.unused_old_recent_messages_count = 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->first_recent_uid == 0)
0844fff26cb7719e0f0a368d88544156ed6374b6sf map->hdr.first_recent_uid = 1;
0844fff26cb7719e0f0a368d88544156ed6374b6sf index->need_recreate = TRUE;
0844fff26cb7719e0f0a368d88544156ed6374b6sf }
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->first_recent_uid == 0 ||
0844fff26cb7719e0f0a368d88544156ed6374b6sf hdr->first_recent_uid > hdr->next_uid ||
0844fff26cb7719e0f0a368d88544156ed6374b6sf hdr->first_unseen_uid_lowwater > hdr->next_uid ||
0844fff26cb7719e0f0a368d88544156ed6374b6sf hdr->first_deleted_uid_lowwater > hdr->next_uid)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (hdr->messages_count > 0) {
0844fff26cb7719e0f0a368d88544156ed6374b6sf /* last message's UID must be smaller than next_uid.
0844fff26cb7719e0f0a368d88544156ed6374b6sf also make sure it's not zero. */
0844fff26cb7719e0f0a368d88544156ed6374b6sf const struct mail_index_record *rec;
0844fff26cb7719e0f0a368d88544156ed6374b6sf
0844fff26cb7719e0f0a368d88544156ed6374b6sf rec = MAIL_INDEX_MAP_IDX(map, hdr->messages_count-1);
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (rec->uid == 0 || rec->uid >= hdr->next_uid)
0844fff26cb7719e0f0a368d88544156ed6374b6sf return 0;
0844fff26cb7719e0f0a368d88544156ed6374b6sf }
0844fff26cb7719e0f0a368d88544156ed6374b6sf
4aa603e6448b99f9371397d439795c91a93637eand return 1;
e487d6c09669296f94a5190cc34586a98e624a00nd}
0844fff26cb7719e0f0a368d88544156ed6374b6sf
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndstatic void mail_index_map_copy_hdr(struct mail_index_map *map,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd const struct mail_index_header *hdr)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd{
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (hdr->base_header_size < sizeof(map->hdr)) {
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf /* header smaller than ours, make a copy so our newer headers
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd won't have garbage in them */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd memset(&map->hdr, 0, sizeof(map->hdr));
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd memcpy(&map->hdr, hdr, hdr->base_header_size);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd } else {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd map->hdr = *hdr;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* FIXME: backwards compatibility, remove later. In case this index is
06ba4a61654b3763ad65f52283832ebf058fdf1cslive accessed with Dovecot v1.0, avoid recent message counter errors. */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive map->hdr.unused_old_recent_messages_count = 0;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
97a9a944b5887e91042b019776c41d5dd74557aferikabelestatic int mail_index_mmap(struct mail_index_map *map, uoff_t file_size)
4aa603e6448b99f9371397d439795c91a93637eand{
e487d6c09669296f94a5190cc34586a98e624a00nd struct mail_index *index = map->index;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd struct mail_index_record_map *rec_map = map->rec_map;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd const struct mail_index_header *hdr;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd i_assert(rec_map->mmap_base == NULL);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf buffer_free(&rec_map->buffer);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (file_size > SSIZE_T_MAX) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* too large file to map into memory */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_set_error(index, "Index file too large: %s",
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd index->filepath);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return -1;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->mmap_base = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive MAP_PRIVATE, index->fd, 0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (rec_map->mmap_base == MAP_FAILED) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->mmap_base = NULL;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_set_syscall_error(index, "mmap()");
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->mmap_size = file_size;
943058dd6ec8f21d88204c1f2dc67bf86b1d2e5arbowen
4aa603e6448b99f9371397d439795c91a93637eand hdr = rec_map->mmap_base;
e487d6c09669296f94a5190cc34586a98e624a00nd if (rec_map->mmap_size >
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd offsetof(struct mail_index_header, major_version) &&
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* major version change - handle silently */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return 0;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (rec_map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_set_error(index, "Corrupted index file %s: "
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd "File too small (%"PRIuSIZE_T")",
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd index->filepath, rec_map->mmap_size);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return 0;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand }
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) {
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand /* Can't use this file */
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand return 0;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand }
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->mmap_used_size = hdr->header_size +
06ba4a61654b3763ad65f52283832ebf058fdf1cslive hdr->messages_count * hdr->record_size;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (rec_map->mmap_used_size <= rec_map->mmap_size)
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd rec_map->records_count = hdr->messages_count;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive else {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->records_count =
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (rec_map->mmap_size - hdr->header_size) /
97a9a944b5887e91042b019776c41d5dd74557aferikabele hdr->record_size;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->mmap_used_size = hdr->header_size +
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->records_count * hdr->record_size;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_set_error(index, "Corrupted index file %s: "
06ba4a61654b3763ad65f52283832ebf058fdf1cslive "messages_count too large (%u > %u)",
97a9a944b5887e91042b019776c41d5dd74557aferikabele index->filepath, hdr->messages_count,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->records_count);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
43a906741e1d11f0f1d0c189d1b55eafbcc21d14noodl
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_map_copy_hdr(map, hdr);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
43a906741e1d11f0f1d0c189d1b55eafbcc21d14noodl map->hdr_base = rec_map->mmap_base;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive rec_map->records = PTR_OFFSET(rec_map->mmap_base, map->hdr.header_size);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return 1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
4aa603e6448b99f9371397d439795c91a93637eand
e487d6c09669296f94a5190cc34586a98e624a00ndstatic int mail_index_read_header(struct mail_index *index,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd void *buf, size_t buf_size, size_t *pos_r)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd{
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd size_t pos;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd int ret;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand memset(buf, 0, sizeof(struct mail_index_header));
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* try to read the whole header, but it's not necessarily an error to
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd read less since the older versions of the index format could be
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd smaller. Request reading up to buf_size, but accept if we only got
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd the header. */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive pos = 0;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand do {
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand ret = pread(index->fd, PTR_OFFSET(buf, pos),
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc buf_size - pos, pos);
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc if (ret > 0)
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc pos += ret;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand } while (ret > 0 && pos < sizeof(struct mail_index_header));
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand *pos_r = pos;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand return ret;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand}
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletcstatic int
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrandmail_index_try_read_map(struct mail_index_map *map,
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand uoff_t file_size, bool *retry_r, bool try_retry)
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand{
031e53981ec261154d2ee4c83bf321af203d3e24kbrand struct mail_index *index = map->index;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand const struct mail_index_header *hdr;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand unsigned char read_buf[4096];
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand const void *buf;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand void *data = NULL;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand ssize_t ret;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand size_t pos, records_size, initial_buf_pos = 0;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand unsigned int records_count = 0, extra;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand i_assert(map->rec_map->mmap_base == NULL);
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand *retry_r = FALSE;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand ret = mail_index_read_header(index, read_buf, sizeof(read_buf), &pos);
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand buf = read_buf; hdr = buf;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
031e53981ec261154d2ee4c83bf321af203d3e24kbrand hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
031e53981ec261154d2ee4c83bf321af203d3e24kbrand /* major version change - handle silently */
031e53981ec261154d2ee4c83bf321af203d3e24kbrand return 0;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand }
6c4ef4a72d9897e53365b94103f4bd819fd0d3acnd
6c4ef4a72d9897e53365b94103f4bd819fd0d3acnd if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
6c4ef4a72d9897e53365b94103f4bd819fd0d3acnd (ret > 0 || pos >= hdr->base_header_size)) {
6c4ef4a72d9897e53365b94103f4bd819fd0d3acnd if (!mail_index_check_header_compat(index, hdr, file_size)) {
031e53981ec261154d2ee4c83bf321af203d3e24kbrand /* Can't use this file */
031e53981ec261154d2ee4c83bf321af203d3e24kbrand return 0;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand }
031e53981ec261154d2ee4c83bf321af203d3e24kbrand
031e53981ec261154d2ee4c83bf321af203d3e24kbrand initial_buf_pos = pos;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand if (pos > hdr->header_size)
031e53981ec261154d2ee4c83bf321af203d3e24kbrand pos = hdr->header_size;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand
031e53981ec261154d2ee4c83bf321af203d3e24kbrand /* place the base header into memory. */
4aa603e6448b99f9371397d439795c91a93637eand buffer_reset(map->hdr_copy_buf);
e487d6c09669296f94a5190cc34586a98e624a00nd buffer_append(map->hdr_copy_buf, buf, pos);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (pos != hdr->header_size) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* @UNSAFE: read the rest of the header into memory */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd data = buffer_append_space_unsafe(map->hdr_copy_buf,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd hdr->header_size -
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand pos);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd ret = pread_full(index->fd, data,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd hdr->header_size - pos, pos);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (ret > 0) {
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand /* header read, read the records now. */
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand records_size = (size_t)hdr->messages_count * hdr->record_size;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand records_count = hdr->messages_count;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand if (file_size - hdr->header_size < records_size ||
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand (hdr->record_size != 0 &&
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand records_size / hdr->record_size != hdr->messages_count)) {
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand records_count = (file_size - hdr->header_size) /
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand hdr->record_size;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand records_size = (size_t)records_count * hdr->record_size;
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand mail_index_set_error(index, "Corrupted index file %s: "
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand "messages_count too large (%u > %u)",
6bf23e5b5269a4780ed2be820a969831d1cc785fkbrand index->filepath, hdr->messages_count,
4aa603e6448b99f9371397d439795c91a93637eand records_count);
e487d6c09669296f94a5190cc34586a98e624a00nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (map->rec_map->buffer == NULL) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd map->rec_map->buffer =
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd buffer_create_dynamic(default_pool,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd records_size);
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* @UNSAFE */
61d0f219eba8ce646ffd6f2738a60e36e66cf654rbowen buffer_set_used_size(map->rec_map->buffer, 0);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (initial_buf_pos <= hdr->header_size)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd extra = 0;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd else {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd extra = initial_buf_pos - hdr->header_size;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd buffer_append(map->rec_map->buffer,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive CONST_PTR_OFFSET(buf, hdr->header_size),
06ba4a61654b3763ad65f52283832ebf058fdf1cslive extra);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (records_size > extra) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive data = buffer_append_space_unsafe(map->rec_map->buffer,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive records_size - extra);
f6066dc0a6ad0432b74774e290c04c3cc4aa2dafrbowen ret = pread_full(index->fd, data, records_size - extra,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive hdr->header_size + extra);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (ret < 0) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (errno == ESTALE && try_retry) {
97a9a944b5887e91042b019776c41d5dd74557aferikabele /* a new index file was renamed over this one. */
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf *retry_r = TRUE;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return 0;
97a9a944b5887e91042b019776c41d5dd74557aferikabele }
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf mail_index_set_syscall_error(index, "pread_full()");
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
97a9a944b5887e91042b019776c41d5dd74557aferikabele }
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf if (ret == 0) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_set_error(index,
97a9a944b5887e91042b019776c41d5dd74557aferikabele "Corrupted index file %s: File too small",
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf index->filepath);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return 0;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf map->rec_map->records =
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf buffer_get_modifiable_data(map->rec_map->buffer, NULL);
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf map->rec_map->records_count = records_count;
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf mail_index_map_copy_hdr(map, hdr);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive map->hdr_base = map->hdr_copy_buf->data;
97a9a944b5887e91042b019776c41d5dd74557aferikabele return 1;
c6a2d6fa44f8698851dec5051ee3782c2913605fnd}
67c9cb8a211ba641c62f3c8db6fb5b7abc2a6ea8rbowen
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic int mail_index_read_map(struct mail_index_map *map, uoff_t file_size,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive unsigned int *lock_id)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive struct mail_index *index = map->index;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_sync_lost_handler_t *const *handlers;
5238f0f8774d14ac2a433e1ae85d4db5814a56c8sf struct stat st;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive unsigned int i, count;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int ret;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive bool try_retry, retry;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* notify all "sync lost" handlers */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive handlers = array_get(&index->sync_lost_handlers, &count);
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf for (i = 0; i < count; i++)
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf (*handlers[i])(index);
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf for (i = 0;; i++) {
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf try_retry = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf if (file_size == (uoff_t)-1) {
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf /* fstat() below failed */
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf ret = 0;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive retry = try_retry;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive } else {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ret = mail_index_try_read_map(map, file_size,
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf &retry, try_retry);
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf }
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf if (ret != 0 || !retry)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive break;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* ESTALE - reopen index file */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_close_file(index);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive *lock_id = 0;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ret = mail_index_try_open_only(index);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (ret <= 0) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (ret == 0) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* the file was lost */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive errno = ENOENT;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_set_syscall_error(index, "open()");
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf }
5238f0f8774d14ac2a433e1ae85d4db5814a56c8sf if (mail_index_lock_shared(index, lock_id) < 0)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf if (fstat(index->fd, &st) == 0)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive file_size = st.st_size;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive else {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (errno != ESTALE) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive mail_index_set_syscall_error(index, "fstat()");
1c0dfae82e30aa9fe4a22f00a83abd827b7a63bfsf return -1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive file_size = (uoff_t)-1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return ret;
7159c12b7697fe9f5ab3a533cc6dfc3d57803053igalic}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic void mail_index_header_init(struct mail_index *index,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive struct mail_index_header *hdr)
031e53981ec261154d2ee4c83bf321af203d3e24kbrand{
031e53981ec261154d2ee4c83bf321af203d3e24kbrand i_assert((sizeof(*hdr) % sizeof(uint64_t)) == 0);
031e53981ec261154d2ee4c83bf321af203d3e24kbrand
031e53981ec261154d2ee4c83bf321af203d3e24kbrand memset(hdr, 0, sizeof(*hdr));
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc
031e53981ec261154d2ee4c83bf321af203d3e24kbrand hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
031e53981ec261154d2ee4c83bf321af203d3e24kbrand hdr->base_header_size = sizeof(*hdr);
031e53981ec261154d2ee4c83bf321af203d3e24kbrand hdr->header_size = sizeof(*hdr);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive hdr->record_size = sizeof(struct mail_index_record);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive#ifndef WORDS_BIGENDIAN
61d0f219eba8ce646ffd6f2738a60e36e66cf654rbowen hdr->compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
cc094350da96eecbed411d410393716ada05c402igalic#endif
cc094350da96eecbed411d410393716ada05c402igalic
cc094350da96eecbed411d410393716ada05c402igalic hdr->indexid = index->indexid;
cc094350da96eecbed411d410393716ada05c402igalic hdr->log_file_seq = 1;
cc094350da96eecbed411d410393716ada05c402igalic hdr->next_uid = 1;
cc094350da96eecbed411d410393716ada05c402igalic hdr->first_recent_uid = 1;
cc094350da96eecbed411d410393716ada05c402igalic}
4aa603e6448b99f9371397d439795c91a93637eand
cc094350da96eecbed411d410393716ada05c402igalicstruct mail_index_map *mail_index_map_alloc(struct mail_index *index)
cc094350da96eecbed411d410393716ada05c402igalic{
cc094350da96eecbed411d410393716ada05c402igalic struct mail_index_map tmp_map;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
cc094350da96eecbed411d410393716ada05c402igalic memset(&tmp_map, 0, sizeof(tmp_map));
cc094350da96eecbed411d410393716ada05c402igalic mail_index_header_init(index, &tmp_map.hdr);
4aa603e6448b99f9371397d439795c91a93637eand tmp_map.index = index;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive tmp_map.hdr_base = &tmp_map.hdr;
4aa603e6448b99f9371397d439795c91a93637eand
e487d6c09669296f94a5190cc34586a98e624a00nd /* a bit kludgy way to do this, but it initializes everything
97a9a944b5887e91042b019776c41d5dd74557aferikabele nicely and correctly */
c6a2d6fa44f8698851dec5051ee3782c2913605fnd return mail_index_map_clone(&tmp_map);
67c9cb8a211ba641c62f3c8db6fb5b7abc2a6ea8rbowen}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
97a9a944b5887e91042b019776c41d5dd74557aferikabelestatic int mail_index_map_latest_file(struct mail_index *index)
97a9a944b5887e91042b019776c41d5dd74557aferikabele{
97a9a944b5887e91042b019776c41d5dd74557aferikabele struct mail_index_map *old_map, *new_map;
97a9a944b5887e91042b019776c41d5dd74557aferikabele struct stat st;
97a9a944b5887e91042b019776c41d5dd74557aferikabele unsigned int lock_id;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive uoff_t file_size;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive bool use_mmap;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int ret, try;
97a9a944b5887e91042b019776c41d5dd74557aferikabele
97a9a944b5887e91042b019776c41d5dd74557aferikabele ret = mail_index_reopen_if_changed(index);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (ret <= 0) {
97a9a944b5887e91042b019776c41d5dd74557aferikabele if (ret < 0)
97a9a944b5887e91042b019776c41d5dd74557aferikabele return -1;
97a9a944b5887e91042b019776c41d5dd74557aferikabele
97a9a944b5887e91042b019776c41d5dd74557aferikabele /* the index file is lost/broken. let's hope that we can
97a9a944b5887e91042b019776c41d5dd74557aferikabele build it from the transaction log. */
97a9a944b5887e91042b019776c41d5dd74557aferikabele return 0;
97a9a944b5887e91042b019776c41d5dd74557aferikabele }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* the index file is still open, lock it */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (mail_index_lock_shared(index, &lock_id) < 0)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return -1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (index->nfs_flush)
3bfe5718442b1bc7401a4d513762858997bcf708sf nfs_flush_attr_cache_fd_locked(index->filepath, index->fd);
3bfe5718442b1bc7401a4d513762858997bcf708sf
3bfe5718442b1bc7401a4d513762858997bcf708sf if (fstat(index->fd, &st) == 0)
3bfe5718442b1bc7401a4d513762858997bcf708sf file_size = st.st_size;
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf else {
3bfe5718442b1bc7401a4d513762858997bcf708sf if (errno != ESTALE) {
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf mail_index_set_syscall_error(index, "fstat()");
3bfe5718442b1bc7401a4d513762858997bcf708sf mail_index_unlock(index, &lock_id);
3bfe5718442b1bc7401a4d513762858997bcf708sf return -1;
3bfe5718442b1bc7401a4d513762858997bcf708sf }
5cf9b7c2c028e09a3640165231e57043cb071963rjung file_size = (uoff_t)-1;
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf }
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf
3bfe5718442b1bc7401a4d513762858997bcf708sf /* mmaping seems to be slower than just reading the file, so even if
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf mmap isn't disabled don't use it unless the file is large enough */
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf use_mmap = !index->mmap_disable && file_size != (uoff_t)-1 &&
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf file_size > MAIL_INDEX_MMAP_MIN_SIZE;
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf
173e5f4d5ec46b5febb74ce860d753bb1faaba0fsf new_map = mail_index_map_alloc(index);
3bfe5718442b1bc7401a4d513762858997bcf708sf if (use_mmap) {
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton new_map->rec_map->lock_id = lock_id;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = mail_index_mmap(new_map, file_size);
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton } else {
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = mail_index_read_map(new_map, file_size, &lock_id);
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton mail_index_unlock(index, &lock_id);
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton }
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton for (try = 0; ret > 0; try++) {
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton /* make sure the header is ok before using this mapping */
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = mail_index_map_check_header(new_map);
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton if (ret > 0) {
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton if (mail_index_map_parse_extensions(new_map) < 0)
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = 0;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton else if (mail_index_map_parse_keywords(new_map) < 0)
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = 0;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton }
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton if (ret != 0 || try == 2)
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton break;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton /* fsck and try again */
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton old_map = index->map;
4aa603e6448b99f9371397d439795c91a93637eand index->map = new_map;
4aa603e6448b99f9371397d439795c91a93637eand if (mail_index_fsck(index) < 0) {
e487d6c09669296f94a5190cc34586a98e624a00nd ret = -1;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton break;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* fsck replaced the map */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd new_map = index->map;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd index->map = old_map;
eaeb7393a93910f37b697c302d656f3ec2351835pquerna }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (ret <= 0) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_unmap(&new_map);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return ret;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd i_assert(new_map->rec_map->records != NULL);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive index->last_read_log_file_seq = new_map->hdr.log_file_seq;
1428f44b421e1c9ee0721b4b709dd10064758c40rbowen index->last_read_log_file_head_offset =
1428f44b421e1c9ee0721b4b709dd10064758c40rbowen new_map->hdr.log_file_head_offset;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive index->last_read_log_file_tail_offset =
4aa603e6448b99f9371397d439795c91a93637eand new_map->hdr.log_file_tail_offset;
4eeaef742633166aa4f72437918cd2965ace43d5humbedooh index->last_read_stat = st;
4eeaef742633166aa4f72437918cd2965ace43d5humbedooh
4aa603e6448b99f9371397d439795c91a93637eand mail_index_unmap(&index->map);
e487d6c09669296f94a5190cc34586a98e624a00nd index->map = new_map;
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf return 1;
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf}
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf
eaeb7393a93910f37b697c302d656f3ec2351835pquernaint mail_index_map(struct mail_index *index,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd enum mail_index_sync_handler_type type)
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen{
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen int ret;
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen i_assert(index->lock_type != F_WRLCK);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen i_assert(!index->mapping);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen index->mapping = TRUE;
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen if (index->map == NULL)
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen index->map = mail_index_map_alloc(index);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen /* first try updating the existing mapping from transaction log. */
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen if (index->map->hdr.indexid != 0 && index->indexid != 0) {
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen /* we're not creating the index, or opening transaction log.
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf sync this as a view from transaction log. */
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen ret = mail_index_sync_map(&index->map, type, FALSE);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen } else {
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen ret = 0;
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen }
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen if (ret == 0) {
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen /* try to open and read the latest index. if it fails for
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen any reason, we'll fallback to updating the existing mapping
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen from transaction logs (which we'll also do even if the
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen reopening succeeds) */
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen (void)mail_index_map_latest_file(index);
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen
ffc28236b928ae15fc998df17ad4a8fb12b137bcrbowen /* if we're creating the index file, we don't have any
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton logs yet */
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton if (index->log->head != NULL && index->indexid != 0) {
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton /* and update the map with the latest changes from
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton transaction log */
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton ret = mail_index_sync_map(&index->map, type, TRUE);
01f52ba6a87aa39d3873a441369828875c471823trawick }
01f52ba6a87aa39d3873a441369828875c471823trawick }
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton index->mapping = FALSE;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton return ret;
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton}
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton
e7939daf37fd0b91dff4506bde6c9be22046fa21jortonstatic void mail_index_record_map_free(struct mail_index_map *map,
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton struct mail_index_record_map *rec_map)
4aa603e6448b99f9371397d439795c91a93637eand{
e487d6c09669296f94a5190cc34586a98e624a00nd if (rec_map->lock_id != 0)
e7939daf37fd0b91dff4506bde6c9be22046fa21jorton mail_index_unlock(map->index, &rec_map->lock_id);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton if (rec_map->buffer != NULL) {
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton i_assert(rec_map->mmap_base == NULL);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton buffer_free(&rec_map->buffer);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton } else if (rec_map->mmap_base != NULL) {
01f52ba6a87aa39d3873a441369828875c471823trawick i_assert(rec_map->buffer == NULL);
58caaee3494bc4873ae3b89a954beab99143be2cjorton if (munmap(rec_map->mmap_base, rec_map->mmap_size) < 0)
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton mail_index_set_syscall_error(map->index, "munmap()");
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton rec_map->mmap_base = NULL;
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton }
b09fcdfc59ada4712150e7bcc7b502bb9e4601d8rjung array_free(&rec_map->maps);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton i_free(rec_map);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton}
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jortonstatic void mail_index_record_map_unlink(struct mail_index_map *map)
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton{
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton struct mail_index_map *const *maps;
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton unsigned int i, count;
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton maps = array_get(&map->rec_map->maps, &count);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton for (i = 0; i < count; i++) {
c68aa7f213d409d464eaa6b963afb28678548f4frbowen if (maps[i] == map) {
c68aa7f213d409d464eaa6b963afb28678548f4frbowen array_delete(&map->rec_map->maps, i, 1);
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton if (i == 0 && count == 1)
58caaee3494bc4873ae3b89a954beab99143be2cjorton mail_index_record_map_free(map, map->rec_map);
58caaee3494bc4873ae3b89a954beab99143be2cjorton return;
58caaee3494bc4873ae3b89a954beab99143be2cjorton }
58caaee3494bc4873ae3b89a954beab99143be2cjorton }
58caaee3494bc4873ae3b89a954beab99143be2cjorton i_unreached();
58caaee3494bc4873ae3b89a954beab99143be2cjorton}
58caaee3494bc4873ae3b89a954beab99143be2cjorton
58caaee3494bc4873ae3b89a954beab99143be2cjortonvoid mail_index_unmap(struct mail_index_map **_map)
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton{
4aa603e6448b99f9371397d439795c91a93637eand struct mail_index_map *map = *_map;
e487d6c09669296f94a5190cc34586a98e624a00nd
ad6b0682327d02eb005f5b8a99ef94fe0b73ea47jorton *_map = NULL;
58caaee3494bc4873ae3b89a954beab99143be2cjorton if (--map->refcount > 0)
58caaee3494bc4873ae3b89a954beab99143be2cjorton return;
58caaee3494bc4873ae3b89a954beab99143be2cjorton
58caaee3494bc4873ae3b89a954beab99143be2cjorton i_assert(map->refcount == 0);
58caaee3494bc4873ae3b89a954beab99143be2cjorton mail_index_record_map_unlink(map);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton if (map->extension_pool != NULL)
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton pool_unref(&map->extension_pool);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton if (array_is_created(&map->keyword_idx_map))
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton array_free(&map->keyword_idx_map);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton buffer_free(&map->hdr_copy_buf);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton i_free(map);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton}
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jortonstatic void mail_index_map_copy_records(struct mail_index_record_map *dest,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton const struct mail_index_record_map *src,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton unsigned int record_size)
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton{
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton size_t size;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton size = src->records_count * record_size;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->buffer = buffer_create_dynamic(default_pool, I_MIN(size, 1024));
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton buffer_append(dest->buffer, src->records, size);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
01f52ba6a87aa39d3873a441369828875c471823trawick dest->records = buffer_get_modifiable_data(dest->buffer, NULL);
01f52ba6a87aa39d3873a441369828875c471823trawick dest->records_count = src->records_count;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton /* if the map is ever written back to disk, we need to keep track of
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton what has changed. */
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->write_seq_first = src->write_seq_first;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->write_seq_last = src->write_seq_last;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton}
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jortonstatic void mail_index_map_copy_header(struct mail_index_map *dest,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton const struct mail_index_map *src)
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton{
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton /* use src->hdr copy directly, because if we got here
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton from syncing it has the latest changes. */
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->hdr = src->hdr;
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton if (dest->hdr_copy_buf != NULL) {
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton if (src == dest)
4aa603e6448b99f9371397d439795c91a93637eand return;
4eeaef742633166aa4f72437918cd2965ace43d5humbedooh
4eeaef742633166aa4f72437918cd2965ace43d5humbedooh buffer_set_used_size(dest->hdr_copy_buf, 0);
4aa603e6448b99f9371397d439795c91a93637eand } else {
e487d6c09669296f94a5190cc34586a98e624a00nd dest->hdr_copy_buf =
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton buffer_create_dynamic(default_pool,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->hdr.header_size);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton }
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton buffer_append(dest->hdr_copy_buf, &dest->hdr,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton I_MIN(sizeof(dest->hdr), src->hdr.base_header_size));
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton if (src != dest) {
01f52ba6a87aa39d3873a441369828875c471823trawick buffer_write(dest->hdr_copy_buf, src->hdr.base_header_size,
01f52ba6a87aa39d3873a441369828875c471823trawick CONST_PTR_OFFSET(src->hdr_base,
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton src->hdr.base_header_size),
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton src->hdr.header_size - src->hdr.base_header_size);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton }
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton dest->hdr_base = buffer_get_modifiable_data(dest->hdr_copy_buf, NULL);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton i_assert(dest->hdr_copy_buf->used == dest->hdr.header_size);
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton}
c57fa68c99b9e13aeafaf473e4feefaff590edb2jorton
c57fa68c99b9e13aeafaf473e4feefaff590edb2jortonstatic struct mail_index_record_map *
817a2329f22ff84555a29b23248894b999a7336fjimmail_index_record_map_alloc(struct mail_index_map *map)
817a2329f22ff84555a29b23248894b999a7336fjim{
817a2329f22ff84555a29b23248894b999a7336fjim struct mail_index_record_map *rec_map;
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim rec_map = i_new(struct mail_index_record_map, 1);
817a2329f22ff84555a29b23248894b999a7336fjim i_array_init(&rec_map->maps, 4);
817a2329f22ff84555a29b23248894b999a7336fjim array_append(&rec_map->maps, &map, 1);
817a2329f22ff84555a29b23248894b999a7336fjim return rec_map;
817a2329f22ff84555a29b23248894b999a7336fjim}
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjimstruct mail_index_map *mail_index_map_clone(const struct mail_index_map *map)
817a2329f22ff84555a29b23248894b999a7336fjim{
817a2329f22ff84555a29b23248894b999a7336fjim struct mail_index_map *mem_map;
817a2329f22ff84555a29b23248894b999a7336fjim struct mail_index_ext *extensions;
817a2329f22ff84555a29b23248894b999a7336fjim unsigned int i, count;
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim mem_map = i_new(struct mail_index_map, 1);
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->index = map->index;
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->refcount = 1;
817a2329f22ff84555a29b23248894b999a7336fjim if (map->rec_map == NULL) {
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->rec_map = mail_index_record_map_alloc(mem_map);
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->rec_map->buffer =
817a2329f22ff84555a29b23248894b999a7336fjim buffer_create_dynamic(default_pool, 1024);
817a2329f22ff84555a29b23248894b999a7336fjim } else {
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->rec_map = map->rec_map;
817a2329f22ff84555a29b23248894b999a7336fjim array_append(&mem_map->rec_map->maps, &mem_map, 1);
817a2329f22ff84555a29b23248894b999a7336fjim }
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim mail_index_map_copy_header(mem_map, map);
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->write_atomic = map->write_atomic;
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->write_base_header = map->write_base_header;
817a2329f22ff84555a29b23248894b999a7336fjim mem_map->write_ext_header = map->write_ext_header;
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim /* copy extensions */
817a2329f22ff84555a29b23248894b999a7336fjim if (array_is_created(&map->ext_id_map)) {
817a2329f22ff84555a29b23248894b999a7336fjim count = array_count(&map->ext_id_map);
817a2329f22ff84555a29b23248894b999a7336fjim mail_index_map_init_extbufs(mem_map, count + 2);
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim array_append_array(&mem_map->extensions, &map->extensions);
817a2329f22ff84555a29b23248894b999a7336fjim array_append_array(&mem_map->ext_id_map, &map->ext_id_map);
817a2329f22ff84555a29b23248894b999a7336fjim
817a2329f22ff84555a29b23248894b999a7336fjim /* fix the name pointers to use our own pool */
817a2329f22ff84555a29b23248894b999a7336fjim extensions = array_get_modifiable(&mem_map->extensions, &count);
0237f43ab925775250e266e479d0a337ff374a4btakashi for (i = 0; i < count; i++) {
0237f43ab925775250e266e479d0a337ff374a4btakashi i_assert(extensions[i].record_offset +
0237f43ab925775250e266e479d0a337ff374a4btakashi extensions[i].record_size <=
0237f43ab925775250e266e479d0a337ff374a4btakashi mem_map->hdr.record_size);
0237f43ab925775250e266e479d0a337ff374a4btakashi extensions[i].name = p_strdup(mem_map->extension_pool,
0237f43ab925775250e266e479d0a337ff374a4btakashi extensions[i].name);
0237f43ab925775250e266e479d0a337ff374a4btakashi }
0237f43ab925775250e266e479d0a337ff374a4btakashi }
0237f43ab925775250e266e479d0a337ff374a4btakashi
0237f43ab925775250e266e479d0a337ff374a4btakashi /* copy keyword map */
9da97ff0bac3a0ff56a9cdebe6e5ab563636aa86jailletc if (array_is_created(&map->keyword_idx_map)) {
0237f43ab925775250e266e479d0a337ff374a4btakashi i_array_init(&mem_map->keyword_idx_map,
0237f43ab925775250e266e479d0a337ff374a4btakashi array_count(&map->keyword_idx_map) + 4);
0237f43ab925775250e266e479d0a337ff374a4btakashi array_append_array(&mem_map->keyword_idx_map,
9f42bcd0c49a1e8ca25cdc601eeafb0f09529dd1trawick &map->keyword_idx_map);
9f42bcd0c49a1e8ca25cdc601eeafb0f09529dd1trawick }
0237f43ab925775250e266e479d0a337ff374a4btakashi
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand return mem_map;
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand}
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrandvoid mail_index_record_map_move_to_private(struct mail_index_map *map)
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand{
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand struct mail_index_record_map *new_map;
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand if (array_count(&map->rec_map->maps) == 1)
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand return;
0237f43ab925775250e266e479d0a337ff374a4btakashi
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand new_map = mail_index_record_map_alloc(map);
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_map_copy_records(new_map, map->rec_map,
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand map->hdr.record_size);
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_record_map_unlink(map);
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand map->rec_map = new_map;
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand}
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrandvoid mail_index_map_move_to_memory(struct mail_index_map *map)
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand{
a5aa843d28798d8c35a8f6bffef1c4a9df211a01kbrand struct mail_index_record_map *new_map;
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand if (map->rec_map->mmap_base == NULL)
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand return;
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand i_assert(map->rec_map->lock_id != 0);
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand new_map = array_count(&map->rec_map->maps) == 1 ? map->rec_map :
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_record_map_alloc(map);
4aa603e6448b99f9371397d439795c91a93637eand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_map_copy_records(new_map, map->rec_map,
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand map->hdr.record_size);
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_map_copy_header(map, map);
4aa603e6448b99f9371397d439795c91a93637eand
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand if (new_map != map->rec_map) {
434a9abc415b2a75ad9ac513ff5ffccedbb3c1e9kbrand mail_index_record_map_unlink(map);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd map->rec_map = new_map;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd } else {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_unlock(map->index, &new_map->lock_id);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (munmap(new_map->mmap_base, new_map->mmap_size) < 0)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd mail_index_set_syscall_error(map->index, "munmap()");
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd new_map->mmap_base = NULL;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd }
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd}
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndbool mail_index_map_get_ext_idx(struct mail_index_map *map,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd uint32_t ext_id, uint32_t *idx_r)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const uint32_t *id;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (!array_is_created(&map->ext_id_map) ||
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ext_id >= array_count(&map->ext_id_map))
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return FALSE;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive id = array_idx(&map->ext_id_map, ext_id);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive *idx_r = *id;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return *idx_r != (uint32_t)-1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive