mbox-sync.c revision 60d3fa9883237e896a8704275b6116fa46f7ffda
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen required disk I/O. We may need to:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Write missing X-UID and X-IMAPbase headers
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Write missing or broken Content-Length header if there's space
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Expunge specified messages
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Here's how we do it:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Start reading the mails mail headers from the beginning
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - X-Keywords and X-UID headers may contain extra spaces at the end of them,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen remember how much extra each message has and offset to beginning of the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If message flags are dirty and there's enough space to write them, do it
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If we didn't have enough space, remember how much was missing and keep
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the total amount of them
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - When we encounter expunged message, check if the amount of empty space in
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen previous messages plus size of expunged message is enough to cover the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen missing space. If yes,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - execute the rewrite plan
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - forget all the messages before the expunged message. only remember
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen how much data we still have to move to cover the expunged message
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If we encounter end of file, grow the file and execute the rewrite plan
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Rewrite plan goes:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Start from the first message that needs more space
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If there's expunged messages before us, we have to write over them.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Move all messages after it backwards to fill it
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Each moved message's X-Keywords header should have n bytes extra
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen space, unless there's not enough space to do it.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If there's no expunged messages, we can move data either forward or
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen backward to get it. Calculate which requires less moving. Forward
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen counting may encounter more messages which require extra space, count
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If we decide to move forwards and we had to go through dirty
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen messages, do the moving from last to first dirty message
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - If we encounter end of file, grow the file enough to get the required
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen amount of space plus enough space to fill X-Keywords headers full of
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* returns -1 = error, 0 = mbox changed since previous lock, 1 = didn't */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mbox_sync_lock(struct mbox_sync_context *sync_ctx, int lock_type)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen i_assert(lock_type != F_WRLCK || !ibox->mbox_readonly);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (sync_ctx->lock_id == 0 || sync_ctx->input == NULL) {
659fe5d24825b160cae512538088020d97a60239Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (mbox_lock(ibox, lock_type, &sync_ctx->lock_id) <= 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen sync_ctx->file_input = sync_ctx->ibox->mbox_file_stream;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen sync_ctx->input = sync_ctx->ibox->mbox_stream;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* we didn't have the file open before -> it changed */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (st.st_mtime != old_st.st_mtime || st.st_size != old_st.st_size ||
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* same as before. we'll have to fix mbox stream to contain
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen correct from_offset, hdr_offset and body_offset. so, seek
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen to from_offset and read through the header. */
96c253a039f102fa78a313ee05200ab3970112dcTimo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, old_from_offset) < 0) {
96c253a039f102fa78a313ee05200ab3970112dcTimo Sirainen "Message offset %s changed unexpectedly for mbox file "
96c253a039f102fa78a313ee05200ab3970112dcTimo Sirainen "%s", dec2str(old_from_offset), sync_ctx->ibox->path);
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen (void)istream_raw_mbox_get_body_offset(sync_ctx->input);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* put the extra space between last message's header and body */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen file_size = i_stream_get_size(sync_ctx->file_input) + grow_size;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if (file_set_size(sync_ctx->fd, file_size) < 0) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox_set_syscall_error(sync_ctx->ibox, "file_set_size()");
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (mbox_move(sync_ctx, mail_ctx->body_offset, src_offset,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic void mbox_sync_buffer_delete_old(buffer_t *syncs_buf, uint32_t uid)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen sync = buffer_get_modifyable_data(syncs_buf, &size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_set_used_size(syncs_buf, dest * sizeof(*sync));
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* get EOF */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_ctx->seq > 1 && sync_ctx->dest_first_mail) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* First message was expunged and this is the next one.
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen Skip \n header */
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->from_offset);
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* save the offset permanently with recent flag state */
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen mail_ctx->mail.from_offset = mail_ctx->from_offset;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if ((mail_ctx->mail.flags & MBOX_NONRECENT) == 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* need to add 'O' flag to Status-header */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen // FIXME: save it somewhere
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int mbox_sync_buf_have_expunges(buffer_t *syncs_buf)
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen for (i = 0; i < size; i++) {
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (sync[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (sync_ctx->ibox->mbox_readonly || sync_ctx->index_sync_ctx == NULL)
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen /* nothing for this or the future ones */
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen mbox_sync_buffer_delete_old(sync_ctx->syncs, uid);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_APPEND) {
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen sync_ctx->update_base_uid_last = sync_rec->uid2;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen *sync_expunge_r = mbox_sync_buf_have_expunges(sync_ctx->syncs);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic void mbox_sync_apply_index_syncs(buffer_t *syncs_buf, uint8_t *flags,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen for (i = 0; i < size; i++) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (sync[i].type != MAIL_INDEX_SYNC_TYPE_FLAGS)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_index_sync_flags_apply(&sync[i], flags, keywords);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenmbox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uint32_t uid, const struct mail_index_record **rec_r)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen messages_count = mail_index_view_get_message_count(sync_ctx->sync_view);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* externally expunged message, remove from index */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen if (ret == 0 && uid < sync_ctx->hdr->next_uid) {
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen /* this UID was already in index and it was expunged */
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen "mbox sync: Expunged message reappeared in mailbox %s "
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen /* new UID in the middle of the mailbox - shouldn't happen */
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen "mbox sync: UID inserted in the middle of mailbox %s "
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen "(%u > %u)", sync_ctx->ibox->path, rec->uid, uid);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainenstatic int mbox_sync_find_index_md5(struct mbox_sync_context *sync_ctx,
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen unsigned char hdr_md5_sum[],
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen messages_count = mail_index_view_get_message_count(sync_ctx->sync_view);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (mail_index_lookup_extra(sync_ctx->sync_view,
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen /* externally expunged message, remove from index */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic int mbox_sync_get_from_offset(struct mbox_sync_context *sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* see if from_offset needs updating */
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (mail_index_lookup_extra(sync_ctx->sync_view, seq,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenmbox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (mbox_sync_get_from_offset(sync_ctx, sync_ctx->idx_seq,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_index_update_extra_rec(sync_ctx->t, sync_ctx->idx_seq,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic int mbox_sync_update_index(struct mbox_sync_context *sync_ctx,
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen struct mbox_sync_mail *mail = &mail_ctx->mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* new message */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen mbox_flags = mail->flags & (MAIL_FLAGS_MASK^MAIL_RECENT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen /*FIXME:mail_cache_add(sync_ctx->cache_trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_CACHE_UID_STRING,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_data(mail_ctx->uidl),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_len(mail_ctx->uidl));*/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* see if flags changed */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen memcpy(idx_keywords, rec->keywords, INDEX_KEYWORDS_BYTE_COUNT);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mbox_flags = (rec->flags & ~MAIL_FLAGS_MASK) |
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (mail->flags & (MAIL_FLAGS_MASK^MAIL_RECENT));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* update from_offsets, but not if we're going to rewrite this message.
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen rewriting would just move it anyway. */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen int nocheck = rec == NULL || sync_ctx->expunged_space > 0;
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen if (mbox_sync_update_from_offset(sync_ctx, mail, nocheck) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream *input = ctx->sync_ctx->file_input;
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen const unsigned char *data;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen buffer_set_used_size(ctx->sync_ctx->from_line, 0);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen from_line_size = ctx->hdr_offset - ctx->from_offset;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_append(ctx->sync_ctx->from_line, data, size);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenmbox_write_from_line(struct mbox_sync_mail_context *ctx, off_t move_diff)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (pwrite_full(ctx->sync_ctx->fd, str_data(str), str_len(str),
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen mbox_set_syscall_error(ctx->sync_ctx->ibox, "pwrite_full()");
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainenstatic void update_from_offsets(struct mbox_sync_context *sync_ctx)
ab6315aa0d5c83f4f1dc98b3715826a686aebffdTimo Sirainen uint32_t idx, idx_seq, extra_idx = sync_ctx->ibox->mbox_extra_idx;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mails = buffer_get_modifyable_data(sync_ctx->mails, &size);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen i_assert(sync_ctx->seq - sync_ctx->need_space_seq + 1 == size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen for (; idx < size; idx++, idx_seq++, mails++) {
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen mail_index_update_extra_rec(sync_ctx->t, idx_seq, extra_idx,
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainenstatic int mbox_sync_check_excl_lock(struct mbox_sync_context *sync_ctx)
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen if (sync_ctx->ibox->mbox_lock_type == F_RDLCK) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((ret = mbox_sync_lock(sync_ctx, F_WRLCK)) < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((ret = mbox_sync_check_excl_lock(mail_ctx->sync_ctx)) < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_ctx->mail.offset = mail_ctx->from_offset;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_ctx->body_offset - mail_ctx->from_offset +
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* expunging first message, fix space to contain next
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen message's \n header too since it will be removed. */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_ctx->sync_ctx->expunged_space += mail_ctx->mail.space;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainenstatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* move the header backwards to fill expunged space */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if ((ret = mbox_sync_check_excl_lock(sync_ctx)) < 0)
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen /* read the From-line before rewriting overwrites it */
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen mbox_sync_update_header(mail_ctx, sync_ctx->syncs);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen ret = mbox_sync_try_rewrite(mail_ctx, move_diff, FALSE);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen /* rewrite successful, write From-line to
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen new location */
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen if (mbox_write_from_line(mail_ctx, move_diff) < 0)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if ((ret = mbox_sync_check_excl_lock(sync_ctx)) < 0)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox_sync_update_header(mail_ctx, sync_ctx->syncs);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, 0, FALSE)) < 0)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* nothing to do */
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen if (ret == 0 && sync_ctx->need_space_seq == 0) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* first mail with no space to write it */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen sync_ctx->need_space_idx_seq = sync_ctx->idx_seq;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* create dummy message to describe the expunged data */
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen buffer_append(sync_ctx->mails, &mail, sizeof(mail));
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainenmbox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen buffer_append(sync_ctx->mails, &mail_ctx->mail, sizeof(mail_ctx->mail));
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* we have enough space now */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* don't waste too much on extra spacing */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen sync_ctx->expunged_space = sync_ctx->space_diff - extra_space;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if (mbox_sync_rewrite(sync_ctx, sync_ctx->space_diff,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* mail_ctx may contain wrong data after rewrite, so make sure we
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen don't try to access it */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmbox_sync_seek_to_uid(struct mbox_sync_context *sync_ctx, uint32_t uid)
if (seq1 == 0)
if (min_message_count != 0)
ret = 0;
&expunged) < 0)
if (size == 0)
if (ret < 0)
if (ret == 0) {
uid = 0;
if (ret < 0)
if (ret == 0)
uid = 0;
&rec) < 0)
if (!expunged) {
if (ret < 0) {
return ret;
if (!expunged) {
rec) < 0)
if (!expunged) {
int need_rewrite;
if (need_rewrite) {
trailer_size) < 0)
int ret;
if (sync_header)
FALSE);
unsigned int lock_id = 0;
if (lock) {
if (sync_header)
ret = 0;
if (lock)
if (last_commit) {
if (ret <= 0) {
if (ret < 0)
return ret;
lock_id = 0;
if (ret < 0)
if (ret < 0)
&seq,
&offset) < 0) {
unsigned int lock_id = 0;
return ret;