mail-index.c revision 0c27b881989bc2b391281650ee89a8cc4d89f5e7
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2003-2004 Timo Sirainen */
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic int mail_index_try_open_only(struct mail_index *index);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index->extension_pool = pool_alloconly_create("extension", 256);
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen index->extensions = buffer_create_dynamic(index->extension_pool, 64);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen index->sync_handlers = buffer_create_dynamic(default_pool, 64);
847caf605dc11acfb1861586b558d9cca4a85cb0Timo Sirainen index->expunge_handlers = buffer_create_dynamic(default_pool, 32);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenuint32_t mail_index_ext_register(struct mail_index *index, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen extensions = buffer_get_data(index->extensions, &ext_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen sizeof(struct mail_index_sync_handler) == ext_count);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen /* see if it's already there */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen for (i = 0; i < ext_count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ext.name = p_strdup(index->extension_pool, name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append(index->extensions, &ext, sizeof(ext));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mail_index_register_expunge_handler(struct mail_index *index,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen buffer_write(index->expunge_handlers, ext_id * sizeof(cb),
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenvoid mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen memset(&h, 0, sizeof(h));
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen buffer_write(index->sync_handlers, ext_id * sizeof(h), &h, sizeof(h));
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipekstatic void mail_index_map_init_extbufs(struct mail_index_map *map,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ext_size = initial_count * sizeof(struct mail_index_ext);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ext_id_map_size = initial_count * sizeof(uint32_t);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen map->extensions = buffer_create_dynamic(map->extension_pool, ext_size);
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek buffer_create_dynamic(map->extension_pool, ext_id_map_size);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenuint32_t mail_index_map_lookup_ext(struct mail_index_map *map, const char *name)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen extensions = buffer_get_data(map->extensions, &size);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (i = 0; i < size; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmail_index_map_register_ext(struct mail_index *index,
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen uint32_t idx, ext_id, empty_id = (uint32_t)-1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ext = buffer_append_space_unsafe(map->extensions, sizeof(*ext));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ext->name = p_strdup(map->extension_pool, name);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ext_id = mail_index_ext_register(index, name, hdr_size,
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen while (map->ext_id_map->used < ext_id * sizeof(uint32_t))
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen buffer_append(map->ext_id_map, &empty_id, sizeof(empty_id));
1728ff34ee03de825ad3aeed67d19f8ae140ee2eTimo Sirainen buffer_write(map->ext_id_map, ext_id * sizeof(uint32_t),
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int size_check(size_t *size_left, size_t size)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen size_t size = sizeof(struct mail_index_ext_header) + name_len;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen return MAIL_INDEX_HEADER_SIZE_ALIGN(size) - size;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainenstatic int mail_index_read_extensions(struct mail_index *index,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int i, old_count;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* extension headers always start from 64bit offsets, so if base header
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk doesn't happen to be 64bit aligned we'll skip some bytes */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen /* nothing to do, skip allocatations and all */
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen old_count = index->extensions->used / sizeof(struct mail_index_ext);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen mail_index_map_init_extbufs(map, old_count + 5);
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen for (i = 0; i < old_count; i++)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen buffer_append(map->ext_id_map, &ext_id, sizeof(ext_id));
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (!size_check(&size_left, sizeof(*ext_hdr)) ||
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen !size_check(&size_left, ext_hdr->name_size) ||
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen !size_check(&size_left, get_align(ext_hdr->name_size)) ||
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen "Header extension goes outside header",
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen offset += ext_hdr->name_size + get_align(ext_hdr->name_size);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen name = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic int mail_index_check_header(struct mail_index *index,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const struct mail_index_header *hdr = &map->hdr;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen unsigned char compat_data[sizeof(hdr->compat_data)];
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* major version change - handle silently(?) */
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen if (memcmp(hdr->compat_data, compat_data, sizeof(compat_data)) != 0) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* architecture change - handle silently(?) */
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen /* we've already complained about it */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* following some extra checks that only take a bit of CPU */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen "uid_validity = 0, next_uid = %u",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (hdr->keywords_mask_size != sizeof(keywords_mask_t)) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen "keywords_mask_size mismatch: %d != %d",
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen sizeof(struct mail_index_record));
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (hdr->recent_messages_count > hdr->messages_count ||
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen hdr->seen_messages_count > hdr->messages_count ||
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen hdr->deleted_messages_count > hdr->messages_count)
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (hdr->first_recent_uid_lowwater > hdr->next_uid ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen hdr->first_unseen_uid_lowwater > hdr->next_uid ||
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen hdr->first_deleted_uid_lowwater > hdr->next_uid)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return mail_index_read_extensions(index, map);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic void mail_index_map_clear(struct mail_index *index,
638600575ee95f2513c683ef09cb188f76eacd22Timo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mail_index_set_syscall_error(index, "munmap()");
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainenvoid mail_index_unmap(struct mail_index *index, struct mail_index_map *map)
7d2d0ae1131c8b632cc7e86000adaaf8c9ef42a9Timo Sirainenstatic void mail_index_unmap_forced(struct mail_index *index,
eaa2d473ed2ecdb9856cd98a33f4d3063cfaf2a1Timo Sirainenstatic void mail_index_map_copy_hdr(struct mail_index_map *map,
655fc45da67a4cfa63d9d12cf106961a1afc12b9Aki Tuomi /* header smaller than ours, make a copy so our newer headers
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen won't have garbage in them */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen memcpy(&map->hdr, hdr, hdr->base_header_size);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic int mail_index_mmap(struct mail_index *index, struct mail_index_map *map)
1728ff34ee03de825ad3aeed67d19f8ae140ee2eTimo Sirainen /* we had temporarily used a buffer, eg. for updating index */
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen mail_index_set_syscall_error(index, "mmap()");
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen offsetof(struct mail_index_header, major_version) &&
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* major version change - handle silently */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen records_count = (map->mmap_size - hdr->header_size) /
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen "messages_count too large (%u > %u)",
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen map->records = PTR_OFFSET(map->mmap_base, map->hdr.header_size);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic int mail_index_read_header(struct mail_index *index,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (pos = 0; ret > 0 && pos < sizeof(*hdr); ) {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenstatic int mail_index_read_map(struct mail_index *index,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ret = mail_index_read_header(index, &hdr, &pos);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen hdr.major_version != MAIL_INDEX_MAJOR_VERSION) {
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen /* major version change - handle silently */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (hdr.base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen "Corrupted header sizes (base %u, full %u)",
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen buffer_append(map->hdr_copy_buf, &hdr, hdr.base_header_size);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* @UNSAFE */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen data = buffer_append_space_unsafe(map->hdr_copy_buf,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen records_size = hdr.messages_count * hdr.record_size;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen map->buffer = buffer_create_dynamic(default_pool,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* @UNSAFE */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen data = buffer_append_space_unsafe(map->buffer, records_size);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen ret = pread_full(index->fd, data, records_size,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_index_set_syscall_error(index, "pread_full()");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen "Corrupted index file %s: File too small",
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen index->sync_log_file_offset = hdr.log_file_int_offset;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int mail_index_sync_from_transactions(struct mail_index *index,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen const struct mail_index_header *map_hdr = &(*map)->hdr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* read the real log position where we are supposed to be
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = mail_index_read_header(index, &hdr, &pos);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mail_index_set_syscall_error(index, "pread()");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (map_hdr->log_file_seq == hdr.log_file_seq &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen map_hdr->log_file_int_offset == hdr.log_file_int_offset) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* nothing to do */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (map_hdr->log_file_seq > hdr.log_file_seq ||
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen map_hdr->log_file_int_offset > hdr.log_file_int_offset)) {
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen /* we went too far, have to re-read the file */
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen hdr.log_file_ext_offset != hdr.log_file_int_offset) {
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen /* too much trouble to get this right. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* sync everything there is */
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen log_view = mail_transaction_log_view_open(index->log);
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen while ((ret = mail_transaction_log_view_next(log_view, &thdr, &tdata,
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if (mail_index_sync_record(&sync_map_ctx, thdr, tdata) < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* make sure log file offsets get copied. most of the other
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen fields should stay the same. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int mail_index_read_map_with_retry(struct mail_index *index,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* sync this as a view from transaction log. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = mail_index_sync_from_transactions(index, map,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* transaction log lost/broken, fallback to re-reading it */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* FIXME: file cache need to be reset (except not really with
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen sync_to_index if we were just rewinding..) */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (i = 0; i < MAIL_INDEX_ESTALE_RETRY_COUNT; i++) {
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen ret = mail_index_read_map(index, *map, &retry);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen /* ESTALE - reopen index file */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen mail_index_set_syscall_error(index, "close()");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* the file was lost */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_index_set_syscall_error(index, "open()");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* Too many ESTALE retries */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mail_index_set_syscall_error(index, "read_map()");
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic int mail_index_map_try_existing(struct mail_index_map *map)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen /* always check corrupted-flag to avoid errors later */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen used_size = hdr->header_size + hdr->messages_count * hdr->record_size;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (map->mmap_size >= used_size && map->hdr_base == hdr) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenint mail_index_map(struct mail_index *index, int force)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(index->map == NULL || index->map->refcount > 0);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = mail_index_map_try_existing(index->map);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* we're syncing, don't break the mapping */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (index->map != NULL && index->map->refcount > 1) {
1f4399a277b861419b82758ab0462e90c00a4c41Timo Sirainen /* this map is already used by some views and they may have
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen pointers into it. leave them and create a new mapping. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* create a copy of the mapping instead so we don't
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen have to re-read it */
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen buffer_create_dynamic(default_pool, sizeof(map->hdr));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen mail_index_set_syscall_error(index, "munmap()");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = mail_index_read_map_with_retry(index, &map, force);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainenmail_index_map_clone(struct mail_index_map *map, uint32_t new_record_size)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int i, count;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mem_map->buffer = buffer_create_dynamic(default_pool, size);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen buffer_append(mem_map->buffer, map->records, size);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen copy_size = I_MIN(map->hdr.record_size, new_record_size);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen dest = buffer_append_space_unsafe(mem_map->buffer,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mem_map->records = buffer_get_modifyable_data(mem_map->buffer, NULL);
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi buffer_create_dynamic(default_pool, map->hdr.header_size);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen buffer_append_zero(mem_map->hdr_copy_buf, sizeof(*hdr));
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen map->hdr.header_size - map->hdr.base_header_size);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen hdr = buffer_get_modifyable_data(mem_map->hdr_copy_buf, NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* copy extensions */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen count = map->ext_id_map->used / sizeof(uint32_t);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mail_index_map_init_extbufs(mem_map, count + 2);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_append_buf(mem_map->extensions, map->extensions,
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen buffer_append_buf(mem_map->ext_id_map, map->ext_id_map,
e36574dadcac802d6780fa94ee45951e75594c96Timo Sirainen /* fix the name pointers to use our own pool */
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen extensions = buffer_get_modifyable_data(mem_map->extensions,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen for (i = 0; i < count; i++) {
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen extensions[i].name = p_strdup(mem_map->extension_pool,
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenint mail_index_map_get_ext_idx(struct mail_index_map *map,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen map->ext_id_map->used / sizeof(*id_map) <= ext_id)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int mail_index_try_open_only(struct mail_index *index)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen for (i = 0; i < 3; i++) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen /* May happen with some OSes with NFS. Try again, although
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen there's still a race condition with another computer
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen creating the index file again. However, we can't try forever
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen as ESTALE happens also if index directory has been deleted
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen from server.. */
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return mail_index_set_syscall_error(index, "open()");
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen /* have to create it */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenmail_index_try_open(struct mail_index *index, unsigned int *lock_id_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int lock_id;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (mail_index_lock_shared(index, FALSE, &lock_id) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* it's corrupted - recreate it */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenint mail_index_write_base_header(struct mail_index *index,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen hdr_size = I_MIN(sizeof(*hdr), hdr->base_header_size);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (msync(index->map->mmap_base, hdr_size, MS_SYNC) < 0)
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen return mail_index_set_syscall_error(index, "msync()");
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (pwrite_full(index->fd, hdr, hdr_size, 0) < 0) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen mail_index_set_syscall_error(index, "pwrite_full()");
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen buffer_write(index->map->hdr_copy_buf, 0, hdr, hdr_size);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen return mail_index_file_set_syscall_error(index, path, "open()");
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (index->gid != (gid_t)-1 && fchown(fd, (uid_t)-1, index->gid) < 0) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen mail_index_file_set_syscall_error(index, path, "fchown()");
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenstatic int mail_index_create(struct mail_index *index,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* log file lock protects index creation */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* create it fully in index.tmp first */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen index->fd = mail_index_create_tmp_file(index, &path);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch else if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen mail_index_file_set_syscall_error(index, path, "write_full()");
4fce6ce68d13836faf6d68f35855eba4573b42b2Timo Sirainen /* it's corrupted even while we just created it,
4fce6ce68d13836faf6d68f35855eba4573b42b2Timo Sirainen should never happen unless someone pokes the file directly */
4fce6ce68d13836faf6d68f35855eba4573b42b2Timo Sirainen "Newly created index file is corrupted: %s", path);
6763c5f6246a0705b141d99d32fe9e2096042bd3Timo Sirainen mail_index_file_set_syscall_error(index, path,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* make it visible to others */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenstatic void mail_index_header_init(struct mail_index_header *hdr)
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen hdr->record_size = sizeof(struct mail_index_record);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen hdr->keywords_mask_size = sizeof(keywords_mask_t);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen hdr->compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen/* returns -1 = error, 0 = won't create, 1 = ok */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkstatic int mail_index_open_files(struct mail_index *index,
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen unsigned int lock_id = 0;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen else if (ret == 0) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* doesn't exist, or corrupted */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen } else if (ret < 0)
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen index->log = mail_transaction_log_open_or_create(index);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (mail_index_lock_shared(index, FALSE, &lock_id) < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen index->cache = mail_cache_open_or_create(index);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (index->hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* corrupted, reopen files */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen index->filepath = i_strconcat(index->dir, "/", index->prefix, NULL);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen (flags & MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE) != 0;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* don't even bother to handle dotlocking without mmap being
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen disabled. that combination simply doesn't make any sense */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen i_assert(lock_method != MAIL_INDEX_LOCK_DOTLOCK ||
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* completely broken, reopen */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* too many tries */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid mail_index_close(struct mail_index *index)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mail_index_set_syscall_error(index, "close()");
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint mail_index_reopen(struct mail_index *index, int fd)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen unsigned int old_shared_locks, old_lock_id, lock_id = 0;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* new file, new locks. the old fd can keep it's locks, they don't
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen matter anymore as no-one's going to modify the file. */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen ret = mail_index_lock_shared(index, FALSE, &lock_id);
d85f37fe02fadcd5144560495a7196133c8ec947Timo Sirainen else if (ret == 0) {
d85f37fe02fadcd5144560495a7196133c8ec947Timo Sirainen /* index file is lost */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* read the new mapping. note that with mmap_disable we want
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen to keep the old mapping in index->map so we can update it
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen by reading transaction log. */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen mail_index_set_syscall_error(index, "close()");
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mail_index_set_syscall_error(index, "close()");
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenint mail_index_refresh(struct mail_index *index)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen return mail_index_set_syscall_error(index, "fstat()");
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen mail_index_set_syscall_error(index, "stat()");
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* lost it? recreate */
20856c63a2c0f694f32db4368cea2505937570cbTimo Sirainenstruct mail_cache *mail_index_get_cache(struct mail_index *index)
20856c63a2c0f694f32db4368cea2505937570cbTimo Sirainenint mail_index_set_error(struct mail_index *index, const char *fmt, ...)
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainenvoid mail_index_set_inconsistent(struct mail_index *index)
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainenvoid mail_index_mark_corrupted(struct mail_index *index)
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (mail_index_write_base_header(index, &hdr) == 0) {
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen mail_index_set_syscall_error(index, "fsync()");
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainenint mail_index_set_syscall_error(struct mail_index *index,
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen return mail_index_set_error(index, "%s failed with index file %s: %m",
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainenint mail_index_file_set_syscall_error(struct mail_index *index,
64ee8113a88e5d6e3cba7b1c4abd537cc2632bb9Timo Sirainen return mail_index_set_error(index, "%s failed with file %s: %m",
64ee8113a88e5d6e3cba7b1c4abd537cc2632bb9Timo Sirainenenum mail_index_error mail_index_get_last_error(struct mail_index *index)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenconst char *mail_index_get_error_message(struct mail_index *index)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenvoid mail_index_reset_error(struct mail_index *index)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenuint32_t mail_index_uint32_to_offset(uint32_t offset)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenuint32_t mail_index_offset_to_uint32(uint32_t offset)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const unsigned char *buf = (const unsigned char *) &offset;