changeset 2743:2cada6a7f3eb HEAD

If rewriting began with expunged data areas, we didn't overwrite them which left garbage into mbox and broke things.
author Timo Sirainen <tss@iki.fi>
date Thu, 14 Oct 2004 20:56:39 +0300
parents 192da9681e1b
children 1c4b1e78ffc5
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.c
diffstat 3 files changed, 48 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/mbox/mbox-sync-private.h	Thu Oct 14 15:27:09 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-sync-private.h	Thu Oct 14 20:56:39 2004 +0300
@@ -130,7 +130,7 @@
 				  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,
-		      uoff_t end_offset, uoff_t move_diff, uoff_t extra_space,
+		      uoff_t end_offset, off_t move_diff, 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);
--- a/src/lib-storage/index/mbox/mbox-sync-rewrite.c	Thu Oct 14 15:27:09 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-sync-rewrite.c	Thu Oct 14 20:56:39 2004 +0300
@@ -276,7 +276,8 @@
 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 padding,
-				   uoff_t move_diff, uoff_t end_offset)
+				   off_t move_diff, uoff_t expunged_space,
+				   uoff_t end_offset)
 {
 	struct mbox_sync_mail_context mail_ctx;
 	uint32_t old_prev_msg_uid;
@@ -301,7 +302,14 @@
 	   so we have to fool it. */
 	old_prev_msg_uid = sync_ctx->prev_msg_uid;
 	sync_ctx->prev_msg_uid = mails[idx].uid == 0 ? 0 : mails[idx].uid-1;
-	sync_ctx->dest_first_mail = mails[idx].from_offset == 0;
+	if (mails[idx].from_offset+1 - expunged_space != 0) {
+		sync_ctx->dest_first_mail = mails[idx].from_offset == 0;
+	} else {
+		/* we need to skip over the initial \n (it's already counted in
+		   expunged_space) */
+		sync_ctx->dest_first_mail = TRUE;
+		mails[idx].from_offset++;
+	}
 
 	mbox_sync_parse_next_mail(sync_ctx->input, &mail_ctx);
 	if (mails[idx].space != 0)
@@ -313,6 +321,14 @@
 			str_append_c(mail_ctx.header, '\n');
 	}
 
+	if (sync_ctx->dest_first_mail && expunged_space > 0) {
+		/* move From-line (after parsing headers so we don't
+		   overwrite them) */
+		if (mbox_move(sync_ctx, 0, mails[idx].from_offset,
+			      mails[idx].offset - mails[idx].from_offset) < 0)
+			return -1;
+	}
+
 	sync_ctx->prev_msg_uid = old_prev_msg_uid;
 	sync_ctx->dest_first_mail = FALSE;
 
@@ -340,6 +356,7 @@
 
 	/* the header may actually be moved backwards if there was expunged
 	   space which we wanted to remove */
+	i_assert(dest_offset >= str_len(mail_ctx.header));
 	dest_offset -= str_len(mail_ctx.header);
 	if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header),
 			str_len(mail_ctx.header), dest_offset) < 0) {
@@ -361,11 +378,12 @@
 }
 
 int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx,
-		      uoff_t end_offset, uoff_t move_diff, uoff_t extra_space,
+		      uoff_t end_offset, off_t move_diff, uoff_t extra_space,
 		      uint32_t first_seq, uint32_t last_seq)
 {
 	struct mbox_sync_mail *mails;
 	uoff_t offset, dest_offset, next_end_offset, next_move_diff;
+	uoff_t expunged_space;
 	uint32_t idx, first_nonexpunged_idx, padding_per_mail;
 	size_t size;
 	int ret = 0;
@@ -385,21 +403,23 @@
 
 	/* after expunge the next mail must have been missing space, or we
 	   would have moved it backwards already */
+	expunged_space = 0;
 	for (first_nonexpunged_idx = 0;; first_nonexpunged_idx++) {
 		i_assert(first_nonexpunged_idx != idx);
 		if ((mails[first_nonexpunged_idx].flags & MBOX_EXPUNGED) == 0)
 			break;
+                expunged_space += mails[first_nonexpunged_idx].space;
 	}
 	i_assert(mails[first_nonexpunged_idx].space < 0);
 
 	/* start moving backwards. */
 	while (idx-- > first_nonexpunged_idx) {
 		if (idx == first_nonexpunged_idx) {
-			/* give the rest of the extra space to first mail */
-			i_assert((uoff_t)-mails[idx].space <= move_diff);
-			i_assert(move_diff + mails[idx].space >=
-				 padding_per_mail);
-			padding_per_mail = move_diff + mails[idx].space;
+			/* give the rest of the extra space to first mail.
+			   we might also have to move the mail backwards to
+			   fill the expunged space */
+			padding_per_mail = move_diff + expunged_space +
+				mails[idx].space;
 		}
 
 		next_end_offset = mails[idx].offset;
@@ -409,12 +429,15 @@
 			next_move_diff = -mails[idx].space;
 			if (mbox_sync_read_and_move(sync_ctx, mails,
 						    first_seq + idx, idx,
-						    padding_per_mail, move_diff,
+						    padding_per_mail,
+						    move_diff, expunged_space,
 						    end_offset) < 0) {
 				ret = -1;
 				break;
 			}
 			move_diff -= next_move_diff + mails[idx].space;
+			if (idx == first_nonexpunged_idx)
+				move_diff += expunged_space;
 		} else {
 			/* this mail provides more space. just move it forward
 			   from the extra space offset and set end_offset to
@@ -447,6 +470,8 @@
 			mails[idx].offset += move_diff;
 		}
 
+		i_assert(idx > 0 || move_diff == 0);
+
 		end_offset = next_end_offset;
 		mails[idx].from_offset += move_diff;
 		i_assert(move_diff < OFF_T_MAX);
--- a/src/lib-storage/index/mbox/mbox-sync.c	Thu Oct 14 15:27:09 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-sync.c	Thu Oct 14 20:56:39 2004 +0300
@@ -105,11 +105,6 @@
 
 	if (mail_ctx->seq == 1)
 		sync_ctx->seen_first_mail = TRUE;
-	if (mail_ctx->seq > 1 && sync_ctx->dest_first_mail) {
-		/* First message was expunged and this is the next one.
-		   Skip \n header */
-		mail_ctx->mail.from_offset++;
-	}
 
 	mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
 	i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
@@ -530,6 +525,13 @@
 		/* move the header backwards to fill expunged space */
 		move_diff = -sync_ctx->expunged_space;
 
+		if (sync_ctx->dest_first_mail) {
+			/* we're moving this mail to beginning of file.
+			   skip the initial \n (it's already counted in
+			   expunged_space) */
+			mail_ctx->mail.from_offset++;
+		}
+
 		/* read the From-line before rewriting overwrites it */
 		if (mbox_read_from_line(mail_ctx) < 0)
 			return -1;
@@ -546,6 +548,12 @@
 			mail_ctx->mail.offset += move_diff;
 			if (mbox_write_from_line(mail_ctx) < 0)
 				return -1;
+		} else {
+			if (sync_ctx->dest_first_mail) {
+				/* didn't have enough space, move the offset
+				   back so seeking into it doesn't fail */
+				mail_ctx->mail.from_offset--;
+			}
 		}
 	} else if (mail_ctx->need_rewrite ||
 		   buffer_get_used_size(sync_ctx->syncs) != 0 ||