mail-index.c revision d1faa68ce3878906b99aa96a06bdb7139e23bac9
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int extra;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->mmap_full_length < sizeof(MailIndexHeader)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen extra = (index->mmap_full_length - sizeof(MailIndexHeader)) %
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* partial write or corrupted -
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen truncate the file to valid length */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (void)ftruncate(index->fd, (off_t)index->mmap_full_length);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* keep the header set even if we fail, so we can update the flags */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (hdr->used_file_size > index->mmap_full_length) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_corrupted(index, "used_file_size larger than real "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((hdr->used_file_size - sizeof(MailIndexHeader)) %
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen sizeof(MailIndexRecord) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_corrupted(index, "Invalid used_file_size in header "
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (hdr->messages_count < hdr->seen_messages_count) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index_set_corrupted(index, "Invalid seen messages count "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (hdr->messages_count < hdr->deleted_messages_count) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_corrupted(index, "Invalid deleted messages count "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index->mmap_used_length = hdr->used_file_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index->header = (MailIndexHeader *) index->mmap_base;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* make sure file size hasn't changed */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->header->sync_id == index->sync_id) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index->mmap_used_length = index->header->used_file_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->mmap_used_length > index->mmap_full_length) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "updating sync_id");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return index_set_syscall_error(index, "msync()");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (munmap(index->mmap_base, index->mmap_full_length) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return index_set_syscall_error(index, "munmap()");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index->mmap_base = mmap_rw_file(index->fd, &index->mmap_full_length);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (munmap_anon(index->mmap_base, index->mmap_full_length) < 0)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen index_set_syscall_error(index, "munmap_anon()");
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (munmap(index->mmap_base, index->mmap_full_length) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int mail_index_sync_file(MailIndex *index)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (msync(index->mmap_base, index->mmap_used_length, MS_SYNC) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "msync()");
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen if (!mail_modifylog_sync_file(index->modifylog))
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* keep index's modify stamp same as the sync file's stamp */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "utime()");
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return index_set_syscall_error(index, "fsync()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenint mail_index_fmsync(MailIndex *index, size_t size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (msync(index->mmap_base, size, MS_SYNC) < 0)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return index_set_syscall_error(index, "msync()");
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return index_set_syscall_error(index, "fsync()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic void mail_index_update_header_changes(MailIndex *index)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen index->header->cache_fields = index->set_cache_fields;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen ((lock_type) == MAIL_LOCK_UNLOCK ? F_UNLCK : \
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_WRLCK)
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainenint mail_index_try_lock(MailIndex *index, MailLockType lock_type)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = file_try_lock(index->fd, MAIL_LOCK_TO_FLOCK(lock_type));
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen index_set_syscall_error(index, "file_try_lock()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int mail_index_write_header_changes(MailIndex *index)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* use our own locking here so we don't mess up with any other
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen index states, like inconsistency. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "file_wait_lock()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen failed = msync(index->mmap_base, sizeof(MailIndexHeader), MS_SYNC) < 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "file_wait_lock()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int mail_index_lock_remove(MailIndex *index)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "file_wait_lock()");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* reset last_lookup so rebuilds don't try to use it */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* releasing shared lock. we may need to update some
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen flags in header. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((old_flags | index->set_flags) != old_flags ||
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (old_cache | index->set_cache_fields) != old_cache)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return mail_index_write_header_changes(index);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int mail_index_lock_change(MailIndex *index, MailLockType lock_type)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* shared -> exclusive isn't allowed */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* index is in inconsistent state and nothing else than
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen free() is allowed for it. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (file_wait_lock(index->fd, MAIL_LOCK_TO_FLOCK(lock_type)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return index_set_syscall_error(index, "file_wait_lock()");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->indexid != index->header->indexid) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* index was rebuilt, there's no way we can maintain
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen consistency */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_error(index, "Warning: Inconsistency - Index "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "%s was rebuilt while we had it open",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* while holding exclusive lock, keep the FSCK flag on.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen when the lock is released, the FSCK flag will also be
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mail_index_fmsync(index, sizeof(MailIndexHeader))) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mail_index_set_lock(MailIndex *index, MailLockType lock_type)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* anonymous mmaps are private and don't need any locking */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* dropping exclusive lock (either unlock or to shared) */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen keep_fsck = (index->set_flags & MAIL_INDEX_FLAG_FSCK) != 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* remove the FSCK flag only after successful fsync() */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_index_sync_file(index) && !keep_fsck) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_FSCK;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (msync(index->mmap_base, sizeof(MailIndexHeader),
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we only failed to remove the fsck flag,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen so this isn't fatal. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return mail_index_lock_change(index, lock_type);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mail_index_verify_hole_range(MailIndex *index)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* make sure position is valid */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (hdr->first_hole_position < sizeof(MailIndexHeader) ||
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen sizeof(MailIndexHeader)) % sizeof(MailIndexRecord) != 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index_set_corrupted(index, "first_hole_position contains "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "invalid value");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* make sure position is in range.. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (hdr->first_hole_position >= index->mmap_used_length) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index_set_corrupted(index, "first_hole_position points "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "outside file");
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* and finally check that first_hole_records is in valid range */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen sizeof(MailIndexHeader)) / sizeof(MailIndexRecord);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (index->header->first_hole_records > max_records ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen first_records + index->header->first_hole_records > max_records) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_corrupted(index, "first_hole_records points "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "outside file");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo SirainenMailIndexHeader *mail_index_get_header(MailIndex *index)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo SirainenMailIndexRecord *mail_index_lookup(MailIndex *index, unsigned int seq)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index->last_lookup != NULL && index->last_lookup->uid != 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* wanted the same record as last time */
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen /* out of range */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* easy, it's just at the expected index */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen format = "Invalid first_hole_position in header: %"PRIuUOFF_T;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MAIL_INDEX_RECORD_COUNT(index) - hdr->messages_count) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* only one hole in file, skip it and we're at
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen correct position */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen format = "Invalid hole locations in header: %"PRIuUOFF_T;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* find from binary tree */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pos = mail_tree_lookup_sequence(index->tree, seq);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen index_set_corrupted(index, "Sequence %u not found from "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "binary tree (%u msgs says header)",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen format = "Invalid offset returned by binary tree: %"PRIuUOFF_T;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen pos > index->mmap_used_length - sizeof(MailIndexRecord) ||
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen (pos - sizeof(MailIndexHeader)) % sizeof(MailIndexRecord) != 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen rec = (MailIndexRecord *) ((char *) index->mmap_base + pos);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo SirainenMailIndexRecord *mail_index_next(MailIndex *index, MailIndexRecord *rec)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(rec >= (MailIndexRecord *) index->mmap_base);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* go to the next non-deleted record */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen end_rec = (MailIndexRecord *) ((char *) index->mmap_base +
905457e0982fc15930d90e174f271dc69f9afcf9Timo SirainenMailIndexRecord *mail_index_lookup_uid_range(MailIndex *index,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int *seq_r)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen pos = mail_tree_lookup_uid_range(index->tree, seq_r,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen rec = (MailIndexRecord *) ((char *) index->mmap_base + pos);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (rec->uid < first_uid || rec->uid > last_uid) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index_set_error(index, "Corrupted binary tree for index %s: "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "lookup returned offset to wrong UID "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index->set_flags |= MAIL_INDEX_FLAG_REBUILD_TREE;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenindex_lookup_data_field(MailIndex *index, MailIndexRecord *rec, MailField field)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* first check if the field even could be in the file */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if ((index->header->cache_fields & field) == 0) {
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen /* no, but make sure the future records will have it.
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen we don't immediately mark the index to cache this
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen field for old messages as some clients never ask
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen the info again */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* this is at least the second time it's being asked,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen make sure it'll be cached soon. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index->set_flags |= MAIL_INDEX_FLAG_CACHE_FIELDS;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return mail_index_data_lookup(index->data, rec, field);
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainenconst char *mail_index_lookup_field(MailIndex *index, MailIndexRecord *rec,
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen datarec = index_lookup_data_field(index, rec, field);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!mail_index_data_record_verify(index->data, datarec)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* index is corrupted, it will be rebuilt */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenconst void *mail_index_lookup_field_raw(MailIndex *index, MailIndexRecord *rec,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen datarec = index_lookup_data_field(index, rec, field);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid mail_index_mark_flag_changes(MailIndex *index, MailIndexRecord *rec,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if ((old_flags & MAIL_SEEN) == 0 && (new_flags & MAIL_SEEN)) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* unseen -> seen */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } else if ((old_flags & MAIL_SEEN) && (new_flags & MAIL_SEEN) == 0) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* seen -> unseen */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* this is the first unseen message */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index->header->first_unseen_uid_lowwater = rec->uid;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen } else if (rec->uid < index->header->first_unseen_uid_lowwater)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index->header->first_unseen_uid_lowwater = rec->uid;
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (index->header->seen_messages_count == 0) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index_set_corrupted(index, "seen_messages_count in "
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "header is invalid");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* undeleted -> deleted */
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen if (index->header->deleted_messages_count == 1) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* this is the first deleted message */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index->header->first_deleted_uid_lowwater = rec->uid;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen } else if (rec->uid < index->header->first_deleted_uid_lowwater)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index->header->first_deleted_uid_lowwater = rec->uid;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen /* deleted -> undeleted */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if (index->header->deleted_messages_count == 0) {
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen index_set_corrupted(index, "deleted_messages_count in "
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "header is invalid");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic void update_first_hole_records(MailIndex *index)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* see if first_hole_records can be grown */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen rec = (MailIndexRecord *) ((char *) index->mmap_base +
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen end_rec = (MailIndexRecord *) ((char *) index->mmap_base +
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic int mail_index_truncate_hole(MailIndex *index)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen index->mmap_used_length = index->header->used_file_size;
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen /* all mail was deleted, truncate data file */
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainenint mail_index_expunge(MailIndex *index, MailIndexRecord *rec,
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (!mail_modifylog_add_expunge(index->modifylog, seq,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* expunge() may be called while index is being rebuilt and when
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen there's no hash yet */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* make sure it also gets updated */
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen index->header->flags |= MAIL_INDEX_FLAG_REBUILD_TREE;
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen /* setting UID to 0 is enough for deleting the mail from index */
18a41cbd38f83429b790414c1159c097af4a59b8Timo Sirainen /* update last_lookup_seq */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* note that last_lookup can be left to point to
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen invalid record so that next() works properly */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* update first hole */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (hdr->first_hole_position < sizeof(MailIndexRecord)) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* first deleted message in index */
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen } else if (hdr->first_hole_position - sizeof(MailIndexRecord) == pos) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen /* deleted the previous record before hole */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen hdr->first_hole_position -= sizeof(MailIndexRecord);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen (hdr->first_hole_records * sizeof(MailIndexRecord)) == pos) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* deleted the next record after hole */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* second hole coming to index file */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* new hole before the old hole */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* update message counts */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* corrupted */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen index_set_corrupted(index, "Header says there's no mail "
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen "while expunging");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_index_mark_flag_changes(index, rec, rec->msg_flags, 0);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if ((hdr->first_hole_position - sizeof(MailIndexHeader)) /
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen sizeof(MailIndexRecord) == hdr->messages_count) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* the hole reaches end of file, truncate it */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* update deleted_space in data file */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen (void)mail_index_data_add_deleted_space(index->data,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenint mail_index_update_flags(MailIndex *index, MailIndexRecord *rec,
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen mail_index_mark_flag_changes(index, rec, rec->msg_flags, flags);
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen mail_modifylog_add_flags(index->modifylog, seq,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen pos = index->mmap_full_length + (grow_count * sizeof(MailIndexRecord));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen base = mremap_anon(index->mmap_base, index->mmap_full_length,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return index_set_syscall_error(index, "mremap_anon()");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (file_set_size(index->fd, (off_t)pos) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return index_set_syscall_error(index, "file_set_size()");
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen /* file size changed, let others know about it too by changing
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen sync_id in header. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mail_index_append_begin(MailIndex *index, MailIndexRecord **rec)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (index->mmap_used_length == index->mmap_full_length) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(index->header->used_file_size == index->mmap_used_length);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_assert(index->mmap_used_length + sizeof(MailIndexRecord) <=
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen destrec = (MailIndexRecord *) ((char *) index->mmap_base +
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen memcpy(destrec, *rec, sizeof(MailIndexRecord));
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index->header->used_file_size += sizeof(MailIndexRecord);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen index->mmap_used_length += sizeof(MailIndexRecord);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint mail_index_append_end(MailIndex *index, MailIndexRecord *rec)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenconst char *mail_index_get_last_error(MailIndex *index)
41955c400476941fa274f18b106a5922866fd780Timo Sirainenint mail_index_is_diskspace_error(MailIndex *index)
41955c400476941fa274f18b106a5922866fd780Timo Sirainen return !index->inconsistent && index->nodiskspace;