mail-cache-lookup.c revision adef31eb09ce4092968afc81680524ffb626b21e
/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "str.h"
#include "mail-cache-private.h"
#define CACHE_PREFETCH IO_BLOCK_SIZE
const struct mail_cache_record **rec_r)
{
const struct mail_cache_record *rec;
const void *data;
int ret;
/* records are always 32-bit aligned */
return -1;
}
/* we don't know yet how large the record is, so just guess */
&data) < 0)
return -1;
return -1;
}
return -1;
}
/* larger than we guessed. map the rest of the record. */
return -1;
if (ret == 0) {
return -1;
}
}
return 0;
}
{
struct mail_index_map *map;
const void *data;
/* no cache offsets */
return 0;
}
if (offset == 0)
return 0;
i_unreached();
return offset;
}
static int
{
int i, ret;
if (offset == 0)
return 0;
/* reset_id must match file_seq or the offset is for a different cache
file. if this happens, try if reopening the cache helps. if not,
it was probably for an old cache file that's already lost by now. */
i = 0;
return 0;
/* we're probably compressing */
return 0;
}
/* error / we already have the latest file open */
return ret;
}
}
return 1;
}
{
/* looping happens only in rare error conditions, so it's enough if we
just catch it eventually. we do this by checking if we've seen
more record data than possible in the accessed file area. */
if (loop_track->size_sum == 0) {
/* first call */
} else {
}
return loop_track->size_sum >
}
struct mail_cache_lookup_iterate_ctx *ctx_r)
{
int ret;
/* look up the first offset */
if (ret <= 0) {
}
}
}
static bool
{
&ctx->trans_next_idx);
return FALSE;
return TRUE;
}
static int
{
return -1;
/* end of this record list. check newly appended data. */
return 0;
/* check data still in memory. this works for recent mails
even with INDEX=MEMORY */
if (!ctx->memory_appends_checked) {
return 1;
}
return 0;
/* check data already written to cache file */
if (ctx->disk_appends_checked ||
return 0;
}
return 0;
/* look up the next record */
return -1;
"record list is circular");
return -1;
}
return 1;
}
struct mail_cache_iterate_field *field_r)
{
unsigned int field_idx;
unsigned int data_size;
int ret;
"record has invalid size");
return -1;
}
return ret;
}
/* return the next field */
/* new field, have to re-read fields header to figure
out its size. don't do this if we're compressing. */
if (mail_cache_header_fields_read(cache) < 0)
return -1;
}
"field index too large (%u >= %u)",
return -1;
}
/* field reading might have re-mmaped the file and
caused rec pointer to break. need to get it again. */
return -1;
}
/* variable size field. get its size from the file. */
}
"record continues outside its allocated size");
return -1;
}
/* each record begins from 32bit aligned position */
return 1;
}
{
struct mail_cache_lookup_iterate_ctx iter;
struct mail_cache_iterate_field field;
int ret;
if (++view->cached_exists_value == 0) {
/* wrapped, we'll have to clear the buffer */
}
}
return ret;
}
static bool
{
}
unsigned int field)
{
return 0;
/* FIXME: we should discard the cache if view has been synced */
return -1;
}
}
{
}
{
}
static int
unsigned int field_idx, unsigned int field_size,
{
struct mail_cache_iterate_field field;
const unsigned char *src;
unsigned char *dest;
unsigned int i;
int ret;
/* make sure all bits are cleared first */
continue;
/* merge all bits */
}
}
{
const struct mail_cache_field *field_def;
struct mail_cache_lookup_iterate_ctx iter;
struct mail_cache_iterate_field field;
int ret;
if (ret <= 0)
return ret;
/* the field should exist */
dest_buf);
}
/* return the first one that's found. if there are multiple
they're all identical. */
break;
}
}
return ret;
}
struct header_lookup_data {
const unsigned char *data;
};
struct header_lookup_line {
struct header_lookup_data *data;
};
struct header_lookup_context {
struct mail_cache_view *view;
};
enum {
};
const struct mail_cache_iterate_field *field)
{
struct header_lookup_line hdr_line;
struct header_lookup_data *hdr_data;
void *data_dup;
unsigned int i, lines_count, pos;
/* data = { line_nums[], 0, "headers" } */
if (lines[i] == 0)
break;
}
lines_count = i;
if (data_size > 0) {
}
for (i = 0; i < lines_count; i++) {
}
}
const struct header_lookup_line *l2)
{
}
static int
{
struct mail_cache_lookup_iterate_ctx iter;
struct mail_cache_iterate_field field;
struct header_lookup_context ctx;
struct header_lookup_line *lines;
int ret;
if (fields_count == 0)
return 1;
/* update the decision state regardless of whether the fields
actually exist or not. */
for (i = 0; i < fields_count; i++)
/* mark all the fields we want to find. */
for (i = 0; i < fields_count; i++) {
return 0;
if (field_idxs[i] > max_field)
max_field = field_idxs[i];
}
/* lookup the fields */
/* a) don't want it, b) duplicate */
} else {
}
}
if (ret < 0)
return -1;
/* check that all fields were found */
for (i = 0; i <= max_field; i++) {
if (field_state[i] == HDR_FIELD_STATE_WANT)
return 0;
}
/* we need to return headers in the order they existed originally.
we can do this by sorting the messages by their line numbers. */
/* then start filling dest buffer from the headers */
for (i = 0; i < count; i++) {
/* find the end of the (multiline) header */
if (*p == '\n' &&
p++;
break;
}
}
/* if there are more lines for this header, the following lines
continue after this one. so skip this line. */
}
return 1;
}
unsigned int fields_count)
{
int ret;
T_BEGIN {
&pool);
pool_unref(&pool);
} T_END;
return ret;
}
static uint32_t
{
/* find the newest mail that has anything in cache */
return seq;
}
return 0;
}
const char *
{
return "Cache file is unusable";
if (offset != 0) {
return t_strdup_printf(
"Index reset_id=%u doesn't match cache reset_id=%u",
}
return t_strdup_printf(
"Mail has other cached fields, reset_id=%u", reset_id);
}
if (seq == 0) {
return t_strdup_printf("Cache file is empty, reset_id=%u",
}
return t_strdup_printf(
"Mail not cached, highest cached seq=%u uid=%u: "
"Index reset_id=%u doesn't match cache reset_id=%u",
}
return t_strdup_printf(
"Mail not cached, highest cached seq=%u uid=%u: reset_id=%u",
}