mail-transaction-log-view.c revision b5ac20e30146562322ceb7939f044d52d1e51184
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "lib.h"
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen#include "array.h"
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "mail-index-private.h"
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "mail-transaction-log-private.h"
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "mail-transaction-util.h"
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenstruct mail_transaction_log_view {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct mail_transaction_log *log;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen struct mail_transaction_log_view *next;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uint32_t min_file_seq, max_file_seq;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uoff_t min_file_offset, max_file_offset;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen enum mail_transaction_type type_mask;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen struct mail_transaction_header tmp_hdr;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
3448096d5b1cd324ed5132045de0345cd7120a25Timo Sirainen /* a list of log files we've referenced. we have to keep this list
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen explicitly because more files may be added into the linked list
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen at any time. */
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen ARRAY_DEFINE(file_refs, struct mail_transaction_log_file *);
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody struct mail_transaction_log_file *cur, *head, *tail;
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody uoff_t cur_offset;
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen uint32_t prev_file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen uoff_t prev_file_offset;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen unsigned int broken:1;
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen};
72c4ef3b44c50c662b37bba93b463b0caeb63a4fTimo Sirainen
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovilastruct mail_transaction_log_view *
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmodymail_transaction_log_view_open(struct mail_transaction_log *log)
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody{
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen struct mail_transaction_log_view *view;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view = i_new(struct mail_transaction_log_view, 1);
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view->log = log;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view->broken = TRUE;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view->head = view->tail = view->log->head;
202468f94e6c6c8b5d3d98ee74e01bb0d0bb04aaTimo Sirainen view->head->refcount++;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen i_array_init(&view->file_refs, 8);
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen array_append(&view->file_refs, &view->head, 1);
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen view->next = log->views;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen log->views = view;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen return view;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen}
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainenstatic void
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainenmail_transaction_log_view_unref_all(struct mail_transaction_log_view *view)
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen{
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila struct mail_transaction_log_file *const *files;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen unsigned int i, count;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila files = array_get(&view->file_refs, &count);
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen for (i = 0; i < count; i++)
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen files[i]->refcount--;
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen array_clear(&view->file_refs);
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen}
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainenvoid mail_transaction_log_view_close(struct mail_transaction_log_view **_view)
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen{
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen struct mail_transaction_log_view *view = *_view;
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen struct mail_transaction_log_view **p;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen *_view = NULL;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen for (p = &view->log->views; *p != NULL; p = &(*p)->next) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (*p == view) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen *p = view->next;
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen break;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen }
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen mail_transaction_log_view_unref_all(view);
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen mail_transaction_logs_clean(view->log);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen array_free(&view->file_refs);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen i_free(view);
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen}
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainenvoid mail_transaction_log_views_close(struct mail_transaction_log *log)
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen{
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen struct mail_transaction_log_view *view;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen for (view = log->views; view != NULL; view = view->next)
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen view->log = NULL;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen}
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainenint
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainenmail_transaction_log_view_set(struct mail_transaction_log_view *view,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uint32_t min_file_seq, uoff_t min_file_offset,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uint32_t max_file_seq, uoff_t max_file_offset,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen enum mail_transaction_type type_mask)
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen{
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen struct mail_transaction_log_file *file, *first;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uint32_t seq;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uoff_t end_offset;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen int ret;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen i_assert(view->log != NULL);
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen i_assert(min_file_seq <= max_file_seq);
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (view->log == NULL) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen /* transaction log is closed already. this log view shouldn't
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen be used anymore. */
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen return -1;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen }
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (min_file_seq == 0) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen /* index file doesn't exist yet. this transaction log should
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen start from the beginning */
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (view->log->files->hdr.prev_file_seq != 0) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen /* but it doesn't */
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen return 0;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen min_file_seq = view->log->files->hdr.file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen min_file_offset = 0;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen if (max_file_seq == 0) {
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen max_file_seq = min_file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen max_file_offset = min_file_offset;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen if (min_file_seq == view->log->files->hdr.prev_file_seq &&
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen min_file_offset == view->log->files->hdr.prev_file_offset) {
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen /* we can skip this */
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen min_file_seq = view->log->files->hdr.file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen min_file_offset = 0;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (min_file_seq > max_file_seq) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* empty view */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen max_file_seq = min_file_seq;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen max_file_offset = min_file_offset;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
3448096d5b1cd324ed5132045de0345cd7120a25Timo Sirainen }
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen /* find the oldest log file first. */
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody ret = mail_transaction_log_find_file(view->log, min_file_seq, &file);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (ret <= 0)
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen return ret;
78f87ea1d30f3f54bdf8560ea947ab7ee094283aTeemu Huovila
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen if (min_file_offset == 0) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* this could happen if internal transactions haven't yet been
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen committed but external are. just assume we're at the
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen beginning. */
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila min_file_offset = file->hdr.hdr_size;
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila if (max_file_offset == 0 && min_file_seq == max_file_seq)
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila max_file_offset = min_file_offset;
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody }
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen i_assert(min_file_offset >= file->hdr.hdr_size);
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen if (min_file_seq == max_file_seq && min_file_offset > max_file_offset) {
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen /* log file offset is probably corrupted in the index file. */
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen mail_transaction_log_view_set_corrupted(view,
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen "file_seq=%u, min_file_offset (%"PRIuUOFF_T
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen ") > max_file_offset (%"PRIuUOFF_T")",
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen min_file_seq, min_file_offset, max_file_offset);
202468f94e6c6c8b5d3d98ee74e01bb0d0bb04aaTimo Sirainen return -1;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen }
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen end_offset = min_file_seq == max_file_seq ?
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen max_file_offset : (uoff_t)-1;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen ret = mail_transaction_log_file_map(file, min_file_offset, end_offset);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (ret <= 0)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return ret;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen first = file;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen for (seq = min_file_seq+1; seq <= max_file_seq; seq++) {
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen file = file->next;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila if (file == NULL || file->hdr.file_seq != seq) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila /* see if we could find the missing file */
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen ret = mail_transaction_log_find_file(view->log,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen seq, &file);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (ret <= 0) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (ret < 0)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return -1;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen /* not found / corrupted */
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen file = NULL;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (file == NULL && max_file_seq == (uint32_t)-1) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* we just wanted to sync everything */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_assert(max_file_offset == (uoff_t)-1);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen max_file_seq = seq-1;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen break;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* missing files in the middle */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return 0;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
3448096d5b1cd324ed5132045de0345cd7120a25Timo Sirainen
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila end_offset = file->hdr.file_seq == max_file_seq ?
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila max_file_offset : (uoff_t)-1;
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody ret = mail_transaction_log_file_map(file, file->hdr.hdr_size,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen end_offset);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (ret <= 0)
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen return ret;
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen i_assert(max_file_offset == (uoff_t)-1 ||
b04e76cbc807707d299055be79500f8ff131da43Timo Sirainen max_file_offset <= file->sync_offset);
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila /* we have all of them. update refcounts. */
0c5854b6891c59c1c3f443569bc823d7db571582Teemu Huovila mail_transaction_log_view_unref_all(view);
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view->tail = first;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen view->head = view->log->head;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen /* reference all used files */
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen for (file = view->tail; file != NULL; file = file->next) {
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen array_append(&view->file_refs, &file, 1);
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen file->refcount++;
b6b06530d654f0436bfbaefc1e988d53fff0cbeeTimo Sirainen }
202468f94e6c6c8b5d3d98ee74e01bb0d0bb04aaTimo Sirainen
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen view->prev_file_seq = 0;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen view->prev_file_offset = 0;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen view->cur = first;
83172e28d4ac684dfed83f7c9db933493d7c5922Timo Sirainen view->cur_offset = min_file_offset;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen view->min_file_seq = min_file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen view->min_file_offset = min_file_offset;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen view->max_file_seq = max_file_seq;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen view->max_file_offset = max_file_offset;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen view->type_mask = type_mask;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila view->broken = FALSE;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_assert(view->cur_offset <= view->cur->sync_offset);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_assert(view->cur->hdr.file_seq == min_file_seq);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen return 1;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainenvoid
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainenmail_transaction_log_view_get_prev_pos(struct mail_transaction_log_view *view,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen uint32_t *file_seq_r,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen uoff_t *file_offset_r)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen *file_seq_r = view->prev_file_seq;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila *file_offset_r = view->prev_file_offset;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila}
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovilastatic bool
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovilamail_transaction_log_view_get_last(struct mail_transaction_log_view *view,
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila struct mail_transaction_log_file **last_r,
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila uoff_t *last_offset_r)
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila{
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila struct mail_transaction_log_file *cur = view->cur;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila uoff_t cur_offset = view->cur_offset;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila bool last = FALSE;
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila if (cur == NULL) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila *last_r = NULL;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila return TRUE;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila }
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila for (;;) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila if (cur->hdr.file_seq == view->max_file_seq) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila /* last file */
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila if (cur_offset == view->max_file_offset ||
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila cur_offset == cur->sync_offset) {
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody /* we're all finished */
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila last = TRUE;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila }
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila } else if (cur_offset == cur->sync_offset) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila /* end of file, go to next one */
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila if (cur->next == NULL) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila last = TRUE;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila } else {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila cur = cur->next;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila cur_offset = cur->hdr.hdr_size;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila continue;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila }
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila }
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila /* not EOF */
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila break;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila }
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila *last_r = cur;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila *last_offset_r = cur_offset;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila return last;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila}
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovilabool mail_transaction_log_view_is_last(struct mail_transaction_log_view *view)
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila{
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila struct mail_transaction_log_file *cur;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila uoff_t cur_offset;
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila return mail_transaction_log_view_get_last(view, &cur, &cur_offset);
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila}
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovilavoid
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovilamail_transaction_log_view_set_corrupted(struct mail_transaction_log_view *view,
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila const char *fmt, ...)
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila{
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen va_list va;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen view->broken = TRUE;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen va_start(va, fmt);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen t_push();
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen mail_transaction_log_file_set_corrupted(view->log->head, "%s",
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen t_strdup_vprintf(fmt, va));
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen t_pop();
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen va_end(va);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen}
908c417cc19ec4a2a01db542498c13ade3943601Timo Sirainen
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainenbool
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenmail_transaction_log_view_is_corrupted(struct mail_transaction_log_view *view)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return view->broken;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenstatic bool
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainenlog_view_is_record_valid(struct mail_transaction_log_file *file,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen const struct mail_transaction_header *hdr,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen const void *data,
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen const struct mail_transaction_type_map *type_rec)
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen{
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen enum mail_transaction_type rec_type;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen buffer_t *uid_buf;
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uint32_t rec_size;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen bool ret = TRUE;
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen rec_size = mail_index_offset_to_uint32(hdr->size) - sizeof(*hdr);
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* we want to be extra careful with expunges */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (rec_type != (MAIL_TRANSACTION_EXPUNGE |
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen MAIL_TRANSACTION_EXPUNGE_PROT)) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen mail_transaction_log_file_set_corrupted(file,
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila "expunge record missing protection mask");
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila return FALSE;
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila }
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila } else if (rec_type != type_rec->type) {
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila mail_transaction_log_file_set_corrupted(file,
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila "extra bits in header type: 0x%x", rec_type);
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila return FALSE;
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila }
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila /* records that are exported by syncing and view syncing will be
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila checked here so that we don't have to implement the same validation
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen multiple times. other records are checked internally by
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen mail_index_sync_record(). */
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen t_push();
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen switch (rec_type) {
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen case MAIL_TRANSACTION_EXPUNGE:
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen data, rec_size);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen array_create_from_buffer(&uids, uid_buf,
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen sizeof(struct mail_transaction_expunge));
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen break;
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE:
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen data, rec_size);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen array_create_from_buffer(&uids, uid_buf,
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen sizeof(struct mail_transaction_flag_update));
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen break;
62fc0b4f07eb6f18a3bff4b1fccb636e6fae3cf4Timo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE: {
c4b772bfbdafe68ac1a0076eab26cd681f8e5046Timo Sirainen const struct mail_transaction_keyword_update *rec = data;
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen unsigned int seqset_offset;
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen if ((seqset_offset % 4) != 0)
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen seqset_offset += 4 - (seqset_offset % 4);
c4b772bfbdafe68ac1a0076eab26cd681f8e5046Timo Sirainen
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen if (seqset_offset >= rec_size ||
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen ((rec_size - seqset_offset) % (sizeof(uint32_t)*2)) != 0) {
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen mail_transaction_log_file_set_corrupted(file,
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen "Invalid keyword update record size");
c4b772bfbdafe68ac1a0076eab26cd681f8e5046Timo Sirainen ret = FALSE;
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen break;
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen }
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
c4b772bfbdafe68ac1a0076eab26cd681f8e5046Timo Sirainen CONST_PTR_OFFSET(data, seqset_offset),
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen rec_size - seqset_offset);
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen array_create_from_buffer(&uids, uid_buf, sizeof(uint32_t)*2);
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen break;
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen }
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET:
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen data, rec_size);
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen array_create_from_buffer(&uids, uid_buf,
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen sizeof(struct mail_transaction_keyword_reset));
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen break;
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen default:
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen break;
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (array_is_created(&uids)) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen const struct seq_range *rec, *prev = NULL;
f5c0d5cada4da23a167c38426d0c481a3e1d5583Timo Sirainen unsigned int i, count = array_count(&uids);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen for (i = 0; i < count; i++, prev = rec) {
3a54211bd6c4dc3f8687c16020770551cf83a548Teemu Huovila rec = array_idx(&uids, i);
568fec5b1e629f25d288b48007485b9aa4a018b1Timo Sirainen if (rec->seq1 > rec->seq2 || rec->seq1 == 0) {
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila mail_transaction_log_file_set_corrupted(file,
fdf70410de49eadfbb77997bb60ebba19aee4752Teemu Huovila "Invalid UID range "
e4bf76afb82ea28ec9d06823fa7deed5f8277183Timo Sirainen "(%u .. %u, type=0x%x)",
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen rec->seq1, rec->seq2, rec_type);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen ret = FALSE;
b1965419f329eb7cf78ee39e7c5942462eabb256Timo Sirainen break;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
b1965419f329eb7cf78ee39e7c5942462eabb256Timo Sirainen if (prev != NULL && rec->seq1 <= prev->seq2) {
b1965419f329eb7cf78ee39e7c5942462eabb256Timo Sirainen mail_transaction_log_file_set_corrupted(file,
b1965419f329eb7cf78ee39e7c5942462eabb256Timo Sirainen "Non-sorted UID ranges (type=0x%x)",
b1965419f329eb7cf78ee39e7c5942462eabb256Timo Sirainen rec_type);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen ret = FALSE;
break;
}
}
}
t_pop();
return ret;
}
static int
log_view_get_next(struct mail_transaction_log_view *view,
const struct mail_transaction_header **hdr_r,
const void **data_r)
{
const struct mail_transaction_header *hdr;
struct mail_transaction_log_file *file;
const struct mail_transaction_type_map *type_rec;
const void *data;
unsigned int record_size;
enum mail_transaction_type rec_type;
uint32_t full_size;
size_t file_size;
if (view->cur == NULL)
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. */
if (mail_transaction_log_view_get_last(view, &view->cur,
&view->cur_offset)) {
/* if the last file was the beginning of a file, we want to
move prev pointers there */
view->prev_file_seq = view->cur->hdr.file_seq;
view->prev_file_offset = view->cur_offset;
view->cur = NULL;
return 0;
}
view->prev_file_seq = view->cur->hdr.file_seq;
view->prev_file_offset = view->cur_offset;
file = view->cur;
data = buffer_get_data(file->buffer, &file_size);
file_size += file->buffer_offset;
if (view->cur_offset + sizeof(*hdr) > file_size) {
mail_transaction_log_file_set_corrupted(file,
"offset points outside file "
"(%"PRIuUOFF_T" + %"PRIuSIZE_T" > %"PRIuSIZE_T")",
view->cur_offset, sizeof(*hdr), file_size);
return -1;
}
i_assert(view->cur_offset >= file->buffer_offset);
hdr = CONST_PTR_OFFSET(data, view->cur_offset - file->buffer_offset);
data = CONST_PTR_OFFSET(hdr, sizeof(*hdr));
rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
full_size = mail_index_offset_to_uint32(hdr->size);
if (full_size < sizeof(*hdr)) {
/* we'll fail below with "records size too small" */
type_rec = NULL;
record_size = 0;
} else {
type_rec = mail_transaction_type_lookup(hdr->type);
if (type_rec != NULL)
record_size = type_rec->record_size;
else {
mail_transaction_log_file_set_corrupted(file,
"unknown record type 0x%x", rec_type);
return -1;
}
}
if (full_size < sizeof(*hdr) + record_size) {
mail_transaction_log_file_set_corrupted(file,
"record size too small (type=0x%x, "
"offset=%"PRIuUOFF_T", size=%u)",
rec_type, view->cur_offset, full_size);
return -1;
}
if (record_size != 0 &&
(full_size - sizeof(*hdr)) % record_size != 0) {
mail_transaction_log_file_set_corrupted(file,
"record size wrong (type 0x%x, "
"offset=%"PRIuUOFF_T", size=%"PRIuSIZE_T" %% %u != 0)",
rec_type, view->cur_offset, (full_size - sizeof(*hdr)),
record_size);
return -1;
}
if (file_size - view->cur_offset < full_size) {
mail_transaction_log_file_set_corrupted(file,
"record size too large (type=0x%x, "
"offset=%"PRIuUOFF_T", size=%u, end=%"PRIuSIZE_T")",
rec_type, view->cur_offset, full_size, file_size);
return -1;
}
if (!log_view_is_record_valid(file, hdr, data, type_rec))
return -1;
*hdr_r = hdr;
*data_r = data;
view->cur_offset += full_size;
return 1;
}
int mail_transaction_log_view_next(struct mail_transaction_log_view *view,
const struct mail_transaction_header **hdr_r,
const void **data_r, bool *skipped_r)
{
const struct mail_transaction_header *hdr;
const void *data;
int ret = 0;
if (skipped_r != NULL)
*skipped_r = FALSE;
if (view->broken)
return -1;
while ((ret = log_view_get_next(view, &hdr, &data)) > 0) {
if ((view->type_mask & hdr->type) != 0) {
/* looks like this is within our mask, but expunge
protection may mess up the check. */
if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0 ||
(view->type_mask & MAIL_TRANSACTION_EXPUNGE) != 0)
break;
}
/* we don't want this record */
if (skipped_r != NULL)
*skipped_r = TRUE;
/* FIXME: hide flag/cache updates for appends if
append isn't in mask */
}
if (ret < 0) {
view->cur_offset = view->cur->sync_offset;
return -1;
}
if (ret == 0)
return 0;
view->tmp_hdr = *hdr;
view->tmp_hdr.size =
mail_index_offset_to_uint32(view->tmp_hdr.size) - sizeof(*hdr);
i_assert(view->tmp_hdr.size != 0);
if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
/* hide expunge protection */
view->tmp_hdr.type &= ~MAIL_TRANSACTION_EXPUNGE_PROT;
}
*hdr_r = &view->tmp_hdr;
*data_r = data;
return 1;
}
void mail_transaction_log_view_seek(struct mail_transaction_log_view *view,
uint32_t seq, uoff_t offset)
{
struct mail_transaction_log_file *file;
i_assert(seq >= view->min_file_seq && seq <= view->max_file_seq);
i_assert(seq != view->min_file_seq || offset >= view->min_file_offset);
i_assert(seq != view->max_file_seq || offset < view->max_file_offset);
if (view->cur == NULL || seq != view->cur->hdr.file_seq) {
for (file = view->tail; file != NULL; file = file->next) {
if (file->hdr.file_seq == seq)
break;
}
i_assert(file != NULL);
view->cur = file;
}
view->cur_offset = offset;
}