mail-cache.c revision 5c841f2879f7870540c231a12eebfb5f6425219c
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Copyright (C) 2003 Timo Sirainen */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define _XOPEN_SOURCE 500 /* for pwrite() / Linux */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "lib.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "buffer.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "byteorder.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "file-lock.h"
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek#include "file-set-size.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "ioloop.h"
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek#include "mmap-util.h"
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek#include "write-full.h"
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek#include "mail-index.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "mail-index-util.h"
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher#include "mail-cache.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include <stddef.h>
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include <unistd.h>
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include <sys/stat.h>
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek/* Never compress the file if it's smaller than this */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define COMPRESS_MIN_SIZE (1024*50)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Compress the file when deleted space reaches n% of total size */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define COMPRESS_PERCENTAGE 20
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek/* Compress the file when n% of rows contain continued rows.
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek 200% means that there's 2 continued rows per record. */
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek#define COMPRESS_CONTINUED_PERCENTAGE 200
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek/* Initial size for the file */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define MAIL_CACHE_INITIAL_SIZE (sizeof(struct mail_cache_header) + 10240)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* When more space is needed, grow the file n% larger than the previous size */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define MAIL_CACHE_GROW_PERCENTAGE 10
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define MAIL_CACHE_LOCK_TIMEOUT 120
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define MAIL_CACHE_LOCK_STALE_TIMEOUT 60
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define CACHE_RECORD(cache, data_pos) \
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ((struct mail_cache_record *) \
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ((char *) (cache)->mmap_base + ((data_pos) & ~3)))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagherstruct mail_cache_header {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek uint32_t indexid;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t continued_record_count;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t used_file_size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t deleted_space;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t used_fields; /* enum mail_cache_field */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t field_usage_start; /* time_t */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t field_usage_counts[32];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t header_offsets[MAIL_CACHE_HEADERS_COUNT];
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher};
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstruct mail_cache_record {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t fields; /* enum mail_cache_field */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher uint32_t next_offset;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher uint32_t size; /* full record size, including this header */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher};
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstruct mail_cache {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek struct mail_index *index;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek char *filepath;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek int fd;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek void *mmap_base;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek size_t mmap_length;
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher uint32_t used_file_size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_header *header;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher pool_t split_header_pool;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t split_offsets[MAIL_CACHE_HEADERS_COUNT];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *const *split_headers[MAIL_CACHE_HEADERS_COUNT];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher enum mail_cache_field default_cache_fields;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher enum mail_cache_field never_cache_fields;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_transaction_ctx *trans_ctx;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned int locks;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek unsigned int anon_mmap:1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned int mmap_refresh:1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned int silent:1;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek};
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstruct mail_cache_transaction_ctx {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache *cache;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher unsigned int next_unused_header_lowwater;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned int last_idx;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct mail_cache_record cache_rec;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher buffer_t *cache_data;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher unsigned int first_uid, last_uid, prev_uid;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher enum mail_cache_field prev_fields;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_t *index_marks, *cache_marks;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher};
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherunsigned int mail_cache_field_sizes[32] = {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher sizeof(enum mail_index_record_flag),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher sizeof(uoff_t),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher 16,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher sizeof(struct mail_sent_date),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher sizeof(time_t),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher sizeof(uoff_t),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher sizeof(uoff_t),
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher 0, 0, 0, 0, 0,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* variable sized */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher};
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherenum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT] = {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MAIL_CACHE_HEADERS1,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher MAIL_CACHE_HEADERS2,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher MAIL_CACHE_HEADERS3,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MAIL_CACHE_HEADERS4
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher};
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const unsigned char *null4[] = { 0, 0, 0, 0 };
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const char *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghermail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int mail_cache_write(struct mail_cache_transaction_ctx *ctx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic struct mail_cache_record *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghermail_cache_lookup(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct mail_index_record *rec,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek enum mail_cache_field fields);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic uint32_t uint32_to_offset(uint32_t offset)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned char buf[4];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(offset < 0x40000000);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek i_assert((offset & 3) == 0);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset >>= 2;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buf[2] = 0x80 | ((offset & 0x00003f80) >> 7);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek buf[3] = 0x80 | (offset & 0x0000007f);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return *((uint32_t *) buf);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic uint32_t offset_to_uint32(uint32_t offset)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const unsigned char *buf = (const unsigned char *) &offset;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((offset & 0x80808080) != 0x80808080)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return (((uint32_t)buf[3] & 0x7f) << 2) |
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (((uint32_t)buf[2] & 0x7f) << 9) |
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (((uint32_t)buf[1] & 0x7f) << 16) |
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (((uint32_t)buf[0] & 0x7f) << 23);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekstatic int mail_cache_set_syscall_error(struct mail_cache *cache,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const char *function)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek i_assert(function != NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ENOSPACE(errno)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->nodiskspace = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher index_set_error(cache->index, "%s failed with index cache file %s: %m",
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher function, cache->filepath);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic int mail_cache_create_memory(struct mail_cache *cache,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct mail_cache_header *hdr)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_length = MAIL_CACHE_INITIAL_SIZE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_base = mmap_anon(cache->mmap_length);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->mmap_base == MAP_FAILED) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher index_set_error(cache->index, "mmap_anon(%"PRIuSIZE_T")",
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher cache->mmap_length);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->header = cache->mmap_base;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *cache->header = *hdr;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->anon_mmap = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->filepath = i_strdup_printf("(in-memory index cache for %s)",
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->mailbox_path);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void mail_cache_file_close(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->anon_mmap) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (munmap_anon(cache->mmap_base, cache->mmap_length) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_syscall_error(cache, "munmap_anon()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else if (cache->mmap_base != NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (munmap(cache->mmap_base, cache->mmap_length) < 0)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_set_syscall_error(cache, "munmap()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_base = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->header = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_length = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->fd != -1) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (close(cache->fd) < 0)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_set_syscall_error(cache, "close()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->fd = -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int mail_cache_file_reopen(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int fd;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (cache->anon_mmap) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* cache was set corrupted, we'll have to quit */
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek return FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek fd = open(cache->filepath, O_RDWR);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (fd == -1)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return mail_cache_set_syscall_error(cache, "open()");
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_cache_file_close(cache);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek cache->fd = fd;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic int mmap_verify_header(struct mail_cache *cache)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct mail_cache_header *hdr;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* check that the header is still ok */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->mmap_length < sizeof(struct mail_cache_header))
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return mail_cache_set_corrupted(cache, "File too small");
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek cache->header = hdr = cache->mmap_base;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->header->indexid != cache->index->indexid) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* index id changed */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (cache->header->indexid != 0)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek mail_cache_set_corrupted(cache, "indexid changed");
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->index->inconsistent = TRUE; /* easiest way to rebuild */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache->trans_ctx != NULL) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* we've updated used_file_size, do nothing */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek cache->used_file_size = nbo_to_uint32(hdr->used_file_size);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* only check the header if we're locked */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->locks == 0)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->used_file_size < sizeof(struct mail_cache_header)) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_cache_set_corrupted(cache, "used_file_size too small");
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return FALSE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if ((cache->used_file_size % sizeof(uint32_t)) != 0) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek mail_cache_set_corrupted(cache, "used_file_size not aligned");
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->used_file_size > cache->mmap_length) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* maybe a crash truncated the file - just fix it */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek hdr->used_file_size = uint32_to_nbo(cache->mmap_length & ~3);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (msync(cache->mmap_base, sizeof(*hdr), MS_SYNC) < 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return mail_cache_set_syscall_error(cache, "msync()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic int mmap_update_nocheck(struct mail_cache *cache,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek size_t offset, size_t size)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->header != NULL &&
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek cache->header->indexid != cache->index->indexid) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* indexid changed, most likely it was rebuilt.
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek try reopening. */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_cache_file_reopen(cache))
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* force mmap refresh */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek size = 0;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (size != 0 && offset < cache->mmap_length &&
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek size <= cache->mmap_length - offset) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* already mapped */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!cache->mmap_refresh)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek cache->mmap_refresh = FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache->anon_mmap)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->mmap_base != NULL) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (cache->locks != 0) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* in the middle of transaction - write the changes */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (msync(cache->mmap_base, cache->mmap_length,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MS_SYNC) < 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_syscall_error(cache, "msync()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (munmap(cache->mmap_base, cache->mmap_length) < 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher mail_cache_set_syscall_error(cache, "munmap()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(cache->fd != -1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* map the whole file */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->header = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_length = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_base = mmap_rw_file(cache->fd, &cache->mmap_length);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (cache->mmap_base == MAP_FAILED) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->mmap_base = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return mail_cache_set_syscall_error(cache, "mmap()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int mmap_update(struct mail_cache *cache, size_t offset, size_t size)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return mmap_update_nocheck(cache, offset, size) &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mmap_verify_header(cache);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct stat st;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_file_close(cache);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->fd = open(cache->filepath, O_RDWR);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (cache->fd == -1) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (errno == ENOENT)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return 0;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher mail_cache_set_syscall_error(cache, "open()");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return -1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (fstat(cache->fd, &st) < 0) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher mail_cache_set_syscall_error(cache, "fstat()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (st.st_size < sizeof(struct mail_cache_header))
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->mmap_refresh = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mmap_update_nocheck(cache, 0, sizeof(struct mail_cache_header)))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* verify that this really is the cache for wanted index */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->silent = silent;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mmap_verify_header(cache)) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher cache->silent = FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->silent = FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return 1;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void mail_index_clear_cache_offsets(struct mail_index *index)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct mail_index_record *rec;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher index->sync_stamp = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rec = index->lookup(index, 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (rec != NULL) {
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek rec->cache_offset = 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek rec = index->next(index, rec);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekstatic int mail_cache_open_or_create_file(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_header *hdr)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int ret, fd;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->filepath = i_strconcat(cache->index->filepath,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MAIL_CACHE_FILE_PREFIX, NULL);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher ret = mail_cache_open_and_verify(cache, FALSE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret != 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return ret > 0;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* we'll have to clear cache_offsets which requires exclusive lock */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->inconsistent = FALSE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (!mail_index_set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return FALSE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* maybe a rebuild.. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher MAIL_CACHE_LOCK_STALE_TIMEOUT, NULL, NULL);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (fd == -1) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_syscall_error(cache, "file_dotlock_open()");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* see if someone else just created the cache file */
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek ret = mail_cache_open_and_verify(cache, TRUE);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek if (ret != 0) {
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return ret > 0;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek }
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek /* rebuild then */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_set_syscall_error(cache, "write_full()");
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return FALSE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_set_syscall_error(cache, "file_set_size()");
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return FALSE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_index_clear_cache_offsets(cache->index);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_file_close(cache);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek cache->fd = dup(fd);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return FALSE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek cache->mmap_refresh = TRUE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return FALSE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek}
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
0172959f117b545c8a6b1893f5f56818d82dd624Jakub Hrozekint mail_cache_open_or_create(struct mail_index *index)
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek{
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek struct mail_cache_header hdr;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek struct mail_cache *cache;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memset(&hdr, 0, sizeof(hdr));
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek hdr.indexid = index->indexid;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache = i_new(struct mail_cache, 1);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher cache->index = index;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->fd = -1;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher cache->split_header_pool = pool_alloconly_create("Headers", 512);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher index->cache = cache;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* we'll do anon-mmaping only if initially requested. if we fail
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher because of out of disk space, we'll just let the main index code
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek know it and fail. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (INDEX_IS_IN_MEMORY(index)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mail_cache_create_memory(cache, &hdr)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_free(cache);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return FALSE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mail_cache_open_or_create_file(cache, &hdr)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_free(cache);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* unset inconsistency - we already rebuilt the cache file */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher index->inconsistent = FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid mail_cache_free(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(cache->trans_ctx == NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->cache = NULL;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher mail_cache_file_close(cache);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher pool_unref(cache->split_header_pool);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_free(cache->filepath);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek i_free(cache);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid mail_cache_set_defaults(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher enum mail_cache_field default_cache_fields,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher enum mail_cache_field never_cache_fields)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->default_cache_fields = default_cache_fields;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher cache->never_cache_fields = never_cache_fields;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const struct mail_cache_record *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghermail_cache_compress_record(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_index_record *rec, int header_idx,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t *size_r)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher enum mail_cache_field orig_cached_fields, cached_fields, field;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_record cache_rec;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_t *buffer;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek const void *data;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher size_t size, pos;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher uint32_t nb_size;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher int i;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek memset(&cache_rec, 0, sizeof(cache_rec));
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer = buffer_create_dynamic(data_stack_pool, 4096, (size_t)-1);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher orig_cached_fields = mail_cache_get_fields(cache, rec);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher cached_fields = orig_cached_fields & ~MAIL_CACHE_HEADERS_MASK;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher buffer_append(buffer, &cache_rec, sizeof(cache_rec));
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher for (i = 0, field = 1; i < 31; i++, field <<= 1) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if ((cached_fields & field) == 0)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher continue;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (!mail_cache_lookup_field(cache, rec, field, &data, &size)) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher cached_fields &= ~field;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher continue;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher }
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher nb_size = uint32_to_nbo((uint32_t)size);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if ((field & MAIL_CACHE_FIXED_MASK) == 0)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_append(buffer, &nb_size, sizeof(nb_size));
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_append(buffer, data, size);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if ((size & 3) != 0)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_append(buffer, null4, 4 - (size & 3));
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* now merge all the headers if we have them all */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if ((orig_cached_fields & mail_cache_header_fields[header_idx]) != 0) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek nb_size = 0;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek pos = buffer_get_used_size(buffer);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek buffer_append(buffer, &nb_size, sizeof(nb_size));
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek for (i = 0; i <= header_idx; i++) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek field = mail_cache_header_fields[i];
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (mail_cache_lookup_field(cache, rec, field,
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek &data, &size) && size > 1) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek size--; /* terminating \0 */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek buffer_append(buffer, data, size);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek nb_size += size;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek buffer_append(buffer, "", 1);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek nb_size++;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if ((nb_size & 3) != 0)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek buffer_append(buffer, null4, 4 - (nb_size & 3));
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek nb_size = uint32_to_nbo(nb_size);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek buffer_write(buffer, pos, &nb_size, sizeof(nb_size));
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cached_fields |= MAIL_CACHE_HEADERS1;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek cache_rec.fields = cached_fields;
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek cache_rec.size = uint32_to_nbo(buffer_get_used_size(buffer));
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek buffer_write(buffer, 0, &cache_rec, sizeof(cache_rec));
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek data = buffer_get_data(buffer, &size);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek *size_r = size;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return data;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozekstatic int mail_cache_copy(struct mail_cache *cache, int fd)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_cache_header *hdr;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const struct mail_cache_record *cache_rec;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_index_record *rec;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek enum mail_cache_field used_fields;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek unsigned char *mmap_base;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek const char *str;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek uint32_t new_file_size, offset, size, nb_size;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek int i, header_idx;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* pick some reasonably good file size */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek new_file_size = cache->used_file_size -
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek nbo_to_uint32(cache->header->deleted_space);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek new_file_size = (new_file_size + 1023) & ~1023;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (new_file_size < MAIL_CACHE_INITIAL_SIZE)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek new_file_size = MAIL_CACHE_INITIAL_SIZE;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (file_set_size(fd, new_file_size) < 0)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek return mail_cache_set_syscall_error(cache, "file_set_size()");
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mmap_base = mmap(NULL, new_file_size, PROT_READ | PROT_WRITE,
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek MAP_SHARED, fd, 0);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (mmap_base == MAP_FAILED)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek return mail_cache_set_syscall_error(cache, "mmap()");
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek /* skip file's header */
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek hdr = (struct mail_cache_header *) mmap_base;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek offset = sizeof(*hdr);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek /* merge all the header pieces into one. if some message doesn't have
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek all the required pieces, we'll just have to drop them all. */
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek for (i = MAIL_CACHE_HEADERS_COUNT-1; i >= 0; i--) {
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek str = mail_cache_get_header_fields_str(cache, i);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (str != NULL)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek break;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek }
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (str == NULL)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek header_idx = -1;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek else {
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek hdr->header_offsets[0] = uint32_to_offset(offset);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek header_idx = i;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size = strlen(str) + 1;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek nb_size = uint32_to_nbo(size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy(mmap_base + offset, &nb_size, sizeof(nb_size));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset += sizeof(nb_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy(mmap_base + offset, str, size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset += (size + 3) & ~3;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher used_fields = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rec = cache->index->lookup(cache->index, 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (rec != NULL) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache_rec = mail_cache_lookup(cache, rec, 0);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache_rec == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rec->cache_offset = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else if (offset_to_uint32(cache_rec->next_offset) == 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* just one unmodified block, copy it */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek size = nbo_to_uint32(cache_rec->size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(offset + size <= new_file_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy(mmap_base + offset, cache_rec, size);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher rec->cache_offset = uint32_to_offset(offset);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size = (size + 3) & ~3;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset += size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* multiple blocks, sort them into buffer */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_push();
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache_rec = mail_cache_compress_record(cache, rec,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher header_idx,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher &size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek i_assert(offset + size <= new_file_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy(mmap_base + offset, cache_rec, size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher used_fields |= cache_rec->fields;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_pop();
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek rec->cache_offset = uint32_to_offset(offset);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher offset += size;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher rec = cache->index->next(cache->index, rec);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* update header */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher hdr->indexid = cache->index->indexid;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher hdr->used_file_size = uint32_to_nbo(offset);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher hdr->used_fields = used_fields;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher hdr->field_usage_start = uint32_to_nbo(ioloop_time);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* write everything to disk */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (msync(mmap_base, offset, MS_SYNC) < 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return mail_cache_set_syscall_error(cache, "msync()");
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (munmap(mmap_base, new_file_size) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return mail_cache_set_syscall_error(cache, "munmap()");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (fdatasync(fd) < 0)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return mail_cache_set_syscall_error(cache, "fdatasync()");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return TRUE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekint mail_cache_compress(struct mail_cache *cache)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher{
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher int fd, ret = TRUE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek i_assert(cache->trans_ctx == NULL);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (!cache->index->set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (mail_cache_lock(cache, TRUE) <= 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek MAIL_CACHE_LOCK_STALE_TIMEOUT, NULL, NULL);
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if (fd == -1) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_syscall_error(cache, "file_dotlock_open()");
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek return FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek }
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek /* now we'll begin the actual moving. keep rebuild-flag on
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek while doing it. */
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek cache->index->header->flags |= MAIL_INDEX_HDR_FLAG_REBUILD;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if (!mail_index_fmdatasync(cache->index, cache->index->header_size))
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek return FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if (!mail_cache_copy(cache, fd)) {
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek ret = FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek } else {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_cache_file_close(cache);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->fd = dup(fd);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_cache_set_syscall_error(cache,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek "file_dotlock_replace()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ret = FALSE;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek }
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (!mmap_update(cache, 0, 0))
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek ret = FALSE;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek }
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek cache->index->header->flags &= ~(MAIL_INDEX_HDR_FLAG_REBUILD |
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek if (!mail_cache_unlock(cache))
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek ret = FALSE;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek return ret;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozekint mail_cache_truncate(struct mail_cache *cache)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek{
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek struct mail_cache_header hdr;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek int ret, fd;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memset(&hdr, 0, sizeof(hdr));
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek hdr.indexid = cache->index->indexid;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek cache->used_file_size = sizeof(hdr);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache->anon_mmap) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek *cache->header = hdr;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek return TRUE;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek }
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek ret = mail_cache_open_and_verify(cache, TRUE);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (ret != 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return ret > 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek MAIL_CACHE_LOCK_STALE_TIMEOUT, NULL, NULL);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (fd == -1) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_syscall_error(cache, "file_dotlock_open()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_syscall_error(cache, "write_full()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_syscall_error(cache, "file_set_size()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (void)file_dotlock_delete(cache->filepath, fd);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_file_close(cache);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->fd = dup(fd);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->mmap_refresh = TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekint mail_cache_mark_file_deleted(struct mail_cache *cache)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek uint32_t indexid = 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache->anon_mmap)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->header->indexid = 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek else {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (pwrite(cache->fd, &indexid, sizeof(indexid), 0) < 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return mail_cache_set_syscall_error(cache, "pwrite()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekint mail_cache_lock(struct mail_cache *cache, int nonblock)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek int ret;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->locks++ != 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->anon_mmap)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (nonblock) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = file_try_lock(cache->fd, F_WRLCK);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (ret < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_syscall_error(cache, "file_try_lock()");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher } else {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher ret = file_wait_lock(cache->fd, F_WRLCK);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret <= 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher mail_cache_set_syscall_error(cache, "file_wait_lock()");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret > 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mmap_verify_header(cache)) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (void)mail_cache_unlock(cache);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ret = -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return ret;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherint mail_cache_unlock(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (--cache->locks > 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->anon_mmap)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (file_wait_lock(cache->fd, F_UNLCK) <= 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallaghervoid mail_cache_unlock_later(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->cache_later_locks++;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekint mail_cache_is_locked(struct mail_cache *cache)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cache->locks > 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherint mail_cache_transaction_begin(struct mail_cache *cache, int nonblock,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_transaction_ctx **ctx_r)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek i_assert(cache->trans_ctx == NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = mail_cache_lock(cache, nonblock);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret <= 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *ctx_r = i_new(struct mail_cache_transaction_ctx, 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (*ctx_r)->cache = cache;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher (*ctx_r)->cache_data =
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_create_dynamic(system_pool, 8192, (size_t)-1);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher (*ctx_r)->last_idx = (unsigned int)-1;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher cache->trans_ctx = *ctx_r;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return 1;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherint mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher int ret = TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(ctx->cache->trans_ctx != NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (void)mail_cache_transaction_rollback(ctx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mail_cache_unlock(ctx->cache))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->cache->trans_ctx = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ctx->cache_marks != NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_free(ctx->cache_marks);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (ctx->index_marks != NULL)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_free(ctx->index_marks);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_free(ctx->cache_data);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free(ctx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->last_idx = (unsigned int)-1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->next_unused_header_lowwater = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->first_uid = ctx->last_uid = ctx->prev_uid = 0;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher ctx->prev_fields = 0;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ctx->cache_marks != NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_set_used_size(ctx->cache_marks, 0);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ctx->index_marks != NULL)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher buffer_set_used_size(ctx->index_marks, 0);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_set_used_size(ctx->cache_data, 0);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void mark_update(buffer_t **buf, uint32_t offset, uint32_t data)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (*buf == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *buf = buffer_create_dynamic(system_pool, 1024, (size_t)-1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* data is in big endian, we want to update only the lowest byte */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_append(*buf, &offset, sizeof(offset));
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek buffer_append(*buf, &data, sizeof(data));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagherstatic int write_mark_updates(struct mail_index *index, buffer_t *marks,
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher const char *path, int fd)
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const uint32_t *data, *end;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher size_t size;
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek data = buffer_get_data(marks, &size);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher end = data + size/sizeof(uint32_t);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek while (data < end) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (pwrite(fd, data+1, sizeof(*data), data[0]) < 0) {
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek index_file_set_syscall_error(index, path, "pwrite()");
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek return FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher data += 2;
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void write_mark_updates_in_memory(buffer_t *marks, void *mmap_base,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek size_t mmap_length)
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek const unsigned char *data, *end;
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek uint32_t offset;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek size_t size;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek data = buffer_get_data(marks, &size);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek end = data + size;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek while (data < end) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memcpy(&offset, data, sizeof(offset));
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher data += sizeof(offset);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher i_assert(offset <= mmap_length - sizeof(uint32_t));
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher memcpy((char *) mmap_base + offset, data, sizeof(uint32_t));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek data += sizeof(uint32_t);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekstatic void commit_all_changes_in_memory(struct mail_cache_transaction_ctx *ctx)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek struct mail_cache *cache = ctx->cache;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (ctx->cache_marks != NULL) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek write_mark_updates_in_memory(ctx->cache_marks,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek cache->mmap_base,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek cache->mmap_length);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (ctx->index_marks != NULL) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek write_mark_updates_in_memory(ctx->index_marks,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek cache->index->mmap_base,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek cache->index->mmap_used_length);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagherstatic int commit_all_changes(struct mail_cache_transaction_ctx *ctx)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher{
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher struct mail_cache *cache = ctx->cache;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek uint32_t cont;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (ctx->cache->anon_mmap) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher commit_all_changes_in_memory(ctx);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return TRUE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher /* write everything to disk */
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (msync(cache->mmap_base, cache->mmap_length, MS_SYNC) < 0)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return mail_cache_set_syscall_error(cache, "msync()");
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (fdatasync(cache->fd) < 0)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return mail_cache_set_syscall_error(cache, "fdatasync()");
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (ctx->cache_marks != NULL &&
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher buffer_get_used_size(ctx->cache_marks) != 0) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher /* now that we're sure it's there, set on all the used-bits */
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (!write_mark_updates(cache->index, ctx->cache_marks,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->filepath, cache->fd))
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher /* update continued records count */
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher cont = nbo_to_uint32(cache->header->continued_record_count);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher cont += buffer_get_used_size(ctx->cache_marks) /
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (sizeof(uint32_t) * 2);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (cont * 100 / cache->index->header->messages_count >=
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek COMPRESS_CONTINUED_PERCENTAGE &&
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->used_file_size >= COMPRESS_MIN_SIZE) {
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* too many continued rows, compress */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->index->set_flags |=
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek cache->header->continued_record_count = uint32_to_nbo(cont);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* write index last */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (ctx->index_marks != NULL &&
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_get_used_size(ctx->index_marks) != 0) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (!mail_index_fmdatasync(cache->index,
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher cache->index->mmap_used_length))
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!write_mark_updates(cache->index, ctx->index_marks,
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher cache->index->filepath,
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher cache->index->fd))
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return TRUE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagherint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher{
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher int ret = TRUE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (ctx->last_idx != (unsigned int)-1) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (!mail_cache_write(ctx))
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->cache->header->used_file_size =
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher uint32_to_nbo(ctx->cache->used_file_size);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (!commit_all_changes(ctx))
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher ret = FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (ctx->next_unused_header_lowwater == MAIL_CACHE_HEADERS_COUNT) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher /* they're all used - compress the cache to get more */
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher ctx->cache->index->set_flags |=
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher mail_cache_transaction_flush(ctx);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher return ret;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher}
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekint mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher{
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher struct mail_cache *cache = ctx->cache;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher unsigned int i;
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* no need to actually modify the file - we just didn't update
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher used_file_size */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher cache->used_file_size = nbo_to_uint32(cache->header->used_file_size);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek /* make sure we don't cache the headers */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (offset_to_uint32(cache->header->header_offsets[i]) == 0)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher cache->split_offsets[i] = 1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher mail_cache_transaction_flush(ctx);
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek return TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagherstatic int mail_cache_grow(struct mail_cache *cache, uint32_t size)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher{
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher struct stat st;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher void *base;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher uoff_t grow_size, new_fsize;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher new_fsize = cache->used_file_size + size;
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (grow_size < 16384)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher grow_size = 16384;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher new_fsize += grow_size;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher new_fsize &= ~1023;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (cache->anon_mmap) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher i_assert(new_fsize < SSIZE_T_MAX);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek base = mremap_anon(cache->mmap_base, cache->mmap_length,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher (size_t)new_fsize, MREMAP_MAYMOVE);
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek if (base == MAP_FAILED) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_set_syscall_error(cache, "mremap_anon()");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher cache->mmap_base = base;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher cache->mmap_length = (size_t)new_fsize;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher cache->header = cache->mmap_base;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return TRUE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (fstat(cache->fd, &st) < 0)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return mail_cache_set_syscall_error(cache, "fstat()");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (cache->used_file_size + size <= (uoff_t)st.st_size) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* no need to grow, just update mmap */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (!mmap_update(cache, 0, 0))
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return FALSE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek i_assert(cache->mmap_length >= (uoff_t)st.st_size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return TRUE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (st.st_size < (off_t)sizeof(struct mail_cache_header))
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return mail_cache_set_corrupted(cache, "Header is missing");
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (file_set_size(cache->fd, (off_t)new_fsize) < 0)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return mail_cache_set_syscall_error(cache, "file_set_size()");
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek return mmap_update(cache, 0, 0);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek uint32_t size)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek{
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* NOTE: must be done within transaction or rollback would break it */
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek uint32_t offset;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek i_assert((size & 3) == 0);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek offset = ctx->cache->used_file_size;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if (offset >= 0x40000000) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher index_set_error(ctx->cache->index, "Cache file too large: %s",
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->cache->filepath);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (offset + size > ctx->cache->mmap_length) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mail_cache_grow(ctx->cache, size))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->cache->used_file_size += size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return offset;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const char *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghermail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher uint32_t offset, data_size;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek unsigned char *buf;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset = offset_to_uint32(cache->header->header_offsets[idx]);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (offset == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mmap_update(cache, offset, 1024))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (offset + sizeof(data_size) > cache->mmap_length) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher mail_cache_set_corrupted(cache, "Header %u points outside file",
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek idx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher buf = cache->mmap_base;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memcpy(&data_size, buf + offset, sizeof(data_size));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher data_size = nbo_to_uint32(data_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher offset += sizeof(data_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (data_size == 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_corrupted(cache,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher "Header %u points to empty string", idx);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!mmap_update(cache, offset, data_size))
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return NULL;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (offset + data_size > cache->mmap_length) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_corrupted(cache, "Header %u points outside file",
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher idx);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buf = cache->mmap_base;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (buf[offset + data_size - 1] != '\0') {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher mail_cache_set_corrupted(cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Header %u points to invalid string", idx);
bdd205037059e56484de3174951b22ff8f0f79f8Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek return buf + offset;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const char *const *
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghersplit_header(struct mail_cache *cache, const char *header)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const char *const *arr, *const *tmp;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *null = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher char *str;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_t *buf;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (header == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher arr = t_strsplit(header, "\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buf = buffer_create_dynamic(cache->split_header_pool, 32, (size_t)-1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher for (tmp = arr; *tmp != NULL; tmp++) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher str = p_strdup(cache->split_header_pool, *tmp);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_append(buf, &str, sizeof(str));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_append(buf, &null, sizeof(null));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return buffer_get_data(buf, NULL);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherconst char *const *mail_cache_get_header_fields(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher unsigned int idx)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const char *str;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int i;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* t_strsplit() is a bit slow, so we cache it */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (cache->header->header_offsets[idx] != cache->split_offsets[idx]) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher p_clear(cache->split_header_pool);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher t_push();
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->split_offsets[i] =
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->header->header_offsets[i];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher str = mail_cache_get_header_fields_str(cache, i);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->split_headers[i] = split_header(cache, str);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_pop();
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return cache->split_headers[idx];
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherint mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher unsigned int idx, const char *const headers[])
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache *cache = ctx->cache;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t offset, update_offset, size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_t *buffer;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(idx >= ctx->next_unused_header_lowwater);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_assert(offset_to_uint32(cache->header->header_offsets[idx]) == 0);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_push();
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer = buffer_create_dynamic(data_stack_pool, 512, (size_t)-1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (*headers != NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (buffer_get_used_size(buffer) != 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_append(buffer, "\n", 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_append(buffer, *headers, strlen(*headers));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher headers++;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_append(buffer, null4, 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size = buffer_get_used_size(buffer);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if ((size & 3) != 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_append(buffer, null4, 4 - (size & 3));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size += 4 - (size & 3);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher offset = mail_cache_append_space(ctx, size + sizeof(uint32_t));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (offset != 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy((char *) cache->mmap_base + offset + sizeof(uint32_t),
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buffer_get_data(buffer, NULL), size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size = uint32_to_nbo(size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy((char *) cache->mmap_base + offset,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher &size, sizeof(uint32_t));
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* update cached headers */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher cache->split_offsets[idx] = cache->header->header_offsets[idx];
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher cache->split_headers[idx] =
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher split_header(cache, buffer_get_data(buffer, NULL));
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* mark used-bit to be updated later. not really needed for
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher read-safety, but if transaction get rolled back we can't let
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek this point to invalid location. */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher update_offset = (char *) &cache->header->header_offsets[idx] -
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher (char *) cache->mmap_base;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher mark_update(&ctx->cache_marks, update_offset,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_to_offset(offset));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* make sure get_header_fields() still works for this header
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek while the transaction isn't yet committed. */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher ctx->next_unused_header_lowwater = idx + 1;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek t_pop();
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return offset > 0;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek}
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozekstatic struct mail_cache_record *
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozekcache_get_record(struct mail_cache *cache, uint32_t offset)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek struct mail_cache_record *cache_rec;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek size_t size;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek offset = offset_to_uint32(offset);
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek if (offset == 0)
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mmap_update(cache, offset, sizeof(*cache_rec) + 1024))
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek if (offset + sizeof(*cache_rec) > cache->mmap_length) {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek mail_cache_set_corrupted(cache, "record points outside file");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek }
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek cache_rec = CACHE_RECORD(cache, offset);
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek size = nbo_to_uint32(cache_rec->size);
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek if (size < sizeof(*cache_rec)) {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek mail_cache_set_corrupted(cache, "invalid record size");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek }
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek if (!mmap_update(cache, offset, size))
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (offset + size > cache->mmap_length) {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek mail_cache_set_corrupted(cache, "record points outside file");
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek }
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return cache_rec;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek}
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekstatic struct mail_cache_record *
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozekcache_get_next_record(struct mail_cache *cache, struct mail_cache_record *rec)
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek{
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek struct mail_cache_record *next;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek next = cache_get_record(cache, rec->next_offset);
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek if (next != NULL && next <= rec) {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek mail_cache_set_corrupted(cache, "next_offset points backwards");
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return NULL;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek }
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek return next;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozekstatic int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek{
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek struct mail_cache *cache = ctx->cache;
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek struct mail_cache_record *cache_rec, *next;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_index_record *rec;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek uint32_t write_offset, update_offset;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const void *buf;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek size_t size, buf_size;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buf = buffer_get_data(ctx->cache_data, &buf_size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek size = sizeof(*cache_rec) + buf_size;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->cache_rec.size = uint32_to_nbo(size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek write_offset = mail_cache_append_space(ctx, size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (write_offset == 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek rec = INDEX_RECORD_AT(ctx->cache->index, ctx->last_idx);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->last_idx = (unsigned int)-1;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache_rec = cache_get_record(cache, rec->cache_offset);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache_rec == NULL) {
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek /* first cache record - update offset in index file */
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
fbeb1aba9e11e7aab8adac943276ca040f0c5311Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* mark cache_offset to be updated later */
056302a92862fda16351d7192600746746f38e5dStephen Gallagher update_offset = (char *) &rec->cache_offset -
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher (char *) cache->index->mmap_base;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher mark_update(&ctx->index_marks, update_offset,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher uint32_to_offset(write_offset));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek } else {
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek /* find the last cache record */
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek while ((next = cache_get_next_record(cache, cache_rec)) != NULL)
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek cache_rec = next;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek /* mark next_offset to be updated later */
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek update_offset = (char *) &cache_rec->next_offset -
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek (char *) cache->mmap_base;
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher mark_update(&ctx->cache_marks, update_offset,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher uint32_to_offset(write_offset));
056302a92862fda16351d7192600746746f38e5dStephen Gallagher }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
056302a92862fda16351d7192600746746f38e5dStephen Gallagher memcpy((char *) cache->mmap_base + write_offset,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher &ctx->cache_rec, sizeof(ctx->cache_rec));
056302a92862fda16351d7192600746746f38e5dStephen Gallagher memcpy((char *) cache->mmap_base + write_offset +
056302a92862fda16351d7192600746746f38e5dStephen Gallagher sizeof(ctx->cache_rec), buf, buf_size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
056302a92862fda16351d7192600746746f38e5dStephen Gallagher /* reset the write context */
056302a92862fda16351d7192600746746f38e5dStephen Gallagher memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
056302a92862fda16351d7192600746746f38e5dStephen Gallagher buffer_set_used_size(ctx->cache_data, 0);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return TRUE;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher}
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekstatic struct mail_cache_record *
056302a92862fda16351d7192600746746f38e5dStephen Gallaghermail_cache_lookup(struct mail_cache *cache, const struct mail_index_record *rec,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher enum mail_cache_field fields)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
056302a92862fda16351d7192600746746f38e5dStephen Gallagher struct mail_cache_record *cache_rec;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek unsigned int idx;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher if (cache->trans_ctx != NULL &&
056302a92862fda16351d7192600746746f38e5dStephen Gallagher cache->trans_ctx->first_uid <= rec->uid &&
056302a92862fda16351d7192600746746f38e5dStephen Gallagher cache->trans_ctx->last_uid >= rec->uid &&
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (cache->trans_ctx->prev_uid != rec->uid || fields == 0 ||
056302a92862fda16351d7192600746746f38e5dStephen Gallagher (cache->trans_ctx->prev_fields & fields) != 0)) {
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher /* we have to auto-commit since we're not capable of looking
056302a92862fda16351d7192600746746f38e5dStephen Gallagher into uncommitted records. it would be possible by checking
056302a92862fda16351d7192600746746f38e5dStephen Gallagher index_marks and cache_marks, but it's just more trouble
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek than worth. */
056302a92862fda16351d7192600746746f38e5dStephen Gallagher idx = INDEX_RECORD_INDEX(cache->index, rec);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher if (cache->trans_ctx->last_idx == idx) {
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher if (!mail_cache_write(cache->trans_ctx))
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return NULL;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher }
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (!mail_cache_transaction_commit(cache->trans_ctx))
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return NULL;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher cache_rec = cache_get_record(cache, rec->cache_offset);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (cache_rec == NULL)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return NULL;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher return cache_rec;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher}
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekstatic int get_field_num(enum mail_cache_field field)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher{
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher unsigned int mask;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher int i;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if ((field & mask) != 0)
45db68ae27147955a4be4c2c772041824c0dc00fStephen Gallagher return i;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher return -1;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozekstatic size_t get_insert_offset(struct mail_cache_transaction_ctx *ctx,
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek enum mail_cache_field field)
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek{
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek const unsigned char *buf;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek unsigned int mask;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek uint32_t data_size;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek size_t offset = 0;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek int i;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek buf = buffer_get_data(ctx->cache_data, NULL);
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if ((field & mask) != 0)
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek return offset;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if ((ctx->cache_rec.fields & mask) != 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher data_size = mail_cache_field_sizes[i];
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek else {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher memcpy(&data_size, buf + offset,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher sizeof(data_size));
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek data_size = nbo_to_uint32(data_size);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher offset += sizeof(data_size);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher offset += (data_size + 3) & ~3;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_unreached();
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return offset;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagherint mail_cache_add(struct mail_cache_transaction_ctx *ctx,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_index_record *rec, enum mail_cache_field field,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher const void *data, size_t data_size)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher{
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek uint32_t nb_data_size;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek size_t full_size, offset;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek unsigned char *buf;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek unsigned int idx;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher int field_num;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(data_size > 0);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(data_size < (uint32_t)-1);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher nb_data_size = uint32_to_nbo((uint32_t)data_size);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek if ((field & MAIL_CACHE_FIXED_MASK) != 0) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher field_num = get_field_num(field);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(field_num != -1);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek i_assert(mail_cache_field_sizes[field_num] == data_size);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek } else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek i_assert(((char *) data)[data_size-1] == '\0');
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek }
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* NOTE: we use index because the record pointer might not last. */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek idx = INDEX_RECORD_INDEX(ctx->cache->index, rec);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek if (ctx->last_idx != idx && ctx->last_idx != (unsigned int)-1) {
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek if (!mail_cache_write(ctx))
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek return FALSE;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->last_idx = idx;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek i_assert((ctx->cache_rec.fields & field) == 0);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek full_size = (data_size + 3) & ~3;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek if ((field & MAIL_CACHE_FIXED_MASK) == 0)
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek full_size += sizeof(nb_data_size);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* fields must be ordered. find where to insert it. */
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek if (field > ctx->cache_rec.fields)
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek buf = buffer_append_space_unsafe(ctx->cache_data, full_size);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek else {
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek offset = get_insert_offset(ctx, field);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_copy(ctx->cache_data, offset + full_size,
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek ctx->cache_data, offset, (size_t)-1);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek buf = buffer_get_space_unsafe(ctx->cache_data,
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek offset, full_size);
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek }
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek ctx->cache_rec.fields |= field;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek /* @UNSAFE */
056302a92862fda16351d7192600746746f38e5dStephen Gallagher if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memcpy(buf, &nb_data_size, sizeof(nb_data_size));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher buf += sizeof(nb_data_size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher memcpy(buf, data, data_size); buf += data_size;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if ((data_size & 3) != 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memset(buf, 0, 4 - (data_size & 3));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* remember the transaction uid range */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (rec->uid < ctx->first_uid || ctx->first_uid == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher ctx->first_uid = rec->uid;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (rec->uid > ctx->last_uid)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->last_uid = rec->uid;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ctx->prev_uid != rec->uid) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->prev_uid = rec->uid;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ctx->prev_fields = 0;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek ctx->prev_fields |= field;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherint mail_cache_delete(struct mail_cache_transaction_ctx *ctx,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_index_record *rec)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct mail_cache *cache = ctx->cache;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_cache_record *cache_rec;
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek uint32_t deleted_space;
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek uoff_t max_del_space;
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek cache_rec = mail_cache_lookup(cache, rec, 0);
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek if (cache_rec == NULL)
d6d50c17e94dc0d3000345e8a933311c14bbb828Jakub Hrozek return TRUE;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* NOTE: it would be nice to erase the cached data for the record,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher but some other processes might still be using them. So, we just
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher update the deleted_space in header */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher deleted_space = nbo_to_uint32(cache->header->deleted_space);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher do {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher deleted_space -= nbo_to_uint32(cache_rec->size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache_rec = cache_get_next_record(cache, cache_rec);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher } while (cache_rec != NULL);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* see if we've reached the max. deleted space in file */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher max_del_space = cache->used_file_size / 100 * COMPRESS_PERCENTAGE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (deleted_space >= max_del_space &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->used_file_size >= COMPRESS_MIN_SIZE)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->index->set_flags |= MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache->header->deleted_space = uint32_to_nbo(deleted_space);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekenum mail_cache_field
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghermail_cache_get_fields(struct mail_cache *cache,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct mail_index_record *rec)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct mail_cache_record *cache_rec;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek enum mail_cache_field fields = 0;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache_rec = mail_cache_lookup(cache, rec, 0);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (cache_rec != NULL) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher fields |= cache_rec->fields;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek cache_rec = cache_get_next_record(cache, cache_rec);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return fields;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozekstatic int cache_get_field(struct mail_cache *cache,
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek struct mail_cache_record *cache_rec,
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek enum mail_cache_field field,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher void **data_r, size_t *size_r)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher unsigned char *buf;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek unsigned int mask;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher uint32_t rec_size, data_size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher size_t offset, next_offset;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int i;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher rec_size = nbo_to_uint32(cache_rec->size);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher buf = (unsigned char *) cache_rec;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek offset = sizeof(*cache_rec);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((cache_rec->fields & mask) == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher continue;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* all records are at least 32bit. we have to check this
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher before getting data_size. */
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if (offset + sizeof(uint32_t) > rec_size) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_corrupted(cache,
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek "Record continues outside it's allocated size");
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek return FALSE;
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek }
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek
6463ed1dcdd45416468b3fa178bd856b5a9ed2c3Jakub Hrozek if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher data_size = mail_cache_field_sizes[i];
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek else {
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek memcpy(&data_size, buf + offset, sizeof(data_size));
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek data_size = nbo_to_uint32(data_size);
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek offset += sizeof(data_size);
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek next_offset = offset + ((data_size + 3) & ~3);
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek if (next_offset > rec_size) {
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek mail_cache_set_corrupted(cache,
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek "Record continues outside it's allocated size");
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek }
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek if (field == mask) {
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek if (data_size == 0) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_corrupted(cache,
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek "Field size is 0");
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek return FALSE;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek }
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek *data_r = buf + offset;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek *size_r = data_size;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek return TRUE;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek }
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek offset = next_offset;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek }
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek i_unreached();
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek return FALSE;
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek}
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozekstatic int cache_lookup_field(struct mail_cache *cache,
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek const struct mail_index_record *rec,
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek enum mail_cache_field field,
a9228ebcce14888b3123bdf46e610e0900bcd2ccJakub Hrozek void **data_r, size_t *size_r)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct mail_cache_record *cache_rec;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache_rec = mail_cache_lookup(cache, rec, field);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher while (cache_rec != NULL) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if ((cache_rec->fields & field) != 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cache_get_field(cache, cache_rec, field,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher data_r, size_r);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache_rec = cache_get_next_record(cache, cache_rec);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekint mail_cache_lookup_field(struct mail_cache *cache,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_index_record *rec,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek enum mail_cache_field field,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const void **data_r, size_t *size_r)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek void *data;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!cache_lookup_field(cache, rec, field, &data, size_r))
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher *data_r = data;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
056302a92862fda16351d7192600746746f38e5dStephen Gallagherconst char *mail_cache_lookup_string_field(struct mail_cache *cache,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher const struct mail_index_record *rec,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher enum mail_cache_field field)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek const void *data;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher size_t size;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher i_assert((field & MAIL_CACHE_STRING_MASK) != 0);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return NULL;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (((const char *) data)[size-1] != '\0') {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek mail_cache_set_corrupted(cache,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher "String field %x doesn't end with NUL", field);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return NULL;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher }
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return data;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagherint mail_cache_copy_fixed_field(struct mail_cache *cache,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher const struct mail_index_record *rec,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher enum mail_cache_field field,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek void *buffer, size_t buffer_size)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
056302a92862fda16351d7192600746746f38e5dStephen Gallagher const void *data;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher size_t size;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher i_assert((field & MAIL_CACHE_FIXED_MASK) != 0);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return FALSE;
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher if (buffer_size != size) {
056302a92862fda16351d7192600746746f38e5dStephen Gallagher i_panic("cache: fixed field %x wrong size "
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek "(%"PRIuSIZE_T" vs %"PRIuSIZE_T")",
056302a92862fda16351d7192600746746f38e5dStephen Gallagher field, size, buffer_size);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher }
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher memcpy(buffer, data, buffer_size);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher return TRUE;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher}
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
056302a92862fda16351d7192600746746f38e5dStephen Gallaghervoid mail_cache_mark_missing(struct mail_cache *cache,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher enum mail_cache_field fields)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
056302a92862fda16351d7192600746746f38e5dStephen Gallagher // FIXME: count these
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek}
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagherenum mail_index_record_flag
056302a92862fda16351d7192600746746f38e5dStephen Gallaghermail_cache_get_index_flags(struct mail_cache *cache,
056302a92862fda16351d7192600746746f38e5dStephen Gallagher const struct mail_index_record *rec)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
056302a92862fda16351d7192600746746f38e5dStephen Gallagher enum mail_index_record_flag flags;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek if (!mail_cache_copy_fixed_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek &flags, sizeof(flags)))
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek return 0;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return flags;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek}
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozekint mail_cache_update_index_flags(struct mail_cache *cache,
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek struct mail_index_record *rec,
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek enum mail_index_record_flag flags)
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek void *data;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek size_t size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(cache->locks > 0);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!cache_lookup_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek &data, &size)) {
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek mail_cache_set_corrupted(cache,
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek "Missing index flags for record %u", rec->uid);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek return FALSE;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek }
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek memcpy(data, &flags, sizeof(flags));
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek return TRUE;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozekint mail_cache_update_location_offset(struct mail_cache *cache,
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek struct mail_index_record *rec,
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek uoff_t offset)
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek{
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek void *data;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek size_t size;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek i_assert(cache->locks > 0);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek if (!cache_lookup_field(cache, rec, MAIL_CACHE_LOCATION_OFFSET,
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek &data, &size)) {
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_set_corrupted(cache,
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek "Missing location offset for record %u", rec->uid);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek }
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek memcpy(data, &offset, sizeof(offset));
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek return TRUE;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek}
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozekvoid *mail_cache_get_mmaped(struct mail_cache *cache, size_t *size)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (!mmap_update(cache, 0, 0))
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek return NULL;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek *size = cache->mmap_length;
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return cache->mmap_base;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek}
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozekint mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek{
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek va_list va;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek mail_cache_mark_file_deleted(cache);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek cache->index->inconsistent = TRUE; /* easiest way to rebuild */
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (cache->silent)
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek return FALSE;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek va_start(va, fmt);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek t_push();
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek index_set_error(cache->index, "Corrupted index cache file %s: %s",
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cache->filepath, t_strdup_vprintf(fmt, va));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_pop();
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher va_end(va);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return FALSE;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher}
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher