bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_open(struct mail_transaction_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen view = i_new(struct mail_transaction_log_view, 1);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen array_append(&view->file_refs, &view->head, 1);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenmail_transaction_log_view_unref_all(struct mail_transaction_log_view *view)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_transaction_log_file *const *files;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen for (i = 0; i < count; i++)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid mail_transaction_log_view_close(struct mail_transaction_log_view **_view)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct mail_transaction_log_view *view = *_view;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen for (p = &view->log->views; *p != NULL; p = &(*p)->next) {
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainenstatic const char *
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainenmail_transaction_log_get_file_seqs(struct mail_transaction_log *log)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen for (file = log->files; file != NULL; file = file->next)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenint mail_transaction_log_view_set(struct mail_transaction_log_view *view,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen uint32_t min_file_seq, uoff_t min_file_offset,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen uint32_t max_file_seq, uoff_t max_file_offset,
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen struct mail_transaction_log_file *file, *const *files;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen unsigned int i;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen /* transaction log is closed already. this log view shouldn't
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen be used anymore. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* index file doesn't exist yet. this transaction log should
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen start from the beginning */
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen if (view->log->files->hdr.prev_file_seq != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* but it doesn't */
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Wanted log beginning, but found prev_file_seq=%u",
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen min_file_seq = view->log->files->hdr.file_seq;
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen for (file = view->log->files; file != NULL; file = file->next) {
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen if (file != NULL && min_file_offset == file->hdr.prev_file_offset) {
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen /* we can (and sometimes must) skip to the next file */
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen for (file = view->log->files; file != NULL; file = file->next) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (file != NULL && max_file_offset == file->hdr.prev_file_offset) {
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen /* we can skip to the next file. we've delayed checking for
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen min_file_seq <= max_file_seq until now, because it's not
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen really an error to specify the same position twice (even if
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen in "wrong" order) */
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. */
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Invalid offset: file_seq=%u, min_file_offset (%"PRIuUOFF_T
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen min_file_seq, min_file_offset, max_file_offset);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mail_transaction_log_view_set_corrupted(view, "%s", *reason_r);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen for (seq = min_file_seq; seq <= max_file_seq; seq++) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen /* see if we could find the missing file. if we know
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen the max. file sequence or we don't have the the min.
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen file, make sure NFS attribute cache gets flushed if
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen necessary. */
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen ret = mail_transaction_log_find_file(view->log, seq,
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen "Failed to find file seq=%u: %s",
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* not found / corrupted */
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (file == NULL || file->hdr.file_seq != seq) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (file == NULL && max_file_seq == (uint32_t)-1 &&
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* we just wanted to sync everything */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* if any of the found files reset the index,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ignore any missing files up to it */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* missing files in the middle */
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen "Missing middle file seq=%u (between %u..%u, we have seqs %s): %s",
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen mail_transaction_log_get_file_seqs(view->log), reason);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* we can ignore the missing file */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* beginning of the file */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* we don't actually want to show anything */
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (min_file_offset < view->tail->hdr.hdr_size) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* log file offset is probably corrupted in the index file. */
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Invalid min_file_offset: file_seq=%u, min_file_offset (%"PRIuUOFF_T
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen ") < hdr_size (%u)",
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen min_file_seq, min_file_offset, view->tail->hdr.hdr_size);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mail_transaction_log_view_set_corrupted(view, "%s", *reason_r);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (max_file_offset < view->head->hdr.hdr_size) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* log file offset is probably corrupted in the index file. */
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Invalid max_file_offset: file_seq=%u, min_file_offset (%"PRIuUOFF_T
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen ") < hdr_size (%u)",
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen max_file_seq, max_file_offset, view->head->hdr.hdr_size);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mail_transaction_log_view_set_corrupted(view, "%s", *reason_r);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* we have all of them. update refcounts. */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* Reference all used files. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen view->cur_offset = view->cur->hdr.file_seq == min_file_seq ?
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* Map the files only after we've found them all. Otherwise if we map
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen one file and then another file just happens to get rotated, we could
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen include both files in the view but skip the last transactions from
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen the first file.
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen We're mapping the files in reverse order so that _log_file_map()
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen can verify that prev_file_offset matches how far it actually managed
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen to sync the file. */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen for (i = array_count(&view->file_refs); i > 0; i--) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen start_offset = file->hdr.file_seq == min_file_seq ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_offset = file->hdr.file_seq == max_file_seq ?
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen ret = mail_transaction_log_file_map(file, start_offset,
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Failed to map file seq=%u "
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen "offset=%"PRIuUOFF_T"..%"PRIuUOFF_T" (ret=%d): %s",
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen file->hdr.file_seq, start_offset, end_offset, ret, *reason_r);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* this file resets the index.
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen don't bother reading the others. */
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen if (min_file_seq == view->head->hdr.file_seq &&
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen /* log file offset is probably corrupted in the index file. */
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen "Invalid offset: file_seq=%u, min_file_offset (%"PRIuUOFF_T
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen ") > sync_offset (%"PRIuUOFF_T")", min_file_seq,
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mail_transaction_log_view_set_corrupted(view, "%s", *reason_r);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen view->max_file_offset = I_MIN(max_file_offset, view->head->sync_offset);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (mail_transaction_log_file_get_highest_modseq_at(view->cur,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen view->cur_offset, &view->prev_modseq, reason_r) < 0)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen i_assert(view->cur_offset <= view->cur->sync_offset);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenint mail_transaction_log_view_set_all(struct mail_transaction_log_view *view)
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen struct mail_transaction_log_file *file, *first;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* make sure .log.2 file is opened */
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen (void)mail_transaction_log_find_file(view->log, 1, FALSE, &file, &reason);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen for (file = view->log->files; file != NULL; file = file->next) {
ac8cb75fb110a9d03363d1219a5672ce3c4ff89aTimo Sirainen ret = mail_transaction_log_file_map(file, file->hdr.hdr_size,
ac8cb75fb110a9d03363d1219a5672ce3c4ff89aTimo Sirainen /* corrupted */
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* this file resets the index. skip the old ones. */
ac8cb75fb110a9d03363d1219a5672ce3c4ff89aTimo Sirainen /* index wasn't reset after corruption was found */
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen "Failed to map transaction log %s for all-view: %s",
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen for (file = first; file != NULL; file = file->next) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen view->max_file_seq = view->head->hdr.file_seq;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen view->max_file_offset = view->head->sync_offset;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (mail_transaction_log_file_get_highest_modseq_at(view->cur,
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen view->cur_offset, &view->prev_modseq, &reason) < 0) {
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen "Failed to get modseq in %s for all-view: %s",
c680a6b35b459045e92814778908da5a93922107Timo Sirainenvoid mail_transaction_log_view_clear(struct mail_transaction_log_view *view,
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen mail_transaction_log_find_file(view->log, oldest_file_seq, FALSE,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen view->min_file_offset = view->max_file_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_get_prev_pos(struct mail_transaction_log_view *view,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenmail_transaction_log_view_get_prev_modseq(struct mail_transaction_log_view *view)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenmail_transaction_log_view_get_last(struct mail_transaction_log_view *view,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_transaction_log_file *cur = view->cur;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (cur->hdr.file_seq == view->max_file_seq) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* last file */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* we're all finished */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* end of file, go to next one */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* not EOF */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenbool mail_transaction_log_view_is_last(struct mail_transaction_log_view *view)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return mail_transaction_log_view_get_last(view, &cur, &cur_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_set_corrupted(struct mail_transaction_log_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *fmt, ...)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen mail_transaction_log_file_set_corrupted(view->log->head, "%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_transaction_log_view_is_corrupted(struct mail_transaction_log_view *view)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenlog_view_is_uid_range_valid(struct mail_transaction_log_file *file,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if ((uids->arr.buffer->used % uids->arr.element_size) != 0) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen } else if (count == 0) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (rec->seq1 > rec->seq2 || rec->seq1 == 0) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen "Invalid UID range (%u .. %u, type=0x%x)",
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (prev != NULL && rec->seq1 <= prev->seq2) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen "Non-sorted UID ranges (type=0x%x)", rec_type);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenlog_view_is_record_valid(struct mail_transaction_log_file *file,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen rec_size = mail_index_offset_to_uint32(hdr->size) - sizeof(*hdr);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we want to be extra careful with expunges */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "expunge record missing protection mask");
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE_GUID) != 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (rec_type != (MAIL_TRANSACTION_EXPUNGE_GUID |
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "expunge guid record missing protection mask");
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen "Empty record contents (type=0x%x)", rec_type);
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(). */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if ((rec_size % sizeof(struct mail_index_record)) != 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen "Invalid append record size");
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_const_data(&uid_buf, data, rec_size);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen const struct mail_transaction_expunge_guid *recs = data;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "Invalid expunge guid record size");
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen for (i = 0; i < count; i++) {
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen "Expunge guid record with uid=0");
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_const_data(&uid_buf, data, rec_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct mail_transaction_keyword_update *rec = data;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen "Trying to use empty keyword");
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "Invalid keyword update record size");
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_const_data(&uid_buf, data, rec_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen sizeof(struct mail_transaction_keyword_reset));
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen unsigned int i;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen for (i = 0; i < rec_size; ) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen /* should be just extra padding */
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (i + sizeof(*rec) + rec->name_size > rec_size) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen "ext intro: name_size too large");
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if ((i % 4) != 0)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen unsigned int i;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen for (i = 0; i+2 < rec_size && attr_changes[i] != '\0'; ) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (attr_changes[i] != '+' && attr_changes[i] != '-') {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen "attribute update: Invalid prefix 0x%02x",
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (attr_changes[i] != 'p' && attr_changes[i] != 's') {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen "attribute update: Invalid type 0x%02x",
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen "attribute update: Empty key");
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (i == 0 || (i < rec_size && attr_changes[i] != '\0')) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen "attribute update doesn't end with NUL");
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (!log_view_is_uid_range_valid(file, rec_type, &uids))
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainenlog_view_get_next(struct mail_transaction_log_view *view,
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen const void **data_r)
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 /* 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;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen view->prev_file_seq = view->cur->hdr.file_seq;
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen file_size = file->buffer->used + file->buffer_offset;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (view->cur_offset + sizeof(*hdr) > file_size) {
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen "offset points outside file "
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen "(%"PRIuUOFF_T" + %"PRIuSIZE_T" > %"PRIuSIZE_T")",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_assert(view->cur_offset >= file->buffer_offset);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen hdr = CONST_PTR_OFFSET(data, view->cur_offset - file->buffer_offset);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen rec_type = hdr->type & MAIL_TRANSACTION_TYPE_MASK;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen full_size = mail_index_offset_to_uint32(hdr->size);
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "record size too small (type=0x%x, "
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (file_size - view->cur_offset < full_size) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "record size too large (type=0x%x, "
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen "offset=%"PRIuUOFF_T", size=%u, end=%"PRIuSIZE_T")",
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen rec_type, view->cur_offset, full_size, file_size);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = log_view_is_record_valid(file, hdr, data) ? 1 : -1;
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen mail_transaction_update_modseq(hdr, data, &view->prev_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen MAIL_TRANSACTION_LOG_HDR_VERSION(&file->hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_transaction_log_view_next(struct mail_transaction_log_view *view,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen const void **data_r)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen /* drop expunge protection */
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen (MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT) ||
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen (MAIL_TRANSACTION_EXPUNGE_GUID | MAIL_TRANSACTION_EXPUNGE_PROT))
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen view->tmp_hdr.type = hdr->type & ~MAIL_TRANSACTION_EXPUNGE_PROT;
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen /* return record's size */
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen view->tmp_hdr.size = mail_index_offset_to_uint32(hdr->size);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid mail_transaction_log_view_mark(struct mail_transaction_log_view *view)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(view->cur->hdr.file_seq == view->prev_file_seq);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid mail_transaction_log_view_rewind(struct mail_transaction_log_view *view)