mail-cache.c revision e015e2f7e7f48874495f9df8b0dd192b7ffcb5cc
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "buffer.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "hash.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "file-lock.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mmap-util.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "write-full.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-cache-private.h"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <unistd.h>
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenuint32_t mail_cache_uint32_to_offset(uint32_t offset)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned char buf[4];
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(offset < 0x40000000);
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen i_assert((offset & 3) == 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen offset >>= 2;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buf[2] = 0x80 | ((offset & 0x00003f80) >> 7);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen buf[3] = 0x80 | (offset & 0x0000007f);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return *((uint32_t *) buf);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenuint32_t mail_cache_offset_to_uint32(uint32_t offset)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const unsigned char *buf = (const unsigned char *) &offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((offset & 0x80808080) != 0x80808080)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return (((uint32_t)buf[3] & 0x7f) << 2) |
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (((uint32_t)buf[2] & 0x7f) << 9) |
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen (((uint32_t)buf[1] & 0x7f) << 16) |
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (((uint32_t)buf[0] & 0x7f) << 23);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_cache_set_syscall_error(struct mail_cache *cache,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *function)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(function != NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ENOSPACE(errno)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cache->index->nodiskspace = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_set_error(cache->index,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "%s failed with index cache file %s: %m",
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen function, cache->filepath);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen}
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen va_list va;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)unlink(cache->filepath);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_cache_file_close(cache);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen va_start(va, fmt);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen t_push();
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->filepath, t_strdup_vprintf(fmt, va));
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen t_pop();
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen va_end(va);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen}
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainenvoid mail_cache_file_close(struct mail_cache *cache)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen{
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (cache->mmap_base != NULL) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->mmap_base = NULL;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->hdr = NULL;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->mmap_length = 0;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (cache->fd != -1) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (close(cache->fd) < 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_cache_set_syscall_error(cache, "close()");
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->fd = -1;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen}
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainenint mail_cache_reopen(struct mail_cache *cache)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen{
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache) && cache->need_compress) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* unusable, we're just waiting for compression */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen return 0;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_cache_file_close(cache);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cache->fd = open(cache->filepath, O_RDWR);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (cache->fd == -1) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (errno == ENOENT)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen cache->need_compress = TRUE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen else
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mail_cache_map(cache, 0, 0) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mail_cache_header_fields_read(cache) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* still different - maybe a race condition or maybe the
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen file_seq really is corrupted. either way, this shouldn't
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen happen often so we'll just mark cache to be compressed
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen later which fixes this. */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen cache->need_compress = TRUE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 0;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenstatic int mmap_verify_header(struct mail_cache *cache)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen const struct mail_cache_header *hdr;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* check that the header is still ok */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_cache_set_corrupted(cache, "File too small");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return FALSE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen cache->hdr = hdr = cache->mmap_base;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (cache->hdr->version != MAIL_CACHE_VERSION) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* version changed - upgrade silently */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return FALSE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (cache->hdr->indexid != cache->index->indexid) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* index id changed */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_cache_set_corrupted(cache, "indexid changed");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return FALSE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* only check the header if we're locked */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (cache->locked)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return TRUE;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (hdr->used_file_size < sizeof(struct mail_cache_header)) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size too small");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if ((hdr->used_file_size % sizeof(uint32_t)) != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size not aligned");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (hdr->used_file_size > cache->mmap_length) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too large");
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return FALSE;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return TRUE;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen}
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainenint mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen{
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (size == 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen size = sizeof(struct mail_cache_header);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (offset < cache->mmap_length &&
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen size <= cache->mmap_length - offset) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen /* already mapped */
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return 0;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (cache->mmap_base != NULL) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen } else {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (cache->fd == -1) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* unusable, waiting for compression */
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen i_assert(cache->need_compress);
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* map the whole file */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen cache->hdr = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cache->mmap_length = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen cache->mmap_base = mmap_ro_file(cache->fd, &cache->mmap_length);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (cache->mmap_base == MAP_FAILED) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cache->mmap_base = NULL;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen mail_cache_set_syscall_error(cache, "mmap()");
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen return -1;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!mmap_verify_header(cache)) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->need_compress = TRUE;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
49ec317299dedfbc27be79ab97d5b7a8ba7a4eacTimo Sirainen return 0;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainenstatic int mail_cache_open_and_verify(struct mail_cache *cache)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->filepath = i_strconcat(cache->index->filepath,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen MAIL_CACHE_FILE_PREFIX, NULL);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->fd = open(cache->filepath, O_RDWR);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (cache->fd == -1) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (errno == ENOENT) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen cache->need_compress = TRUE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return 0;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
009217abb57a24a4076092e8e4e165545747839eStephan Bosch return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return mail_cache_header_fields_read(cache);
49ec317299dedfbc27be79ab97d5b7a8ba7a4eacTimo Sirainen}
009217abb57a24a4076092e8e4e165545747839eStephan Bosch
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct mail_cache *cache;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache = i_new(struct mail_cache, 1);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->index = index;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->fd = -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cache->field_pool = pool_alloconly_create("Cache fields", 512);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen cache->field_name_hash =
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hash_create(default_pool, cache->field_pool, 0,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!index->mmap_disable && !index->mmap_no_write) {
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (mail_cache_open_and_verify(cache) < 0) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* failed for some reason - doesn't really matter,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen it's disabled for now. */
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen mail_cache_file_close(cache);
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen }
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen return cache;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_cache_free(struct mail_cache *cache)
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_cache_file_close(cache);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen hash_destroy(cache->field_name_hash);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen pool_unref(cache->field_pool);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_free(cache->file_field_map);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_free(cache->filepath);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_free(cache);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen}
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainenint mail_cache_lock(struct mail_cache *cache)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen{
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen int i, ret;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen i_assert(!cache->locked);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen return 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* we want the latest cache file */
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen if ((ret = mail_cache_reopen(cache)) <= 0)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return ret;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen }
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen for (i = 0; i < 3; i++) {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if ((ret = file_wait_lock(cache->fd, F_WRLCK)) <= 0) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock()");
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen break;
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen }
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen cache->locked = TRUE;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq) {
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen /* got it */
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen break;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
87842f621233257b7a7945d994ba931508b34877Timo Sirainen /* okay, so it was just compressed. try again. */
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen mail_cache_unlock(cache);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen if ((ret = mail_cache_reopen(cache)) <= 0)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen return ret;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen ret = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (ret > 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cache->hdr_copy = *cache->hdr;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen return ret;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen}
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainenstatic void mail_cache_update_need_compress(struct mail_cache *cache)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen{
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen const struct mail_cache_header *hdr = cache->hdr;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen unsigned int cont_percentage;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen uoff_t max_del_space;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen cont_percentage = hdr->continued_record_count * 100 /
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen (cache->index->map->records_count == 0 ? 1 :
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen cache->index->map->records_count);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen if (cont_percentage >= COMPRESS_CONTINUED_PERCENTAGE &&
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen hdr->used_file_size >= COMPRESS_MIN_SIZE) {
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen /* too many continued rows, compress */
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen cache->need_compress = TRUE;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen /* see if we've reached the max. deleted space in file */
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen max_del_space = hdr->used_file_size / 100 * COMPRESS_PERCENTAGE;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (hdr->deleted_space >= max_del_space &&
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen hdr->used_file_size >= COMPRESS_MIN_SIZE)
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen cache->need_compress = TRUE;
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen}
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainenvoid mail_cache_unlock(struct mail_cache *cache)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen{
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen i_assert(cache->locked);
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen cache->locked = FALSE;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (cache->hdr_modified) {
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen cache->hdr_modified = FALSE;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (pwrite_full(cache->fd, &cache->hdr_copy,
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen sizeof(cache->hdr_copy), 0) < 0)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen mail_cache_update_need_compress(cache);
87842f621233257b7a7945d994ba931508b34877Timo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (file_wait_lock(cache->fd, F_UNLCK) <= 0)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen}
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainenstruct mail_cache_view *
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainenmail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen{
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen struct mail_cache_view *view;
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view = i_new(struct mail_cache_view, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->cache = cache;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->view = iview;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen view->cached_exists_buf =
892e25e1c0caad62ced087d9eba2741a59e3d9ceTimo Sirainen buffer_create_dynamic(default_pool,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen cache->file_fields_count + 10,
3c3001681da75afc68578a180ec8f8b2d6dfacfaTimo Sirainen (size_t)-1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return view;
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid mail_cache_view_close(struct mail_cache_view *view)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen buffer_free(view->cached_exists_buf);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_free(view);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen