mail-index-map.c revision 746d35bf3dba3ae5ddbcecb9732f60d5e9de77ef
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (C) 2003-2007 Timo Sirainen */
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomistatic void mail_index_map_init_extbufs(struct mail_index_map *map,
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_index_ext) + sizeof(uint32_t))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* try to use the existing pool's size for initial_count so
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen we don't grow it unneededly */
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen size = p_get_max_easy_alloc_size(map->extension_pool);
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen p_array_init(&map->extensions, map->extension_pool, initial_count);
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenbool mail_index_map_lookup_ext(struct mail_index_map *map, const char *name,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen unsigned int i, size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen extensions = array_get(&map->extensions, &size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < size; i++) {
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi size_t size = sizeof(struct mail_index_ext_header) + name_len;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomimail_index_map_register_ext(struct mail_index_map *map, const char *name,
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen i_assert(!mail_index_map_lookup_ext(map, name, NULL));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext->name = p_strdup(map->extension_pool, name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext->hdr_offset = ext_offset + get_ext_size(strlen(name));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext->index_idx = mail_index_ext_register(map->index, name, hdr_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Update index ext_id -> map ext_id mapping. Fill non-used
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext_ids with (uint32_t)-1 */
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen while (array_count(&map->ext_id_map) < ext->index_idx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&map->ext_id_map, &empty_idx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainenint mail_index_map_ext_get_next(struct mail_index_map *map,
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen unsigned int *offset_p,
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen const struct mail_index_ext_header **ext_hdr_r,
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen const char **name_r)
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen /* Extension header contains:
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen - struct mail_index_ext_header
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen - name (not 0-terminated)
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen - 64bit alignment padding
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen - extension header contents
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen - 64bit alignment padding
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen if (offset + sizeof(*ext_hdr) >= map->hdr.header_size)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen *name_r = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen if (strcmp(*name_r, str_sanitize(*name_r, -1)) != 0) {
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen /* we allow only plain ASCII names, so this extension
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen is most likely broken */
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen /* finally make sure that the hdr_size is small enough.
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen do this last so that we could return a usable name. */
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainenint mail_index_map_ext_hdr_check(const struct mail_index_header *hdr,
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen (ext_hdr->record_align == 0 && ext_hdr->record_size != 0)) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (ext_hdr->record_offset + ext_hdr->record_size > hdr->record_size) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen *error_r = t_strdup_printf("Record field points "
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen "outside record size (%u+%u > %u)",
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen (hdr->record_size % ext_hdr->record_align) != 0)) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen *error_r = t_strdup_printf("Record field alignmentation %u "
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenstatic int mail_index_map_parse_extensions(struct mail_index_map *map)
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen /* extension headers always start from 64bit offsets, so if base header
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen doesn't happen to be 64bit aligned we'll skip some bytes */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* nothing to do, skip allocatations and all */
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen for (i = 0; i < old_count; i++)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (i = 0; offset < map->hdr.header_size; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "Header extension #%d (%s) goes outside header",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen "Broken extension #%d (%s): %s",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (mail_index_map_lookup_ext(map, name, NULL)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Duplicate header extension %s",
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen mail_index_map_register_ext(map, name, ext_offset,
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainenint mail_index_map_parse_keywords(struct mail_index_map *map)
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen const struct mail_index_keyword_header *kw_hdr;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen unsigned int i, name_area_end_offset, old_count;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &idx)) {
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen /* Extension header contains:
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen - struct mail_index_keyword_header
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen - struct mail_index_keyword_header_rec * keywords_count
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen - const char names[] * keywords_count
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen i_assert(ext->hdr_offset < map->hdr.header_size);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen /* Keywords can only be added into same mapping. Removing requires a
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen new mapping (recreating the index file) */
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen /* nothing changed */
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen /* make sure the header is valid */
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen "Keywords removed unexpectedly",
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen "keywords_count larger than header size",
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen for (i = 0; i < kw_hdr->keywords_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (kw_rec[i].name_offset > name_area_end_offset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "name_offset points outside allocated header",
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen "Keyword header doesn't end with NUL",
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen /* create file -> index mapping */
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen /* Check that existing headers are still the same. It's behind DEBUG
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen since it's pretty useless waste of CPU normally. */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *keyword = name + kw_rec[i].name_offset;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen const unsigned int *old_idx;
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen unsigned int idx;
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen old_idx = array_idx(&map->keyword_idx_map, i);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (!mail_index_keyword_lookup(index, keyword, &idx) ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen "Keywords changed unexpectedly",
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen /* Register the newly seen keywords */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen const char *keyword = name + kw_rec[i].name_offset;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen unsigned int idx;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen "Empty keyword name in header",
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen mail_index_keyword_lookup_or_create(index, keyword, &idx);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainenstatic bool mail_index_check_header_compat(struct mail_index *index,
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen enum mail_index_header_compat_flags compat_flags = 0;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* major version change - handle silently(?) */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* we've already complained about it */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* architecture change */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen mail_index_set_error(index, "Rebuilding index file %s: "
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen "CPU architecture changed",
bb86f8f22f2561438ce710d2113f04a4d0082b50Timo Sirainen if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen "Corrupted header sizes (base %u, full %u)",
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen "indexid changed: %u -> %u",
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen mail_transaction_log_indexid_changed(index->log);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainenint mail_index_map_check_header(struct mail_index_map *map)
dad1d7b721e80a7e6c0282ace93aef86312fa579Timo Sirainen const struct mail_index_header *hdr = &map->hdr;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* following some extra checks that only take a bit of CPU */
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen sizeof(struct mail_index_record));
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1)
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (hdr->messages_count > map->rec_map->records_count)
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (hdr->seen_messages_count > hdr->messages_count ||
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen hdr->deleted_messages_count > hdr->messages_count)
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen hdr->first_unseen_uid_lowwater > hdr->next_uid ||
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen hdr->first_deleted_uid_lowwater > hdr->next_uid)
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* last message's UID must be smaller than next_uid.
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen also make sure it's not zero. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, hdr->messages_count-1);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (rec->uid == 0 || rec->uid >= hdr->next_uid)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenstatic void mail_index_map_copy_hdr(struct mail_index_map *map,
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen if (hdr->base_header_size < sizeof(map->hdr)) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* header smaller than ours, make a copy so our newer headers
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen won't have garbage in them */
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen memcpy(&map->hdr, hdr, hdr->base_header_size);
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen /* FIXME: backwards compatibility, remove later. In case this index is
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen accessed with Dovecot v1.0, avoid recent message counter errors. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen map->hdr.unused_old_recent_messages_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mail_index_mmap(struct mail_index_map *map, uoff_t file_size)
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen struct mail_index_record_map *rec_map = map->rec_map;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* too large file to map into memory */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen mail_index_set_error(index, "Index file too large: %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec_map->mmap_base = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen mail_index_set_syscall_error(index, "mmap()");
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi offsetof(struct mail_index_header, major_version) &&
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi /* major version change - handle silently */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rec_map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) {
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen /* Can't use this file */
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (rec_map->mmap_used_size <= rec_map->mmap_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen "messages_count too large (%u > %u)",
a835194f9a9dae88528367a791cbc282589f6c01Timo Sirainen rec_map->records = PTR_OFFSET(rec_map->mmap_base, map->hdr.header_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mail_index_read_header(struct mail_index *index,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen memset(buf, 0, sizeof(struct mail_index_header));
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen /* try to read the whole header, but it's not necessarily an error to
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen read less since the older versions of the index format could be
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen smaller. Request reading up to buf_size, but accept if we only got
17018da24e7dbb419c5047c316caadcb2fc5364aTimo Sirainen the header. */
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen } while (ret > 0 && pos < sizeof(struct mail_index_header));
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainenmail_index_try_read_map(struct mail_index_map *map,
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen uoff_t file_size, bool *retry_r, bool try_retry)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const void *buf;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen size_t pos, records_size, initial_buf_pos = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_index_read_header(index, read_buf, sizeof(read_buf), &pos);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen /* major version change - handle silently */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mail_index_check_header_compat(index, hdr, file_size)) {
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen /* Can't use this file */
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen /* place the base header into memory. */
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen /* @UNSAFE: read the rest of the header into memory */
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen data = buffer_append_space_unsafe(map->hdr_copy_buf,
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen /* header read, read the records now. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen records_size = (size_t)hdr->messages_count * hdr->record_size;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen if (file_size - hdr->header_size < records_size ||
5bdad39213d28ab35e615a7f4ea1712ab25b6a80Timo Sirainen records_size / hdr->record_size != hdr->messages_count)) {
5bdad39213d28ab35e615a7f4ea1712ab25b6a80Timo Sirainen records_count = (file_size - hdr->header_size) /
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen records_size = (size_t)records_count * hdr->record_size;
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen "messages_count too large (%u > %u)",
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen /* @UNSAFE */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen buffer_set_used_size(map->rec_map->buffer, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = buffer_append_space_unsafe(map->rec_map->buffer,
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen ret = pread_full(index->fd, data, records_size - extra,
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen /* a new index file was renamed over this one. */
1c0590b2729567ad60dafde4d2c5f19635755a3dTimo Sirainen mail_index_set_syscall_error(index, "pread_full()");
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen "Corrupted index file %s: File too small",
84da9c6d6e162b064608cbfa9a47e0d60553c593Timo Sirainen buffer_get_modifiable_data(map->rec_map->buffer, NULL);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_index_read_map(struct mail_index_map *map, uoff_t file_size)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen mail_index_sync_lost_handler_t *const *handlers;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen unsigned int i, count;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen /* notify all "sync lost" handlers */
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen for (i = 0; i < count; i++)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen for (i = 0;; i++) {
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen try_retry = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen /* fstat() below failed */
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen /* ESTALE - reopen index file */
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen mail_index_set_syscall_error(index, "close()");
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen /* the file was lost */
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen mail_index_set_syscall_error(index, "open()");
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen mail_index_set_syscall_error(index, "fstat()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_index_header_init(struct mail_index *index,
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen i_assert((sizeof(*hdr) % sizeof(uint64_t)) == 0);
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainen hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainen hdr->record_size = sizeof(struct mail_index_record);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen hdr->compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainenstruct mail_index_map *mail_index_map_alloc(struct mail_index *index)
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen /* a bit kludgy way to do this, but it initializes everything
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen nicely and correctly */
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainenstatic int mail_index_map_latest_file(struct mail_index *index)
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen unsigned int lock_id;
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen /* the index file is lost/broken. let's hope that we can
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen build it from the transaction log. */
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen /* the index file is still open, lock it */
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen if (mail_index_lock_shared(index, &lock_id) < 0)
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen nfs_flush_attr_cache_fd(index->filepath, index->fd);
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen mail_index_set_syscall_error(index, "fstat()");
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen /* mmaping seems to be slower than just reading the file, so even if
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen mmap isn't disabled don't use it unless the file is large enough */
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen use_mmap = !index->mmap_disable && file_size != (uoff_t)-1 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_index_read_map(new_map, file_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure the header is ok before using this mapping */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_index_map_parse_extensions(new_map) < 0)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen else if (mail_index_map_parse_keywords(new_map) < 0)
128ea07dab8d67124ea74bcc085a478784b6358aTimo Sirainen /* fsck and try again */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* fsck replaced the map */
8fa86f7ef06aa6cf0239c7ca2eb98889691d40d4Timo Sirainen index->last_read_log_file_seq = new_map->hdr.log_file_seq;
ret = 0;
if (ret == 0) {
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;