From: Timo Sirainen Date: Sat, 13 Dec 2008 09:21:21 +0000 (+0200) Subject: mbox: Don't cache mbox state after it has been unlocked. X-Git-Tag: 1.2.alpha5~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8e;p=thirdparty%2Fdovecot%2Fcore.git mbox: Don't cache mbox state after it has been unlocked. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/mbox/istream-raw-mbox.c b/src/lib-storage/index/mbox/istream-raw-mbox.c index 52670fc414..241a5e39e1 100644 --- a/src/lib-storage/index/mbox/istream-raw-mbox.c +++ b/src/lib-storage/index/mbox/istream-raw-mbox.c @@ -15,8 +15,11 @@ struct raw_mbox_istream { uoff_t from_offset, hdr_offset, body_offset, mail_size; uoff_t input_peak_offset; + unsigned int locked:1; + unsigned int seeked:1; unsigned int crlf_ending:1; unsigned int corrupted:1; + unsigned int mail_size_forced:1; unsigned int eof:1; unsigned int header_missing_eoh:1; }; @@ -144,6 +147,7 @@ static ssize_t i_stream_raw_mbox_read(struct istream_private *stream) int eoh_char, tz; bool crlf_ending = FALSE; + i_assert(rstream->seeked); i_assert(stream->istream.v_offset >= rstream->from_offset); if (stream->istream.eof) @@ -315,8 +319,9 @@ static ssize_t i_stream_raw_mbox_read(struct istream_private *stream) /* istream_raw_mbox_set_next_offset() used invalid cached next_offset? */ i_error("Next message unexpectedly lost from mbox file " - "%s at %"PRIuUOFF_T, rstream->path, - rstream->hdr_offset + rstream->mail_size); + "%s at %"PRIuUOFF_T" (%s)", rstream->path, + rstream->hdr_offset + rstream->mail_size, + rstream->mail_size_forced ? "cached" : "noncached"); rstream->eof = TRUE; rstream->corrupted = TRUE; rstream->istream.istream.stream_errno = EINVAL; @@ -455,6 +460,8 @@ uoff_t istream_raw_mbox_get_start_offset(struct istream *stream) struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream->real_stream; + i_assert(rstream->seeked); + return rstream->from_offset; } @@ -463,6 +470,8 @@ uoff_t istream_raw_mbox_get_header_offset(struct istream *stream) struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream->real_stream; + i_assert(rstream->seeked); + if (rstream->hdr_offset == rstream->from_offset) (void)i_stream_raw_mbox_read(&rstream->istream); @@ -482,6 +491,8 @@ uoff_t istream_raw_mbox_get_body_offset(struct istream *stream) uoff_t offset; size_t pos; + i_assert(rstream->seeked); + if (rstream->body_offset != (uoff_t)-1) return rstream->body_offset; @@ -516,6 +527,7 @@ uoff_t istream_raw_mbox_get_body_size(struct istream *stream, size_t size; uoff_t old_offset, body_size, next_body_offset; + i_assert(rstream->seeked); i_assert(rstream->hdr_offset != (uoff_t)-1); i_assert(rstream->body_offset != (uoff_t)-1); @@ -569,6 +581,8 @@ time_t istream_raw_mbox_get_received_time(struct istream *stream) struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream->real_stream; + i_assert(rstream->seeked); + if (rstream->received_time == (time_t)-1) (void)i_stream_raw_mbox_read(&rstream->istream); return rstream->received_time; @@ -579,6 +593,8 @@ const char *istream_raw_mbox_get_sender(struct istream *stream) struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream->real_stream; + i_assert(rstream->seeked); + if (rstream->sender == NULL) (void)i_stream_raw_mbox_read(&rstream->istream); return rstream->sender == NULL ? "" : rstream->sender; @@ -589,6 +605,8 @@ bool istream_raw_mbox_has_crlf_ending(struct istream *stream) struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream->real_stream; + i_assert(rstream->seeked); + return rstream->crlf_ending; } @@ -627,17 +645,21 @@ int istream_raw_mbox_seek(struct istream *stream, uoff_t offset) (struct raw_mbox_istream *)stream->real_stream; bool check; + i_assert(rstream->locked); + rstream->corrupted = FALSE; rstream->eof = FALSE; rstream->istream.istream.eof = FALSE; - if (rstream->mail_size != (uoff_t)-1 && + /* if seeked is FALSE, we unlocked in the middle. don't try to use + any cached state then. */ + if (rstream->mail_size != (uoff_t)-1 && rstream->seeked && rstream->hdr_offset + rstream->mail_size == offset) { istream_raw_mbox_next(stream, (uoff_t)-1); return 0; } - if (offset == rstream->from_offset) { + if (offset == rstream->from_offset && rstream->seeked) { /* back to beginning of current message */ offset = rstream->hdr_offset; check = offset == 0; @@ -657,6 +679,7 @@ int istream_raw_mbox_seek(struct istream *stream, uoff_t offset) rstream->hdr_offset = offset; check = TRUE; } + rstream->seeked = TRUE; i_stream_seek_mark(stream, offset); i_stream_seek_mark(rstream->istream.parent, offset); @@ -673,6 +696,7 @@ void istream_raw_mbox_set_next_offset(struct istream *stream, uoff_t offset) i_assert(rstream->hdr_offset != (uoff_t)-1); + rstream->mail_size_forced = TRUE; rstream->mail_size = offset - rstream->hdr_offset; } @@ -691,3 +715,20 @@ bool istream_raw_mbox_is_corrupted(struct istream *stream) return rstream->corrupted; } + +void istream_raw_mbox_set_locked(struct istream *stream) +{ + struct raw_mbox_istream *rstream = + (struct raw_mbox_istream *)stream->real_stream; + + rstream->locked = TRUE; +} + +void istream_raw_mbox_set_unlocked(struct istream *stream) +{ + struct raw_mbox_istream *rstream = + (struct raw_mbox_istream *)stream->real_stream; + + rstream->locked = FALSE; + rstream->seeked = FALSE; +} diff --git a/src/lib-storage/index/mbox/istream-raw-mbox.h b/src/lib-storage/index/mbox/istream-raw-mbox.h index 8bc4c8fa2c..4f2705d1d6 100644 --- a/src/lib-storage/index/mbox/istream-raw-mbox.h +++ b/src/lib-storage/index/mbox/istream-raw-mbox.h @@ -46,5 +46,9 @@ void istream_raw_mbox_set_next_offset(struct istream *stream, uoff_t offset); bool istream_raw_mbox_is_eof(struct istream *stream); /* Returns TRUE if we've noticed corruption in used offsets/sizes. */ bool istream_raw_mbox_is_corrupted(struct istream *stream); +/* Change stream's locking state. We'll assert-crash if stream is tried to be + read while it's unlocked. */ +void istream_raw_mbox_set_locked(struct istream *stream); +void istream_raw_mbox_set_unlocked(struct istream *stream); #endif diff --git a/src/lib-storage/index/mbox/mbox-file.c b/src/lib-storage/index/mbox/mbox-file.c index 72c962320f..4f12f05f6f 100644 --- a/src/lib-storage/index/mbox/mbox-file.c +++ b/src/lib-storage/index/mbox/mbox-file.c @@ -66,28 +66,26 @@ int mbox_file_open_stream(struct mbox_mailbox *mbox) if (mbox->mbox_file_stream != NULL) { /* read-only mbox stream */ i_assert(mbox->mbox_fd == -1 && mbox->mbox_readonly); + } else { + if (mbox->mbox_fd == -1) { + if (mbox_file_open(mbox) < 0) + return -1; + } - mbox->mbox_stream = - i_stream_create_raw_mbox(mbox->mbox_file_stream, - mbox->path); - return 0; - } - - if (mbox->mbox_fd == -1) { - if (mbox_file_open(mbox) < 0) - return -1; - } - - if (mbox->mbox_writeonly) - mbox->mbox_file_stream = i_stream_create_from_data(NULL, 0); - else { - mbox->mbox_file_stream = - i_stream_create_fd(mbox->mbox_fd, - MAIL_READ_BLOCK_SIZE, FALSE); + if (mbox->mbox_writeonly) { + mbox->mbox_file_stream = + i_stream_create_from_data(NULL, 0); + } else { + mbox->mbox_file_stream = + i_stream_create_fd(mbox->mbox_fd, + MAIL_READ_BLOCK_SIZE, FALSE); + } } mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream, mbox->path); + if (mbox->mbox_lock_type != F_UNLCK) + istream_raw_mbox_set_locked(mbox->mbox_stream); return 0; } diff --git a/src/lib-storage/index/mbox/mbox-lock.c b/src/lib-storage/index/mbox/mbox-lock.c index ad7ad1c8df..905b504b4a 100644 --- a/src/lib-storage/index/mbox/mbox-lock.c +++ b/src/lib-storage/index/mbox/mbox-lock.c @@ -5,6 +5,7 @@ #include "nfs-workarounds.h" #include "mail-index-private.h" #include "mbox-storage.h" +#include "istream-raw-mbox.h" #include "mbox-file.h" #include "mbox-lock.h" @@ -714,6 +715,8 @@ int mbox_lock(struct mbox_mailbox *mbox, int lock_type, mbox->mbox_excl_locks++; *lock_id_r = mbox->mbox_lock_id + 1; } + if (mbox->mbox_stream != NULL) + istream_raw_mbox_set_locked(mbox->mbox_stream); return 1; } @@ -759,6 +762,10 @@ int mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id) } /* all locks gone */ + /* make sure we don't read the stream while unlocked */ + if (mbox->mbox_stream != NULL) + istream_raw_mbox_set_unlocked(mbox->mbox_stream); + memset(&ctx, 0, sizeof(ctx)); ctx.mbox = mbox; diff --git a/src/lib-storage/index/mbox/mbox-mail.c b/src/lib-storage/index/mbox/mbox-mail.c index 6ff5811529..9336390a08 100644 --- a/src/lib-storage/index/mbox/mbox-mail.c +++ b/src/lib-storage/index/mbox/mbox-mail.c @@ -194,9 +194,10 @@ mbox_mail_get_next_offset(struct index_mail *mail, uoff_t *next_offset_r) } /* We can't really trust trans_view. The next message may already be - expunged from it. Also there hdr.messages_count may be incorrect. + expunged from it. Also hdr.messages_count may be incorrect there. So refresh the index to get the latest changes and get the next message's offset using a new view. */ + i_assert(mbox->mbox_lock_type != F_UNLCK); if (mbox_sync_header_refresh(mbox) < 0) return -1;