mbox-sync.c revision d0e5f8252516c4d4df2fbcdae4d37f9e5f931199
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen required disk I/O. We may need to:
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
6246b93fb37890dcb2f4df9896438f3f376ab284Timo Sirainen - Write missing X-UID and X-IMAPbase headers
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen - Write missing or broken Content-Length header if there's space
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen - Expunge specified messages
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Here's how we do it:
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen - Start reading the mails from the beginning
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen of them, remember how much each message has and offset to beginning of the
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - If header needs to be rewritten and there's enough space, do it
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - If we didn't have enough space, remember how much was missing
660b4d36110c44b1e4b4b45a78c22d1569ccdb54Timo Sirainen - Continue reading and counting the padding in each message. If available
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen - When we encounter expunged message, treat all of it as padding and
283ccfe110ed62e48f36e0d84e47da8cae5106beTimo Sirainen rewrite previous messages if needed (and there's enough space).
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen missing Content-Length header and padding. Message bodies are moved
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen without modifications.
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Rewriting is done by moving message body forward, rewriting message's
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen header and doing the same for previous message, until all of them are
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
306f6bb8791755257c0db900f17659402c660057Timo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenstatic int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen /* put the padding between last message's header and body */
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen file_size = i_stream_get_size(sync_ctx->file_input) + grow_size;
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen if (file_set_size(sync_ctx->fd, file_size) < 0) {
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen mbox_set_syscall_error(sync_ctx->ibox, "file_set_size()");
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (mbox_move(sync_ctx, mail_ctx->body_offset, src_offset,
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainenstatic void mbox_sync_buffer_delete_old(buffer_t *syncs_buf, uint32_t uid)
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen sync = buffer_get_modifyable_data(syncs_buf, &size);
36d2b3dc8766ef336a289a51075ca2f3236ef1efTimo Sirainen buffer_set_used_size(syncs_buf, dest * sizeof(*sync));
5561fe7754843250d0f2701332f63467f77f71dbTimo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
c7398cd92a003144358c121bdea63fba35b884aeTimo Sirainen /* get EOF */
c7398cd92a003144358c121bdea63fba35b884aeTimo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
d6500661eb699ff335ac570c8646b6e067e1aac6Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen if (mail_ctx->seq > 1 && sync_ctx->dest_first_mail) {
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen /* First message was expunged and this is the next one.
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen Skip \n header */
d514e6e6ea2320c18c58e0ade9184f5aa67d491bTimo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
d514e6e6ea2320c18c58e0ade9184f5aa67d491bTimo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if ((mail_ctx->mail.flags & MBOX_NONRECENT) == 0 && !mail_ctx->pseudo) {
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen /* need to add 'O' flag to Status-header */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic int mbox_sync_buf_have_expunges(buffer_t *syncs_buf)
fdb97244fa45c32c3593726c15aa69ce29bc7121Timo Sirainen for (i = 0; i < size; i++) {
fdb97244fa45c32c3593726c15aa69ce29bc7121Timo Sirainen if (sync[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
6246b93fb37890dcb2f4df9896438f3f376ab284Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
fdb97244fa45c32c3593726c15aa69ce29bc7121Timo Sirainen if (sync_ctx->ibox->mbox_readonly || sync_ctx->index_sync_ctx == NULL)
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen /* nothing for this or the future ones */
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen mbox_sync_buffer_delete_old(sync_ctx->syncs, uid);
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND) {
6246b93fb37890dcb2f4df9896438f3f376ab284Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
if (ret == 0) {
if (!*sync_expunge_r)
for (i = 0; i < size; i++) {
int ret = 0;
if (ret < 0) {
ret = 0;
return ret;
unsigned char hdr_md5_sum[],
const void *data;
int ret;
if (ret < 0) {
&data) < 0) {
int nocheck)
const void *data;
if (!nocheck) {
&data) < 0) {
INDEX_KEYWORDS_BYTE_COUNT) != 0) {
const unsigned char *data;
if (from_line_size == 0)
int ret;
if (ret < 0)
if (ret > 0) {
if (seq == 0) {
seq++;
if (ret < 0) {
if (ret == 0) {
old_offset) < 0) {
messages_count : 0);
&expunged) < 0)
if (size == 0)
if (ret <= 0)
return ret;
uid = 0;
if (ret < 0)
if (ret == 0)
uid = 0;
&rec) < 0)
if (!expunged) {
if (ret < 0)
if (!expunged) {
rec) < 0)
if (!expunged) {
if (!partial)
int need_rewrite;
if (need_rewrite) {
trailer_size) < 0)
min_msg_count = 0;
if (ret <= 0) {
if (ret < 0)
unsigned int lock_id = 0;
if (!changed)
lock_id = 0;
if (changed) {
if (ret <= 0) {
if (ret < 0)
if (lock_id != 0)
return ret;
if (lock_id != 0)
if (lock_id == 0) {
goto __again;
if (ret < 0)
if (ret < 0)
if (ret < 0)
&seq,
&offset) < 0) {
index_sync_ctx) < 0) {
unsigned int read_lock_id = 0;
return ret;
struct mailbox_sync_context *
int ret = 0;