[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-sync-private.h, 1.66, 1.67 mbox-sync-rewrite.c, 1.78, 1.79 mbox-sync.c, 1.204, 1.205

tss at dovecot.org tss at dovecot.org
Wed Mar 21 23:57:19 EET 2007


Update of /var/lib/cvs/dovecot/src/lib-storage/index/mbox
In directory talvi:/tmp/cvs-serv22766/lib-storage/index/mbox

Modified Files:
	mbox-sync-private.h mbox-sync-rewrite.c mbox-sync.c 
Log Message:
Check if mbox has been modified externally before doing any dangerous
writes. Also changed the old "space needed changed unexpectedly" assert to a
more informative panic.



Index: mbox-sync-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-private.h,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -d -r1.66 -r1.67
--- mbox-sync-private.h	14 Mar 2007 12:09:39 -0000	1.66
+++ mbox-sync-private.h	21 Mar 2007 21:57:16 -0000	1.67
@@ -6,6 +6,8 @@
 
 ARRAY_DEFINE_TYPE(sync_recs, struct mail_index_sync_rec);
 
+#include <sys/stat.h>
+
 enum mbox_sync_flags {
 	MBOX_SYNC_LAST_COMMIT	= 0x01,
 	MBOX_SYNC_HEADER	= 0x02,
@@ -105,6 +107,7 @@
 
 	time_t orig_mtime;
 	uoff_t orig_size;
+	struct stat last_stat;
 
 	struct mail_index_sync_ctx *index_sync_ctx;
 	struct mail_index_view *sync_view;
@@ -161,6 +164,8 @@
 				 struct mbox_sync_mail *mail,
 				 bool *keywords_changed_r);
 int mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset);
+bool mbox_sync_file_is_ext_modified(struct mbox_sync_context *sync_ctx);
+void mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty);
 int mbox_move(struct mbox_sync_context *sync_ctx,
 	      uoff_t dest, uoff_t source, uoff_t size);
 void mbox_sync_move_buffer(struct mbox_sync_mail_context *ctx,

Index: mbox-sync-rewrite.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync-rewrite.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- mbox-sync-rewrite.c	21 Mar 2007 21:12:56 -0000	1.78
+++ mbox-sync-rewrite.c	21 Mar 2007 21:57:16 -0000	1.79
@@ -55,7 +55,7 @@
 				       "o_stream_send_istream()");
 	}
 
-	i_stream_sync(sync_ctx->input);
+	mbox_sync_file_updated(sync_ctx, FALSE);
 	o_stream_destroy(&output);
 	return (int)ret;
 }
@@ -79,6 +79,7 @@
 		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
 		return -1;
 	}
+	mbox_sync_file_updated(sync_ctx, TRUE);
 	return 0;
 }
 
@@ -314,7 +315,7 @@
 		mbox_sync_first_mail_written(ctx, ctx->hdr_offset + move_diff);
 	}
 
-	i_stream_sync(sync_ctx->input);
+	mbox_sync_file_updated(sync_ctx, FALSE);
 	return 1;
 }
 
@@ -408,19 +409,15 @@
 		i_stream_seek(sync_ctx->input, mail_ctx->body_offset);
 	}
 
-	if (first_nonexpunged && expunged_space > 0) {
-		/* move From-line (after parsing headers so we don't
-		   overwrite them) */
-		if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
-			      mails[idx].from_offset,
-			      mails[idx].offset - mails[idx].from_offset) < 0)
-			return -1;
-	}
-
 	if (mail_ctx->mail.space <= 0) {
 		need_space = str_len(mail_ctx->header) - mail_ctx->mail.space -
 			(mail_ctx->body_offset - mail_ctx->hdr_offset);
 		if (need_space != (uoff_t)-mails[idx].space) {
+			/* this check works only if we're doing the first
+			   write, or if the file size was changed externally */
+			if (mbox_sync_file_is_ext_modified(sync_ctx))
+				return -1;
+
 			i_panic("mbox %s: seq=%u uid=%u uid_broken=%d "
 				"originally needed %"PRIuUOFF_T
 				" bytes, now needs %"PRIuSIZE_T" bytes",
@@ -430,6 +427,15 @@
 		}
 	}
 
+	if (first_nonexpunged && expunged_space > 0) {
+		/* move From-line (after parsing headers so we don't
+		   overwrite them) */
+		if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
+			      mails[idx].from_offset,
+			      mails[idx].offset - mails[idx].from_offset) < 0)
+			return -1;
+	}
+
 	if (mails[idx].space == 0) {
 		/* don't touch spacing */
 	} else if (padding < (uoff_t)mail_ctx->mail.space) {
@@ -458,6 +464,7 @@
 		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
 		return -1;
 	}
+	mbox_sync_file_updated(sync_ctx, TRUE);
 
 	if (sync_ctx->dest_first_mail) {
 		mbox_sync_first_mail_written(mail_ctx, dest_offset);
@@ -585,7 +592,7 @@
 	i_assert(mails[idx].from_offset == start_offset);
 	i_assert(move_diff + (off_t)expunged_space >= 0);
 
-	i_stream_sync(sync_ctx->input);
+	mbox_sync_file_updated(sync_ctx, FALSE);
 	sync_ctx->prev_msg_uid = orig_prev_msg_uid;
 	return ret;
 }

