mail-index.c revision 92888ef30960c30ccc9e030fe7eab5d4d04a7d1c
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny/* Copyright (C) 2003-2004 Timo Sirainen */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystruct mail_index *mail_index_alloc(const char *dir, const char *prefix)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_index_check_header(struct mail_index *index,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* major version change - handle silently(?) */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (memcmp(hdr->compat_data, compat_data, sizeof(compat_data)) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* architecture change - handle silently(?) */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if ((map->hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* either a crash or we've already complained about it */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* following some extra checks that only take a bit of CPU */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_set_error(index, "Corrupted index file %s: "
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny "uid_validity = 0, next_uid = %u",
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (hdr->recent_messages_count > hdr->messages_count ||
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny hdr->seen_messages_count > hdr->messages_count ||
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny hdr->deleted_messages_count > hdr->messages_count)
8bbf89c5ab798c112773fe23515c3a9df56dde71Nick Guay if (hdr->first_recent_uid_lowwater > hdr->next_uid ||
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny hdr->first_unseen_uid_lowwater > hdr->next_uid ||
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mail_index_map_clear(struct mail_index *index,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyvoid mail_index_unmap(struct mail_index *index, struct mail_index_map *map)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic void mail_index_unmap_forced(struct mail_index *index,
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidekstatic int mail_index_mmap(struct mail_index *index, struct mail_index_map *map)
894d18ff4178f40a18bbfece8fae270d8307eac6Jakub Hrozek if (map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_set_error(index, "Corrupted index file %s: "
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek hdr->messages_count * sizeof(struct mail_index_record);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny records_count = (map->mmap_size - hdr->header_size) /
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny sizeof(struct mail_index_record);
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek mail_index_set_error(index, "Corrupted index file %s: "
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek "messages_count too large (%u > %u)",
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* header smaller than ours, make a copy so our newer headers
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny won't have garbage in them */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny memcpy(&map->hdr_copy, map->hdr, map->hdr->header_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny map->records = PTR_OFFSET(map->mmap_base, map->hdr->header_size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_index_read_map(struct mail_index *index,
894d18ff4178f40a18bbfece8fae270d8307eac6Jakub Hrozek for (pos = 0; ret > 0 && pos < sizeof(hdr); ) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny sizeof(struct mail_index_record);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny map->buffer = buffer_create_dynamic(default_pool,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* @UNSAFE */
ecfd767c65c39414a86937380b9986c6d2e0aecfJakub Hrozek data = buffer_append_space_unsafe(map->buffer, records_size);
ecfd767c65c39414a86937380b9986c6d2e0aecfJakub Hrozek ret = pread_full(index->fd, data, records_size,
ecfd767c65c39414a86937380b9986c6d2e0aecfJakub Hrozek mail_index_set_syscall_error(index, "pread_full()");
ecfd767c65c39414a86937380b9986c6d2e0aecfJakub Hrozek "Unexpected EOF while reading index file");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_index_read_map_with_retry(struct mail_index *index,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny for (i = 0; i < MAIL_INDEX_ESTALE_RETRY_COUNT; i++) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* ESTALE - reopen index file */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* the file was lost */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* Too many ESTALE retries */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_set_syscall_error(index, "read_map()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_index_map(struct mail_index *index, int force)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* we have modified this mapping and it's waiting to
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny be written to disk once we drop exclusive lock.
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mapping couldn't have changed, so do nothing. */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* FIXME: we need to re-read header */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* see if re-mmaping is needed (file has grown) */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny hdr->messages_count * sizeof(struct mail_index_record);
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny if (mail_index_read_map_with_retry(index, map) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny map->log_file_offset = map->hdr->log_file_offset;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystruct mail_index_map *mail_index_map_to_memory(struct mail_index_map *map)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny size = map->records_count * sizeof(struct mail_index_record);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mem_map->buffer = buffer_create_dynamic(default_pool, size, (size_t)-1);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny buffer_append(mem_map->buffer, map->records, size);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mem_map->records = buffer_get_modifyable_data(mem_map->buffer, NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny I_MIN(hdr->header_size, sizeof(mem_map->hdr_copy)));
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyvoid mail_index_header_init(struct mail_index_header *hdr)
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny hdr->compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zelenyint mail_index_write_header(struct mail_index *index,
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny memcpy(index->map->mmap_base, hdr, sizeof(*hdr));
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny if (msync(index->map->mmap_base, sizeof(*hdr), MS_SYNC) < 0)
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny return mail_index_set_syscall_error(index, "msync()");
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny if (pwrite_full(index->fd, hdr, sizeof(*hdr), 0) < 0) {
1a3e6221b38a7cae27d7e84a30bb8ea3c3900a47Jan Zeleny mail_index_set_syscall_error(index, "pwrite_full()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenyint mail_index_create_tmp_file(struct mail_index *index, const char **path_r)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const char *path;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny path = *path_r = t_strconcat(index->filepath, ".tmp", NULL);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny fd = open(path, O_RDWR|O_CREAT|O_TRUNC, index->mode);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny return mail_index_file_set_syscall_error(index, path, "open()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_file_set_syscall_error(index, path, "fchown()");
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zelenystatic int mail_index_create(struct mail_index *index,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny const char *path;
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* log file lock protects index creation */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny /* create it fully in index.tmp first */
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny index->fd = mail_index_create_tmp_file(index, &path);
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny else if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny mail_index_file_set_syscall_error(index, path, "write_full()");
if (ret < 0) {
unsigned int lock_id;
int ret;
*lock_id_r = 0;
if (ret <= 0)
return ret;
if (ret == 0) {
*lock_id_r = 0;
return ret;
unsigned int lock_id = 0;
int ret;
if (ret > 0)
else if (ret == 0) {
} else if (ret < 0)
if (lock_id != 0)
int i = 0, ret;
if (ret <= 0)
if (ret == 0) {
if (ret <= 0)
return ret;
const char *function)
const char *filepath,
const char *function)
return MAIL_INDEX_ERROR_DISKSPACE;
return MAIL_INDEX_ERROR_INTERNAL;
return MAIL_INDEX_ERROR_NONE;