mail-transaction-log-view.c revision 527ed64bc924b4a13b570a8450f8be3efdf71879
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_transaction_log_view {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log *log;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_view *next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t min_file_seq, max_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t min_file_offset, max_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_transaction_type type_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_header tmp_hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mail_transaction_log_file *cur, *head, *tail;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen uoff_t cur_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t prev_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t prev_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int broken:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_transaction_log_view *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_open(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_view *view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view = i_new(struct mail_transaction_log_view, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->log = log;
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen view->broken = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->head = view->tail = view->log->head;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->head->refcount++;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->next = log->views;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->views = view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_transaction_log_view_close(struct mail_transaction_log_view *view)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct mail_transaction_log_view **p;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mail_transaction_log_file *file;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen for (p = &view->log->views; *p != NULL; p = &(*p)->next) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (*p == view) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen *p = view->next;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen break;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen for (file = view->tail; file != view->head; file = file->next)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file->refcount--;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->head->refcount--;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen mail_transaction_logs_clean(view->log);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenvoid mail_transaction_log_views_close(struct mail_transaction_log *log)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct mail_transaction_log_view *view;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen for (view = log->views; view != NULL; view = view->next)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen view->log = NULL;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen}
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_set(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t min_file_seq, uoff_t min_file_offset,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t max_file_seq, uoff_t max_file_offset,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_transaction_type type_mask)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* FIXME: error handling for "not found" case is bad.. should the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen caller after all check it and handle as it sees best..? */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_file *file, *first;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t end_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(min_file_seq <= max_file_seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (view->log == NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return -1;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (min_file_seq == view->log->tail->hdr.prev_file_seq &&
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen min_file_offset == view->log->tail->hdr.prev_file_offset) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* we can skip this */
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen min_file_seq = view->log->tail->hdr.file_seq;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen min_file_offset = sizeof(struct mail_transaction_log_header);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (min_file_seq > max_file_seq) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* empty view */
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen max_file_seq = min_file_seq;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen max_file_offset = min_file_offset;
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen }
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen ret = mail_transaction_log_file_find(view->log, min_file_seq, &file);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (ret <= 0) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen if (ret == 0) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen mail_index_set_error(view->log->index,
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen "Lost transaction log file %s seq %u",
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen view->log->tail->filepath, min_file_seq);
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen return -1;
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen }
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen /* check these later than others as index file may have corrupted
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen log_file_offset. we should have recreated the log file and
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen skipped min_file_seq file above.. max_file_offset can be broken
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen only if min_file_seq = max_file_seq. */
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen i_assert(min_file_offset >= sizeof(struct mail_transaction_log_header));
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen i_assert(max_file_offset >= sizeof(struct mail_transaction_log_header));
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen i_assert(min_file_seq != max_file_seq ||
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen min_file_offset <= max_file_offset);
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_offset = min_file_seq == max_file_seq ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_file_offset : (uoff_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_file_map(file, min_file_offset, end_offset);
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (ret <= 0) {
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (ret == 0) {
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen mail_index_set_error(view->log->index,
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "Lost transaction log file %s seq %u",
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen file->filepath, file->hdr.file_seq);
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (seq = min_file_seq+1; seq <= max_file_seq; seq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = file->next;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen mail_index_set_error(view->log->index,
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "Lost transaction log file %s seq %u",
8830fab191cab8440281eb641dfdd93974b2933bTimo Sirainen view->log->tail->filepath, seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_offset = file->hdr.file_seq == max_file_seq ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_file_offset : (uoff_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = mail_transaction_log_file_map(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(struct mail_transaction_log_header),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_offset);
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (ret == 0) {
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen mail_index_set_error(view->log->index,
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "Lost transaction log file %s seq %u",
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen file->filepath, file->hdr.file_seq);
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen i_assert(max_file_offset == (uoff_t)-1 ||
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen max_file_offset <= file->sync_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* we have all of them. update refcounts. */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (view->tail->hdr.file_seq < first->hdr.file_seq) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* unref old files */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen for (file = view->tail; file != first; file = file->next)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file->refcount--;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->tail = first;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen } else {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* going backwards, reference them */
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen for (file = first; file != view->tail; file = file->next)
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen file->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* reference all new files */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen for (file = view->head->next; file != NULL; file = file->next)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file->refcount++;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->head = view->log->head;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->prev_file_seq = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->prev_file_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur = first;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur_offset = min_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->min_file_seq = min_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->min_file_offset = min_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->max_file_seq = max_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->max_file_offset = max_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->type_mask = type_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->broken = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_get_prev_pos(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t *file_seq_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t *file_offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_seq_r = view->prev_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_offset_r = view->prev_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_set_corrupted(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *fmt, ...)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_list va;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->broken = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_start(va, fmt);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_push();
c1d45cada20777e1973579d40d0ebe43f89bb053Timo Sirainen mail_transaction_log_file_set_corrupted(view->log->head, "%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_strdup_vprintf(fmt, va));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen va_end(va);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_is_corrupted(struct mail_transaction_log_view *view)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return view->broken;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int log_view_get_next(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header **hdr_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void **data_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header *hdr;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen struct mail_transaction_log_file *file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_type_map *type_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int record_size;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen uint32_t hdr_size;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen size_t file_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen for (;;) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file = view->cur;
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen if (file == NULL)
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen return 0;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen view->prev_file_seq = file->hdr.file_seq;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->prev_file_offset = view->cur_offset;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (view->cur_offset != file->sync_offset)
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur = file->next;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur_offset = sizeof(struct mail_transaction_log_header);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen if (view->cur_offset >= view->max_file_offset &&
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen file->hdr.file_seq == view->max_file_seq)
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen return 0;
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen data = buffer_get_data(file->buffer, &file_size);
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen file_size += file->buffer_offset;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (view->cur_offset + sizeof(*hdr) > file_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen "offset points outside file "
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen "(%"PRIuUOFF_T" + %"PRIuSIZE_T" > %"PRIuSIZE_T")",
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur_offset, sizeof(*hdr), file_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen hdr = CONST_PTR_OFFSET(data, view->cur_offset - file->buffer_offset);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen data = CONST_PTR_OFFSET(hdr, sizeof(*hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen hdr_size = mail_index_offset_to_uint32(hdr->size);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (file_size - view->cur_offset < hdr_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen "record size too large (type=0x%x, offset=%"PRIuUOFF_T
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen ", size=%u, end=%"PRIuSIZE_T")",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->type & MAIL_TRANSACTION_TYPE_MASK,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->cur_offset, hdr_size, file_size);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->cur_offset = file_size;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen return -1;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (hdr_size < sizeof(*hdr)) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen "record size too small (type=0x%x, size=%u)",
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen hdr->type & MAIL_TRANSACTION_TYPE_MASK, hdr_size);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen view->cur_offset = file_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen type_rec = mail_transaction_type_lookup(hdr->type);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (type_rec != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen record_size = type_rec->record_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "unknown record type 0x%x",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->type & MAIL_TRANSACTION_TYPE_MASK);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->cur_offset = file->sync_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) !=
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "found expunge without protection mask");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) != type_rec->type) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "extra bits in header type: 0x%x",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->type & MAIL_TRANSACTION_TYPE_MASK);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen } else if (hdr->type == MAIL_TRANSACTION_EXTRA_REC_UPDATE) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen const struct mail_transaction_extra_rec_header *ehdr = data;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen if (ehdr->data_id >= view->log->index->extra_records_count) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen mail_transaction_log_file_set_corrupted(file,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen "extra record update out of range (%u > %u)",
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen ehdr->data_id,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen view->log->index->extra_records_count);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return -1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if ((hdr_size - sizeof(*hdr)) % record_size != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "record size wrong (type 0x%x, %u %% %u != 0)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->type & MAIL_TRANSACTION_TYPE_MASK,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen (hdr_size - sizeof(*hdr)), record_size);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->cur_offset = file->sync_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *hdr_r = hdr;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen *data_r = data;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->cur_offset += hdr_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_view_next(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header **hdr_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void **data_r, int *skipped_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_header *hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (skipped_r != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *skipped_r = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (view->broken)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((ret = log_view_get_next(view, &hdr, &data)) > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((view->type_mask & hdr->type) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we don't want this record */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (skipped_r != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *skipped_r = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* FIXME: hide flag/cache updates for appends if
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen append isn't in mask */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->tmp_hdr = *hdr;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen view->tmp_hdr.size =
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen mail_index_offset_to_uint32(view->tmp_hdr.size) - sizeof(*hdr);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen i_assert(view->tmp_hdr.size != 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* hide expunge protection */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->tmp_hdr.type &= ~MAIL_TRANSACTION_EXPUNGE_PROT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen *hdr_r = &view->tmp_hdr;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen *data_r = data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}