mbox-sync.c revision dda2c506c8fc8ac2f88272de4523ded42baa0aa0
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen required disk I/O. We may need to:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - Write missing X-UID and X-IMAPbase headers
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen - Write missing or broken Content-Length header if there's space
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen - Expunge specified messages
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen Here's how we do it:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - Start reading the mails mail headers from the beginning
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - X-Keywords and X-UID headers may contain extra spaces at the end of them,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen remember how much extra each message has and offset to beginning of the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - If message flags are dirty and there's enough space to write them, do it
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - If we didn't have enough space, remember how much was missing and keep
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen the total amount of them
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - When we encounter expunged message, check if the amount of empty space in
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen previous messages plus size of expunged message is enough to cover the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen missing space. If yes,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - execute the rewrite plan
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen - forget all the messages before the expunged message. only remember
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen how much data we still have to move to cover the expunged message
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen - If we encounter end of file, grow the file and execute the rewrite plan
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen Rewrite plan goes:
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen - Start from the first message that needs more space
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen - If there's expunged messages before us, we have to write over them.
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen - Move all messages after it backwards to fill it
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen - Each moved message's X-Keywords header should have n bytes extra
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen space, unless there's not enough space to do it.
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen - If there's no expunged messages, we can move data either forward or
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen backward to get it. Calculate which requires less moving. Forward
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen counting may encounter more messages which require extra space, count
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen - If we decide to move forwards and we had to go through dirty
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen messages, do the moving from last to first dirty message
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen - If we encounter end of file, grow the file enough to get the required
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen amount of space plus enough space to fill X-Keywords headers full of
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* put the extra space between last message's header and body */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen file_size = i_stream_get_size(sync_ctx->file_input) + grow_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (file_set_size(sync_ctx->fd, file_size) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_set_syscall_error(sync_ctx->ibox, "file_set_size()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mbox_move(sync_ctx, mail_ctx->body_offset, src_offset,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void mbox_sync_buffer_delete_old(buffer_t *syncs_buf, uint32_t uid)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sync = buffer_get_modifyable_data(syncs_buf, &size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_set_used_size(syncs_buf, dest * sizeof(*sync));
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* set input->eof */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_ctx->seq > 1 && sync_ctx->first_uid == mail_ctx->mail.uid) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* First message was expunged and this is the next one.
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen Skip \n header */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx, FALSE);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->from_offset);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen /* save the offset permanently with recent flag state */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen mail_ctx->mail.from_offset = mail_ctx->from_offset;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if ((mail_ctx->mail.flags & MBOX_NONRECENT) == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* need to add 'O' flag to Status-header */
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen // FIXME: save it somewhere
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen mbox_sync_buffer_delete_old(sync_ctx->syncs, uid);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void mbox_sync_apply_index_syncs(buffer_t *syncs_buf, uint8_t *flags,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen for (i = 0; i < size; i++)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_sync_flags_apply(&sync[i], flags, keywords);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmbox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint32_t uid, const struct mail_index_record **rec_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen messages_count = mail_index_view_get_message_count(sync_ctx->sync_view);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* externally expunged message, remove from index */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* new UID in the middle of the mailbox - shouldn't happen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "mbox sync: UID inserted in the middle of mailbox "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_mark_corrupted(sync_ctx->ibox->index);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmbox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* see if from_offset needs updating */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_index_lookup_extra(sync_ctx->sync_view,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_update_extra_rec(sync_ctx->t, sync_ctx->idx_seq,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_sync_update_index(struct mbox_sync_context *sync_ctx,
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen /* new message */
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen mbox_flags = mail->flags & (MAIL_FLAGS_MASK^MAIL_RECENT);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* see if flags changed */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memcpy(idx_keywords, rec->keywords, INDEX_KEYWORDS_BYTE_COUNT);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_flags = (rec->flags & ~MAIL_FLAGS_MASK) |
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (mail->flags & (MAIL_FLAGS_MASK^MAIL_RECENT));
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen /* update from_offsets, but not if we're going to rewrite this message.
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen rewriting would just move it anyway. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int nocheck = rec == NULL || sync_ctx->expunged_space > 0;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (mbox_sync_update_from_offset(sync_ctx, mail, nocheck) < 0)
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainenstatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen struct istream *input = ctx->sync_ctx->file_input;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_set_used_size(ctx->sync_ctx->from_line, 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen from_line_size = ctx->hdr_offset - ctx->from_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_append(ctx->sync_ctx->from_line, data, size);
263946a65b625fd4198619a8626db0f36bbafd66Timo Sirainenmbox_write_from_line(struct mbox_sync_mail_context *ctx, off_t move_diff)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (pwrite_full(ctx->sync_ctx->fd, str_data(str), str_len(str),
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mbox_set_syscall_error(ctx->sync_ctx->ibox, "pwrite_full()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenupdate_from_offsets(struct index_mailbox *ibox,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk struct mail_index_transaction *t, buffer_t *mails_buf,
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen mails = buffer_get_modifyable_data(mails_buf, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_update_extra_rec(t, seq1, extra_idx,
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic int mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (mail_ctx->sync_ctx->ibox->mbox_lock_type == F_RDLCK)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen mail_ctx->mail.offset = mail_ctx->from_offset;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen mail_ctx->body_offset - mail_ctx->from_offset +
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* expunging first message, fix space to contain next
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen message's \n header too since it will be removed. */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen mail_ctx->sync_ctx->expunged_space += mail_ctx->mail.space;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* move the header backwards to fill expunged space */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (sync_ctx->ibox->mbox_lock_type == F_RDLCK)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* read the From-line before rewriting overwrites it */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen mbox_sync_update_header(mail_ctx, sync_ctx->syncs);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, move_diff)) < 0)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen /* rewrite successful, write From-line to
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen new location */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (mbox_write_from_line(mail_ctx, move_diff) < 0)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (sync_ctx->ibox->mbox_lock_type == F_RDLCK)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mbox_sync_update_header(mail_ctx, sync_ctx->syncs);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, move_diff)) < 0)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen /* nothing to do */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (ret == 0 && sync_ctx->need_space_seq == 0) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* first mail with no space to write it */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* create dummy message to describe the expunged data */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen buffer_append(sync_ctx->mails, &mail, sizeof(mail));
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenmbox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen buffer_append(sync_ctx->mails, &mail_ctx->mail, sizeof(mail_ctx->mail));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we have enough space now */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* don't waste too much on extra spacing */
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen sync_ctx->expunged_space = sync_ctx->space_diff - extra_space;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mbox_sync_rewrite(sync_ctx, sync_ctx->need_space_seq, sync_ctx->seq,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen update_from_offsets(sync_ctx->ibox, sync_ctx->t, sync_ctx->mails,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* mail_ctx may contain wrong data after rewrite, so make sure we
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen don't try to access it */
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainenstatic int mbox_sync_parse_all(struct mbox_sync_context *sync_ctx,
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen sync_ctx->file_input = sync_ctx->ibox->mbox_file_stream;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen sync_ctx->input = sync_ctx->ibox->mbox_stream;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen while ((ret = mbox_sync_read_next_mail(sync_ctx, mail_ctx)) > 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* get all sync records related to this message */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mbox_sync_read_index_syncs(sync_ctx, uid, &expunged) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* -1 = error, -2 = need exclusive lock */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mbox_sync_read_index_rec(sync_ctx, uid, &rec) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mbox_sync_update_index(sync_ctx, &mail_ctx->mail,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mbox_sync_handle_missing_space(mail_ctx) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else if (sync_ctx->expunged_space > 0 && !expunged) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* move the body */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* rest of the messages in index don't exist -> expunge them */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen messages_count = mail_index_view_get_message_count(sync_ctx->sync_view);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mail_index_expunge(sync_ctx->t, ++sync_ctx->idx_seq);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen trailer_size = i_stream_get_size(sync_ctx->file_input) -
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen sync_ctx->space_diff += sync_ctx->expunged_space;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen sync_ctx->expunged_space -= -sync_ctx->space_diff;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (sync_ctx->seq != sync_ctx->need_space_seq) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen buffer_append(sync_ctx->mails, &mail_ctx->mail,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen update_from_offsets(sync_ctx->ibox, sync_ctx->t,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* copy trailer, then truncate the file */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen offset = i_stream_get_size(sync_ctx->file_input) -
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mbox_set_syscall_error(sync_ctx->ibox, "ftruncate()");
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx)
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen if (fstat(sync_ctx->ibox->mbox_fd, &st) < 0) {
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen mbox_set_syscall_error(sync_ctx->ibox, "fstat()");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen offsetof(struct mail_index_header, uid_validity),
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if (sync_ctx->next_uid != sync_ctx->hdr->next_uid) {
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen &sync_ctx->next_uid, sizeof(sync_ctx->next_uid));
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen if ((uint32_t)st.st_mtime != sync_ctx->hdr->sync_stamp) {
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen offsetof(struct mail_index_header, sync_stamp),
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if ((uint64_t)st.st_size != sync_ctx->hdr->sync_size) {
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen offsetof(struct mail_index_header, sync_size),
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic void mbox_sync_restart(struct mbox_sync_context *sync_ctx)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen sync_ctx->prev_msg_uid = sync_ctx->first_uid = 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sync_ctx->t = mail_index_transaction_begin(sync_ctx->sync_view, FALSE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int mbox_sync_do(struct mbox_sync_context *sync_ctx, int index_synced)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen lock_type = mail_index_sync_have_more(sync_ctx->index_sync_ctx) ?
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if ((ret = mbox_lock(ibox, lock_type, &sync_ctx->lock_id)) <= 0)
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if ((ret = mbox_sync_parse_all(sync_ctx, &mail_ctx)) == -1)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* we want to modify mbox, get exclusive lock. this requires
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen dropping the read lock first, so we have to parse the whole
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mbox again */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if ((ret = mbox_lock(ibox, F_WRLCK, &sync_ctx->lock_id)) <= 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* FIXME: if mbox timestamp hasn't changed and it's older than
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen 2 secs, we could continue from where we left */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (mbox_sync_parse_all(sync_ctx, &mail_ctx) < 0)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0)
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainen if (sync_ctx->base_uid_last+1 != sync_ctx->next_uid) {
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainen // FIXME: rewrite X-IMAPbase header
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* only syncs left should be just appends (and their updates)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen which weren't synced yet for some reason (crash). we'll just
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ignore them, as we've overwritten them above. */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while (mail_index_sync_next(sync_ctx->index_sync_ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mbox_sync_update_index_header(sync_ctx) < 0)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int mbox_sync_has_changed(struct index_mailbox *ibox)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (mail_index_get_header(ibox->view, &hdr) < 0) {
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen return (uint32_t)st.st_mtime != hdr->sync_stamp ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mbox_sync(struct index_mailbox *ibox, int last_commit)
95d9395d15540b3a96f75c7f9fd73e6d8ad5e897Timo Sirainen ret = mail_index_sync_begin(ibox->index, &index_sync_ctx, &sync_view,
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen sync_ctx.from_line = str_new(default_pool, 256);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen sync_ctx.header = str_new(default_pool, 4096);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sync_ctx.t = mail_index_transaction_begin(sync_view, FALSE);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sync_ctx.mails = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sync_ctx.syncs = buffer_create_dynamic(default_pool, 256, (size_t)-1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_index_get_header(sync_view, &sync_ctx.hdr);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen if (mbox_sync_do(&sync_ctx, index_synced) < 0)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen else if (mail_index_transaction_commit(sync_ctx.t, &seq, &offset) < 0)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenint mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct index_mailbox *ibox = (struct index_mailbox *)box;