mail-cache.c revision 131b073bdc3650083b00616dc778dd3017c2bbb5
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenvoid mail_cache_set_syscall_error(struct mail_cache *cache,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_index_file_set_syscall_error(cache->index, cache->filepath,
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic void mail_cache_unlink(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenvoid mail_cache_reset(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* mark the cache as unusable */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen "Corrupted index cache file %s: %s",
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenvoid mail_cache_file_close(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "close()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic void mail_cache_init_file_cache(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen (void)file_cache_set_size(cache->file_cache, st.st_size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic bool mail_cache_need_reopen(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* we're waiting for compression */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* disabled */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* see if the file has changed */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if ((cache->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (nfs_safe_stat(cache->filepath, &st) < 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "stat()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* file changed */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if ((cache->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* if the old file has been deleted, the new file may have
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen the same inode as the old one. we'll catch this here by
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen checking if fstat() fails with ESTALE */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenint mail_cache_reopen(struct mail_cache *cache)
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* reopening does no good */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (ext == NULL || cache->hdr->file_seq != ext->reset_id) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* still different - maybe a race condition or maybe the
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen file_seq really is corrupted. either way, this shouldn't
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen happen often so we'll just mark cache to be compressed
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen later which fixes this. */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainenstatic void mail_cache_update_need_compress(struct mail_cache *cache)
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen const struct mail_cache_header *hdr = cache->hdr;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen cont_percentage = hdr->continued_record_count * 100 /
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen (cache->index->map->rec_map->records_count == 0 ? 1 :
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (cont_percentage >= MAIL_CACHE_COMPRESS_CONTINUED_PERCENTAGE &&
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* too many continued rows, compress */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen cache->need_compress_file_seq = hdr->file_seq;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* see if we've reached the max. deleted space in file */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen max_del_space = file_size / 100 * MAIL_CACHE_COMPRESS_PERCENTAGE;
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen cache->need_compress_file_seq = hdr->file_seq;
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmodystatic bool mail_cache_verify_header(struct mail_cache *cache,
2f16d2e0b4408370cd44db359759b23a8c0656d3Phil Carmody /* check that the header is still ok */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_corrupted(cache, "File too small");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen /* version changed - upgrade silently */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (hdr->compat_sizeof_uoff_t != sizeof(uoff_t)) {
9644b7914445f0fb1098038218bfcb7d135a8698Timo Sirainen /* architecture change - handle silently(?) */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen /* index id changed - handle silently */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen mail_cache_set_corrupted(cache, "file_seq is 0");
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainenmail_cache_map_finish(struct mail_cache *cache, uoff_t offset, size_t size,
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen const struct mail_cache_header *hdr = hdr_data;
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen /* verify the header validity only with offset=0. this way
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen we won't waste time re-verifying it all the time */
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainenmail_cache_map_with_read(struct mail_cache *cache, size_t offset, size_t size,
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen const void **data_r)
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen cache->read_offset + cache->read_buf->used >= offset+size) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen /* already mapped */
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen *data_r = CONST_PTR_OFFSET(cache->read_buf->data,
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen return mail_cache_map_finish(cache, offset, size, hdr_data, TRUE);
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen if (offset == 0 && size < MAIL_CACHE_MIN_HEADER_READ_SIZE) {
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen /* we can usually read the fields header after the cache
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen header. we need them both, so try to read them all with one
45b0d8d0b97be14d10e3a3c12c169e4b352b2aacTimo Sirainen pread() call. */
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen data = buffer_append_space_unsafe(cache->read_buf, size);
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen mail_cache_set_syscall_error(cache, "read()");
5806683c1c3f5b1997e92a023c0fe39912d4df5dTimo Sirainen return mail_cache_map_finish(cache, offset, size, hdr_data, TRUE);
const void **data_r)
const void *data;
if (size == 0)
if (ret < 0) {
const void *data;
&data) < 0)
int ret;
if (ret > 0)
if (ret < 0) {
return ret;
return cache;
return cache;
return cache;
unsigned int timeout_secs;
int ret;
if (ret < 0) {
if (ret <= 0)
return ret;
TRUE);
bool nonblock)
const void *data;
int i, ret;
(require_same_reset_id || i == 0)) {
ret = 0;
ret = 0;
if (ret > 0) {
sizeof(struct mail_cache_header));
return ret;
int ret = 0;
return ret;
if (*offset == 0) {
struct mail_cache_view *
return view;
bool update)
&message_count)) {
return first_new_seq;