mail-index-map.c revision 5806683c1c3f5b1997e92a023c0fe39912d4df5d
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenvoid 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))
221351ed85c839e0b03d82c47654c3d17202e3dbTimo Sirainen pool_alloconly_create(MEMPOOL_GROWING"map extensions",
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);
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainenbool mail_index_map_lookup_ext(struct mail_index_map *map, const char *name,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, size;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen extensions = array_get(&map->extensions, &size);
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen for (i = 0; i < size; i++) {
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainenunsigned int mail_index_map_ext_hdr_offset(unsigned int name_len)
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen size_t size = sizeof(struct mail_index_ext_header) + name_len;
3675a7e9bd3775ba13fe8bc93915902513a0f1a4Timo Sirainenmail_index_map_register_ext(struct mail_index_map *map,
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen i_assert(!mail_index_map_lookup_ext(map, name, NULL));
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ext->name = p_strdup(map->extension_pool, name);
3675a7e9bd3775ba13fe8bc93915902513a0f1a4Timo Sirainen ext->index_idx = mail_index_ext_register(map->index, name,
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);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenint mail_index_map_ext_get_next(struct mail_index_map *map,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen unsigned int *offset_p,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen const struct mail_index_ext_header **ext_hdr_r,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen const char **name_r)
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen /* Extension header contains:
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen - struct mail_index_ext_header
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen - name (not 0-terminated)
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen - 64bit alignment padding
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen - extension header contents
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen - 64bit alignment padding
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen if (offset + sizeof(*ext_hdr) >= map->hdr.header_size)
8ababf3e7b15f793370d1dedf85825d38b42633fTimo Sirainen offset += mail_index_map_ext_hdr_offset(ext_hdr->name_size);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen *name_r = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen if (strcmp(*name_r, str_sanitize(*name_r, -1)) != 0) {
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen /* we allow only plain ASCII names, so this extension
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen is most likely broken */
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen /* finally make sure that the hdr_size is small enough.
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen do this last so that we could return a usable name. */
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainenint mail_index_map_ext_hdr_check(const struct mail_index_header *hdr,
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen (ext_hdr->record_align == 0 && ext_hdr->record_size != 0)) {
f46068919d4b3e1f36028c4182108c169f914019Timo Sirainen /* if we get here from extension introduction, record_offset=0 and
f46068919d4b3e1f36028c4182108c169f914019Timo Sirainen hdr->record_size hasn't been updated yet */
f46068919d4b3e1f36028c4182108c169f914019Timo Sirainen ext_hdr->record_offset + ext_hdr->record_size > hdr->record_size) {
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen *error_r = t_strdup_printf("Record field points "
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen "outside record size (%u+%u > %u)",
6c9699d37fbe4d8af3682ee7f341ede8d54faa87Timo Sirainen (ext_hdr->record_offset % ext_hdr->record_align) != 0) {
9573f4283f9118315b0865998d43223fedee0246Timo Sirainen *error_r = t_strdup_printf("Record field alignment %u "
6c9699d37fbe4d8af3682ee7f341ede8d54faa87Timo Sirainen (hdr->record_size % ext_hdr->record_align) != 0) {
6c9699d37fbe4d8af3682ee7f341ede8d54faa87Timo Sirainen *error_r = t_strdup_printf("Record size not aligned by %u "
6c9699d37fbe4d8af3682ee7f341ede8d54faa87Timo Sirainen "as required by extension",
ed50658501d9ae8c85f6264831056b1debed11c3Timo Sirainen if (ext_hdr->hdr_size > MAIL_INDEX_EXT_HEADER_MAX_SIZE) {
ed50658501d9ae8c85f6264831056b1debed11c3Timo Sirainen *error_r = t_strdup_printf("Headersize too large (%u)",
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);
91add6e26ed2b91e15276c96ffe02d9f71476d71Timo Sirainen /* FIXME: backwards compatibility, remove later. In case this index is
91add6e26ed2b91e15276c96ffe02d9f71476d71Timo Sirainen accessed with Dovecot v1.0, avoid recent message counter errors. */
91add6e26ed2b91e15276c96ffe02d9f71476d71Timo Sirainen map->hdr.unused_old_recent_messages_count = 0;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int mail_index_mmap(struct mail_index_map *map, uoff_t file_size)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen struct mail_index_record_map *rec_map = map->rec_map;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* too large file to map into memory */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(index, "Index file too large: %s",
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen rec_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 */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (rec_map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Can't use this file */
2aa3ac8bfb8fea49fd0ab6d56afcb3af3375d22cTimo Sirainen if (rec_map->mmap_used_size <= rec_map->mmap_size)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "messages_count too large (%u > %u)",
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen rec_map->records = PTR_OFFSET(rec_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) /
2aa3ac8bfb8fea49fd0ab6d56afcb3af3375d22cTimo Sirainen records_size = (size_t)records_count * hdr->record_size;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "messages_count too large (%u > %u)",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* @UNSAFE */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen buffer_set_used_size(map->rec_map->buffer, 0);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen data = buffer_append_space_unsafe(map->rec_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",
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen buffer_get_modifiable_data(map->rec_map->buffer, NULL);
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainenstatic int mail_index_read_map(struct mail_index_map *map, uoff_t file_size,
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen unsigned int *lock_id)
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 /* the file was lost */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "open()");
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen if (mail_index_lock_shared(index, lock_id) < 0)
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 */
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen/* returns -1 = error, 0 = index files are unusable,
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen 1 = index files are usable or at least repairable */
1fd0d511885c30028aba388588151acf4ee85e75Timo 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)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen nfs_flush_attr_cache_fd_locked(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 &&
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen ret = mail_index_read_map(new_map, file_size, &lock_id);
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen /* the index files are unusable */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* make sure the header is ok before using this mapping */
746d35bf3dba3ae5ddbcecb9732f60d5e9de77efTimo Sirainen if (mail_index_map_parse_extensions(new_map) < 0)
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen else if (mail_index_map_parse_keywords(new_map) < 0)
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* fsck and try again */
180503c08ebd58174c4f7f1652d716266877e2a3Timo Sirainen /* fsck replaced the map */
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. */
2b8fab6d39e8d1dbd3d546d2577fc1caeafdd64aTimo Sirainen /* we're not creating/opening the index.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sync this as a view from transaction log. */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen ret = mail_index_sync_map(&index->map, type, FALSE);
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen /* try to open and read the latest index. if it fails, we'll
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen fallback to updating the existing mapping from transaction
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen logs (which we'll also do even if the reopening succeeds).
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen if index files are unusable (e.g. major version change)
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen don't even try to use the transaction log. */
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen /* if we're creating the index file, we don't have any
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen if (index->log->head != NULL && index->indexid != 0) {
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen /* and update the map with the latest changes
9a0c37cb8588cd287106374eda22a7ea3e2742b2Timo Sirainen from transaction log */
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen } else if (ret == 0) {
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen /* make sure we don't try to open the file again */
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen if (unlink(index->filepath) < 0 && errno != ENOENT)
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen mail_index_set_syscall_error(index, "unlink()");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic void mail_index_record_map_free(struct mail_index_map *map,
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen mail_index_unlock(map->index, &rec_map->lock_id);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (munmap(rec_map->mmap_base, rec_map->mmap_size) < 0)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_set_syscall_error(map->index, "munmap()");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic void mail_index_record_map_unlink(struct mail_index_map *map)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen unsigned int i, count;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen maps = array_get(&map->rec_map->maps, &count);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen for (i = 0; i < count; i++) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_record_map_free(map, map->rec_map);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenvoid mail_index_unmap(struct mail_index_map **_map)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic void mail_index_map_copy_records(struct mail_index_record_map *dest,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen dest->buffer = buffer_create_dynamic(default_pool, I_MIN(size, 1024));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen buffer_append(dest->buffer, src->records, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest->records = buffer_get_modifiable_data(dest->buffer, NULL);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* if the map is ever written back to disk, we need to keep track of
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen what has changed. */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic void mail_index_map_copy_header(struct mail_index_map *dest,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* 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));
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen buffer_write(dest->hdr_copy_buf, src->hdr.base_header_size,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen src->hdr.header_size - src->hdr.base_header_size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest->hdr_base = buffer_get_modifiable_data(dest->hdr_copy_buf, NULL);
5787e39e2be32f657b8c98fee8bac794aa852cf8Timo Sirainen i_assert(dest->hdr_copy_buf->used == dest->hdr.header_size);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenmail_index_record_map_alloc(struct mail_index_map *map)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen rec_map = i_new(struct mail_index_record_map, 1);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_index_map *mail_index_map_clone(const struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen mem_map->rec_map = mail_index_record_map_alloc(mem_map);
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen array_append(&mem_map->rec_map->maps, &mem_map, 1);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mem_map->write_base_header = map->write_base_header;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo 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,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* copy keyword map */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (array_is_created(&map->keyword_idx_map)) {
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenvoid mail_index_record_map_move_to_private(struct mail_index_map *map)
d0ab5936be1cd971007fc2241e0be120c442cb84Timo Sirainen mail_index_map_copy_records(new_map, map->rec_map,
90a989e4f8bcb4fb86af32cbae577402e3f92b1aTimo Sirainen new_map->modseq = mail_index_map_modseq_clone(map->rec_map->modseq);
d0ab5936be1cd971007fc2241e0be120c442cb84Timo Sirainen if (new_map->records_count != map->hdr.messages_count) {
d0ab5936be1cd971007fc2241e0be120c442cb84Timo Sirainen new_map->records_count = map->hdr.messages_count;
d0ab5936be1cd971007fc2241e0be120c442cb84Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, new_map->records_count-1);
d0ab5936be1cd971007fc2241e0be120c442cb84Timo Sirainen buffer_set_used_size(new_map->buffer, new_map->records_count *
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_index_map_move_to_memory(struct mail_index_map *map)
7de1c472fd23ddac6b4dc5cbeee6fa6a8418b071Timo Sirainen new_map->modseq = map->rec_map->modseq == NULL ? NULL :
7de1c472fd23ddac6b4dc5cbeee6fa6a8418b071Timo Sirainen mail_index_map_modseq_clone(map->rec_map->modseq);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_map_copy_records(new_map, map->rec_map,
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen mail_index_unlock(map->index, &new_map->lock_id);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (munmap(new_map->mmap_base, new_map->mmap_size) < 0)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_set_syscall_error(map->index, "munmap()");