mail-index-map.c revision 1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen/* Copyright (C) 2003-2007 Timo Sirainen */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic void mail_index_map_init_extbufs(struct mail_index_map *map,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen sizeof(struct mail_index_ext) + sizeof(uint32_t))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* try to use the existing pool's size for initial_count so
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen we don't grow it unneededly */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen size = p_get_max_easy_alloc_size(map->extension_pool);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen p_array_init(&map->extensions, map->extension_pool, initial_count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenuint32_t mail_index_map_lookup_ext(struct mail_index_map *map, const char *name)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, size;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen extensions = array_get(&map->extensions, &size);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < size; i++) {
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenmail_index_map_register_ext(struct mail_index_map *map, const char *name,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(mail_index_map_lookup_ext(map, name) == (uint32_t)-1);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext->name = p_strdup(map->extension_pool, name);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen ext->index_idx = mail_index_ext_register(map->index, name, hdr_size,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Update index ext_id -> map ext_id mapping. Fill non-used
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext_ids with (uint32_t)-1 */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen while (array_count(&map->ext_id_map) < ext->index_idx)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen array_append(&map->ext_id_map, &empty_idx, 1);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic bool size_check(size_t *size_left, size_t size)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen size_t size = sizeof(struct mail_index_ext_header) + name_len;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return MAIL_INDEX_HEADER_SIZE_ALIGN(size) - size;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int mail_index_parse_extensions(struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, old_count;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* extension headers always start from 64bit offsets, so if base header
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen doesn't happen to be 64bit aligned we'll skip some bytes */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* nothing to do, skip allocatations and all */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < old_count; i++)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0; offset < map->hdr.header_size; i++) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Extension header contains:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen - struct mail_index_ext_header
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen - name (not 0-terminated)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen - 64bit alignment padding
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen - extension header contents
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen - 64bit alignment padding
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (!size_check(&size_left, sizeof(*ext_hdr)) ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen !size_check(&size_left, ext_hdr->name_size) ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen !size_check(&size_left, get_align(ext_hdr->name_size)) ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Header extension goes outside header",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen offset += ext_hdr->name_size + get_align(ext_hdr->name_size);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen name = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_map_lookup_ext(map, name) != (uint32_t)-1) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Duplicate header extension %s",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen (ext_hdr->record_align == 0 && ext_hdr->record_size != 0) ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "Broken header extension %s",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext_hdr->record_offset + ext_hdr->record_size) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Record field %s points outside record size "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext_hdr->record_offset, ext_hdr->record_size);
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen (map->hdr.record_size % ext_hdr->record_align) != 0)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Record field %s alignmentation %u not used",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->filepath, name, ext_hdr->record_align);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic bool mail_index_check_header_compat(struct mail_index *index,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen enum mail_index_header_compat_flags compat_flags = 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* major version change - handle silently(?) */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we've already complained about it */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* architecture change */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Rebuilding index file %s: "
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "CPU architecture changed",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "Corrupted header sizes (base %u, full %u)",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen "indexid changed: %u -> %u",
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen mail_transaction_log_indexid_changed(index->log);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int mail_index_check_header(struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen const struct mail_index_header *hdr = &map->hdr;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* following some extra checks that only take a bit of CPU */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "uid_validity = 0, next_uid = %u",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen sizeof(struct mail_index_record));
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (hdr->seen_messages_count > hdr->messages_count ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->deleted_messages_count > hdr->messages_count)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->first_unseen_uid_lowwater > hdr->next_uid ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->first_deleted_uid_lowwater > hdr->next_uid)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* last message's UID must be smaller than next_uid.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen also make sure it's not zero. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, map->records_count-1);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (rec->uid == 0 || rec->uid >= hdr->next_uid)
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic void mail_index_map_clear(struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen mail_index_set_syscall_error(map->index, "munmap()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic void mail_index_map_copy_hdr(struct mail_index_map *map,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (hdr->base_header_size < sizeof(map->hdr)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* header smaller than ours, make a copy so our newer headers
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen won't have garbage in them */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen memcpy(&map->hdr, hdr, hdr->base_header_size);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int mail_index_mmap(struct mail_index_map *map, uoff_t file_size)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* we had temporarily used a buffer, eg. for updating index */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* too large file to map into memory */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Index file too large: %s",
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainen map->mmap_base = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "mmap()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen offsetof(struct mail_index_header, major_version) &&
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* major version change - handle silently */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_check_header_compat(index, hdr, map->mmap_size)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Can't use this file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen records_count = (map->mmap_size - hdr->header_size) /
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "messages_count too large (%u > %u)",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen map->records = PTR_OFFSET(map->mmap_base, map->hdr.header_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int mail_index_read_header(struct mail_index *index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen memset(buf, 0, sizeof(struct mail_index_header));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* try to read the whole header, but it's not necessarily an error to
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen read less since the older versions of the index format could be
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen smaller. Request reading up to buf_size, but accept if we only got
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen the header. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } while (ret > 0 && pos < sizeof(struct mail_index_header));
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenmail_index_try_read_map(struct mail_index_map *map,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uoff_t file_size, bool *retry_r, bool try_retry)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const void *buf;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen size_t pos, records_size, initial_buf_pos = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_index_read_header(index, read_buf, sizeof(read_buf), &pos);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* major version change - handle silently */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_check_header_compat(index, hdr, file_size)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Can't use this file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* place the base header into memory. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* @UNSAFE: read the rest of the header into memory */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen data = buffer_append_space_unsafe(map->hdr_copy_buf,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* header read, read the records now. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen records_size = (size_t)hdr->messages_count * hdr->record_size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file_size - hdr->header_size < records_size ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen records_size / hdr->record_size != hdr->messages_count)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen records_count = (file_size - hdr->header_size) /
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "messages_count too large (%u > %u)",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen map->buffer = buffer_create_dynamic(default_pool,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* @UNSAFE */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = buffer_append_space_unsafe(map->buffer,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = pread_full(index->fd, data, records_size - extra,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* a new index file was renamed over this one. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "pread_full()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Corrupted index file %s: File too small",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->records = buffer_get_modifiable_data(map->buffer, NULL);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int mail_index_read_map(struct mail_index_map *map, uoff_t file_size)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_lost_handler_t *const *handlers;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* notify all "sync lost" handlers */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen handlers = array_get(&index->sync_lost_handlers, &count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < count; i++)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0;; i++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen try_retry = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* fstat() below failed */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* ESTALE - reopen index file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "close()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* the file was lost */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "open()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_syscall_error(index, "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void mail_index_header_init(struct mail_index *index,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert((sizeof(*hdr) % sizeof(uint64_t)) == 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->record_size = sizeof(struct mail_index_record);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hdr->compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_index_map *mail_index_map_alloc(struct mail_index *index)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* a bit kludgy way to do this, but it initializes everything
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen nicely and correctly */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int mail_index_map_latest_file(struct mail_index *index,
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen unsigned int lock_id;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* the index file is lost/broken. let's hope that we can
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen build it from the transaction log. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* the index file is still open, lock it */
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen if (mail_index_lock_shared(index, &lock_id) < 0)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen nfs_flush_attr_cache_fd(index->filepath, index->fd);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_syscall_error(index, "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* mmaping seems to be slower than just reading the file, so even if
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mmap isn't disabled don't use it unless the file is large enough */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen use_mmap = !index->mmap_disable && file_size != (uoff_t)-1 &&
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen ret = mail_index_read_map(new_map, file_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* make sure the header is ok before using this mapping */
8e57335924f5ff57cbd1929ec99764dc267c3312Timo Sirainen index->last_read_log_file_seq = new_map->hdr.log_file_seq;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* first try updating the existing mapping from transaction log. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we're not creating the index, or opening transaction log.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sync this as a view from transaction log. */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen ret = mail_index_sync_map(&index->map, type, FALSE);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* try to open and read the latest index. if it fails for
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen any reason, we'll fallback to updating the existing mapping
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen from transaction logs (which we'll also do even if the
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen reopening succeeds) */
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen (void)mail_index_map_latest_file(index, &index->map);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* if we're creating the index file, we don't have any
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* and update the map with the latest changes from
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen transaction log */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen ret = mail_index_sync_map(&index->map, type, TRUE);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenvoid mail_index_unmap(struct mail_index_map **_map)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenint mail_index_map_lock(struct mail_index_map *map)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen if (map->lock_id != 0 || MAIL_INDEX_MAP_IS_IN_MEMORY(map))
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainen if (mail_index_lock_shared(map->index, &map->lock_id) < 0)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenvoid mail_index_map_unlock(struct mail_index_map *map)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void mail_index_map_copy(struct mail_index_map *dest,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* copy records */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen size = src->records_count * src->hdr.record_size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest->buffer = buffer_create_dynamic(default_pool, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen buffer_append(dest->buffer, src->records, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest->records = buffer_get_modifiable_data(dest->buffer, NULL);
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen /* copy header. use src->hdr copy directly, because if we got here
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen from syncing it has the latest changes. */
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen I_MIN(sizeof(dest->hdr), src->hdr.base_header_size));
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen buffer_write(dest->hdr_copy_buf, src->hdr.base_header_size,
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen CONST_PTR_OFFSET(src->hdr_base, src->hdr.base_header_size),
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen src->hdr.header_size - src->hdr.base_header_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest->hdr_base = buffer_get_modifiable_data(dest->hdr_copy_buf, NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_index_map *mail_index_map_clone(const struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if the map is ever written back to disk, we need to keep track of
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen what has changed. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mem_map->write_seq_first = map->write_seq_first;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mem_map->write_seq_last = map->write_seq_last;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mem_map->write_base_header = map->write_base_header;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mem_map->write_ext_header = map->write_ext_header;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* copy extensions */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_map_init_extbufs(mem_map, count + 2);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen array_append_array(&mem_map->extensions, &map->extensions);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen array_append_array(&mem_map->ext_id_map, &map->ext_id_map);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* fix the name pointers to use our own pool */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen extensions = array_get_modifiable(&mem_map->extensions, &count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < count; i++) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen extensions[i].name = p_strdup(mem_map->extension_pool,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_index_map_move_to_memory(struct mail_index_map *map)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)