mail-index.c revision 3ec64baf598256c4a2b652899982ea235440a1d4
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mail_index_try_open_only(struct mail_index *index);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenstatic void mail_index_create_in_memory(struct mail_index *index,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch pool_alloconly_create(MEMPOOL_GROWING"index extension", 1024);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch p_array_init(&index->extensions, index->extension_pool, 5);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch array_create(&index->mail_index_module_contexts, default_pool,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch sizeof(void *), I_MIN(5, mail_index_module_id));
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch mail_index_ext_register(index, "keywords", 128, 2, 1);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch index->keywords_pool = pool_alloconly_create("keywords", 512);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch hash_create(default_pool, index->keywords_pool, 0,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch strcase_hash, (hash_cmp_callback_t *)strcasecmp);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschvoid mail_index_free(struct mail_index **_index)
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen array_free(&index->mail_index_module_contexts);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const struct mail_index_registered_ext *extensions;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int i, ext_count;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen extensions = array_get(&index->extensions, &ext_count);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen /* see if it's already there */
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen for (i = 0; i < ext_count; i++) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen rext.name = p_strdup(index->extension_pool, name);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen i_assert(rext->expunge_handler == NULL || rext->expunge_handler == cb);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen rext->expunge_handler_call_always = call_always;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid mail_index_unregister_expunge_handler(struct mail_index *index,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen rext = array_idx_modifiable(&index->extensions, ext_id);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch rext = array_idx_modifiable(&index->extensions, ext_id);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(rext->sync_handler.callback == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid mail_index_unregister_sync_handler(struct mail_index *index,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch rext = array_idx_modifiable(&index->extensions, ext_id);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch i_assert(rext->sync_handler.callback != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid mail_index_register_sync_lost_handler(struct mail_index *index,
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch array_append(&index->sync_lost_handlers, &cb, 1);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Boschvoid mail_index_unregister_sync_lost_handler(struct mail_index *index,
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch mail_index_sync_lost_handler_t *const *handlers;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch unsigned int i, count;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch handlers = array_get(&index->sync_lost_handlers, &count);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch for (i = 0; i < count; i++) {
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen array_delete(&index->sync_lost_handlers, i, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mail_index_map_init_extbufs(struct mail_index_map *map,
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen sizeof(struct mail_index_ext) + sizeof(uint32_t))
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen /* try to use the existing pool's size for initial_count so
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen we don't grow it unneededly */
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen size = p_get_max_easy_alloc_size(map->extension_pool);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen p_array_init(&map->extensions, map->extension_pool, initial_count);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenuint32_t mail_index_map_lookup_ext(struct mail_index_map *map, const char *name)
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen unsigned int i, size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen extensions = array_get(&map->extensions, &size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < size; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_index_map_register_ext(struct mail_index *index,
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen i_assert(mail_index_map_lookup_ext(map, name) == (uint32_t)-1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ext->name = p_strdup(map->extension_pool, name);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ext->index_idx = mail_index_ext_register(index, name, hdr_size,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* Update index ext_id -> map ext_id mapping. Fill non-used
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ext_ids with (uint32_t)-1 */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (array_count(&map->ext_id_map) < ext->index_idx)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen array_append(&map->ext_id_map, &empty_idx, 1);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool size_check(size_t *size_left, size_t size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t size = sizeof(struct mail_index_ext_header) + name_len;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return MAIL_INDEX_HEADER_SIZE_ALIGN(size) - size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mail_index_parse_extensions(struct mail_index *index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int i, old_count;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* extension headers always start from 64bit offsets, so if base header
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen doesn't happen to be 64bit aligned we'll skip some bytes */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen /* nothing to do, skip allocatations and all */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < old_count; i++)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* Extension header contains:
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen - struct mail_index_ext_header
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen - name (not 0-terminated)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen - 64bit alignment padding
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen - extension header contents
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen - 64bit alignment padding
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!size_check(&size_left, sizeof(*ext_hdr)) ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen !size_check(&size_left, ext_hdr->name_size) ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen !size_check(&size_left, get_align(ext_hdr->name_size)) ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Header extension goes outside header",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen offset += ext_hdr->name_size + get_align(ext_hdr->name_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen name = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail_index_map_lookup_ext(map, name) != (uint32_t)-1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen "Duplicate header extension %s",
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen ext_hdr->record_offset + ext_hdr->record_size) {
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen "Record field %s points outside record size "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ext_hdr->record_offset, ext_hdr->record_size);
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen if ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (map->hdr.record_size % ext_hdr->record_align) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Record field %s alignmentation %u not used",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index->filepath, name, ext_hdr->record_align);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenbool mail_index_keyword_lookup(struct mail_index *index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int *idx_r)
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen /* keywords_hash keeps a name => index mapping of keywords.
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen Keywords are never removed from it, so the index values are valid
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen for the lifetime of the mail_index. */
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen if (hash_lookup_full(index->keywords_hash, keyword, NULL, &value)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *idx_r = POINTER_CAST_TO(value, unsigned int);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen hash_insert(index->keywords_hash, keyword_dup, POINTER_CAST(*idx_r));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint mail_index_map_parse_keywords(struct mail_index *index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_index_keyword_header *kw_hdr;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int i, name_area_end_offset, old_count;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen /* Extension header contains:
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen - struct mail_index_keyword_header
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen - struct mail_index_keyword_header_rec * keywords_count
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen - const char names[] * keywords_count
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen i_assert(ext->hdr_offset < map->hdr.header_size);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* Keywords can only be added into same mapping. Removing requires a
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen new mapping (recreating the index file) */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* nothing changed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* make sure the header is valid */
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Keywords removed unexpectedly",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen "keywords_count larger than header size",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name;
280503e88a6b2f72a32a8fbe363794abaaa845d6Timo Sirainen for (i = 0; i < kw_hdr->keywords_count; i++) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (kw_rec[i].name_offset > name_area_end_offset) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "name_offset points outside allocated header",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Keyword header doesn't end with NUL",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* create file -> index mapping */
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count);
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen /* Check that existing headers are still the same. It's behind DEBUG
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen since it's pretty useless waste of CPU normally. */
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *keyword = name + kw_rec[i].name_offset;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned int *old_idx;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen unsigned int idx;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen old_idx = array_idx(&map->keyword_idx_map, i);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!mail_index_keyword_lookup(index, keyword, FALSE, &idx) ||
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Keywords changed unexpectedly",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* Register the newly seen keywords */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const char *keyword = name + kw_rec[i].name_offset;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen unsigned int idx;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen (void)mail_index_keyword_lookup(index, keyword, TRUE, &idx);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschconst ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* Make sure all the keywords are in index->keywords. It's quick to do
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if nothing has changed. */
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch (void)mail_index_map_parse_keywords(index, index->map);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschstatic int mail_index_check_header(struct mail_index *index,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const struct mail_index_header *hdr = &map->hdr;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch enum mail_index_header_compat_flags compat_flags = 0;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* major version change - handle silently(?) */
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* architecture change - handle silently(?) */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* we've already complained about it */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* following some extra checks that only take a bit of CPU */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "uid_validity = 0, next_uid = %u",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen sizeof(struct mail_index_record));
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (hdr->recent_messages_count > hdr->messages_count ||
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen hdr->seen_messages_count > hdr->messages_count ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen hdr->deleted_messages_count > hdr->messages_count)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (hdr->first_recent_uid_lowwater > hdr->next_uid ||
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen hdr->first_unseen_uid_lowwater > hdr->next_uid ||
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen hdr->first_deleted_uid_lowwater > hdr->next_uid)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* last message's UID must be smaller than next_uid.
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen also make sure it's not zero. */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, map->records_count-1);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (rec->uid == 0 || rec->uid >= hdr->next_uid)
7fa573e6ea36024f618492e7d3649a69c1b41028Timo Sirainen return mail_index_parse_extensions(index, map);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainenstatic void mail_index_map_clear(struct mail_index *index,
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen mail_index_set_syscall_error(index, "munmap()");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid mail_index_unmap(struct mail_index *index, struct mail_index_map **_map)
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainenstatic void mail_index_map_copy_hdr(struct mail_index_map *map,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (hdr->base_header_size < sizeof(map->hdr)) {
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen /* header smaller than ours, make a copy so our newer headers
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen won't have garbage in them */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memcpy(&map->hdr, hdr, hdr->base_header_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mail_index_mmap(struct mail_index *index, struct mail_index_map *map)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we had temporarily used a buffer, eg. for updating index */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_syscall_error(index, "mmap()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen offsetof(struct mail_index_header, major_version) &&
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* major version change - handle silently */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen records_count = (map->mmap_size - hdr->header_size) /
63e376747537cb2dfaa0e36d1bafd19df1443a4eTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "messages_count too large (%u > %u)",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen map->records = PTR_OFFSET(map->mmap_base, map->hdr.header_size);
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainenstatic int mail_index_read_header(struct mail_index *index,
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen memset(buf, 0, sizeof(struct mail_index_header));
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* try to read the whole header, but it's not necessarily an error to
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen read less since the older versions of the index format could be
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch smaller. Request reading up to buf_size, but accept if we only got
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen the header. */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen } while (ret > 0 && pos < sizeof(struct mail_index_header));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_index_read_map(struct mail_index *index, struct mail_index_map *map,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen ret = mail_index_read_header(index, buf, sizeof(buf), &pos);
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen /* major version change - handle silently */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_syscall_error(index, "fstat()");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Corrupted header sizes (base %u, full %u)",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* place the base header into memory. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* @UNSAFE: read the rest of the header into memory */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data = buffer_append_space_unsafe(map->hdr_copy_buf,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* header read, read the records now. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen records_size = (size_t)hdr->messages_count * hdr->record_size;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if ((uoff_t)st.st_size - hdr->header_size < records_size ||
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen records_size / hdr->messages_count != hdr->record_size) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen records_count = (st.st_size - hdr->header_size) /
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "messages_count too large (%u > %u)",
if (ret < 0) {
if (ret == 0) {
&prev_offset);
bool sync_to_index)
const void *tdata;
int ret;
if (sync_to_index) {
MAIL_TRANSACTION_TYPE_MASK) <= 0) {
&skipped)) > 0) {
ret = 0;
&prev_offset);
return ret;
bool sync_to_index)
unsigned int i, count;
int ret;
bool retry;
if (ret != 0)
return ret;
for (i = 0; i < count; i++)
return ret;
if (ret <= 0) {
if (ret == 0) {
int ret;
if (ret > 0)
int ret;
if (ret != 0) {
return ret;
if (ret > 0) {
if (ret < 0)
ret = 0;
else if (ret == 0) {
if (ret <= 0) {
return ret;
int ret;
if (ret > 0)
return ret;
&pos);
if (ret <= 0) {
if (ret == 0) {
if (ret < 0)
return ret;
struct mail_index_map *
unsigned int i, count;
for (i = 0; i < count; i++) {
return mem_map;
unsigned int lock_id;
int ret;
*lock_id_r = 0;
if (ret <= 0)
return ret;
if (ret == 0) {
*lock_id_r = 0;
return ret;
const char *path;
int fd;
return fd;
const char *path;
int ret;
if (ret != 0) {
/* create it fully in index.tmp first */
if (ret == 0) {
if (ret < 0) {
return ret;
#ifndef WORDS_BIGENDIAN
unsigned int lock_id = 0;
int ret;
if (ret > 0)
else if (ret == 0) {
} else if (ret < 0)
if (ret == 0)
if (lock_id != 0) {
lock_id = 0;
if (lock_id == 0) {
int i = 0, ret;
if (ret <= 0)
if (ret == 0) {
if (ret <= 0)
return ret;
ret = 0;
if (ret > 0)
else if (ret == 0) {
if (ret == 0) {
if (lock_id != 0)
if (ret == 0) {
return ret;
unsigned int lock_id;
int ret;
int ret = 0;
return ret;
const char *function)
const char *filepath,
const char *function)
return MAIL_INDEX_ERROR_DISKSPACE;
return MAIL_INDEX_ERROR_INTERNAL;
return MAIL_INDEX_ERROR_NONE;