virtual-sync.c (dovecot-2.3.16) | : | virtual-sync.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 148 | skipping to change at line 148 | |||
/* another process just added a new mailbox. | /* another process just added a new mailbox. | |||
we can't handle this currently. */ | we can't handle this currently. */ | |||
mbox->inconsistent = TRUE; | mbox->inconsistent = TRUE; | |||
mail_storage_set_error(mbox->box.storage, MAIL_ERROR_TEMP, t_strdup_print f( | mail_storage_set_error(mbox->box.storage, MAIL_ERROR_TEMP, t_strdup_print f( | |||
"Backend mailbox '%s' added by another session. " | "Backend mailbox '%s' added by another session. " | |||
"Reopen the virtual mailbox.", name)); | "Reopen the virtual mailbox.", name)); | |||
return -1; | return -1; | |||
} | } | |||
static bool | ||||
virtual_mailbox_ext2_header_read(struct virtual_mailbox *mbox, | ||||
struct mail_index_view *view, | ||||
const struct virtual_mail_index_header *ext_hdr) | ||||
{ | ||||
const char *box_path = mailbox_get_path(&mbox->box); | ||||
const struct virtual_mail_index_ext2_header *ext2_hdr; | ||||
const struct virtual_mail_index_mailbox_ext2_record *ext2_rec; | ||||
const void *ext2_data; | ||||
size_t ext2_size; | ||||
struct virtual_backend_box *bbox; | ||||
mail_index_get_header_ext(view, mbox->virtual_ext2_id, | ||||
&ext2_data, &ext2_size); | ||||
ext2_hdr = ext2_data; | ||||
if (ext2_size == 0) { | ||||
/* ext2 is missing - silently add it */ | ||||
return FALSE; | ||||
} | ||||
if (ext2_size < sizeof(*ext2_hdr)) { | ||||
i_error("virtual index %s: Invalid ext2 header size: %zu", | ||||
box_path, ext2_size); | ||||
return FALSE; | ||||
} | ||||
if (ext2_hdr->hdr_size > ext2_size) { | ||||
i_error("virtual index %s: ext2 header size too large: %u > %zu", | ||||
box_path, ext2_hdr->hdr_size, ext2_size); | ||||
return FALSE; | ||||
} | ||||
if (ext2_hdr->ext_record_size < sizeof(*ext2_rec)) { | ||||
i_error("virtual index %s: Invalid ext2 record size: %u", | ||||
box_path, ext2_hdr->ext_record_size); | ||||
return FALSE; | ||||
} | ||||
if (ext_hdr->change_counter != ext2_hdr->change_counter) { | ||||
i_warning("virtual index %s: " | ||||
"Extension header change_counter mismatch (%u != %u) - | ||||
" | ||||
"Index was modified by an older version?", | ||||
box_path, ext_hdr->change_counter, | ||||
ext2_hdr->change_counter); | ||||
return FALSE; | ||||
} | ||||
size_t mailboxes_size = ext2_size - ext2_hdr->hdr_size; | ||||
if (mailboxes_size % ext2_hdr->ext_record_size != 0 || | ||||
mailboxes_size / ext2_hdr->ext_record_size != ext_hdr->mailbox_count) | ||||
{ | ||||
i_error("virtual index %s: Invalid ext2 size: " | ||||
"hdr_size=%u record_size=%u total_size=%zu mailbox_count= | ||||
%u", | ||||
box_path, ext2_hdr->hdr_size, ext2_hdr->ext_record_size, | ||||
ext2_size, ext_hdr->mailbox_count); | ||||
return FALSE; | ||||
} | ||||
ext2_rec = CONST_PTR_OFFSET(ext2_data, ext2_hdr->hdr_size); | ||||
array_foreach_elem(&mbox->backend_boxes, bbox) { | ||||
if (bbox->sync_mailbox_idx1 == 0) | ||||
continue; | ||||
guid_128_copy(bbox->sync_guid, | ||||
ext2_rec[bbox->sync_mailbox_idx1-1].guid); | ||||
} | ||||
return TRUE; | ||||
} | ||||
int virtual_mailbox_ext_header_read(struct virtual_mailbox *mbox, | int virtual_mailbox_ext_header_read(struct virtual_mailbox *mbox, | |||
struct mail_index_view *view, | struct mail_index_view *view, | |||
bool *broken_r) | bool *broken_r) | |||
{ | { | |||
const char *box_path = mailbox_get_path(&mbox->box); | const char *box_path = mailbox_get_path(&mbox->box); | |||
const struct virtual_mail_index_header *ext_hdr; | const struct virtual_mail_index_header *ext_hdr; | |||
const struct mail_index_header *hdr; | const struct mail_index_header *hdr; | |||
const struct virtual_mail_index_mailbox_record *mailboxes; | const struct virtual_mail_index_mailbox_record *mailboxes; | |||
struct virtual_backend_box *bbox, **bboxes; | struct virtual_backend_box *bbox, **bboxes; | |||
const void *ext_data; | const void *ext_data; | |||
skipping to change at line 260 | skipping to change at line 324 | |||
bbox->sync_mailbox_idx1 = i+1; | bbox->sync_mailbox_idx1 = i+1; | |||
} | } | |||
ext_name_offset += mailboxes[i].name_len; | ext_name_offset += mailboxes[i].name_len; | |||
prev_mailbox_id = mailboxes[i].id; | prev_mailbox_id = mailboxes[i].id; | |||
} | } | |||
if (i < ext_mailbox_count) { | if (i < ext_mailbox_count) { | |||
*broken_r = TRUE; | *broken_r = TRUE; | |||
mbox->ext_header_rewrite = TRUE; | mbox->ext_header_rewrite = TRUE; | |||
ret = 0; | ret = 0; | |||
} | } | |||
if (!*broken_r && ext_mailbox_count > 0) { | ||||
if (!virtual_mailbox_ext2_header_read(mbox, view, ext_hdr)) | ||||
mbox->ext_header_rewrite = TRUE; | ||||
} | ||||
mbox->highest_mailbox_id = ext_hdr == NULL ? 0 : | mbox->highest_mailbox_id = ext_hdr == NULL ? 0 : | |||
ext_hdr->highest_mailbox_id; | ext_hdr->highest_mailbox_id; | |||
/* do not mark it initialized if it's broken */ | /* do not mark it initialized if it's broken */ | |||
mbox->sync_initialized = !*broken_r; | mbox->sync_initialized = !*broken_r; | |||
/* assign new mailbox IDs if any are missing */ | /* assign new mailbox IDs if any are missing */ | |||
bboxes = array_get_modifiable(&mbox->backend_boxes, &count); | bboxes = array_get_modifiable(&mbox->backend_boxes, &count); | |||
for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | |||
if (bboxes[i]->mailbox_id == 0) { | if (bboxes[i]->mailbox_id == 0) { | |||
bboxes[i]->mailbox_id = ++mbox->highest_mailbox_id; | bboxes[i]->mailbox_id = ++mbox->highest_mailbox_id; | |||
skipping to change at line 284 | skipping to change at line 353 | |||
array_sort(&mbox->backend_boxes, bbox_mailbox_id_cmp); | array_sort(&mbox->backend_boxes, bbox_mailbox_id_cmp); | |||
if (ret == 0) | if (ret == 0) | |||
mbox->ext_header_rewrite = TRUE; | mbox->ext_header_rewrite = TRUE; | |||
return ret; | return ret; | |||
} | } | |||
static void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx) | static void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx) | |||
{ | { | |||
struct virtual_mail_index_header ext_hdr; | struct virtual_mail_index_header ext_hdr; | |||
struct virtual_mail_index_mailbox_record mailbox; | struct virtual_mail_index_mailbox_record mailbox; | |||
struct virtual_mail_index_mailbox_ext2_record ext2_rec; | ||||
struct virtual_backend_box **bboxes; | struct virtual_backend_box **bboxes; | |||
buffer_t *buf; | buffer_t *buf, *buf2; | |||
const void *ext_data; | const void *ext_data; | |||
size_t ext_size; | size_t ext_size; | |||
unsigned int i, mailbox_pos, name_pos, count; | unsigned int i, mailbox_pos, name_pos, count; | |||
bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count); | bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count); | |||
mailbox_pos = sizeof(ext_hdr); | mailbox_pos = sizeof(ext_hdr); | |||
name_pos = mailbox_pos + sizeof(mailbox) * count; | name_pos = mailbox_pos + sizeof(mailbox) * count; | |||
i_zero(&ext_hdr); | i_zero(&ext_hdr); | |||
i_zero(&mailbox); | i_zero(&mailbox); | |||
i_zero(&ext2_rec); | ||||
ext_hdr.change_counter = ++ctx->mbox->prev_change_counter; | ext_hdr.change_counter = ++ctx->mbox->prev_change_counter; | |||
ext_hdr.mailbox_count = count; | ext_hdr.mailbox_count = count; | |||
ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id; | ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id; | |||
ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32; | ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32; | |||
buf = t_buffer_create(name_pos + 256); | buf = buffer_create_dynamic(default_pool, name_pos + 256); | |||
buffer_append(buf, &ext_hdr, sizeof(ext_hdr)); | buffer_append(buf, &ext_hdr, sizeof(ext_hdr)); | |||
struct virtual_mail_index_ext2_header ext2_hdr = { | ||||
.version = VIRTUAL_MAIL_INDEX_EXT2_HEADER_VERSION, | ||||
.ext_record_size = sizeof(struct virtual_mail_index_mailbox_ext2_ | ||||
record), | ||||
.hdr_size = sizeof(struct virtual_mail_index_ext2_header), | ||||
.change_counter = ext_hdr.change_counter, | ||||
}; | ||||
buf2 = buffer_create_dynamic(default_pool, sizeof(ext2_hdr) + | ||||
sizeof(ext2_rec) * count); | ||||
buffer_append(buf2, &ext2_hdr, sizeof(ext2_hdr)); | ||||
for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | |||
i_assert(i == 0 || | i_assert(i == 0 || | |||
bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id); | bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id); | |||
bboxes[i]->sync_mailbox_idx1 = i+1; | bboxes[i]->sync_mailbox_idx1 = i+1; | |||
mailbox.id = bboxes[i]->mailbox_id; | mailbox.id = bboxes[i]->mailbox_id; | |||
mailbox.name_len = strlen(bboxes[i]->name); | mailbox.name_len = strlen(bboxes[i]->name); | |||
mailbox.uid_validity = bboxes[i]->sync_uid_validity; | mailbox.uid_validity = bboxes[i]->sync_uid_validity; | |||
mailbox.highest_modseq = bboxes[i]->ondisk_highest_modseq; | mailbox.highest_modseq = bboxes[i]->ondisk_highest_modseq; | |||
mailbox.next_uid = bboxes[i]->sync_next_uid; | mailbox.next_uid = bboxes[i]->sync_next_uid; | |||
buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox)); | buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox)); | |||
buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len); | buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len); | |||
guid_128_copy(ext2_rec.guid, bboxes[i]->sync_guid); | ||||
buffer_append(buf2, &ext2_rec, sizeof(ext2_rec)); | ||||
mailbox_pos += sizeof(mailbox); | mailbox_pos += sizeof(mailbox); | |||
name_pos += mailbox.name_len; | name_pos += mailbox.name_len; | |||
/* repair the value */ | /* repair the value */ | |||
if (ctx->mbox->highest_mailbox_id < mailbox.id) | if (ctx->mbox->highest_mailbox_id < mailbox.id) | |||
ctx->mbox->highest_mailbox_id = mailbox.id; | ctx->mbox->highest_mailbox_id = mailbox.id; | |||
} | } | |||
if (ctx->mbox->highest_mailbox_id != ext_hdr.highest_mailbox_id) { | if (ctx->mbox->highest_mailbox_id != ext_hdr.highest_mailbox_id) { | |||
ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id; | ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id; | |||
buffer_write(buf, 0, &ext_hdr, sizeof(ext_hdr)); | buffer_write(buf, 0, &ext_hdr, sizeof(ext_hdr)); | |||
} | } | |||
i_assert(buf->used == name_pos); | i_assert(buf->used == name_pos); | |||
/* update base extension */ | ||||
mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id, | mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id, | |||
&ext_data, &ext_size); | &ext_data, &ext_size); | |||
if (ext_size < name_pos) { | if (ext_size < name_pos) { | |||
mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id, | mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id, | |||
name_pos, | name_pos, | |||
sizeof(struct virtual_mail_index_record), | sizeof(struct virtual_mail_index_record), | |||
sizeof(uint32_t)); | sizeof(uint32_t)); | |||
} | } | |||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | |||
0, buf->data, name_pos); | 0, buf->data, name_pos); | |||
/* update ext2 */ | ||||
mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext2_id, | ||||
&ext_data, &ext_size); | ||||
if (ext_size != buf2->used) { | ||||
mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext2_id, | ||||
buf2->used, 0, 0); | ||||
} | ||||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext2_id, | ||||
0, buf2->data, buf2->used); | ||||
buffer_free(&buf); | ||||
buffer_free(&buf2); | ||||
} | } | |||
static void virtual_sync_ext_header_update(struct virtual_sync_context *ctx) | static void virtual_sync_ext_header_update(struct virtual_sync_context *ctx) | |||
{ | { | |||
struct virtual_mail_index_header ext_hdr; | struct virtual_mail_index_header ext_hdr; | |||
if (!ctx->ext_header_changed) | if (!ctx->ext_header_changed) | |||
return; | return; | |||
/* we changed something - update the change counter in header */ | /* we changed something - update the change counter in header */ | |||
ext_hdr.change_counter = ++ctx->mbox->prev_change_counter; | ext_hdr.change_counter = ++ctx->mbox->prev_change_counter; | |||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | |||
offsetof(struct virtual_mail_index_header, change_counter), | offsetof(struct virtual_mail_index_header, change_counter), | |||
&ext_hdr.change_counter, sizeof(ext_hdr.change_counter)); | &ext_hdr.change_counter, sizeof(ext_hdr.change_counter)); | |||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext2_id, | ||||
offsetof(struct virtual_mail_index_ext2_header, change_counter), | ||||
&ext_hdr.change_counter, sizeof(ext_hdr.change_counter)); | ||||
} | } | |||
static int virtual_sync_index_rec(struct virtual_sync_context *ctx, | static int virtual_sync_index_rec(struct virtual_sync_context *ctx, | |||
const struct mail_index_sync_rec *sync_rec) | const struct mail_index_sync_rec *sync_rec) | |||
{ | { | |||
uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id; | uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id; | |||
struct virtual_backend_box *bbox; | struct virtual_backend_box *bbox; | |||
const struct virtual_mail_index_record *vrec; | const struct virtual_mail_index_record *vrec; | |||
const void *data; | const void *data; | |||
enum mail_flags flags; | enum mail_flags flags; | |||
skipping to change at line 1112 | skipping to change at line 1212 | |||
if (mailbox_sync_deinit(&sync_ctx, &sync_status) < 0) { | if (mailbox_sync_deinit(&sync_ctx, &sync_status) < 0) { | |||
if (mailbox_get_last_mail_error(bbox->box) != MAIL_ERROR_NOTFOUND ) | if (mailbox_get_last_mail_error(bbox->box) != MAIL_ERROR_NOTFOUND ) | |||
return -1; | return -1; | |||
/* mailbox was deleted */ | /* mailbox was deleted */ | |||
virtual_sync_backend_box_deleted(ctx, bbox); | virtual_sync_backend_box_deleted(ctx, bbox); | |||
return 0; | return 0; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
static bool | ||||
virtual_bbox_mailbox_equals(struct virtual_backend_box *bbox, | ||||
const struct mailbox_status *status, | ||||
struct mailbox_metadata *metadata, | ||||
const char **reason_r) | ||||
{ | ||||
if (!guid_128_equals(bbox->sync_guid, metadata->guid)) { | ||||
*reason_r = t_strdup_printf("GUID changed: %s -> %s", | ||||
guid_128_to_string(bbox->sync_guid), | ||||
guid_128_to_string(metadata->guid)); | ||||
return FALSE; | ||||
} | ||||
if (bbox->sync_uid_validity != status->uidvalidity) { | ||||
*reason_r = t_strdup_printf("UIDVALIDITY changed: %u -> %u", | ||||
bbox->sync_uid_validity, status->uidvalidity); | ||||
return FALSE; | ||||
} | ||||
if (bbox->sync_next_uid != status->uidnext) { | ||||
*reason_r = t_strdup_printf("UIDNEXT changed: %u -> %u", | ||||
bbox->sync_next_uid, status->uidnext); | ||||
return FALSE; | ||||
} | ||||
if (bbox->sync_highest_modseq != status->highest_modseq) { | ||||
*reason_r = t_strdup_printf("HIGHESTMODSEQ changed: " | ||||
"%"PRIu64" -> %"PRIu64, | ||||
bbox->sync_highest_modseq, status->highest_modseq); | ||||
return FALSE; | ||||
} | ||||
return TRUE; | ||||
} | ||||
static void virtual_sync_backend_ext_header(struct virtual_sync_context *ctx, | static void virtual_sync_backend_ext_header(struct virtual_sync_context *ctx, | |||
struct virtual_backend_box *bbox) | struct virtual_backend_box *bbox) | |||
{ | { | |||
const unsigned int uidval_pos = | const unsigned int uidval_pos = | |||
offsetof(struct virtual_mail_index_mailbox_record, | offsetof(struct virtual_mail_index_mailbox_record, | |||
uid_validity); | uid_validity); | |||
struct mailbox_status status; | struct mailbox_status status; | |||
struct virtual_mail_index_mailbox_record mailbox; | struct virtual_mail_index_mailbox_record mailbox; | |||
unsigned int mailbox_offset; | struct virtual_mail_index_mailbox_ext2_record ext2; | |||
unsigned int mailbox_offset, ext2_offset; | ||||
uint64_t wanted_ondisk_highest_modseq; | uint64_t wanted_ondisk_highest_modseq; | |||
struct mailbox_metadata metadata; | ||||
const char *reason; | ||||
mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY | | mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY | | |||
STATUS_HIGHESTMODSEQ, &status); | STATUS_HIGHESTMODSEQ, &status); | |||
wanted_ondisk_highest_modseq = | wanted_ondisk_highest_modseq = | |||
array_count(&bbox->sync_pending_removes) > 0 ? 0 : | array_count(&bbox->sync_pending_removes) > 0 ? 0 : | |||
status.highest_modseq; | status.highest_modseq; | |||
if (bbox->sync_uid_validity == status.uidvalidity && | if (mailbox_get_metadata(bbox->box, MAILBOX_METADATA_GUID, | |||
bbox->sync_next_uid == status.uidnext && | &metadata) < 0) { | |||
bbox->sync_highest_modseq == status.highest_modseq && | /* Either a temporary failure or the mailbox was already | |||
deleted. Either way, it doesn't really matter at this point. | ||||
We'll just leave the error handling until the next sync. */ | ||||
return; | ||||
} | ||||
if (virtual_bbox_mailbox_equals(bbox, &status, &metadata, &reason) && | ||||
bbox->ondisk_highest_modseq == wanted_ondisk_highest_modseq) | bbox->ondisk_highest_modseq == wanted_ondisk_highest_modseq) | |||
return; | return; | |||
/* mailbox changed - update extension header */ | /* mailbox changed - update extension header */ | |||
bbox->sync_uid_validity = status.uidvalidity; | bbox->sync_uid_validity = status.uidvalidity; | |||
bbox->sync_highest_modseq = status.highest_modseq; | bbox->sync_highest_modseq = status.highest_modseq; | |||
bbox->ondisk_highest_modseq = wanted_ondisk_highest_modseq; | bbox->ondisk_highest_modseq = wanted_ondisk_highest_modseq; | |||
bbox->sync_next_uid = status.uidnext; | bbox->sync_next_uid = status.uidnext; | |||
guid_128_copy(bbox->sync_guid, metadata.guid); | ||||
if (ctx->mbox->ext_header_rewrite) { | if (ctx->mbox->ext_header_rewrite) { | |||
/* we'll rewrite the entire header later */ | /* we'll rewrite the entire header later */ | |||
return; | return; | |||
} | } | |||
i_zero(&mailbox); | i_zero(&mailbox); | |||
mailbox.uid_validity = bbox->sync_uid_validity; | mailbox.uid_validity = bbox->sync_uid_validity; | |||
mailbox.highest_modseq = bbox->ondisk_highest_modseq; | mailbox.highest_modseq = bbox->ondisk_highest_modseq; | |||
mailbox.next_uid = bbox->sync_next_uid; | mailbox.next_uid = bbox->sync_next_uid; | |||
i_zero(&ext2); | ||||
guid_128_copy(ext2.guid, bbox->sync_guid); | ||||
i_assert(bbox->sync_mailbox_idx1 > 0); | i_assert(bbox->sync_mailbox_idx1 > 0); | |||
mailbox_offset = sizeof(struct virtual_mail_index_header) + | mailbox_offset = sizeof(struct virtual_mail_index_header) + | |||
(bbox->sync_mailbox_idx1-1) * sizeof(mailbox); | (bbox->sync_mailbox_idx1-1) * sizeof(mailbox); | |||
ext2_offset = sizeof(struct virtual_mail_index_ext2_header) + | ||||
(bbox->sync_mailbox_idx1-1) * sizeof(ext2); | ||||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id, | |||
mailbox_offset + uidval_pos, | mailbox_offset + uidval_pos, | |||
CONST_PTR_OFFSET(&mailbox, uidval_pos), | CONST_PTR_OFFSET(&mailbox, uidval_pos), | |||
sizeof(mailbox) - uidval_pos); | sizeof(mailbox) - uidval_pos); | |||
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext2_id, | ||||
ext2_offset, &ext2, sizeof(ext2)); | ||||
ctx->ext_header_changed = TRUE; | ctx->ext_header_changed = TRUE; | |||
} | } | |||
static void virtual_sync_backend_box_deleted(struct virtual_sync_context *ctx, | static void virtual_sync_backend_box_deleted(struct virtual_sync_context *ctx, | |||
struct virtual_backend_box *bbox) | struct virtual_backend_box *bbox) | |||
{ | { | |||
ARRAY_TYPE(seq_range) removed_uids; | ARRAY_TYPE(seq_range) removed_uids; | |||
const struct virtual_backend_uidmap *uidmap; | const struct virtual_backend_uidmap *uidmap; | |||
/* delay its full removal until the next time we open the virtual | /* delay its full removal until the next time we open the virtual | |||
skipping to change at line 1204 | skipping to change at line 1352 | |||
return 0; | return 0; | |||
} | } | |||
return 1; | return 1; | |||
} | } | |||
static int virtual_sync_backend_box(struct virtual_sync_context *ctx, | static int virtual_sync_backend_box(struct virtual_sync_context *ctx, | |||
struct virtual_backend_box *bbox) | struct virtual_backend_box *bbox) | |||
{ | { | |||
enum mailbox_sync_flags sync_flags; | enum mailbox_sync_flags sync_flags; | |||
struct mailbox_status status; | struct mailbox_status status; | |||
const char *reason; | ||||
int ret; | int ret; | |||
if (bbox->deleted) | if (bbox->deleted) | |||
return 0; | return 0; | |||
/* if we already did some changes to index, commit them before | /* if we already did some changes to index, commit them before | |||
syncing starts. */ | syncing starts. */ | |||
virtual_backend_box_sync_mail_unset(bbox); | virtual_backend_box_sync_mail_unset(bbox); | |||
sync_flags = ctx->flags & (MAILBOX_SYNC_FLAG_FULL_READ | | sync_flags = ctx->flags & (MAILBOX_SYNC_FLAG_FULL_READ | | |||
MAILBOX_SYNC_FLAG_FULL_WRITE | | MAILBOX_SYNC_FLAG_FULL_WRITE | | |||
MAILBOX_SYNC_FLAG_FAST); | MAILBOX_SYNC_FLAG_FAST); | |||
if (bbox->search_result == NULL) { | if (bbox->search_result == NULL) { | |||
struct mailbox_metadata metadata; | ||||
/* a) first sync in this process. | /* a) first sync in this process. | |||
b) we had auto-closed this backend mailbox. | b) we had auto-closed this backend mailbox. | |||
first try to quickly check if the mailbox has changed. | first try to quickly check if the mailbox has changed. | |||
if we can do that check from mailbox list index, we don't | if we can do that check from mailbox list index, we don't | |||
even need to open the mailbox. */ | even need to open the mailbox. */ | |||
i_assert(array_count(&bbox->sync_pending_removes) == 0); | i_assert(array_count(&bbox->sync_pending_removes) == 0); | |||
if (bbox->box->opened || bbox->open_failed) { | if (bbox->box->opened || bbox->open_failed) { | |||
/* a) index already opened, refresh it | /* a) index already opened, refresh it | |||
b) delayed error handling for mailbox_open() | b) delayed error handling for mailbox_open() | |||
that failed in virtual_notify_changes() */ | that failed in virtual_notify_changes() */ | |||
if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbo x, sync_flags)) <= 0) | if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbo x, sync_flags)) <= 0) | |||
return ret; | return ret; | |||
bbox->open_failed = FALSE; | bbox->open_failed = FALSE; | |||
} | } | |||
if (mailbox_get_status(bbox->box, STATUS_UIDVALIDITY | | if ((mailbox_get_status(bbox->box, STATUS_UIDVALIDITY | | |||
STATUS_UIDNEXT | STATUS_HIGHESTMODSEQ, | STATUS_UIDNEXT | STATUS_HIGHESTMODSEQ, | |||
&status) < 0) { | &status) < 0) || | |||
(mailbox_get_metadata(bbox->box, MAILBOX_METADATA_GUID, | ||||
&metadata) < 0)) { | ||||
if (mailbox_get_last_mail_error(bbox->box) != MAIL_ERROR_ NOTFOUND) | if (mailbox_get_last_mail_error(bbox->box) != MAIL_ERROR_ NOTFOUND) | |||
return -1; | return -1; | |||
/* mailbox was deleted */ | /* mailbox was deleted */ | |||
virtual_sync_backend_box_deleted(ctx, bbox); | virtual_sync_backend_box_deleted(ctx, bbox); | |||
return 0; | return 0; | |||
} | } | |||
if (status.uidvalidity == bbox->sync_uid_validity && | if (guid_128_is_empty(bbox->sync_guid)) { | |||
status.uidnext == bbox->sync_next_uid && | /* upgrading from old virtual index */ | |||
status.highest_modseq == bbox->sync_highest_modseq) { | guid_128_copy(bbox->sync_guid, metadata.guid); | |||
ctx->mbox->ext_header_rewrite = TRUE; | ||||
} | ||||
if (virtual_bbox_mailbox_equals(bbox, &status, &metadata, &reason | ||||
)) { | ||||
/* mailbox hasn't changed since we last opened it, | /* mailbox hasn't changed since we last opened it, | |||
skip it for now. | skip it for now. | |||
we'll still need to create the bbox->uids mapping | we'll still need to create the bbox->uids mapping | |||
using the current index. */ | using the current index. */ | |||
if (array_count(&bbox->uids) == 0) | if (array_count(&bbox->uids) == 0) | |||
virtual_sync_backend_handle_old_vmsgs(ctx, bbox, NULL); | virtual_sync_backend_handle_old_vmsgs(ctx, bbox, NULL); | |||
return 0; | return 0; | |||
} | } | |||
e_debug(ctx->mbox->box.event, "Backend mailbox %s changed: %s", | ||||
bbox->box->vname, reason); | ||||
if (!bbox->box->opened) { | if (!bbox->box->opened) { | |||
/* first time we're opening the index */ | /* first time we're opening the index */ | |||
if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbo x, sync_flags)) <= 0) | if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbo x, sync_flags)) <= 0) | |||
return ret; | return ret; | |||
} | } | |||
virtual_backend_box_sync_mail_set(bbox); | virtual_backend_box_sync_mail_set(bbox); | |||
if (status.uidvalidity != bbox->sync_uid_validity) { | if ((status.uidvalidity != bbox->sync_uid_validity) || | |||
/* UID validity changed since last sync (or this is | !guid_128_equals(metadata.guid, bbox->sync_guid)) { | |||
the first sync), do a full search */ | /* UID validity or GUID changed since last sync (or | |||
this is the first sync), do a full search */ | ||||
bbox->first_sync = TRUE; | ||||
ret = virtual_sync_backend_box_init(bbox); | ret = virtual_sync_backend_box_init(bbox); | |||
} else { | } else { | |||
/* build the initial search using the saved modseq. */ | /* build the initial search using the saved modseq. */ | |||
ret = virtual_sync_backend_box_continue(ctx, bbox); | ret = virtual_sync_backend_box_continue(ctx, bbox); | |||
} | } | |||
i_assert(bbox->search_result != NULL || ret < 0); | i_assert(bbox->search_result != NULL || ret < 0); | |||
} else { | } else { | |||
/* sync using the existing search result */ | /* sync using the existing search result */ | |||
i_assert(bbox->box->opened); | i_assert(bbox->box->opened); | |||
i_array_init(&ctx->sync_expunges, 32); | i_array_init(&ctx->sync_expunges, 32); | |||
skipping to change at line 1330 | skipping to change at line 1490 | |||
vrec = &vmails[i].vrec; | vrec = &vmails[i].vrec; | |||
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) { | if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) { | |||
/* add the rest of the newly seen messages */ | /* add the rest of the newly seen messages */ | |||
for (; j < uidmap_count; j++) { | for (; j < uidmap_count; j++) { | |||
add_rec.rec.real_uid = uidmap[j].real_uid; | add_rec.rec.real_uid = uidmap[j].real_uid; | |||
array_push_back(&ctx->all_adds, &add_rec); | array_push_back(&ctx->all_adds, &add_rec); | |||
} | } | |||
bbox = virtual_backend_box_lookup(ctx->mbox, | bbox = virtual_backend_box_lookup(ctx->mbox, | |||
vrec->mailbox_id); | vrec->mailbox_id); | |||
if (bbox == NULL) { | if (bbox == NULL || bbox->first_sync) { | |||
/* the entire mailbox is lost */ | /* the entire mailbox is lost */ | |||
mail_index_expunge(ctx->trans, vseq); | mail_index_expunge(ctx->trans, vseq); | |||
continue; | continue; | |||
} | } | |||
uidmap = array_get_modifiable(&bbox->uids, | uidmap = array_get_modifiable(&bbox->uids, | |||
&uidmap_count); | &uidmap_count); | |||
j = 0; | j = 0; | |||
add_rec.rec.mailbox_id = bbox->mailbox_id; | add_rec.rec.mailbox_id = bbox->mailbox_id; | |||
bbox->sync_seen = TRUE; | bbox->sync_seen = TRUE; | |||
} | } | |||
skipping to change at line 1387 | skipping to change at line 1547 | |||
struct virtual_backend_box *const *bboxes; | struct virtual_backend_box *const *bboxes; | |||
struct virtual_add_record add_rec; | struct virtual_add_record add_rec; | |||
struct virtual_backend_uidmap *uidmap; | struct virtual_backend_uidmap *uidmap; | |||
unsigned int i, j, count, uidmap_count; | unsigned int i, j, count, uidmap_count; | |||
/* if there are any mailboxes we didn't yet sync, add new messages in | /* if there are any mailboxes we didn't yet sync, add new messages in | |||
them */ | them */ | |||
i_zero(&add_rec); | i_zero(&add_rec); | |||
bboxes = array_get(&ctx->mbox->backend_boxes, &count); | bboxes = array_get(&ctx->mbox->backend_boxes, &count); | |||
for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | |||
bboxes[i]->first_sync = FALSE; /* this is the end of the sync */ | ||||
if (bboxes[i]->sync_seen) | if (bboxes[i]->sync_seen) | |||
continue; | continue; | |||
add_rec.rec.mailbox_id = bboxes[i]->mailbox_id; | add_rec.rec.mailbox_id = bboxes[i]->mailbox_id; | |||
uidmap = array_get_modifiable(&bboxes[i]->uids, &uidmap_count); | uidmap = array_get_modifiable(&bboxes[i]->uids, &uidmap_count); | |||
for (j = 0; j < uidmap_count; j++) { | for (j = 0; j < uidmap_count; j++) { | |||
add_rec.rec.real_uid = uidmap[j].real_uid; | add_rec.rec.real_uid = uidmap[j].real_uid; | |||
array_push_back(&ctx->all_adds, &add_rec); | array_push_back(&ctx->all_adds, &add_rec); | |||
} | } | |||
} | } | |||
End of changes. 28 change blocks. | ||||
15 lines changed or deleted | 182 lines changed or added |