mail-cache.c revision ba482d3624ca4f1b3d638e6e8470ba5134f21493
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen sizeof(struct mail_sent_date),
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen 0, 0, 0, 0, 0,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen /* variable sized */
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainenenum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT] = {
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainenuint32_t mail_cache_uint32_to_offset(uint32_t offset)
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainen buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainenuint32_t mail_cache_offset_to_uint32(uint32_t offset)
9315dd69233d554452df0c12bc57002d2042a8f4Timo Sirainen const unsigned char *buf = (const unsigned char *) &offset;
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainenvoid mail_cache_set_syscall_error(struct mail_cache *cache,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "%s failed with index cache file %s: %m",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenstatic void mail_cache_file_close(struct mail_cache *cache)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "close()");
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenstatic int mail_cache_file_reopen(struct mail_cache *cache)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenstatic int mmap_verify_header(struct mail_cache *cache)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* check that the header is still ok */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_cache_set_corrupted(cache, "File too small");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (cache->hdr->indexid != cache->index->indexid) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* index id changed */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_cache_set_corrupted(cache, "indexid changed");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we've updated used_file_size, do nothing */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* only check the header if we're locked */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen used_file_size = nbo_to_uint32(hdr->used_file_size);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (used_file_size < sizeof(struct mail_cache_header)) {
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too small");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if ((used_file_size % sizeof(uint32_t)) != 0) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size not aligned");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size too large");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic int mmap_update_nocheck(struct mail_cache *cache,
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen#if 0 // FIXME
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen /* if sequence has changed, the file has to be reopened.
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen note that if main index isn't locked, it may change again */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq &&
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* already mapped */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* requesting the whole file - see if we need to
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* in the middle of transaction - write the changes */
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (msync(cache->mmap_base, cache->mmap_length,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_cache_set_syscall_error(cache, "msync()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* map the whole file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cache->mmap_base = mmap_rw_file(cache->fd, &cache->mmap_length);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_cache_set_syscall_error(cache, "mmap()");
075f90abe6b6b12dc72bca21bfce8086b4b190ecTimo Sirainen /* re-mmaped, check header */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenint mail_cache_mmap_update(struct mail_cache *cache, size_t offset, size_t size)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mmap_update_nocheck(cache, offset, size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#if 0 // FIXME
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* see if cache file was rebuilt - do it only once to avoid
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen infinite looping */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq ||
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (st.st_size < sizeof(struct mail_cache_header))
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainen if (mmap_update_nocheck(cache, 0, sizeof(struct mail_cache_header)) < 0)
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen /* verify that this really is the cache for wanted index */
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenstatic int mail_cache_open_or_create_file(struct mail_cache *cache,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen cache->filepath = i_strconcat(cache->index->filepath,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen ret = mail_cache_open_and_verify(cache, FALSE);
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen /* maybe a rebuild.. */
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen fd = file_dotlock_open(cache->filepath, NULL, NULL,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_open()");
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen /* see if someone else just created the cache file */
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen ret = mail_cache_open_and_verify(cache, TRUE);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen (void)file_dotlock_delete(cache->filepath, NULL, fd);
cd5ee8630497fdbd853ef588a858b4ef619a5e03Timo Sirainen /* rebuild then */
7394389230750c45b105cdefb5850c81cae8cdc0Timo Sirainen mail_cache_set_syscall_error(cache, "write_full()");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen (void)file_dotlock_delete(cache->filepath, NULL, fd);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen (void)file_dotlock_delete(cache->filepath, NULL, fd);
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
51920d00fa50edf7b2e9b1019288d64b7abee7f3Timo Sirainen sizeof(struct mail_cache_header)) < 0)
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainenstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen hdr.file_seq = index->hdr->cache_file_seq + 1;
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen cache->split_header_pool = pool_alloconly_create("Headers", 512);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_cache_open_or_create_file(cache, &hdr) < 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* failed for some reason - doesn't really matter,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen just disable caching. */
5a7b52012bf77132bb8f466d07e0e88c63fdba42Timo Sirainen cache->filepath = i_strdup_printf("(disabled cache for %s)",
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenvoid mail_cache_set_defaults(struct mail_cache *cache,
5a7b52012bf77132bb8f466d07e0e88c63fdba42Timo Sirainen cache->default_cache_fields = default_cache_fields;
5a7b52012bf77132bb8f466d07e0e88c63fdba42Timo Sirainen cache->never_cache_fields = never_cache_fields;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen hdr.file_seq = cache->index->hdr->cache_file_seq + 1;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen fd = file_dotlock_open(cache->filepath, NULL, NULL,
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_open()");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "write_full()");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen (void)file_dotlock_delete(cache->filepath, NULL, fd);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen (void)file_dotlock_delete(cache->filepath, NULL, fd);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen sizeof(struct mail_cache_header)) < 0)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenint mail_cache_lock(struct mail_cache *cache, int nonblock)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "file_try_lock()");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock()");
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainen if (mail_cache_mmap_update(cache, 0, 0) < 0) {
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenint mail_cache_unlock(struct mail_cache *cache)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (file_wait_lock(cache->fd, F_UNLCK) <= 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenint mail_cache_is_locked(struct mail_cache *cache)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenint mail_cache_need_reset(struct mail_cache *cache, uint32_t *new_file_seq_r)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenmail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainenvoid mail_cache_view_close(struct mail_cache_view *view)