mbox-sync.c revision 99b621cc5076398c5d780d2ea33dd7391341d630
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include "lib.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "mbox-index.h"
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include "mbox-lock.h"
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include "mail-index-util.h"
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include <stdlib.h>
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include <unistd.h>
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include <fcntl.h>
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen#include <sys/stat.h>
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainenstatic uoff_t get_indexed_mbox_size(struct mail_index *index)
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen{
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen struct mail_index_record *rec;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen uoff_t offset, hdr_size, body_size;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (index->lock_type == MAIL_LOCK_UNLOCK) {
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (!mail_index_set_lock(index, MAIL_LOCK_SHARED))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return 0;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen }
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen /* get the last record */
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen rec = index->header->messages_count == 0 ? NULL :
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen index->lookup(index, index->header->messages_count);
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen offset = 0;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (rec != NULL) {
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen /* get the offset + size of last message, which tells the
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen last known mbox file size */
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (mbox_mail_get_location(index, rec, &offset,
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen &hdr_size, &body_size))
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen offset += hdr_size + body_size;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (offset > OFF_T_MAX) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* too large to fit in off_t */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return 0;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return offset + 1; /* +1 for trailing \n */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen}
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainenstatic int mbox_lock_and_sync_full(struct mail_index *index,
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen enum mail_lock_type data_lock_type)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen enum mail_lock_type lock_type;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* syncing needs exclusive index lock and shared
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen mbox lock, but if we'd want exclusive mbox lock
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen we need to set it here already */
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (index->lock_type == MAIL_LOCK_SHARED)
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen return FALSE;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (index->mbox_lock_type == MAIL_LOCK_UNLOCK) {
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen lock_type = data_lock_type == MAIL_LOCK_EXCLUSIVE ?
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (!mbox_lock(index, lock_type))
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen return FALSE;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen }
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen return mbox_sync_full(index);
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen}
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainenint mbox_index_sync(struct mail_index *index,
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen enum mail_lock_type data_lock_type, int *changes)
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen{
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen struct stat st;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen time_t index_mtime;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen uoff_t filesize;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen int count, fd;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen i_assert(index->lock_type != MAIL_LOCK_SHARED);
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen if (changes != NULL)
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen *changes = FALSE;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen if (index->mbox_sync_counter == index->mbox_lock_counter) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* we've already synced in this locking session */
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen return TRUE;
900d1f655065fa0cfe601f537142eb212ef5c011Timo Sirainen }
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (index->fd == -1) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* anon-mmaped */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index_mtime = index->file_sync_stamp;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen } else {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (fstat(index->fd, &st) < 0)
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen return index_set_syscall_error(index, "fstat()");
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen index_mtime = st.st_mtime;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen count = 0;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen while (stat(index->mailbox_path, &st) < 0) {
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (errno != ENOENT || ++count == 3)
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return mbox_set_syscall_error(index, "stat()");
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* mbox was deleted by someone - happens with some MUAs
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen when all mail is expunged. easiest way to deal with this
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen is to recreate the file. */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen fd = open(index->mailbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (fd != -1)
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen (void)close(fd);
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen else if (errno != EEXIST)
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return mbox_set_syscall_error(index, "open()");
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen filesize = st.st_size;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (index->mbox_ino != st.st_ino ||
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen !CMP_DEV_T(index->mbox_dev, st.st_dev)) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* mbox file was overwritten, close it if it was open */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_dev = st.st_dev;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_ino = st.st_ino;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_size = (uoff_t)-1;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen mbox_file_close_fd(index);
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen }
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (index_mtime != st.st_mtime || index->mbox_size != filesize) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen mbox_file_close_stream(index);
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_size = get_indexed_mbox_size(index);
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (index->file_sync_stamp == 0 &&
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen index->mbox_size == filesize) {
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen /* just opened the mailbox, and the file size is same
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen as we expected. don't bother checking it any
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen further. */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen } else {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (changes != NULL)
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen *changes = TRUE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen if (!mbox_lock_and_sync_full(index, data_lock_type))
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return FALSE;
ab170d6cf8aeb515bac7c07b37e525cbad96c299Timo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if ((index->set_flags & MAIL_INDEX_FLAG_REBUILD) != 0) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* uidvalidity probably changed, rebuild */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (!index->rebuild(index))
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return FALSE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_size = filesize;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->file_sync_stamp = st.st_mtime;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen /* we need some index lock to be able to lock mbox */
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (index->lock_type == MAIL_LOCK_UNLOCK) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (!index->set_lock(index, MAIL_LOCK_SHARED))
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return FALSE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (data_lock_type == MAIL_LOCK_UNLOCK) {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (!mbox_unlock(index))
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return FALSE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen } else {
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen if (!mbox_lock(index, data_lock_type))
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return FALSE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen }
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen index->mbox_sync_counter = index->mbox_lock_counter;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen return TRUE;
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen}
2efe6c8cb2773ac6316638fd9a61d7e8c908153fTimo Sirainen