mail-transaction-log-view.c revision cf05507f63b12bd1ee4efffc2f316ebcd9fd7089
/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "mail-index-private.h"
#include "mail-transaction-log-view-private.h"
struct mail_transaction_log_view *
{
struct mail_transaction_log_view *view;
return view;
}
static void
{
struct mail_transaction_log_file *const *files;
unsigned int i, count;
for (i = 0; i < count; i++)
}
{
struct mail_transaction_log_view **p;
if (*p == view) {
break;
}
}
}
bool *reset_r)
{
unsigned int i;
int ret;
/* transaction log is closed already. this log view shouldn't
be used anymore. */
return -1;
}
if (min_file_seq == 0) {
/* index file doesn't exist yet. this transaction log should
start from the beginning */
/* but it doesn't */
return 0;
}
min_file_offset = 0;
if (max_file_seq == 0) {
}
}
/* we can skip this */
min_file_offset = 0;
if (min_file_seq > max_file_seq) {
/* empty view */
}
}
/* log file offset is probably corrupted in the index file. */
"file_seq=%u, min_file_offset (%"PRIuUOFF_T
return -1;
}
/* log file offset is probably corrupted in the index file. */
"file_seq=%u, min_file_offset (%"PRIuUOFF_T
") < hdr_size (%u)",
return -1;
}
/* see if we could find the missing file. if we know
the max. file sequence, make sure NFS attribute
cache gets flushed if necessary. */
if (ret <= 0) {
if (ret < 0)
return -1;
/* not found / corrupted */
}
}
/* we just wanted to sync everything */
break;
}
/* if any of the found files reset the index,
ignore any missing files up to it */
/* missing files in the middle */
return 0;
}
/* we can ignore the missing file */
break;
}
}
}
}
if (min_file_offset == 0) {
/* beginning of the file */
if (min_file_offset > max_file_offset &&
min_file_seq == max_file_seq) {
/* we don't actually want to show anything */
}
}
/* we have all of them. update refcounts. */
/* Reference all used files. */
break;
}
/* Map the files only after we've found them all. Otherwise if we map
one file and then another file just happens to get rotated, we could
include both files in the view but skip the last transactions from
the first file.
We're mapping the files in reverse order so that _log_file_map()
can verify that prev_file_offset matches how far it actually managed
to sync the file. */
if (ret <= 0)
return ret;
/* this file resets the index.
don't bother reading the others. */
break;
}
i_assert(i == 1);
}
}
/* log file offset is probably corrupted in the index file. */
"file_seq=%u, min_file_offset (%"PRIuUOFF_T
return -1;
}
return -1;
return 1;
}
{
/* make sure .log.2 file is opened */
(uoff_t)-1) < 0)
return -1;
/* this file resets the index. skip the old ones. */
}
}
}
return -1;
return 0;
}
{
struct mail_transaction_log_file *file;
&file) > 0) {
}
}
view->mark_offset = 0;
view->mark_modseq = 0;
view->cur_offset = 0;
view->prev_file_seq = 0;
view->prev_file_offset = 0;
view->prev_modseq = 0;
}
void
{
}
{
return view->prev_modseq;
}
static bool
struct mail_transaction_log_file **last_r,
{
return TRUE;
}
for (;;) {
/* last file */
/* we're all finished */
}
/* end of file, go to next one */
} else {
continue;
}
}
/* not EOF */
break;
}
return last;
}
{
struct mail_transaction_log_file *cur;
}
void
const char *fmt, ...)
{
T_BEGIN {
} T_END;
}
bool
{
}
static bool
{
"Invalid record size (type=0x%x)", rec_type);
return FALSE;
} else if (count == 0) {
"No UID ranges (type=0x%x)", rec_type);
return FALSE;
}
"Invalid UID range (%u .. %u, type=0x%x)",
return FALSE;
}
"Non-sorted UID ranges (type=0x%x)", rec_type);
return FALSE;
}
}
return TRUE;
}
static bool
const struct mail_transaction_header *hdr,
const void *data)
{
/* we want to be extra careful with expunges */
if (rec_type != (MAIL_TRANSACTION_EXPUNGE |
"expunge record missing protection mask");
return FALSE;
}
}
if (rec_type != (MAIL_TRANSACTION_EXPUNGE_GUID |
"expunge guid record missing protection mask");
return FALSE;
}
}
if (rec_size == 0) {
"Empty record contents (type=0x%x)", rec_type);
return FALSE;
}
/* records that are exported by syncing and view syncing will be
checked here so that we don't have to implement the same validation
multiple times. other records are checked internally by
mail_index_sync_record(). */
switch (rec_type) {
case MAIL_TRANSACTION_APPEND:
if ((rec_size % sizeof(struct mail_index_record)) != 0) {
"Invalid append record size");
return FALSE;
}
break;
case MAIL_TRANSACTION_EXPUNGE:
sizeof(struct mail_transaction_expunge));
break;
case MAIL_TRANSACTION_EXPUNGE_GUID: {
unsigned int i, count;
"Invalid expunge guid record size");
return FALSE;
}
for (i = 0; i < count; i++) {
"Expunge guid record with uid=0");
return FALSE;
}
}
break;
}
sizeof(struct mail_transaction_flag_update));
break;
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
unsigned int seqset_offset;
if ((seqset_offset % 4) != 0)
"Trying to use empty keyword");
return FALSE;
}
if (seqset_offset > rec_size) {
"Invalid keyword update record size");
return FALSE;
}
sizeof(uint32_t)*2);
break;
}
sizeof(struct mail_transaction_keyword_reset));
break;
case MAIL_TRANSACTION_EXT_INTRO: {
const struct mail_transaction_ext_intro *rec;
unsigned int i;
for (i = 0; i < rec_size; ) {
/* should be just extra padding */
break;
}
"ext intro: name_size too large");
return FALSE;
}
if ((i % 4) != 0)
i += 4 - (i % 4);
}
}
default:
break;
}
if (array_is_created(&uids)) {
return FALSE;
}
return TRUE;
}
static int
const struct mail_transaction_header **hdr_r,
const void **data_r)
{
const struct mail_transaction_header *hdr;
struct mail_transaction_log_file *file;
const void *data;
int ret;
return 0;
/* prev_file_offset should point to beginning of previous log record.
when we reach EOF, it should be left there, not to beginning of the
next file that's not included inside the view. */
&view->cur_offset)) {
/* if the last file was the beginning of a file, we want to
move prev pointers there */
return 0;
}
"offset points outside file "
return -1;
}
"record size too small (type=0x%x, "
return -1;
}
"record size too large (type=0x%x, "
return -1;
}
T_BEGIN {
} T_END;
if (ret > 0) {
}
return ret;
}
const struct mail_transaction_header **hdr_r,
const void **data_r)
{
const struct mail_transaction_header *hdr;
const void *data;
int ret = 0;
return -1;
if (ret <= 0) {
if (ret < 0)
return ret;
}
/* drop expunge protection */
else
/* return record's size */
return 1;
}
{
}
{
}