mail-index.c revision 02b32cf39a098edf60981fc228e4b034f11f3b90
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
#include "ioloop.h"
#include "file-lock.h"
#include "file-set-size.h"
#include "mmap-util.h"
#include "mail-index.h"
#include "mail-index-data.h"
#include "mail-index-util.h"
#include "mail-hash.h"
#include "mail-modifylog.h"
#include "mail-custom-flags.h"
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
{
unsigned int extra;
index->mmap_used_length = 0;
return FALSE;
}
sizeof(MailIndexRecord);
if (extra != 0) {
/* partial write or corrupted -
truncate the file to valid length */
}
index->last_lookup_seq = 0;
return FALSE;
}
sizeof(MailIndexRecord) != 0) {
return FALSE;
}
return TRUE;
}
{
return mmap_verify(index);
/* make sure file size hasn't changed */
i_panic("Index file size was grown without "
"updating sync_id");
}
return TRUE;
}
}
index->mmap_used_length = 0;
return FALSE;
}
return mmap_verify(index);
}
{
index->set_cache_fields = 0;
}
}
} else {
}
}
}
}
}
}
}
}
{
int failed;
return TRUE;
return FALSE;
}
}
/* keep index's modify stamp same as the sync file's stamp */
return !failed;
}
{
}
return TRUE;
}
{
}
if (index->set_cache_fields != 0) {
index->set_cache_fields = 0;
}
}
#define MAIL_LOCK_TO_FLOCK(lock_type) \
{
int ret;
return TRUE;
return TRUE;
if (ret < 0)
return ret > 0;
}
{
int failed;
/* use our own locking here so we don't mess up with any other
index states, like inconsistency. */
if (failed)
return !failed;
}
{
/* reset last_lookup so rebuilds don't try to use it */
index->last_lookup_seq = 0;
if (old_lock_type == MAIL_LOCK_SHARED) {
/* releasing shared lock. we may need to update some
flags in header. */
return mail_index_write_header_changes(index);
}
return TRUE;
}
{
/* shared -> exclusive isn't allowed */
if (index->inconsistent) {
/* index is in inconsistent state and nothing else than
free() is allowed for it. */
return FALSE;
}
if (!mmap_update(index)) {
return FALSE;
}
/* index was rebuilt, there's no way we can maintain
consistency */
"%s was rebuilt while we had it open",
return FALSE;
}
if (lock_type == MAIL_LOCK_EXCLUSIVE) {
/* while holding exclusive lock, keep the FSCK flag on.
when the lock is released, the FSCK flag will also be
removed. */
return FALSE;
}
}
return TRUE;
}
{
return TRUE;
/* anonymous mmaps are private and don't need any locking */
return TRUE;
}
/* dropping exclusive lock (either unlock or to shared) */
/* remove the FSCK flag only after successful fsync() */
if (mail_index_sync_file(index)) {
MS_SYNC) < 0) {
/* we only failed to remove the fsck flag,
so this isn't fatal. */
}
}
}
if (lock_type == MAIL_LOCK_UNLOCK)
return mail_index_lock_remove(index);
else
}
{
unsigned int max_records, first_records;
if (hdr->first_hole_position == 0)
return TRUE;
/* make sure position is valid */
sizeof(MailIndexHeader)) % sizeof(MailIndexRecord) != 0) {
"invalid value");
return FALSE;
}
/* make sure position is in range.. */
"outside file");
return FALSE;
}
/* and finally check that first_hole_records is in valid range */
sizeof(MailIndexHeader)) / sizeof(MailIndexRecord);
"outside file");
return FALSE;
}
return TRUE;
}
{
}
{
unsigned int rec_seq;
/* wanted the same record as last time */
return index->last_lookup;
}
/* out of range */
return NULL;
}
return NULL;
seekpos = sizeof(MailIndexHeader) +
/* minimum file position for wanted sequence would point
ouside file, so it can't exist. however, header said it
should be found.. */
"Header contains invalid message count");
return NULL;
}
sizeof(MailIndexHeader));
sizeof(MailIndexRecord));
if (hdr->first_hole_position == 0 ||
/* easy, it's just at the expected index */
"wasn't updated properly");
return NULL;
}
return rec;
}
/* we need to walk through the index to get to wanted position */
/* we want to lookup data after last lookup -
this helps us some */
} else {
/* some mails are deleted, jump after the first known hole
and start counting non-deleted messages.. */
}
rec_seq++;
rec++;
}
}
{
return NULL;
/* go to the next non-deleted record */
return rec;
}
return NULL;
}
unsigned int first_uid,
unsigned int last_uid)
{
unsigned int uid, last_try_uid;
return NULL;
/* check if first_uid is the first UID in the index, or an UID
before that. this is quite common and hash lookup would be
useless to try with those nonexisting old UIDs */
sizeof(MailIndexHeader));
} else {
sizeof(MailIndexRecord));
}
/* no messages in index */
return NULL;
}
/* yes, first_uid pointed to beginning of index.
make sure last_uid is in that range too. */
}
/* UID doesn't even exist yet */
return NULL;
}
/* try the few first with hash lookups */
if (pos == 0)
continue;
"lookup returned offset to different "
}
return rec;
}
if (last_try_uid == last_uid)
return NULL;
/* fallback to looking through the whole index - this shouldn't be
needed often, so don't bother trying anything too fancy. */
sizeof(MailIndexHeader));
return NULL;
return rec;
}
rec++;
}
return NULL;
}
static MailIndexDataRecord *
{
/* first check if the field even could be in the file */
/* no, but make sure the future records will have it.
we don't immediately mark the index to cache this
field for old messages as some clients never ask
the info again */
} else {
/* this is at least the second time it's being asked,
make sure it'll be cached soon. */
}
return NULL;
}
}
{
return NULL;
/* index is corrupted, it will be rebuilt */
return NULL;
}
}
{
*size = 0;
return NULL;
}
}
{
unsigned int seq;
/* same as last lookup sequence - too easy */
return index->last_lookup_seq;
}
/* easy, it's just at the expected index */
return INDEX_POSITION_INDEX(
}
return 0;
/* record before first hole */
return INDEX_POSITION_INDEX(
}
/* we know the sequence after the first hole - skip to there and
start browsing the records until ours is found */
seq++;
}
return seq;
}
{
/* unseen -> seen */
/* seen -> unseen */
/* this is the first unseen message */
"header is invalid");
} else {
}
}
if ((old_flags & MAIL_DELETED) == 0 &&
(new_flags & MAIL_DELETED)) {
/* undeleted -> deleted */
/* this is the first deleted message */
} else if ((old_flags & MAIL_DELETED) &&
(new_flags & MAIL_DELETED) == 0) {
/* deleted -> undeleted */
"header is invalid");
} else {
}
}
}
{
/* see if first_hole_records can be grown */
rec++;
}
}
{
if (!mail_index_truncate(index))
return FALSE;
/* all mail was deleted, truncate data file */
return FALSE;
}
return TRUE;
}
unsigned int seq, int external_change)
{
return FALSE;
}
/* expunge() may be called while index is being rebuilt and when
there's no hash yet */
else {
/* make sure it also gets updated */
}
/* setting UID to 0 is enough for deleting the mail from index */
/* update last_lookup_seq */
if (seq != 0) {
/* note that last_lookup can be left to point to
invalid record so that next() works properly */
index->last_lookup_seq--;
}
return FALSE;
/* update first hole */
/* first deleted message in index */
/* deleted the previous record before hole */
} else if (hdr->first_hole_position +
/* deleted the next record after hole */
} else {
/* second hole coming to index file, the index now needs to
be compressed to keep high performance */
/* new hole before the old hole */
}
}
/* update message counts */
if (hdr->messages_count == 0) {
/* corrupted */
"while expunging");
return FALSE;
}
hdr->messages_count--;
/* the hole reaches end of file, truncate it */
(void)mail_index_truncate_hole(index);
} else {
/* update deleted_space in data file */
}
return TRUE;
}
int external_change)
{
return TRUE; /* no changes */
}
{
void *base;
INDEX_GROW_PERCENTAGE / 100;
if (grow_size < 16)
grow_size = 16;
if (base == MAP_FAILED)
return TRUE;
}
}
/* file size changed, let others know about it too by changing
sync_id in header. */
if (!mmap_update(index))
return FALSE;
return TRUE;
}
{
/* we need more space */
if (!mail_index_grow(index))
return FALSE;
}
return TRUE;
}
{
}
return TRUE;
}
{
}
{
return index->nodiskspace;
}
{
return index->inconsistent;
}