Index: mbox-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync.c,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- mbox-sync.c	14 Mar 2007 16:17:58 -0000	1.204
+++ mbox-sync.c	21 Mar 2007 21:57:16 -0000	1.205
@@ -74,6 +74,46 @@
 	return 0;
 }
 
+bool mbox_sync_file_is_ext_modified(struct mbox_sync_context *sync_ctx)
+{
+	struct stat st;
+
+	if (fstat(sync_ctx->write_fd, &st) < 0) {
+		mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
+		return TRUE;
+	}
+
+	if (st.st_size != sync_ctx->last_stat.st_size ||
+	    (sync_ctx->last_stat.st_mtime != 0 &&
+	     (st.st_mtime != sync_ctx->last_stat.st_mtime
+#ifdef HAVE_STAT_TV_NSEC
+	      /* nanoseconds give better precision to this check if they're
+		 supported by the OS */
+	      || st.st_mtim.tv_nsec != sync_ctx->last_stat.st_mtim.tv_nsec
+#endif
+	     ))) {
+		mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
+			"mbox file %s was modified while we were syncing, "
+			"check your locking settings", sync_ctx->mbox->path);
+		return TRUE;
+	}
+
+	sync_ctx->last_stat = st;
+	return FALSE;
+}
+
+void mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
+{
+	if (dirty) {
+		/* just mark the stat as dirty. */
+		sync_ctx->last_stat.st_mtime = 0;
+		return;
+	}
+	if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
+		mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
+	i_stream_sync(sync_ctx->input);
+}
+
 static void mbox_sync_array_delete_to(ARRAY_TYPE(sync_recs) *syncs_arr,
 				      uint32_t last_uid)
 {
@@ -621,6 +661,7 @@
 		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
 		return -1;
 	}
+	mbox_sync_file_updated(sync_ctx, FALSE);
 
 	sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
 	return 0;
@@ -637,7 +678,7 @@
 		return -1;
 	}
 
-	i_stream_sync(ctx->sync_ctx->input);
+	mbox_sync_file_updated(ctx->sync_ctx, FALSE);
 	return 0;
 }
 
@@ -847,6 +888,9 @@
 		extra_space = sync_ctx->space_diff;
 	}
 
+	if (mbox_sync_file_is_ext_modified(sync_ctx))
+		return -1;
+
 	if (mbox_sync_rewrite(sync_ctx,
 			      last_seq == sync_ctx->seq ? mail_ctx : NULL,
 			      end_offset, move_diff, extra_space,
@@ -1181,6 +1225,9 @@
 		} else if (sync_ctx->expunged_space > 0) {
 			if (!expunged) {
 				/* move the body */
+				if (mbox_sync_file_is_ext_modified(sync_ctx))
+					return -1;
+
 				if (mbox_move(sync_ctx,
 					      mail_ctx->body_offset -
 					      sync_ctx->expunged_space,
@@ -1276,9 +1323,6 @@
 		return 0;
 	}
 
-	/* make sure i_stream_stat() doesn't try to use cached file size */
-	i_stream_sync(sync_ctx->file_input);
-
 	st = i_stream_stat(sync_ctx->file_input, TRUE);
 	if (st == NULL) {
 		mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
@@ -1313,6 +1357,9 @@
 
 		i_assert(sync_ctx->space_diff < 0);
 
+		if (mbox_sync_file_is_ext_modified(sync_ctx))
+			return -1;
+
 		if (file_set_size(sync_ctx->write_fd,
 				  file_size + -sync_ctx->space_diff) < 0) {
 			mbox_set_syscall_error(sync_ctx->mbox,
@@ -1323,7 +1370,7 @@
 			}
 			return -1;
 		}
-		i_stream_sync(sync_ctx->input);
+		mbox_sync_file_updated(sync_ctx, FALSE);
 
 		if (mbox_sync_rewrite(sync_ctx, mail_ctx, file_size,
 				      -sync_ctx->space_diff, padding,
@@ -1341,15 +1388,11 @@
 	if (sync_ctx->expunged_space > 0) {
 		i_assert(sync_ctx->write_fd != -1);
 
-		/* copy trailer, then truncate the file */
-		st = i_stream_stat(sync_ctx->file_input, TRUE);
-		if (st == NULL) {
-			mbox_set_syscall_error(sync_ctx->mbox,
-					       "i_stream_stat()");
+		if (mbox_sync_file_is_ext_modified(sync_ctx))
 			return -1;
-		}
 
-		file_size = st->st_size;
+		/* copy trailer, then truncate the file */
+		file_size = sync_ctx->last_stat.st_size;
 		if (file_size == (uoff_t)sync_ctx->expunged_space) {
 			/* everything deleted, the trailer_size still contains
 			   the \n trailer though */
@@ -1376,7 +1419,7 @@
 		}
 
                 sync_ctx->expunged_space = 0;
-		i_stream_sync(sync_ctx->input);
+		mbox_sync_file_updated(sync_ctx, FALSE);
 	}
 	return 0;
 }
@@ -1512,6 +1555,7 @@
 		mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
 		return -1;
 	}
+	sync_ctx->last_stat = *st;
 	sync_ctx->orig_size = st->st_size;
 	sync_ctx->orig_mtime = st->st_mtime;
 



More information about the dovecot-cvs mailing list