mail-cache.c revision cf3bea6d9b57f8608bec22d98ad547a507b05f66
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "lib.h"
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#include "array.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "buffer.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "hash.h"
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen#include "nfs-workarounds.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "file-cache.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "mmap-util.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "write-full.h"
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen#include "mail-cache-private.h"
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen#include <unistd.h>
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildevoid mail_cache_set_syscall_error(struct mail_cache *cache,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde const char *function)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde i_assert(function != NULL);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (ENOSPACE(errno)) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->index->nodiskspace = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_index_set_error(cache->index,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde "%s failed with index cache file %s: %m",
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen function, cache->filepath);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen va_list va;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen (void)unlink(cache->filepath);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* mark the cache as unusable */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->hdr = NULL;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen va_start(va, fmt);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde t_push();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen cache->filepath, t_strdup_vprintf(fmt, va));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen t_pop();
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen va_end(va);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenvoid mail_cache_file_close(struct mail_cache *cache)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (cache->mmap_base != NULL) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (munmap(cache->mmap_base, cache->mmap_length) < 0)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde mail_cache_set_syscall_error(cache, "munmap()");
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (cache->file_cache != NULL)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen file_cache_set_fd(cache->file_cache, -1);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->mmap_base = NULL;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->data = NULL;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->hdr = NULL;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->mmap_length = 0;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->last_field_header_offset = 0;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (cache->file_lock != NULL)
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen file_lock_free(&cache->file_lock);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen cache->locked = FALSE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (cache->fd != -1) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (close(cache->fd) < 0)
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen mail_cache_set_syscall_error(cache, "close()");
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->fd = -1;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen }
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void mail_cache_init_file_cache(struct mail_cache *cache)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen struct stat st;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (cache->file_cache == NULL)
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen return;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (cache->index->nfs_flush) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde nfs_flush_attr_cache_fd(cache->filepath, cache->fd);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde nfs_flush_read_cache(cache->filepath, cache->fd,
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen F_UNLCK, FALSE);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde file_cache_set_fd(cache->file_cache, cache->fd);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fstat(cache->fd, &st) < 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen else
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen file_cache_set_size(cache->file_cache, st.st_size);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool mail_cache_need_reopen(struct mail_cache *cache)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct stat st1, st2;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (MAIL_CACHE_IS_UNUSABLE(cache)) {
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen if (cache->need_compress_file_seq != 0) {
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen /* we're waiting for compression */
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen return FALSE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(cache->index)) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* disabled */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return FALSE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
89fda66c5c4204f3bc27e160fbadb463e028b811Timo Sirainen }
89fda66c5c4204f3bc27e160fbadb463e028b811Timo Sirainen
89fda66c5c4204f3bc27e160fbadb463e028b811Timo Sirainen if (cache->fd == -1)
89fda66c5c4204f3bc27e160fbadb463e028b811Timo Sirainen return TRUE;
89fda66c5c4204f3bc27e160fbadb463e028b811Timo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen /* see if the file has changed */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fstat(cache->fd, &st1) < 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (stat(cache->filepath, &st2) < 0) {
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen mail_cache_set_syscall_error(cache, "stat()");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return st1.st_ino != st2.st_ino ||
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen !CMP_DEV_T(st1.st_dev, st2.st_dev);
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenint mail_cache_reopen(struct mail_cache *cache)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mail_index_view *view;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const struct mail_index_ext *ext;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_assert(!cache->locked);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!mail_cache_need_reopen(cache)) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* reopening does no good */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_file_close(cache);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->fd = nfs_safe_open(cache->filepath,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->index->readonly ? O_RDONLY : O_RDWR);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (cache->fd == -1) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (errno == ENOENT)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen cache->need_compress_file_seq = 0;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen else
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mail_cache_init_file_cache(cache);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (mail_cache_map(cache, 0, 0) < 0)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return -1;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (mail_cache_header_fields_read(cache) < 0)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return -1;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen view = mail_index_view_open(cache->index);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (ext == NULL || cache->hdr->file_seq != ext->reset_id) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* still different - maybe a race condition or maybe the
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen file_seq really is corrupted. either way, this shouldn't
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen happen often so we'll just mark cache to be compressed
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen later which fixes this. */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen cache->need_compress_file_seq = cache->hdr->file_seq;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen mail_index_view_close(&view);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return 0;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen mail_index_view_close(&view);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen i_assert(!MAIL_CACHE_IS_UNUSABLE(cache));
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return 1;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen}
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainenstatic bool mail_cache_verify_header(struct mail_cache *cache)
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen{
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen const struct mail_cache_header *hdr = cache->data;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* check that the header is still ok */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen mail_cache_set_corrupted(cache, "File too small");
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return FALSE;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (hdr->version != MAIL_CACHE_VERSION) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* version changed - upgrade silently */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return FALSE;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (hdr->compat_sizeof_uoff_t != sizeof(uoff_t)) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* architecture change - handle silently(?) */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return FALSE;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (hdr->indexid != cache->index->indexid) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* index id changed - handle silently */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return FALSE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (hdr->file_seq == 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mail_cache_set_corrupted(cache, "file_seq is 0");
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return FALSE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* only check the header if we're locked */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (!cache->locked)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return TRUE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (hdr->used_file_size < sizeof(struct mail_cache_header)) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too small");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if ((hdr->used_file_size % sizeof(uint32_t)) != 0) {
2ba63f475f74b2aa87f9fd9e28a6c5738deb0878Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size not aligned");
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (cache->mmap_base != NULL &&
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen hdr->used_file_size > cache->mmap_length) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too large");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return TRUE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenint mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen{
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen ssize_t ret;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen cache->remap_counter++;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (size == 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen size = sizeof(struct mail_cache_header);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (cache->file_cache != NULL) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->data = NULL;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->hdr = NULL;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen ret = file_cache_read(cache->file_cache, offset, size);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (ret < 0) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen /* In case of ESTALE we'll simply fail without error
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen messages. The caller will then just have to
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen fallback to generating the value itself.
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen We can't simply reopen the cache flie, because
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen using it requires also having updated file
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen offsets. */
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (errno != ESTALE)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen mail_cache_set_syscall_error(cache, "read()");
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return -1;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->data = file_cache_get_map(cache->file_cache,
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen &cache->mmap_length);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (offset == 0) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (!mail_cache_verify_header(cache)) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->need_compress_file_seq =
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache) &&
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->hdr->file_seq != 0 ?
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->hdr->file_seq : 0;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return -1;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde memcpy(&cache->hdr_ro_copy, cache->data,
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen sizeof(cache->hdr_ro_copy));
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->hdr = &cache->hdr_ro_copy;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return 0;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (offset < cache->mmap_length &&
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde size <= cache->mmap_length - offset) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* already mapped */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (cache->mmap_base != NULL) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (munmap(cache->mmap_base, cache->mmap_length) < 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen } else {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (cache->fd == -1) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* unusable, waiting for compression or
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde index is in memory */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde i_assert(cache->need_compress_file_seq != 0 ||
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde MAIL_INDEX_IS_IN_MEMORY(cache->index));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen /* map the whole file */
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->hdr = NULL;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->mmap_length = 0;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cache->mmap_base = mmap_ro_file(cache->fd, &cache->mmap_length);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (cache->mmap_base == MAP_FAILED) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->mmap_base = NULL;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->data = NULL;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde mail_cache_set_syscall_error(cache, "mmap()");
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen cache->data = cache->mmap_base;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!mail_cache_verify_header(cache)) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->need_compress_file_seq =
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen !MAIL_CACHE_IS_UNUSABLE(cache) &&
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen cache->hdr->file_seq != 0 ?
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->hdr->file_seq : 0;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen return -1;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen }
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen cache->hdr = cache->data;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen return 0;
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen}
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainenstatic int mail_cache_try_open(struct mail_cache *cache)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->opened = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(cache->index))
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return 0;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen cache->fd = nfs_safe_open(cache->filepath,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->index->readonly ? O_RDONLY : O_RDWR);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (cache->fd == -1) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (errno == ENOENT) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde cache->need_compress_file_seq = 0;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde mail_cache_init_file_cache(cache);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return -1;
3d422a98304352692cb1f3585ac6481d5c4b4155Timo Sirainen
3d422a98304352692cb1f3585ac6481d5c4b4155Timo Sirainen return 1;
3d422a98304352692cb1f3585ac6481d5c4b4155Timo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenint mail_cache_open_and_verify(struct mail_cache *cache)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen int ret;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ret = mail_cache_try_open(cache);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (ret > 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen ret = mail_cache_header_fields_read(cache);
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen if (ret < 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* failed for some reason - doesn't really matter,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen it's disabled for now. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_file_close(cache);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen return ret;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainenstatic struct mail_cache *mail_cache_alloc(struct mail_index *index)
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen{
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen struct mail_cache *cache;
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen cache = i_new(struct mail_cache, 1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->index = index;
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen cache->fd = -1;
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen cache->filepath =
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen i_strconcat(index->filepath, MAIL_CACHE_FILE_SUFFIX, NULL);
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen cache->field_pool = pool_alloconly_create("Cache fields", 1024);
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen cache->field_name_hash =
28abd7c6e719c430b7ab83b3e5d46f12d197b9caTimo Sirainen hash_create(default_pool, cache->field_pool, 0,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen cache->dotlock_settings.use_excl_lock = index->use_excl_dotlocks;
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen cache->dotlock_settings.nfs_flush = index->nfs_flush;
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen cache->dotlock_settings.timeout = MAIL_CACHE_LOCK_TIMEOUT;
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen cache->dotlock_settings.stale_timeout = MAIL_CACHE_LOCK_CHANGE_TIMEOUT;
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen if (!MAIL_INDEX_IS_IN_MEMORY(index)) {
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen if (index->mmap_disable)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->file_cache = file_cache_new(-1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache->ext_id =
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_index_ext_register(index, "cache", 0,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen sizeof(uint32_t), sizeof(uint32_t));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_index_register_expunge_handler(index, cache->ext_id, FALSE,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_expunge_handler, cache);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_index_register_sync_handler(index, cache->ext_id,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_sync_handler,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen MAIL_INDEX_SYNC_HANDLER_FILE |
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen MAIL_INDEX_SYNC_HANDLER_HEAD |
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen (cache->file_cache == NULL ? 0 :
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen MAIL_INDEX_SYNC_HANDLER_VIEW));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen if (cache->file_cache != NULL) {
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen mail_index_register_sync_lost_handler(index,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde mail_cache_sync_lost_handler);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return cache;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct mail_cache *cache;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen cache = mail_cache_alloc(index);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return cache;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstruct mail_cache *mail_cache_create(struct mail_index *index)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct mail_cache *cache;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen cache = mail_cache_alloc(index);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!MAIL_INDEX_IS_IN_MEMORY(index)) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (unlink(cache->filepath) < 0 && errno != ENOENT)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mail_cache_set_syscall_error(cache, "unlink()");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen return cache;
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen}
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenvoid mail_cache_free(struct mail_cache **_cache)
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen{
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen struct mail_cache *cache = *_cache;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen *_cache = NULL;
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen if (cache->file_cache != NULL) {
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen mail_index_unregister_sync_lost_handler(cache->index,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_cache_sync_lost_handler);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen file_cache_free(&cache->file_cache);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mail_index_unregister_expunge_handler(cache->index, cache->ext_id);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen mail_index_unregister_sync_handler(cache->index, cache->ext_id);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen mail_cache_file_close(cache);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen hash_destroy(&cache->field_name_hash);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen pool_unref(&cache->field_pool);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen i_free(cache->field_file_map);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen i_free(cache->file_field_map);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen i_free(cache->fields);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen i_free(cache->filepath);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen i_free(cache);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenvoid mail_cache_flush_read_cache(struct mail_cache *cache, bool just_locked)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!cache->index->nfs_flush)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* Assume flock() is independent of fcntl() locks. This isn't true
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen with Linux 2.6 NFS, but with it there's no point in using flock() */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (cache->locked &&
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->index->lock_method == FILE_LOCK_METHOD_FCNTL) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen nfs_flush_read_cache(cache->filepath, cache->fd,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen F_WRLCK, just_locked);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen } else {
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen nfs_flush_read_cache(cache->filepath, cache->fd,
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen F_UNLCK, FALSE);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic int mail_cache_lock_file(struct mail_cache *cache)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen int ret;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (cache->index->lock_method != FILE_LOCK_METHOD_DOTLOCK) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(cache->file_lock == NULL);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ret = mail_index_lock_fd(cache->index, cache->filepath,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->fd, F_WRLCK,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen MAIL_CACHE_LOCK_TIMEOUT,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen &cache->file_lock);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen } else {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen i_assert(cache->dotlock == NULL);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ret = file_dotlock_create(&cache->dotlock_settings,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen cache->filepath, 0, &cache->dotlock);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (ret <= 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return ret;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_cache_flush_read_cache(cache, TRUE);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return 1;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic void mail_cache_unlock_file(struct mail_cache *cache)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (cache->index->lock_method != FILE_LOCK_METHOD_DOTLOCK)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen file_unlock(&cache->file_lock);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen else
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen (void)file_dotlock_delete(&cache->dotlock);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenint mail_cache_lock(struct mail_cache *cache, bool require_same_reset_id)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const struct mail_index_ext *ext;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct mail_index_view *iview;
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen uint32_t reset_id;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen int i, ret;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(!cache->locked);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (!cache->opened)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen (void)mail_cache_open_and_verify(cache);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache) ||
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen MAIL_INDEX_IS_IN_MEMORY(cache->index))
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return 0;
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen iview = mail_index_view_open(cache->index);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ext = mail_index_view_get_ext(iview, cache->ext_id);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen reset_id = ext == NULL ? 0 : ext->reset_id;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen mail_index_view_close(&iview);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ext == NULL && require_same_reset_id) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen /* cache not used */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen return 0;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen for (i = 0; i < 3; i++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (cache->hdr->file_seq != reset_id &&
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen (require_same_reset_id || i == 0)) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen /* we want the latest cache file */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ret = mail_cache_reopen(cache);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ret <= 0)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen break;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ret = mail_cache_lock_file(cache);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ret <= 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen break;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen cache->locked = TRUE;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (cache->hdr->file_seq == reset_id ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen !require_same_reset_id) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* got it */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen break;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen /* okay, so it was just compressed. try again. */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch (void)mail_cache_unlock(cache);
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch ret = 0;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ret > 0) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen /* make sure our header is up to date */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (cache->file_cache != NULL) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen file_cache_invalidate(cache->file_cache, 0,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen sizeof(struct mail_cache_header));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (mail_cache_map(cache, 0, 0) == 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->hdr_copy = *cache->hdr;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen else {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen (void)mail_cache_unlock(cache);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ret = -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen i_assert((ret <= 0 && !cache->locked) || (ret > 0 && cache->locked));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return ret;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic void mail_cache_update_need_compress(struct mail_cache *cache)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const struct mail_cache_header *hdr = cache->hdr;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen unsigned int cont_percentage;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen uoff_t max_del_space;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cont_percentage = hdr->continued_record_count * 100 /
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen (cache->index->map->rec_map->records_count == 0 ? 1 :
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->index->map->rec_map->records_count);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (cont_percentage >= MAIL_CACHE_COMPRESS_CONTINUED_PERCENTAGE &&
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen hdr->used_file_size >= MAIL_CACHE_COMPRESS_MIN_SIZE) {
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen /* too many continued rows, compress */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen cache->need_compress_file_seq = hdr->file_seq;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* see if we've reached the max. deleted space in file */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen max_del_space = hdr->used_file_size / 100 *
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen MAIL_CACHE_COMPRESS_PERCENTAGE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (hdr->deleted_space >= max_del_space &&
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen hdr->used_file_size >= MAIL_CACHE_COMPRESS_MIN_SIZE)
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen cache->need_compress_file_seq = hdr->file_seq;
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenint mail_cache_unlock(struct mail_cache *cache)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen int ret = 0;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen i_assert(cache->locked);
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (cache->field_header_write_pending)
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen ret = mail_cache_header_fields_update(cache);
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen cache->locked = FALSE;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache)) {
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen /* we found it to be broken during the lock. just clean up. */
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen cache->hdr_modified = FALSE;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen return -1;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen }
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (cache->hdr_modified) {
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen cache->hdr_modified = FALSE;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (mail_cache_write(cache, &cache->hdr_copy,
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen sizeof(cache->hdr_copy), 0) < 0)
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen ret = -1;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen cache->hdr_ro_copy = cache->hdr_copy;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen mail_cache_update_need_compress(cache);
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen }
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (cache->index->nfs_flush) {
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (fdatasync(cache->fd) < 0)
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen }
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen mail_cache_unlock_file(cache);
d03a871a77f8ec36f48f5fea98d810e51b186fdbTimo Sirainen return ret;
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen}
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainenint mail_cache_write(struct mail_cache *cache, const void *data, size_t size,
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen uoff_t offset)
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen{
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (pwrite_full(cache->fd, data, size, offset) < 0) {
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen return -1;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen }
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen
a43145989f87ec68754e21234e7b6d892c4a4421Timo Sirainen if (cache->file_cache != NULL) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen file_cache_write(cache->file_cache, data, size, offset);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* data pointer may change if file cache was grown */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen cache->data = file_cache_get_map(cache->file_cache,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen &cache->mmap_length);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
36bf6cd88b1c71055ef12b07253f5223d981e43dTimo Sirainen return 0;
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen}
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen
36bf6cd88b1c71055ef12b07253f5223d981e43dTimo Sirainenstruct mail_cache_view *
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenmail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct mail_cache_view *view;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen view = i_new(struct mail_cache_view, 1);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen view->cache = cache;
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen view->view = iview;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_array_init(&view->looping_offsets, 32);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen view->cached_exists_buf =
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen buffer_create_dynamic(default_pool,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen cache->file_fields_count + 10);
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen return view;
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen}
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainen
0f4fb03953afa4a39d5e32e9ca0527c0a84f9aeeTimo Sirainenvoid mail_cache_view_close(struct mail_cache_view *view)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_assert(view->trans_view == NULL);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (view->cache->field_header_write_pending)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen (void)mail_cache_header_fields_update(view->cache);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen array_free(&view->looping_offsets);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen buffer_free(&view->cached_exists_buf);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_free(view);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen