mail-index.c revision 12e1f3cc0cf713ed131df801c36cdf8fe33d174f
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen unsigned int extra;
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen if (index->mmap_full_length < sizeof(MailIndexHeader)) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen extra = (index->mmap_full_length - sizeof(MailIndexHeader)) %
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* partial write or corrupted -
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen truncate the file to valid length */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen (void)ftruncate(index->fd, (off_t)index->mmap_full_length);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen /* keep the header set even if we fail, so we can update the flags */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (hdr->used_file_size > index->mmap_full_length) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "used_file_size larger than real file size "
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if ((hdr->used_file_size - sizeof(MailIndexHeader)) %
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sizeof(MailIndexRecord) != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_corrupted(index, "Invalid used_file_size in header "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (hdr->messages_count < hdr->seen_messages_count) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_corrupted(index, "Invalid seen messages count "
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (hdr->messages_count < hdr->deleted_messages_count) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_corrupted(index, "Invalid deleted messages count "
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->mmap_used_length = hdr->used_file_size;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->header = (MailIndexHeader *) index->mmap_base;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* make sure file size hasn't changed */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index->header->sync_id == index->sync_id) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->mmap_used_length = index->header->used_file_size;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index->mmap_used_length > index->mmap_full_length) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "updating sync_id");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "msync()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (munmap(index->mmap_base, index->mmap_full_length) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "munmap()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->mmap_base = mmap_rw_file(index->fd, &index->mmap_full_length);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (munmap_anon(index->mmap_base, index->mmap_full_length) < 0)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen index_set_syscall_error(index, "munmap_anon()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (munmap(index->mmap_base, index->mmap_full_length) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int mail_index_sync_file(MailIndex *index)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen unsigned int i;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; i < sizeof(fsync_fds)/sizeof(fsync_fds[0]); i++)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!mail_index_data_sync_file(index->data, &fsync_fds[0]))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (msync(index->mmap_base, index->mmap_used_length, MS_SYNC) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "msync()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!mail_tree_sync_file(index->tree, &fsync_fds[1]))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!mail_modifylog_sync_file(index->modifylog, &fsync_fds[2]))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; i < sizeof(fsync_fds)/sizeof(fsync_fds[0]); i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (fsync_fds[i] != -1 && fdatasync(fsync_fds[i]) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_error(index, "fdatasync(%u) failed: %m", i);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "fdatasync()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void mail_index_update_timestamp(MailIndex *index)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* keep index's modify stamp same as the sync file's stamp */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint mail_index_fmdatasync(MailIndex *index, size_t size)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (msync(index->mmap_base, size, MS_SYNC) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "msync()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return index_set_syscall_error(index, "fdatasync()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void mail_index_update_header_changes(MailIndex *index)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->header->cache_fields = index->set_cache_fields;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int mail_index_write_header_changes(MailIndex *index)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* use our own locking here so we don't mess up with any other
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index states, like inconsistency. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen mprotect(index->mmap_base, index->mmap_used_length,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen failed = msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) < 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen mprotect(index->mmap_base, index->mmap_used_length, PROT_NONE);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic int mail_index_lock_remove(MailIndex *index)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* releasing shared lock. we may need to update some
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen flags in header. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if ((old_flags | index->set_flags) != old_flags ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen (old_cache | index->set_cache_fields) != old_cache)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return mail_index_write_header_changes(index);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen debug_mprotect(index->mmap_base, index->mmap_full_length, index);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic int mail_index_lock_change(MailIndex *index, MailLockType lock_type,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen /* shared -> exclusive isn't allowed without try_lock */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(try_lock || lock_type != MAIL_LOCK_EXCLUSIVE ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* index is in inconsistent state and nothing else than
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen free() is allowed for it. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_syscall_error(index, "file_try_lock()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!mail_index_wait_lock(index, fd_lock_type))
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen debug_mprotect(index->mmap_base, index->mmap_full_length, index);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen (void)index->set_lock(index, MAIL_LOCK_UNLOCK);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen if (index->indexid != index->header->indexid) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* index was rebuilt, there's no way we can maintain
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen consistency */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index_set_error(index, "Warning: Inconsistency - Index "
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen "%s was rebuilt while we had it open",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index->header->flags & MAIL_INDEX_FLAG_FSCK) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* someone just partially updated the index, need to fsck it */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* we need exclusive lock so fsck()'s set_lock() won't
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen get us back here */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* check again, in case it was already fscked while we had
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen it unlocked for a while */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index->header->flags & MAIL_INDEX_FLAG_FSCK) {
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen /* drop exclusive lock */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen /* while holding exclusive lock, keep the FSCK flag on.
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen when the lock is released, the FSCK flag will also be
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!mail_index_fmdatasync(index, sizeof(MailIndexHeader))) {
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen (void)index->set_lock(index, MAIL_LOCK_UNLOCK);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int mail_index_lock_full(MailIndex *index, MailLockType lock_type,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* anonymous mmaps are private and don't need any locking */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen debug_mprotect(index->mmap_base, index->mmap_full_length,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen mail_modifylog_notify_lock_drop(index->modifylog);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen /* dropping exclusive lock (either unlock or to shared) */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen keep_fsck = (index->set_flags & MAIL_INDEX_FLAG_FSCK) != 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* remove the FSCK flag only after successful fsync() */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mail_index_sync_file(index) && !keep_fsck) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_FSCK;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (msync(index->mmap_base, sizeof(MailIndexHeader),
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen /* we only failed to remove the fsck flag,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen so this isn't fatal. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return mail_index_lock_change(index, lock_type, try_lock);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint mail_index_set_lock(MailIndex *index, MailLockType lock_type)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return mail_index_lock_full(index, lock_type, FALSE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint mail_index_try_lock(MailIndex *index, MailLockType lock_type)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return mail_index_lock_full(index, lock_type, TRUE);
void *context)
unsigned int max_records;
return TRUE;
return FALSE;
return FALSE;
return TRUE;
const char *error;
unsigned int idx;
return NULL;
return NULL;
idx);
return NULL;
return NULL;
return NULL;
return rec;
return NULL;
return rec;
return NULL;
unsigned int first_uid,
unsigned int last_uid,
unsigned int *seq_r)
unsigned int idx;
return NULL;
return NULL;
return NULL;
return rec;
return NULL;
return NULL;
*size = 0;
return NULL;
*size = 0;
return NULL;
*size = 0;
return NULL;
switch (field) {
case DATA_HDR_INTERNAL_DATE:
case DATA_HDR_VIRTUAL_SIZE:
case DATA_HDR_HEADER_SIZE:
case DATA_HDR_BODY_SIZE:
*size = 0;
return NULL;
return *date;
sizeof(MailIndexHeader)) +
rec++;
sizeof(MailIndexRecord);
return FALSE;
return FALSE;
return TRUE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
int external_change)
unsigned int grow_count;
void *base;
return FALSE;
return TRUE;
return NULL;
return rec;
return FALSE;
return TRUE;
return MAIL_INDEX_ERROR_INCONSISTENT;
return MAIL_INDEX_ERROR_DISKSPACE;
return MAIL_INDEX_ERROR_INTERNAL;
return MAIL_INDEX_ERROR_NONE;