mail-transaction-log-view.c revision 5f78b33aa505b17e23cdf27b071a24e127b3db54
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "array.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mail-index-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log-private.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenstruct mail_transaction_log_view {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log *log;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_view *next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t min_file_seq, max_file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t min_file_offset, max_file_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen struct mail_transaction_header tmp_hdr;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* a list of log files we've referenced. we have to keep this list
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen explicitly because more files may be added into the linked list
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen at any time. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ARRAY_DEFINE(file_refs, struct mail_transaction_log_file *);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_file *cur, *head, *tail;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t cur_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t prev_file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t prev_file_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int broken:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mail_transaction_log_view *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_transaction_log_view_open(struct mail_transaction_log *log)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_view *view;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view = i_new(struct mail_transaction_log_view, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->log = log;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->broken = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->head = view->tail = view->log->head;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->head->refcount++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_array_init(&view->file_refs, 8);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_append(&view->file_refs, &view->head, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->next = log->views;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen log->views = view;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return view;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_transaction_log_view_unref_all(struct mail_transaction_log_view *view)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_file *const *files;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int i, count;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen files = array_get(&view->file_refs, &count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0; i < count; i++)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen files[i]->refcount--;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_clear(&view->file_refs);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_transaction_log_view_close(struct mail_transaction_log_view **_view)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_view *view = *_view;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_view **p;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *_view = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (p = &view->log->views; *p != NULL; p = &(*p)->next) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (*p == view) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *p = view->next;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen break;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_transaction_log_view_unref_all(view);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_transaction_logs_clean(view->log);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen array_free(&view->file_refs);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_free(view);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenvoid mail_transaction_log_views_close(struct mail_transaction_log *log)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_view *view;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (view = log->views; view != NULL; view = view->next)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen view->log = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenint
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmail_transaction_log_view_set(struct mail_transaction_log_view *view,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t min_file_seq, uoff_t min_file_offset,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t max_file_seq, uoff_t max_file_offset)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_transaction_log_file *file, *first;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t end_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(view->log != NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(min_file_seq <= max_file_seq);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (view->log == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* transaction log is closed already. this log view shouldn't
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen be used anymore. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (min_file_seq == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* index file doesn't exist yet. this transaction log should
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen start from the beginning */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (view->log->files->hdr.prev_file_seq != 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* but it doesn't */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_seq = view->log->files->hdr.file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_offset = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (max_file_seq == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_seq = min_file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_offset = min_file_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (min_file_seq == view->log->files->hdr.prev_file_seq &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_offset == view->log->files->hdr.prev_file_offset) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we can skip this */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_seq = view->log->files->hdr.file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_offset = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (min_file_seq > max_file_seq) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* empty view */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_seq = min_file_seq;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_offset = min_file_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* find the oldest log file first. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = mail_transaction_log_find_file(view->log, min_file_seq, &file);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret <= 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (min_file_offset == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* this could happen if internal transactions haven't yet been
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen committed but external are. just assume we're at the
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen beginning. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_offset = file->hdr.hdr_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (max_file_offset == 0 && min_file_seq == max_file_seq)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_offset = min_file_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(min_file_offset >= file->hdr.hdr_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (min_file_seq == max_file_seq && min_file_offset > max_file_offset) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* log file offset is probably corrupted in the index file. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_transaction_log_view_set_corrupted(view,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "file_seq=%u, min_file_offset (%"PRIuUOFF_T
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ") > max_file_offset (%"PRIuUOFF_T")",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen min_file_seq, min_file_offset, max_file_offset);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen end_offset = min_file_seq == max_file_seq ?
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen max_file_offset : (uoff_t)-1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = mail_transaction_log_file_map(file, min_file_offset, end_offset);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret <= 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen first = file;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (seq = min_file_seq+1; seq <= max_file_seq; seq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = file->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* see if we could find the missing file */
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen ret = mail_transaction_log_find_file(view->log,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq, &file);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret <= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0)
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen return -1;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* not found / corrupted */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = NULL;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (file == NULL && max_file_seq == (uint32_t)-1) {
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen /* we just wanted to sync everything */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(max_file_offset == (uoff_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_file_seq = seq-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* missing files in the middle */
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return 0;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen }
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen end_offset = file->hdr.file_seq == max_file_seq ?
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen max_file_offset : (uoff_t)-1;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen ret = mail_transaction_log_file_map(file, file->hdr.hdr_size,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen end_offset);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (ret <= 0)
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen return ret;
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen }
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen i_assert(max_file_offset == (uoff_t)-1 ||
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen max_file_offset <= file->sync_offset);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen /* we have all of them. update refcounts. */
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen mail_transaction_log_view_unref_all(view);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen view->tail = first;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen view->head = view->log->head;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen /* reference all used files */
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen for (file = view->tail; file != NULL; file = file->next) {
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen array_append(&view->file_refs, &file, 1);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen file->refcount++;
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen view->prev_file_seq = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->prev_file_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen view->cur = first;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen view->cur_offset = min_file_offset;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen view->min_file_seq = min_file_seq;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen view->min_file_offset = min_file_offset;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen view->max_file_seq = max_file_seq;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen view->max_file_offset = max_file_offset;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen view->broken = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(view->cur_offset <= view->cur->sync_offset);
9c7e765845357342923e16351181091028e5930fTimo Sirainen i_assert(view->cur->hdr.file_seq == min_file_seq);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 1;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainenvoid
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainenmail_transaction_log_view_get_prev_pos(struct mail_transaction_log_view *view,
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen uint32_t *file_seq_r,
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen uoff_t *file_offset_r)
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen{
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen *file_seq_r = view->prev_file_seq;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *file_offset_r = view->prev_file_offset;
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenstatic bool
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenmail_transaction_log_view_get_last(struct mail_transaction_log_view *view,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen struct mail_transaction_log_file **last_r,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen uoff_t *last_offset_r)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen{
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen struct mail_transaction_log_file *cur = view->cur;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen uoff_t cur_offset = view->cur_offset;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen bool last = FALSE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (cur == NULL) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *last_r = NULL;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return TRUE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (;;) {
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen if (cur->hdr.file_seq == view->max_file_seq) {
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen /* last file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cur_offset == view->max_file_offset ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur_offset == cur->sync_offset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're all finished */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } else if (cur_offset == cur->sync_offset) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* end of file, go to next one */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (cur->next == NULL) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen last = TRUE;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur = cur->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur_offset = cur->hdr.hdr_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen /* not EOF */
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen break;
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *last_r = cur;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen *last_offset_r = cur_offset;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return last;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenbool mail_transaction_log_view_is_last(struct mail_transaction_log_view *view)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *cur;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen uoff_t cur_offset;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return mail_transaction_log_view_get_last(view, &cur, &cur_offset);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenvoid
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainenmail_transaction_log_view_set_corrupted(struct mail_transaction_log_view *view,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const char *fmt, ...)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen{
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen va_list va;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen view->broken = TRUE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen va_start(va, fmt);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen t_push();
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen mail_transaction_log_file_set_corrupted(view->log->head, "%s",
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen t_strdup_vprintf(fmt, va));
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen t_pop();
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen va_end(va);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen}
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenbool
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenmail_transaction_log_view_is_corrupted(struct mail_transaction_log_view *view)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return view->broken;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen}
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic bool
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenlog_view_is_record_valid(struct mail_transaction_log_file *file,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct mail_transaction_header *hdr,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const void *data)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen enum mail_transaction_type rec_type;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen buffer_t *uid_buf = NULL;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen uint32_t rec_size;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen bool ret = TRUE;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen rec_size = mail_index_offset_to_uint32(hdr->size) - sizeof(*hdr);
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* we want to be extra careful with expunges */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rec_type != (MAIL_TRANSACTION_EXPUNGE |
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen MAIL_TRANSACTION_EXPUNGE_PROT)) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen "expunge record missing protection mask");
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return FALSE;
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen }
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rec_size == 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Empty record contents (type=0x%x)", rec_type);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen /* records that are exported by syncing and view syncing will be
d22301419109ed4a38351715e6760011421dadecTimo Sirainen checked here so that we don't have to implement the same validation
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen multiple times. other records are checked internally by
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mail_index_sync_record(). */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen t_push();
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen switch (rec_type) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen case MAIL_TRANSACTION_APPEND:
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if ((rec_size % sizeof(struct mail_index_record)) != 0) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mail_transaction_log_file_set_corrupted(file,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen "Invalid append record size");
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ret = FALSE;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen case MAIL_TRANSACTION_EXPUNGE:
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen data, rec_size);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen array_create_from_buffer(&uids, uid_buf,
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen sizeof(struct mail_transaction_expunge));
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen break;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE:
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen data, rec_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_create_from_buffer(&uids, uid_buf,
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen sizeof(struct mail_transaction_flag_update));
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE: {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_keyword_update *rec = data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int seqset_offset;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if ((seqset_offset % 4) != 0)
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen seqset_offset += 4 - (seqset_offset % 4);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (seqset_offset > rec_size) {
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen mail_transaction_log_file_set_corrupted(file,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen "Invalid keyword update record size");
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ret = FALSE;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen CONST_PTR_OFFSET(data, seqset_offset),
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen rec_size - seqset_offset);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen array_create_from_buffer(&uids, uid_buf, sizeof(uint32_t)*2);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen break;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen }
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET:
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen data, rec_size);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen array_create_from_buffer(&uids, uid_buf,
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen sizeof(struct mail_transaction_keyword_reset));
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen default:
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (array_is_created(&uids)) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen const struct seq_range *rec, *prev = NULL;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen unsigned int i, count = array_count(&uids);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if ((uid_buf->used % uids.arr.element_size) != 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_transaction_log_file_set_corrupted(file,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen "Invalid record size (type=0x%x)", rec_type);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ret = FALSE;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen count = 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen } else if (count == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "No UID ranges (type=0x%x)", rec_type);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = FALSE;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen for (i = 0; i < count; i++, prev = rec) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen rec = array_idx(&uids, i);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if (rec->seq1 > rec->seq2 || rec->seq1 == 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen mail_transaction_log_file_set_corrupted(file,
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen "Invalid UID range "
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen "(%u .. %u, type=0x%x)",
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen rec->seq1, rec->seq2, rec_type);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen ret = FALSE;
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen break;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (prev != NULL && rec->seq1 <= prev->seq2) {
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen mail_transaction_log_file_set_corrupted(file,
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen "Non-sorted UID ranges (type=0x%x)",
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen rec_type);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ret = FALSE;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen break;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen }
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen t_pop();
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenlog_view_get_next(struct mail_transaction_log_view *view,
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen const struct mail_transaction_header **hdr_r,
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen const void **data_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header *hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void *data;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen enum mail_transaction_type rec_type;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen uint32_t full_size;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen size_t file_size;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen if (view->cur == NULL)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return 0;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen /* prev_file_offset should point to beginning of previous log record.
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen when we reach EOF, it should be left there, not to beginning of the
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen next file that's not included inside the view. */
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (mail_transaction_log_view_get_last(view, &view->cur,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen &view->cur_offset)) {
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen /* if the last file was the beginning of a file, we want to
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen move prev pointers there */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen view->prev_file_offset = view->cur_offset;
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen view->cur = NULL;
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen return 0;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen view->prev_file_offset = view->cur_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = view->cur;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = buffer_get_data(file->buffer, &file_size);
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen file_size += file->buffer_offset;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (view->cur_offset + sizeof(*hdr) > file_size) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen mail_transaction_log_file_set_corrupted(file,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen "offset points outside file "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "(%"PRIuUOFF_T" + %"PRIuSIZE_T" > %"PRIuSIZE_T")",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->cur_offset, sizeof(*hdr), file_size);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen return -1;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen }
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen i_assert(view->cur_offset >= file->buffer_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr = CONST_PTR_OFFSET(data, view->cur_offset - file->buffer_offset);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen data = CONST_PTR_OFFSET(hdr, sizeof(*hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen full_size = mail_index_offset_to_uint32(hdr->size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (full_size < sizeof(*hdr)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen "record size too small (type=0x%x, "
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "offset=%"PRIuUOFF_T", size=%u)",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen rec_type, view->cur_offset, full_size);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_size - view->cur_offset < full_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "record size too large (type=0x%x, "
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen "offset=%"PRIuUOFF_T", size=%u, end=%"PRIuSIZE_T")",
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen rec_type, view->cur_offset, full_size, file_size);
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen return -1;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainen if (!log_view_is_record_valid(file, hdr, data))
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen return -1;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen *hdr_r = hdr;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen *data_r = data;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen view->cur_offset += full_size;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen return 1;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen}
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_view_next(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header **hdr_r,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen const void **data_r)
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header *hdr;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen const void *data;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen int ret = 0;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if (view->broken)
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen return -1;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = log_view_get_next(view, &hdr, &data);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if (ret <= 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (ret < 0)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen view->cur_offset = view->cur->sync_offset;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return ret;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen /* drop expunge protection */
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen (MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT))
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen view->tmp_hdr.type = hdr->type & ~MAIL_TRANSACTION_EXPUNGE_PROT;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen else
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen view->tmp_hdr.type = hdr->type;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen /* return record's size */
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen view->tmp_hdr.size = mail_index_offset_to_uint32(hdr->size);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen i_assert(view->tmp_hdr.size > sizeof(*hdr));
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen view->tmp_hdr.size -= sizeof(*hdr);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen *hdr_r = &view->tmp_hdr;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen *data_r = data;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 1;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_transaction_log_view_seek(struct mail_transaction_log_view *view,
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen uint32_t seq, uoff_t offset)
a3d22d3cb0e5436128ca7287cedc921f1789b2c8Timo Sirainen{
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen struct mail_transaction_log_file *file;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen i_assert(seq >= view->min_file_seq && seq <= view->max_file_seq);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_assert(seq != view->min_file_seq || offset >= view->min_file_offset);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen i_assert(seq != view->max_file_seq || offset < view->max_file_offset);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if (view->cur == NULL || seq != view->cur->hdr.file_seq) {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen for (file = view->tail; file != NULL; file = file->next) {
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen if (file->hdr.file_seq == seq)
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen break;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen i_assert(file != NULL);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen view->cur = file;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen }
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen view->cur_offset = offset;
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen}
3a854fc26bcccb0398f0a9a6fa72db1a4ab8f0b8Timo Sirainen