mail-index.c revision 52cd00e0a3f792582d3226d092418b96166cb401
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen unsigned int extra;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen index->header = (MailIndexHeader *) index->mmap_base;
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen (void)munmap(index->mmap_base, index->mmap_length);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen index->mmap_base = mmap_rw_file(index->fd, &index->mmap_length);
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen index_set_error(index, "index: mmap() failed with file %s: %m",
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if (index->mmap_length < sizeof(MailIndexHeader)) {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen index_set_error(index, "truncated index file %s",
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen extra = (index->mmap_length - sizeof(MailIndexHeader)) %
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen /* partial write or corrupted -
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen truncate the file to valid length */
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen (void)ftruncate(index->fd, (off_t)index->mmap_length);
4082d5b171d1c3a00ba705093d62b8afc9cf17aeTimo Sirainen index->header = (MailIndexHeader *) index->mmap_base;
d06d6667bac64aabe1efb216af56ca45108d63b0Timo Sirainen (void)munmap(index->mmap_base, index->mmap_length);
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen if (msync(index->mmap_base, index->mmap_length, MS_SYNC) == -1) {
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen index_set_error(index, "msync() failed for %s: %m",
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen if (!mail_modifylog_sync_file(index->modifylog))
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen /* keep index's modify stamp same as the sync file's stamp */
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen index_set_error(index, "utime() failed for %s: %m",
355fe8b5d02904df39e793f66da5432d86649d4aTimo Sirainen index_set_error(index, "fsync() failed for %s: %m",
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainenint mail_index_fmsync(MailIndex *index, size_t size)
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen if (msync(index->mmap_base, size, MS_SYNC) == -1) {
6646bd844c85d5b27451199d8868b6d2357cd293Timo Sirainen index_set_error(index, "msync() failed for %s: %m",
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen index_set_error(index, "fsync() failed for %s: %m",
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainenstatic void mail_index_update_header_changes(MailIndex *index)
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
e262f3aa3429dbc74f668bc8bd501cf08b955778Timo Sirainen index->header->cache_fields = index->set_cache_fields;
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen ((lock_type) == MAIL_LOCK_UNLOCK ? F_UNLCK : \
25480af2e21cf136e461ec802177f52b43154485Timo Sirainen (lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_WRLCK)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenint mail_index_try_lock(MailIndex *index, MailLockType lock_type)
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* lock whole file */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainenint mail_index_set_lock(MailIndex *index, MailLockType lock_type)
4c9a72e0988d462df49810984dc93b3fd4a24c23Timo Sirainen /* yeah, this function is a bit messy. besides locking, it keeps
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen the index synced and in a good shape. */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen /* index is in inconsistent state and nothing else than
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen free() is allowed for it. */
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen /* shared -> exclusive isn't allowed */
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen if (index->lock_type == MAIL_LOCK_EXCLUSIVE) {
ef174bf5299348e8c0662d235341869f319cfe54Timo Sirainen /* releasing exclusive lock */
749a9676d265a517c7a731f5b9336c524a49e6a6Timo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_FSCK;
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen /* sync mmaped memory */
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen index->lock_type == MAIL_LOCK_UNLOCK && !index->updating) {
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen /* unlock -> lock */
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen /* lock whole file */
ba14267101444b8f144091cefd437e1ea44d3e32Timo Sirainen while (fcntl(index->fd, F_SETLKW, &fl) == -1) {
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* reset last_lookup so rebuilds don't try to use it */
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* we're always mmap()ed when we're locked */
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (index->indexid != index->header->indexid) {
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* index was rebuilt, there's no way we can maintain
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen consistency */
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen index_set_error(index, "Warning: Inconsistency - Index "
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen "%s was rebuilt while we had it open",
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen } else if (old_lock_type == MAIL_LOCK_SHARED) {
c47e837a127c533e67debafde8ccf9691041be16Timo Sirainen /* releasing shared lock */
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen if ((old_flags | index->set_flags) != old_flags ||
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen (old_cache | index->set_cache_fields) != old_cache) {
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen /* need to update the header */
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen if (mail_index_set_lock(index, MAIL_LOCK_EXCLUSIVE))
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen return mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen /* while holding exclusive lock, keep the FSCK flag on.
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen when the lock is released, the FSCK flag will also be
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen if (!mail_index_fmsync(index, sizeof(MailIndexHeader))) {
e4cebacdec9c9e5b685dde5f7cbf7a5cf7e1d248Timo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen if (index->header != NULL && !index->updating &&
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen (index->header->flags & MAIL_INDEX_FLAG_REBUILD) != 0) {
9905ec03fb2011419caeac4cd5a1b6c28ab50a73Timo Sirainen /* index is corrupted, rebuild it */
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen /* reset header so it's not used while being unlocked */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenstatic int read_and_verify_header(int fd, MailIndexHeader *hdr)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen /* read the header */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen if (read(fd, hdr, sizeof(MailIndexHeader)) != sizeof(MailIndexHeader))
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen /* check the compatibility */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen return hdr->compat_data[0] == MAIL_INDEX_VERSION &&
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen hdr->compat_data[1] == MAIL_INDEX_COMPAT_FLAGS &&
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen hdr->compat_data[2] == sizeof(unsigned int) &&
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen/* Returns TRUE if we're compatible with given index file */
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainenstatic int mail_is_compatible_index(const char *path)
90b50df264b57e0f63cd8cc6aea1ce3bb7cf5f64Timo Sirainen compatible = read_and_verify_header(fd, &hdr);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen/* Returns a file name of compatible index */
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainenstatic const char *mail_find_index(MailIndex *index)
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen unsigned int len;
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen /* first try the primary name */
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen i_snprintf(path, sizeof(path), "%s/" INDEX_FILE_PREFIX, index->dir);
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen /* path doesn't exist */
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen index_set_error(index, "Can't open dir %s: %m",
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen if (strncmp(d->d_name, INDEX_FILE_PREFIX, len) == 0) {
5fdeff082e329e4a85bb7e74aaec2c35e2288557Timo Sirainen /* index found, check if we're compatible */
return name;
return FALSE;
return FALSE;
return TRUE;
int update_recent)
const char *path;
return FALSE;
return FALSE;
} while (FALSE);
if (failed)
return !failed;
int update_recent)
const char *path;
return FALSE;
path);
return FALSE;
return FALSE;
/* fallback to index.hostname - we require each system to
hostpid_init();
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
const char *name;
return FALSE;
return FALSE;
return TRUE;
const char *name;
return TRUE;
return FALSE;
return FALSE;
if (failed)
return FALSE;
return TRUE;
return TRUE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
unsigned int lookup_seq)
unsigned int seq;
return NULL;
return NULL;
return NULL;
sizeof(MailIndexHeader));
sizeof(MailIndexRecord));
return NULL;
return rec;
seq++;
rec++;
return rec;
return NULL;
return NULL;
return rec;
return NULL;
unsigned int first_uid,
unsigned int last_uid)
return NULL;
if (pos != 0) {
return (MailIndexRecord *)
return NULL;
sizeof(MailIndexHeader));
return NULL;
return rec;
rec++;
return NULL;
return NULL;
return NULL;
return NULL;
unsigned int seq;
return INDEX_POSITION_INDEX(
return INDEX_POSITION_INDEX(
seq++;
return seq;
rec++;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
if (seq != 0) {
return FALSE;
if (seq != 0) {
return FALSE;
return FALSE;
return TRUE;
int external_change)
if (pos < 0) {
return FALSE;
return FALSE;
return FALSE;
return TRUE;