dovecot-2.0: maildir save: Detect when trying to use duplicate G...

dovecot at dovecot.org dovecot at dovecot.org
Thu Feb 18 05:54:02 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/386b13dfee04
changeset: 10740:386b13dfee04
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Feb 18 05:53:59 2010 +0200
description:
maildir save: Detect when trying to use duplicate GUIDs (filenames) and rename them.

diffstat:

 src/lib-storage/index/maildir/maildir-save.c |  54 ++++++++++++++++++--------
 1 files changed, 37 insertions(+), 17 deletions(-)

diffs (141 lines):

diff -r 9fdeca77d421 -r 386b13dfee04 src/lib-storage/index/maildir/maildir-save.c
--- a/src/lib-storage/index/maildir/maildir-save.c	Thu Feb 18 05:53:08 2010 +0200
+++ b/src/lib-storage/index/maildir/maildir-save.c	Thu Feb 18 05:53:59 2010 +0200
@@ -28,7 +28,7 @@
 
 struct maildir_filename {
 	struct maildir_filename *next;
-	const char *basename;
+	const char *tmp_name, *dest_basename;
 
 	uoff_t size, vsize;
 	enum mail_flags flags;
@@ -69,6 +69,7 @@
 	unsigned int locked:1;
 	unsigned int failed:1;
 	unsigned int last_save_finished:1;
+	unsigned int locked_uidlist_refresh:1;
 };
 
 static int maildir_file_move(struct maildir_save_context *ctx,
@@ -82,7 +83,7 @@
 	   new/ directory can't have flags. alternative would be to write it
 	   in new/ and set the flags dirty in index file, but in that case
 	   external MUAs would see wrong flags. */
-	tmp_path = t_strconcat(ctx->tmpdir, "/", mf->basename, NULL);
+	tmp_path = t_strconcat(ctx->tmpdir, "/", mf->tmp_name, NULL);
 	new_path = newdir ?
 		t_strconcat(ctx->newdir, "/", destname, NULL) :
 		t_strconcat(ctx->curdir, "/", destname, NULL);
@@ -162,7 +163,7 @@
 	keyword_count = _ctx->keywords == NULL ? 0 : _ctx->keywords->count;
 	mf = p_malloc(ctx->pool, sizeof(*mf) +
 		      sizeof(unsigned int) * keyword_count);
-	mf->basename = p_strdup(ctx->pool, base_fname);
+	mf->tmp_name = mf->dest_basename = p_strdup(ctx->pool, base_fname);
 	mf->flags = _ctx->flags;
 	mf->size = (uoff_t)-1;
 	mf->vsize = (uoff_t)-1;
@@ -221,11 +222,11 @@
 }
 
 static bool
-maildir_get_updated_filename(struct maildir_save_context *ctx,
-			     struct maildir_filename *mf,
-			     const char **fname_r)
+maildir_get_dest_filename(struct maildir_save_context *ctx,
+			  struct maildir_filename *mf,
+			  const char **fname_r)
 {
-	const char *basename = mf->basename;
+	const char *basename = mf->dest_basename;
 
 	if (mf->size != (uoff_t)-1 && !mf->preserve_filename) {
 		basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
@@ -261,18 +262,17 @@
 static const char *maildir_mf_get_path(struct maildir_save_context *ctx,
 				       struct maildir_filename *mf)
 {
-	const char *fname;
+	const char *fname, *dir;
 
 	if ((mf->flags & MAILDIR_FILENAME_FLAG_MOVED) == 0) {
 		/* file is still in tmp/ */
-		return t_strdup_printf("%s/%s", ctx->tmpdir, mf->basename);
+		return t_strdup_printf("%s/%s", ctx->tmpdir, mf->tmp_name);
 	}
 
 	/* already moved to new/ or cur/ */
-	if (maildir_get_updated_filename(ctx, mf, &fname))
-		return t_strdup_printf("%s/%s", ctx->newdir, mf->basename);
-	else
-		return t_strdup_printf("%s/%s", ctx->curdir, fname);
+	dir = maildir_get_dest_filename(ctx, mf, &fname) ?
+		ctx->newdir : ctx->curdir;
+	return t_strdup_printf("%s/%s", dir, fname);
 }
 
 const char *maildir_save_file_get_path(struct mailbox_transaction_context *t,
@@ -422,7 +422,7 @@
 				mail_storage_set_critical(storage,
 					"o_stream_send_istream(%s/%s) "
 					"failed: %m",
-					ctx->tmpdir, ctx->file_last->basename);
+					ctx->tmpdir, ctx->file_last->tmp_name);
 			}
 			ctx->failed = TRUE;
 			return -1;
@@ -509,7 +509,7 @@
 		return -1;
 	}
 
-	path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->basename, NULL);
+	path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL);
 	if (o_stream_flush(_ctx->output) < 0) {
 		if (!mail_storage_set_error_from_errno(storage)) {
 			mail_storage_set_critical(storage,
@@ -811,6 +811,23 @@
 	mail_cache_transaction_reset(t->cache_trans);
 }
 
+static void
+maildir_filename_check_conflicts(struct maildir_save_context *ctx,
+				 struct maildir_filename *mf)
+{
+	if (!ctx->locked_uidlist_refresh) {
+		(void)maildir_uidlist_refresh(ctx->mbox->uidlist);
+		ctx->locked_uidlist_refresh = TRUE;
+	}
+
+	if (maildir_uidlist_get_full_filename(ctx->mbox->uidlist,
+					      mf->dest_basename) != NULL) {
+		/* file already exists. give it another name. */
+		mf->dest_basename = p_strdup(ctx->pool,
+					     maildir_filename_generate());
+	}
+}
+
 static int
 maildir_save_move_files_to_newcur(struct maildir_save_context *ctx,
 				  struct maildir_filename **last_mf_r)
@@ -827,7 +844,10 @@
 		T_BEGIN {
 			const char *dest;
 
-			newdir = maildir_get_updated_filename(ctx, mf, &dest);
+			if (mf->preserve_filename)
+				maildir_filename_check_conflicts(ctx, mf);
+
+			newdir = maildir_get_dest_filename(ctx, mf, &dest);
 			if (newdir)
 				new_changed = TRUE;
 			else
@@ -860,7 +880,7 @@
 		bret = seq_range_array_iter_nth(&iter, n++, &uid);
 		i_assert(bret);
 
-		newdir = maildir_get_updated_filename(ctx, mf, &dest);
+		newdir = maildir_get_dest_filename(ctx, mf, &dest);
 		flags = MAILDIR_UIDLIST_REC_FLAG_RECENT;
 		if (newdir)
 			flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;


More information about the dovecot-cvs mailing list