mail-transaction-log-view.c revision 37b805dfb45902b6b41c45482f67e6f98e08b0a3
/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "mail-index-private.h"
#include "mail-transaction-log-private.h"
struct mail_transaction_log_view {
struct mail_transaction_log *log;
struct mail_transaction_log_view *next;
struct mail_transaction_header tmp_hdr;
/* a list of log files we've referenced. we have to keep this list
explicitly because more files may be added into the linked list
at any time. */
struct mail_transaction_log_file *mark_file;
unsigned int broken:1;
};
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;
}
}
}
{
struct mail_transaction_log_view *view;
}
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;
}
if (min_file_offset > 0 &&
/* 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);
}
}
return -1;
return 1;
}
{
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
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_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");
}
break;
case MAIL_TRANSACTION_EXPUNGE:
sizeof(struct mail_transaction_expunge));
break;
sizeof(struct mail_transaction_flag_update));
break;
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
unsigned int seqset_offset;
if ((seqset_offset % 4) != 0)
if (seqset_offset > rec_size) {
"Invalid keyword update record size");
break;
}
break;
}
sizeof(struct mail_transaction_keyword_reset));
break;
default:
break;
}
if (array_is_created(&uids)) {
"Invalid record size (type=0x%x)", rec_type);
count = 0;
} else if (count == 0) {
"No UID ranges (type=0x%x)", rec_type);
}
"Invalid UID range "
"(%u .. %u, type=0x%x)",
break;
}
"Non-sorted UID ranges (type=0x%x)",
rec_type);
break;
}
}
}
return ret;
}
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) {
view->prev_modseq))
view->prev_modseq++;
}
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;
}
{
}
{
}