mail-transaction-log-view.c revision c91de2744f8c1e61e91082ff5e214450f28a0e7c
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "array.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
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen /* a list of log files we've referenced. we have to keep this list
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen explicitly because more files may be added into the linked list
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen at any time. */
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen ARRAY_DEFINE(file_refs, struct mail_transaction_log_file *);
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++;
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen i_array_init(&view->file_refs, 8);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen array_append(&view->file_refs, &view->head, 1);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view->next = log->views;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->views = view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenmail_transaction_log_view_unref_all(struct mail_transaction_log_view *view)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_transaction_log_file *const *files;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen unsigned int i, count;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen files = array_get(&view->file_refs, &count);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen for (i = 0; i < count; i++)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen files[i]->refcount--;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen array_clear(&view->file_refs);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid mail_transaction_log_view_close(struct mail_transaction_log_view **_view)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct mail_transaction_log_view *view = *_view;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct mail_transaction_log_view **p;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_view = NULL;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo 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
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen mail_transaction_log_view_unref_all(view);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen mail_transaction_logs_clean(view->log);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen array_free(&view->file_refs);
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 struct mail_transaction_log_file *file, *first;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t end_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen i_assert(view->log != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(min_file_seq <= max_file_seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (view->log == NULL) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen /* transaction log is closed already. this log view shouldn't
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen be used anymore. */
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return -1;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (min_file_seq == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* index file doesn't exist yet. this transaction log should
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen start from the beginning */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (view->log->files->hdr.prev_file_seq != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* but it doesn't */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen min_file_seq = view->log->files->hdr.file_seq;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen min_file_offset = 0;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (max_file_seq == 0) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen max_file_seq = min_file_seq;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen max_file_offset = min_file_offset;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen }
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
45e62043058738e294f89504c319d852e25943ccTimo Sirainen if (min_file_seq == view->log->files->hdr.prev_file_seq &&
45e62043058738e294f89504c319d852e25943ccTimo Sirainen min_file_offset == view->log->files->hdr.prev_file_offset) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* we can skip this */
45e62043058738e294f89504c319d852e25943ccTimo Sirainen min_file_seq = view->log->files->hdr.file_seq;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen min_file_offset = 0;
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
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* find the oldest log file first. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_find_file(view->log, min_file_seq, &file);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (ret <= 0)
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return ret;
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (min_file_offset == 0) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* this could happen if internal transactions haven't yet been
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen committed but external are. just assume we're at the
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen beginning. */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen min_file_offset = file->hdr.hdr_size;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (max_file_offset == 0 && min_file_seq == max_file_seq)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen max_file_offset = min_file_offset;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen i_assert(min_file_offset >= file->hdr.hdr_size);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (min_file_seq == max_file_seq && min_file_offset > max_file_offset) {
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen /* log file offset is probably corrupted in the index file. */
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen mail_transaction_log_view_set_corrupted(view,
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen "file_seq=%u, min_file_offset (%"PRIuUOFF_T
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen ") > max_file_offset (%"PRIuUOFF_T")",
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen min_file_seq, min_file_offset, max_file_offset);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen return -1;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
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);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (ret <= 0)
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first = file;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (seq = min_file_seq+1; seq <= max_file_seq; seq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file = file->next;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* see if we could find the missing file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_transaction_log_find_file(view->log,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen seq, &file);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (ret <= 0) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (ret < 0)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return -1;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* not found / corrupted */
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen file = NULL;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (file == NULL && max_file_seq == (uint32_t)-1) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* we just wanted to sync everything */
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen i_assert(max_file_offset == (uoff_t)-1);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen max_file_seq = seq-1;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen break;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* missing files in the middle */
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return 0;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_offset = file->hdr.file_seq == max_file_seq ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen max_file_offset : (uoff_t)-1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen ret = mail_transaction_log_file_map(file, file->hdr.hdr_size,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen end_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret <= 0)
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return ret;
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. */
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen mail_transaction_log_view_unref_all(view);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
02a3001389237da331e70c1cf7c85ebc9cf94888Timo Sirainen view->tail = first;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen view->head = view->log->head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen /* reference all used files */
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen for (file = view->tail; file != NULL; file = file->next) {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen array_append(&view->file_refs, &file, 1);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen file->refcount++;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen }
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;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen i_assert(view->cur_offset <= view->cur->sync_offset);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen i_assert(view->cur->hdr.file_seq == min_file_seq);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen return 1;
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
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic bool
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenmail_transaction_log_view_get_last(struct mail_transaction_log_view *view,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file **last_r,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uoff_t *last_offset_r)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file *cur = view->cur;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uoff_t cur_offset = view->cur_offset;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen bool last = FALSE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (cur == NULL) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen *last_r = NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return TRUE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen for (;;) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (cur->hdr.file_seq == view->max_file_seq) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* last file */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (cur_offset == view->max_file_offset ||
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen cur_offset == cur->sync_offset) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* we're all finished */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen last = TRUE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } else if (cur_offset == cur->sync_offset) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* end of file, go to next one */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (cur->next == NULL) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen last = TRUE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen cur = cur->next;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen cur_offset = cur->hdr.hdr_size;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen continue;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* not EOF */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen break;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen *last_r = cur;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen *last_offset_r = cur_offset;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return last;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenbool mail_transaction_log_view_is_last(struct mail_transaction_log_view *view)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file *cur;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uoff_t cur_offset;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return mail_transaction_log_view_get_last(view, &cur, &cur_offset);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo 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
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_is_corrupted(struct mail_transaction_log_view *view)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return view->broken;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic bool
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenlog_view_is_record_valid(struct mail_transaction_log_file *file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct mail_transaction_header *hdr,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const void *data,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct mail_transaction_type_map *type_rec)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen enum mail_transaction_type hdr_type;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen buffer_t *uid_buf;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uint32_t hdr_size;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen bool ret = TRUE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen hdr_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen hdr_size = mail_index_offset_to_uint32(hdr->size) - sizeof(*hdr);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we want to be extra careful with expunges */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (hdr_type != (MAIL_TRANSACTION_EXPUNGE |
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen MAIL_TRANSACTION_EXPUNGE_PROT)) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "expunge record missing protection mask");
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen } else if (hdr_type != type_rec->type) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "extra bits in header type: 0x%x", hdr_type);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* records that are exported by syncing and view syncing will be
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen checked here so that we don't have to implement the same validation
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen multiple times. other records are checked internally by
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_index_sync_record(). */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen t_push();
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen switch (hdr_type) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_TRANSACTION_EXPUNGE: {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen data, hdr_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_create_from_buffer(&uids, uid_buf,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen sizeof(struct mail_transaction_expunge));
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_TRANSACTION_FLAG_UPDATE: {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen data, hdr_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_create_from_buffer(&uids, uid_buf,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen sizeof(struct mail_transaction_flag_update));
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_TRANSACTION_KEYWORD_UPDATE: {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct mail_transaction_keyword_update *rec = data;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen unsigned int seqset_offset;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if ((seqset_offset % 4) != 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen seqset_offset += 4 - (seqset_offset % 4);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (seqset_offset >= hdr_size ||
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ((hdr_size - seqset_offset) % (sizeof(uint32_t)*2)) != 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "Invalid keyword update record size");
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen CONST_PTR_OFFSET(data, seqset_offset),
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen hdr_size - seqset_offset);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_create_from_buffer(&uids, uid_buf, sizeof(uint32_t)*2);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_TRANSACTION_KEYWORD_RESET: {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uid_buf = buffer_create_const_data(pool_datastack_create(),
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen data, hdr_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_create_from_buffer(&uids, uid_buf,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen sizeof(struct mail_transaction_keyword_reset));
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen default:
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (array_is_created(&uids)) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct seq_range *rec, *prev = NULL;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen unsigned int i, count = array_count(&uids);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen for (i = 0; i < count; i++, prev = rec) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen rec = array_idx(&uids, i);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (rec->seq1 > rec->seq2 || rec->seq1 == 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "Invalid UID range "
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "(%u .. %u, type=0x%x)",
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen rec->seq1, rec->seq2, hdr_type);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (prev != NULL && rec->seq1 <= prev->seq2) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "Non-sorted UID ranges (type=0x%x)",
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen hdr_type);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ret = FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen t_pop();
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return ret;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainenstatic int
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainenlog_view_get_next(struct mail_transaction_log_view *view,
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen const struct mail_transaction_header **hdr_r,
834b90e1f426d1e3308670e09c050bcdea546eb8Timo 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;
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen enum mail_transaction_type hdr_type;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen uint32_t hdr_size;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen size_t file_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (view->cur == NULL)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen return 0;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen /* prev_file_offset should point to beginning of previous log record.
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen when we reach EOF, it should be left there, not to beginning of the
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen next file that's not included inside the view. */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (mail_transaction_log_view_get_last(view, &view->cur,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen &view->cur_offset)) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* if the last file was the beginning of a file, we want to
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen move prev pointers there */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen view->prev_file_offset = view->cur_offset;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen view->cur = NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen view->prev_file_offset = view->cur_offset;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen file = view->cur;
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
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_assert(view->cur_offset >= file->buffer_offset);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen hdr = CONST_PTR_OFFSET(data, view->cur_offset - file->buffer_offset);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen data = CONST_PTR_OFFSET(hdr, sizeof(*hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen hdr_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen hdr_size = mail_index_offset_to_uint32(hdr->size);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (hdr_size < sizeof(*hdr)) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we'll fail below with "records size too small" */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen type_rec = NULL;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen record_size = 0;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen } else {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen type_rec = mail_transaction_type_lookup(hdr->type);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (type_rec != NULL)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen record_size = type_rec->record_size;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen else {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mail_transaction_log_file_set_corrupted(file,
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen "unknown record type 0x%x", hdr_type);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (hdr_size < sizeof(*hdr) + record_size) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen mail_transaction_log_file_set_corrupted(file,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "record size too small (type=0x%x, "
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "offset=%"PRIuUOFF_T", size=%u)",
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen hdr_type, view->cur_offset, hdr_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen if (record_size != 0 &&
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen (hdr_size - sizeof(*hdr)) % record_size != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_file_set_corrupted(file,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "record size wrong (type 0x%x, "
01ac83a86f9f29741b585205eefeec9c0c546f8bTimo Sirainen "offset=%"PRIuUOFF_T", size=%"PRIuSIZE_T" %% %u != 0)",
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen hdr_type, view->cur_offset, (hdr_size - sizeof(*hdr)),
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen record_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen if (file_size - view->cur_offset < hdr_size) {
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen mail_transaction_log_file_set_corrupted(file,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "record size too large (type=0x%x, "
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "offset=%"PRIuUOFF_T", size=%u, end=%"PRIuSIZE_T")",
a942db367328a91e3a0b6c810bb8abbcb7663707Timo Sirainen hdr_type, view->cur_offset, hdr_size, file_size);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen return -1;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (!log_view_is_record_valid(file, hdr, data, type_rec))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
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,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const void **data_r, bool *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
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen while ((ret = log_view_get_next(view, &hdr, &data)) > 0) {
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen if ((view->type_mask & hdr->type) != 0) {
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen /* looks like this is within our mask, but expunge
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen protection may mess up the check. */
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0 ||
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen (view->type_mask & MAIL_TRANSACTION_EXPUNGE) != 0)
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen break;
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen }
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
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ret < 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen view->cur_offset = view->cur->sync_offset;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ret == 0)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return 0;
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}
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainenvoid mail_transaction_log_view_seek(struct mail_transaction_log_view *view,
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen uint32_t seq, uoff_t offset)
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen{
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen struct mail_transaction_log_file *file;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_assert(seq >= view->min_file_seq && seq <= view->max_file_seq);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_assert(seq != view->min_file_seq || offset >= view->min_file_offset);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_assert(seq != view->max_file_seq || offset < view->max_file_offset);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (view->cur == NULL || seq != view->cur->hdr.file_seq) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen for (file = view->tail; file != NULL; file = file->next) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (file->hdr.file_seq == seq)
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen break;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_assert(file != NULL);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen view->cur = file;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen view->cur_offset = offset;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen}