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