mail-index.c revision 7b524faf719c9998dd586708d6ee0faa307a6c02
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic int mail_index_try_open_only(struct mail_index *index);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen pool_alloconly_create("extra_infos_pool", 256);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen buffer_create_dynamic(index->extra_infos_pool,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenuint32_t mail_index_register_record_extra(struct mail_index *index,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct mail_index_extra_record_info *einfos;
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen unsigned int i;
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen einfos = buffer_get_data(index->extra_infos, &extra_count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* see if it's there already */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen for (i = 0; i < extra_count; i++) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen i_assert(einfos[i].record_size == record_size);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen info.name = p_strdup(index->extra_infos_pool, name);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen buffer_append(index->extra_infos, &info, sizeof(info));
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void mail_index_map_create_extra_infos(struct mail_index_map *map,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen size_t extra_infos_size, extra_infos_id_map_size, size;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen extra_infos_id_map_size = initial_count * sizeof(uint32_t);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen size = extra_infos_size + extra_infos_id_map_size +
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen map->extra_infos = buffer_create_dynamic(map->extra_records_pool,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen map->extra_infos_id_map = buffer_create_dynamic(map->extra_records_pool,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenuint32_t mail_index_map_register_extra_info(struct mail_index *index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_index_extra_record_info *last_einfo;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen last_einfo = buffer_get_data(map->extra_infos, &size);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen einfo = buffer_append_space_unsafe(map->extra_infos, sizeof(*einfo));
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen einfo->name = p_strdup(map->extra_records_pool, name);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen einfo->record_offset = last_einfo->record_offset +
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen einfo->record_offset = sizeof(struct mail_index_record);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen data_id = mail_index_register_record_extra(index, name,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen buffer_write(map->extra_infos_id_map, data_id * sizeof(uint32_t),
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic int mail_index_read_extra_infos(struct mail_index *index,
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen const struct mail_index_extra_record_info_header *einfo_hdr;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen unsigned int i, old_count;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen /* nothing to do, skip allocatations and all */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen mail_index_map_create_extra_infos(map, old_count + 5);
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen for (i = 0; i < old_count; i++) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen while (offset < map->hdr->header_size && name[offset] != '\0')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Header extension name doesn't end with NUL",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (offset < map->hdr->header_size && (offset % 4) != 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen einfo_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (offset + sizeof(*einfo_hdr) > map->hdr->header_size ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen offset + sizeof(*einfo_hdr) + einfo_hdr->hdr_size >
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Header extension goes outside header",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_map_register_extra_info(index, map,
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen offset += sizeof(*einfo_hdr) + einfo_hdr->hdr_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mail_index_check_header(struct mail_index *index,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_index_header *hdr = map->hdr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned char compat_data[sizeof(hdr->compat_data)];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* major version change - handle silently(?) */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (memcmp(hdr->compat_data, compat_data, sizeof(compat_data)) != 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* architecture change - handle silently(?) */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if ((map->hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* we've already complained about it */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* following some extra checks that only take a bit of CPU */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen "uid_validity = 0, next_uid = %u",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (hdr->keywords_mask_size != sizeof(keywords_mask_t)) {
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch mail_index_set_error(index, "Corrupted index file %s: "
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch "keywords_mask_size mismatch: %d != %d",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (hdr->record_size < sizeof(struct mail_index_record)) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen sizeof(struct mail_index_record));
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch if (hdr->recent_messages_count > hdr->messages_count ||
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen hdr->seen_messages_count > hdr->messages_count ||
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen hdr->deleted_messages_count > hdr->messages_count)
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen if (hdr->first_recent_uid_lowwater > hdr->next_uid ||
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen hdr->first_unseen_uid_lowwater > hdr->next_uid ||
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hdr->first_deleted_uid_lowwater > hdr->next_uid)
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen return mail_index_read_extra_infos(index, map);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void mail_index_map_clear(struct mail_index *index,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mail_index_set_syscall_error(index, "munmap()");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenvoid mail_index_unmap(struct mail_index *index, struct mail_index_map *map)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void mail_index_unmap_forced(struct mail_index *index,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic int mail_index_mmap(struct mail_index *index, struct mail_index_map *map)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* we had temporarily used a buffer, eg. for updating index */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen map->mmap_base = index->lock_type != F_WRLCK ?
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen mail_index_set_syscall_error(index, "mmap()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen records_count = (map->mmap_size - hdr->header_size) /
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen "messages_count too large (%u > %u)",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (map->hdr->base_header_size < sizeof(*map->hdr)) {
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen /* header smaller than ours, make a copy so our newer headers
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen won't have garbage in them */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen buffer_append_zero(map->hdr_copy_buf, sizeof(*map->hdr) -
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mhdr = buffer_get_modifyable_data(map->hdr_copy_buf, NULL);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen map->records = PTR_OFFSET(map->mmap_base, map->hdr->header_size);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen map->records_count = map->hdr->messages_count;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int mail_index_read_map(struct mail_index *index,
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen for (pos = 0; ret > 0 && pos < sizeof(hdr); ) {
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (hdr.base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_index_set_error(index, "Corrupted index file %s: "
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen "Corrupted header sizes (base %u, full %u)",
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen buffer_append_zero(map->hdr_copy_buf, sizeof(hdr) +
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* @UNSAFE */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen hdrp = buffer_get_modifyable_data(map->hdr_copy_buf,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* @UNSAFE */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen records_size = hdr.messages_count * hdr.record_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen map->buffer = buffer_create_dynamic(default_pool,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* @UNSAFE */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen data = buffer_append_space_unsafe(map->buffer, records_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = pread_full(index->fd, data, records_size,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_index_set_syscall_error(index, "pread_full()");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen "Corrupted index file %s: File too small",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int mail_index_read_map_with_retry(struct mail_index *index,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen for (i = 0; i < MAIL_INDEX_ESTALE_RETRY_COUNT; i++) {
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen ret = mail_index_read_map(index, map, &retry);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* ESTALE - reopen index file */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_index_set_syscall_error(index, "close()");
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen /* the file was lost */
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen mail_index_set_syscall_error(index, "open()");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* Too many ESTALE retries */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_index_set_syscall_error(index, "read_map()");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int mail_index_map_try_existing(struct mail_index_map *map)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* always check corrupted-flag to avoid errors later */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen used_size = hdr->header_size + hdr->messages_count * hdr->record_size;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (map->mmap_size >= used_size && map->hdr == hdr) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenint mail_index_map(struct mail_index *index, int force)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = mail_index_map_try_existing(index->map);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (index->map != NULL && index->map->refcount > 1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* this map is already used by some views and they may have
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pointers into it. leave them and create a new mapping. */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen } else if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen /* we have modified this mapping and it's waiting to
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen be written to disk once we drop exclusive lock.
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen mapping couldn't have changed, so do nothing. */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen /* FIXME: we need to re-read header */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (munmap(map->mmap_base, map->mmap_size) < 0)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen mail_index_set_syscall_error(index, "munmap()");
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if ((ret = mail_index_mmap(index, map)) <= 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_index_read_map_with_retry(index, map) < 0) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen map->log_file_offset = map->hdr->log_file_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen map->base_header_size = map->hdr->base_header_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_index_map_to_memory(struct mail_index_map *map, uint32_t new_record_size)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen unsigned int i, count;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen mem_map->buffer = buffer_create_dynamic(default_pool, size, (size_t)-1);
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen buffer_append(mem_map->buffer, map->records, size);
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen copy_size = I_MIN(map->hdr->record_size, new_record_size);
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen dest = buffer_append_space_unsafe(mem_map->buffer,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen mem_map->records = buffer_get_modifyable_data(mem_map->buffer, NULL);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen mem_map->hdr_copy_buf = buffer_create_dynamic(default_pool,
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen buffer_append(mem_map->hdr_copy_buf, map->hdr, map->hdr->header_size);
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen hdr = buffer_get_modifyable_data(mem_map->hdr_copy_buf, NULL);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* copy extra_infos */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count = map->extra_infos_id_map->used / sizeof(uint32_t);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_map_create_extra_infos(mem_map, count);
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen buffer_append_buf(mem_map->extra_infos, map->extra_infos,
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen buffer_append_buf(mem_map->extra_infos_id_map,
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen /* fix the name pointers to use our own pool */
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen einfos = buffer_get_modifyable_data(mem_map->extra_infos, NULL);
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen for (i = 0; i < count; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen einfos[i].name = p_strdup(mem_map->extra_records_pool,
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenint mail_index_map_get_extra_info_idx(struct mail_index_map *map,
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen map->extra_infos_id_map->used / sizeof(*id_map) <= data_id)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int mail_index_try_open_only(struct mail_index *index)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen for (i = 0; i < 3; i++) {
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen /* May happen with some OSes with NFS. Try again, although
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen there's still a race condition with another computer
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen creating the index file again. However, we can't try forever
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen as ESTALE happens also if index directory has been deleted
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen from server.. */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return mail_index_set_syscall_error(index, "open()");
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* have to create it */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenmail_index_try_open(struct mail_index *index, unsigned int *lock_id_r)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen unsigned int lock_id;
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen if (mail_index_lock_shared(index, FALSE, &lock_id) < 0) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* it's corrupted - recreate it */
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainenint mail_index_write_base_header(struct mail_index *index,
3c932c0a21349f23dd38c50c12b3a24717dfbc28Timo Sirainen hdr_size = I_MIN(sizeof(*hdr), hdr->base_header_size);
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen if (msync(index->map->mmap_base, hdr_size, MS_SYNC) < 0)
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen return mail_index_set_syscall_error(index, "msync()");
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen if (pwrite_full(index->fd, hdr, hdr_size, 0) < 0) {
1cb065514fcfe00b684ee274239e3f0390c7fc47Timo Sirainen mail_index_set_syscall_error(index, "pwrite_full()");
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen buffer_write(index->map->hdr_copy_buf, 0, hdr, hdr_size);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(index->hdr == index->map->hdr_copy_buf->data);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return mail_index_file_set_syscall_error(index, path, "open()");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen fchown(index->fd, (uid_t)-1, index->gid) < 0) {
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen mail_index_file_set_syscall_error(index, path, "fchown()");
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainenstatic int mail_index_create(struct mail_index *index,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* log file lock protects index creation */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen /* create it fully in index.tmp first */
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen index->fd = mail_index_create_tmp_file(index, &path);
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen else if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen mail_index_file_set_syscall_error(index, path, "write_full()");
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen /* it's corrupted even while we just created it,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen should never happen unless someone pokes the file directly */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "Newly created index file is corrupted: %s", path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_file_set_syscall_error(index, path,
dbe06905918a415a34c5621b9fdf45be0b9c8e64Timo Sirainen /* make it visible to others */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic void mail_index_header_init(struct mail_index_header *hdr)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen hdr->major_version = MAIL_INDEX_MAJOR_VERSION;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen hdr->minor_version = MAIL_INDEX_MINOR_VERSION;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hdr->record_size = sizeof(struct mail_index_record);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hdr->keywords_mask_size = sizeof(keywords_mask_t);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hdr->compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainen/* returns -1 = error, 0 = won't create, 1 = ok */
faca2afa3576c50caf28e0f009555325d2a49e0bTimo Sirainenstatic int mail_index_open_files(struct mail_index *index,
674f541b16689c0ed090dac32db94463c5af3977Timo Sirainen unsigned int lock_id = 0;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen else if (ret == 0) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* doesn't exist, or corrupted */
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen } else if (ret < 0)
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen index->log = mail_transaction_log_open_or_create(index);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mail_index_lock_shared(index, FALSE, &lock_id) < 0)
50b9773bebe5c66485728e21e4da6e99db388c92Timo Sirainen index->cache = mail_cache_open_or_create(index);
50b9773bebe5c66485728e21e4da6e99db388c92Timo Sirainenint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen index->filepath = i_strconcat(index->dir, "/", index->prefix, NULL);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0;
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen (flags & MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE) != 0;
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen (flags & MAIL_INDEX_OPEN_FLAG_FCNTL_LOCKS_DISABLE) != 0;
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen /* completely broken, reopen */
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen /* too many tries */
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainenvoid mail_index_close(struct mail_index *index)
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen mail_index_set_syscall_error(index, "close()");
984e5c91288139f8a2582be705ee7ef0d157a3f6Timo Sirainenint mail_index_reopen(struct mail_index *index, int fd)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen unsigned int old_shared_locks, old_lock_id, lock_id = 0;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* new file, new locks. the old fd can keep it's locks, they don't
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen matter anymore as no-one's going to modify the file. */
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen ret = mail_index_lock_shared(index, FALSE, &lock_id);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen else if (ret == 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* index file is lost */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_index_set_syscall_error(index, "close()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_syscall_error(index, "close()");
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainenint mail_index_refresh(struct mail_index *index)
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen return mail_index_set_syscall_error(index, "fstat()");
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen mail_index_set_syscall_error(index, "stat()");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* lost it? recreate */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct mail_cache *mail_index_get_cache(struct mail_index *index)
57ff998a443881c8959a8e65f6325cf19fefc1d0Timo Sirainenint mail_index_set_error(struct mail_index *index, const char *fmt, ...)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid mail_index_set_inconsistent(struct mail_index *index)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenvoid mail_index_mark_corrupted(struct mail_index *index)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* make sure we can write the header */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (mprotect(index->map->mmap_base, sizeof(hdr),
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_index_set_syscall_error(index, "mprotect()");
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen if (mail_index_write_base_header(index, &hdr) == 0) {
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen mail_index_set_syscall_error(index, "fsync()");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenint mail_index_set_syscall_error(struct mail_index *index,
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen return mail_index_set_error(index, "%s failed with index file %s: %m",
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainenint mail_index_file_set_syscall_error(struct mail_index *index,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return mail_index_set_error(index, "%s failed with file %s: %m",
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainenenum mail_index_error mail_index_get_last_error(struct mail_index *index)
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainenconst char *mail_index_get_error_message(struct mail_index *index)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid mail_index_reset_error(struct mail_index *index)
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainenuint32_t mail_index_uint32_to_offset(uint32_t offset)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenuint32_t mail_index_offset_to_uint32(uint32_t offset)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const unsigned char *buf = (const unsigned char *) &offset;