Mercurial > dovecot > original-hg > dovecot-1.2
changeset 2164:e5f9d66d6ced HEAD
fixes
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 19 Jun 2004 03:19:48 +0300 |
parents | 506302b8b2fb |
children | 4c5732a9e2bc |
files | src/lib-storage/index/mbox/mbox-sync-private.h src/lib-storage/index/mbox/mbox-sync-rewrite.c src/lib-storage/index/mbox/mbox-sync-update.c src/lib-storage/index/mbox/mbox-sync.c |
diffstat | 4 files changed, 106 insertions(+), 151 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/mbox/mbox-sync-private.h Fri Jun 18 22:27:41 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-private.h Sat Jun 19 03:19:48 2004 +0300 @@ -106,8 +106,8 @@ void mbox_sync_update_header_from(struct mbox_sync_mail_context *ctx, const struct mbox_sync_mail *mail); int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff); -int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, - uint32_t first_seq, uint32_t last_seq, off_t extra_space); +int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, uoff_t extra_space, + uint32_t first_seq, uint32_t last_seq); int mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset); int mbox_move(struct mbox_sync_context *sync_ctx,
--- a/src/lib-storage/index/mbox/mbox-sync-rewrite.c Fri Jun 18 22:27:41 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-rewrite.c Sat Jun 19 03:19:48 2004 +0300 @@ -49,6 +49,28 @@ return (int)ret; } +static int mbox_fill_space(struct mbox_sync_context *sync_ctx, + uoff_t offset, uoff_t size) +{ + unsigned char space[1024]; + + memset(space, ' ', sizeof(space)); + while (size > sizeof(space)) { + if (pwrite_full(sync_ctx->fd, space, + sizeof(space), offset) < 0) { + mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()"); + return -1; + } + size -= sizeof(space); + } + + if (pwrite_full(sync_ctx->fd, space, size, offset) < 0) { + mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()"); + return -1; + } + return 0; +} + static void mbox_sync_headers_add_space(struct mbox_sync_mail_context *ctx, size_t size) { @@ -58,23 +80,11 @@ i_assert(size < SSIZE_T_MAX); - if (ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] == (size_t)-1 && - size >= sizeof("X-Keywords: \n")-1) { - /* Add X-Keywords */ - start_pos = str_len(ctx->header); - if (ctx->have_eoh) - start_pos--; - ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = start_pos; - - str_insert(ctx->header, start_pos, "X-Keywords: \n"); - size -= sizeof("X-Keywords: \n")-1; - } else { - /* Append at the end of X-Keywords header, - or X-UID if it doesn't exist */ - start_pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ? - ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] : - ctx->hdr_pos[MBOX_HDR_X_UID]; - } + /* Append at the end of X-Keywords header, + or X-UID if it doesn't exist */ + start_pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ? + ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] : + ctx->hdr_pos[MBOX_HDR_X_UID]; data = str_data(ctx->header); data_size = str_len(ctx->header); @@ -90,8 +100,8 @@ } } - /* pos points to end of headers now, and start_pos to beginning of - whitespace. */ + /* pos points to end of headers now, and start_pos to beginning + of whitespace. */ buffer_copy(ctx->header, pos + size, ctx->header, pos, (size_t)-1); p = buffer_get_space_unsafe(ctx->header, pos, size); @@ -193,8 +203,9 @@ old_hdr_size = ctx->body_offset - ctx->hdr_offset; new_hdr_size = str_len(ctx->header); - /* do we have enough space? */ - if (new_hdr_size < old_hdr_size) { + if (new_hdr_size <= old_hdr_size) { + /* add space. note that we must call add_space() even if we're + not adding anything so mail.offset gets fixed. */ mbox_sync_headers_add_space(ctx, old_hdr_size - new_hdr_size); } else if (new_hdr_size > old_hdr_size) { /* try removing the space where we can */ @@ -205,6 +216,8 @@ if (new_hdr_size <= old_hdr_size) { /* good, we removed enough. */ i_assert(new_hdr_size == old_hdr_size); + ctx->mail.space = + -(ssize_t)(new_hdr_size - old_hdr_size); } else if (move_diff < 0 && new_hdr_size - old_hdr_size <= -move_diff) { /* moving backwards - we can use the extra space from @@ -256,12 +269,12 @@ static int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx, struct mbox_sync_mail *mails, uint32_t seq, uint32_t idx, - uint32_t extra_per_mail, - uoff_t *end_offset) + uoff_t space_diff, uoff_t end_offset) { struct mbox_sync_mail_context mail_ctx; uint32_t old_prev_msg_uid; - uoff_t offset; + uoff_t hdr_offset, offset, dest_offset; + size_t old_hdr_size, need_space; if (mbox_sync_seek(sync_ctx, mails[idx].from_offset) < 0) return -1; @@ -271,6 +284,7 @@ mail_ctx.seq = seq; mail_ctx.header = sync_ctx->header; + hdr_offset = mails[idx].offset; mail_ctx.mail.offset = mails[idx].offset; mail_ctx.mail.body_size = mails[idx].body_size; @@ -293,96 +307,48 @@ sync_ctx->prev_msg_uid = old_prev_msg_uid; sync_ctx->dest_first_mail = FALSE; - mail_ctx.mail.space = - -(ssize_t)(str_len(mail_ctx.header) - - (mail_ctx.body_offset - mail_ctx.hdr_offset)); - i_assert(mail_ctx.mail.space == mails[idx].space); + old_hdr_size = mail_ctx.body_offset - mail_ctx.hdr_offset; + need_space = str_len(mail_ctx.header) - mail_ctx.mail.space - + old_hdr_size; + i_assert(need_space == -mails[idx].space); + i_assert(space_diff >= need_space); - if (mail_ctx.mail.space <= 0) - mbox_sync_headers_add_space(&mail_ctx, extra_per_mail); - else if (mail_ctx.mail.space <= extra_per_mail) { - mbox_sync_headers_add_space(&mail_ctx, extra_per_mail - - mail_ctx.mail.space); - } else { + if (space_diff - need_space < (uoff_t)mail_ctx.mail.space) { mbox_sync_headers_remove_space(&mail_ctx, mail_ctx.mail.space - - extra_per_mail); + (space_diff - need_space)); + } else { + mbox_sync_headers_add_space(&mail_ctx, space_diff - need_space - + mail_ctx.mail.space); } + mails[idx].offset = mail_ctx.mail.offset; + mails[idx].space = mail_ctx.mail.space; - /* now we have to move it. first move the body of the message, - then write the header and leave the extra space to beginning of - headers. */ + /* move the body of this message and headers of next message forward, + then write the headers */ offset = sync_ctx->input->v_offset; - if (mbox_move(sync_ctx, offset + mails[idx+1].space, offset, - *end_offset - offset - mails[idx+1].space) < 0) + dest_offset = offset + space_diff; + if (mbox_move(sync_ctx, dest_offset, offset, + end_offset - dest_offset) < 0) return -1; - mails[idx+1].from_offset += mails[idx+1].space; - - *end_offset = offset + mails[idx+1].space - str_len(mail_ctx.header); if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header), - str_len(mail_ctx.header), *end_offset) < 0) { + str_len(mail_ctx.header), hdr_offset) < 0) { mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()"); return -1; } - mails[idx].offset = *end_offset; - mails[idx].space += mails[idx+1].space - extra_per_mail; return 0; } -static int mbox_sync_fill_leftover(struct mbox_sync_context *sync_ctx, - struct mbox_sync_mail *mails, - uint32_t seq, uint32_t idx, - uoff_t start_offset, uoff_t end_offset) -{ - struct mbox_sync_mail_context mail_ctx; - uint32_t old_prev_msg_uid; - - i_assert(start_offset < end_offset); - - i_stream_seek(sync_ctx->input, mails[idx].offset); - - memset(&mail_ctx, 0, sizeof(mail_ctx)); - mail_ctx.sync_ctx = sync_ctx; - mail_ctx.seq = seq; - mail_ctx.header = sync_ctx->header; - - mail_ctx.mail.offset = mails[idx].offset; - mail_ctx.mail.body_size = mails[idx].body_size; - - /* mbox_sync_parse_next_mail() checks that UIDs are growing, - so we have to fool it. */ - old_prev_msg_uid = sync_ctx->prev_msg_uid; - sync_ctx->prev_msg_uid = mails[idx].uid-1; - sync_ctx->dest_first_mail = seq == 1; - - mbox_sync_parse_next_mail(sync_ctx->input, &mail_ctx, TRUE); - mbox_sync_update_header_from(&mail_ctx, &mails[idx]); - - sync_ctx->prev_msg_uid = old_prev_msg_uid; - sync_ctx->dest_first_mail = FALSE; - - mbox_sync_headers_add_space(&mail_ctx,end_offset - start_offset); - - if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header), - str_len(mail_ctx.header), start_offset) < 0) { - mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()"); - return -1; - } - - /* just a cleanup - shouldn't be needed anymore */ - mails[idx].offset = start_offset; - mails[idx].space = 0; - return 0; -} - -int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, - uint32_t first_seq, uint32_t last_seq, off_t extra_space) +/* extra_space specifies how many bytes from last_seq's space will be left + over after all the rewrites. */ +int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, uoff_t extra_space, + uint32_t first_seq, uint32_t last_seq) { struct mbox_sync_mail *mails; + uoff_t offset, end_offset, dest_offset, space_diff; + uint32_t idx, extra_per_mail; size_t size; - uoff_t offset, start_offset, end_offset, dest_offset; - uint32_t idx, extra_per_mail; int ret = 0; i_assert(first_seq != last_seq); @@ -396,83 +362,71 @@ data which hasn't yet been copied backwards. to avoid too much complexity, we just leave all the rest of the extra space to first mail */ - extra_per_mail = extra_space / (last_seq - first_seq + 1); idx = last_seq - first_seq; - - if (mails[idx].uid != 0) - mails[idx].space -= extra_per_mail; - i_assert(mails[idx].space >= 0); - end_offset = mails[idx].offset + mails[idx].space; + extra_per_mail = extra_space / (idx + 1); /* after expunge the next mail must have been missing space, or we would have moved it backwards already */ i_assert(mails[0].space < 0 || mails[0].uid == 0); - start_offset = mails[0].offset; + + /* start moving backwards. */ + do { + /* this message's body is always moved space_diff bytes + forward along with next message's headers, so current + message gets temporarily space_diff amount of extra + whitespace. - /* start moving backwards */ - do { + the moving stops at next message's beginning of extra + space. each message gets left extra_per_mail bytes of + space. what gets left over is given to first message */ + i_assert(mails[idx].space > 0); + space_diff = mails[idx].space; + end_offset = mails[idx].offset + mails[idx].space; + + if (mails[idx].uid != 0) { + space_diff -= extra_per_mail; + end_offset -= extra_per_mail; + mails[idx].space = extra_per_mail; + } + idx--; if (mails[idx].space <= 0 && mails[idx].uid != 0) { /* offset points to beginning of headers. read the header again, update it and give enough space to - it */ + fill space_diff */ if (mbox_sync_read_and_move(sync_ctx, mails, first_seq + idx, idx, - extra_per_mail, - &end_offset) < 0) { + space_diff, + end_offset) < 0) { ret = -1; break; } } else { - /* X-Keywords: xx [offset] \n + /* X-Keywords: xx [offset]\n ... - X-Keywords: xx [end_offset] \n + X-Keywords: xx [end_offset] \n move data forward so mails before us gets the extra space (ie. we temporarily get more space to us) */ offset = mails[idx].offset + mails[idx].space; - dest_offset = offset + mails[idx+1].space; + dest_offset = offset + space_diff; if (mbox_move(sync_ctx, dest_offset, offset, end_offset - dest_offset) < 0) { ret = -1; break; } - mails[idx+1].from_offset += mails[idx+1].space; - - mails[idx].space += mails[idx+1].space; - if (mails[idx].uid != 0) - mails[idx].space -= extra_per_mail; - i_assert(mails[idx].space > 0); - end_offset = mails[idx].offset + mails[idx].space; - } - } while (idx > 0); + if (mbox_fill_space(sync_ctx, offset, + dest_offset - offset) < 0) { + ret = -1; + break; + } - if (end_offset != start_offset) { - /* some space was left over - give it to first message. */ - if (mails[0].uid == 0) { - /* "body" start_offset .. end_offset "\nFrom .." - we need to move From-line to start_offset */ - offset = mails[1].offset; - if (mbox_move(sync_ctx, start_offset, end_offset, - offset - end_offset) < 0) - ret = -1; - mails[1].from_offset -= end_offset - start_offset; - idx++; + mails[idx].space += space_diff; + } - start_offset += offset - end_offset; - end_offset = offset; - } else { - /* "\nFrom ..\n" start_offset .. end_offset "hdr.." */ - } - - /* now parse it again and give it more space */ - mails[idx+1].space = 0; /* from_offset doesn't move.. */ - if (mbox_sync_fill_leftover(sync_ctx, mails, - first_seq + idx, idx, - start_offset, end_offset) < 0) - ret = -1; - } + mails[idx+1].from_offset += space_diff; + } while (idx > 0); istream_raw_mbox_flush(sync_ctx->input); return ret;
--- a/src/lib-storage/index/mbox/mbox-sync-update.c Fri Jun 18 22:27:41 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-update.c Sat Jun 19 03:19:48 2004 +0300 @@ -31,7 +31,8 @@ } else { /* FIXME: if (diff < ctx->space && pos < ctx->offset) then move the data only up to space offset and give/take the - space from there. update header_last_change accordingly. */ + space from there. update header_last_change accordingly. + (except pos and offset can't be compared directly) */ ctx->header_last_change = (size_t)-1; for (i = 0; i < MBOX_HDR_COUNT; i++) { if (ctx->hdr_pos[i] > pos &&
--- a/src/lib-storage/index/mbox/mbox-sync.c Fri Jun 18 22:27:41 2004 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync.c Sat Jun 19 03:19:48 2004 +0300 @@ -605,8 +605,8 @@ sync_ctx->expunged_space = 0; } - if (mbox_sync_rewrite(sync_ctx, sync_ctx->need_space_seq, sync_ctx->seq, - sync_ctx->space_diff) < 0) + if (mbox_sync_rewrite(sync_ctx, sync_ctx->space_diff, + sync_ctx->need_space_seq, sync_ctx->seq) < 0) return -1; update_from_offsets(sync_ctx->ibox, sync_ctx->t, sync_ctx->mails, @@ -816,9 +816,9 @@ buffer_append(sync_ctx->mails, &mail_ctx->mail, sizeof(mail_ctx->mail)); - if (mbox_sync_rewrite(sync_ctx, + if (mbox_sync_rewrite(sync_ctx, extra_space, sync_ctx->need_space_seq, - sync_ctx->seq, extra_space) < 0) + sync_ctx->seq) < 0) return -1; update_from_offsets(sync_ctx->ibox, sync_ctx->t,