changeset 4960:4714befe2604 HEAD

Added maildir_copy_preserve_filename setting.
author Timo Sirainen <timo.sirainen@movial.fi>
date Fri, 22 Dec 2006 16:20:36 +0200
parents 4ba6b31ae15e
children e13de4a0bf90
files dovecot-example.conf src/lib-storage/index/maildir/maildir-copy.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-uidlist.h src/master/mail-process.c src/master/master-settings.c src/master/master-settings.h
diffstat 9 files changed, 64 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Fri Dec 22 01:54:17 2006 +0200
+++ b/dovecot-example.conf	Fri Dec 22 16:20:36 2006 +0200
@@ -409,6 +409,14 @@
 # the performance much better, and it's unlikely to have any side effects.
 #maildir_copy_with_hardlinks = no
 
+# When copying a message, try to preserve the base filename. Only if the
+# destination mailbox already contains the same name (ie. the mail is being
+# copied there twice), a new name is given. The destination filename check is
+# done only by looking at dovecot-uidlist file, so if something outside
+# Dovecot does similar filename preserving copies, you may run into problems.
+# NOTE: This setting requires maildir_copy_with_hardlinks = yes to work.
+#maildir_copy_preserve_filename = no
+
 ##
 ## mbox-specific settings
 ##
--- a/src/lib-storage/index/maildir/maildir-copy.c	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-copy.c	Fri Dec 22 16:20:36 2006 +0200
@@ -22,6 +22,7 @@
 
 	unsigned int size_set:1;
 	unsigned int success:1;
+	unsigned int preserve_filename:1;
 };
 
 static int do_save_mail_size(struct maildir_mailbox *mbox, const char *path,
@@ -59,7 +60,8 @@
 {
 	int ret;
 
-	if (mbox->storage->save_size_in_filename && !ctx->size_set) {
+	if (!ctx->preserve_filename && mbox->storage->save_size_in_filename &&
+	    !ctx->size_set) {
 		if ((ret = do_save_mail_size(mbox, path, ctx)) <= 0)
 			return ret;
 	}
@@ -73,7 +75,11 @@
 					       "Not enough disk space");
 			return -1;
 		}
-		if (errno == EACCES || ECANTLINK(errno))
+
+		/* we could handle the EEXIST condition by changing the
+		   filename, but it practically never happens so just fallback
+		   to standard copying for the rare cases when it does. */
+		if (errno == EACCES || ECANTLINK(errno) || errno == EEXIST)
 			return 1;
 
 		mail_storage_set_critical(STORAGE(mbox->storage),
@@ -97,6 +103,7 @@
 		(struct maildir_mailbox *)mail->box;
 	struct maildir_save_context *ctx;
 	struct hardlink_ctx do_ctx;
+	const char *filename = NULL;
 	uint32_t seq;
 
 	i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
@@ -113,9 +120,31 @@
 	memset(&do_ctx, 0, sizeof(do_ctx));
 	do_ctx.dest_path = str_new(default_pool, 512);
 
-	/* the generated filename is _always_ unique, so we don't bother
-	   trying to check if it already exists */
-	do_ctx.dest_fname = maildir_generate_tmp_filename(&ioloop_timeval);
+	if (dest_mbox->storage->copy_preserve_filename) {
+		enum maildir_uidlist_rec_flag src_flags;
+		const char *src_fname;
+
+		/* see if the filename exists in destination maildir's
+		   uidlist. if it doesn't, we can use it. otherwise generate
+		   a new filename */
+		src_fname = maildir_uidlist_lookup(src_mbox->uidlist,
+						   mail->uid, &src_flags);
+		if (src_fname != NULL &&
+		    maildir_uidlist_update(dest_mbox->uidlist) >= 0 &&
+		    maildir_uidlist_get_full_filename(dest_mbox->uidlist,
+						      src_fname) == NULL)
+			filename = t_strcut(src_fname, ':');
+	}
+	if (filename == NULL) {
+		/* the generated filename is _always_ unique, so we don't
+		   bother trying to check if it already exists */
+		do_ctx.dest_fname =
+			maildir_generate_tmp_filename(&ioloop_timeval);
+	} else {
+		do_ctx.dest_fname = filename;
+		do_ctx.preserve_filename = TRUE;
+	}
+
 	if (keywords == NULL || keywords->count == 0) {
 		/* no keywords, hardlink directly to destination */
 		if (flags == MAIL_RECENT) {
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Fri Dec 22 16:20:36 2006 +0200
@@ -177,6 +177,8 @@
 
 	storage->copy_with_hardlinks =
 		getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
+	storage->copy_preserve_filename =
+		getenv("MAILDIR_COPY_PRESERVE_FILENAME") != NULL;
 	storage->stat_dirs = getenv("MAILDIR_STAT_DIRS") != NULL;
 
 	storage->temp_prefix = mailbox_list_get_temp_prefix(list);
--- a/src/lib-storage/index/maildir/maildir-storage.h	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Fri Dec 22 16:20:36 2006 +0200
@@ -49,6 +49,7 @@
 	const char *temp_prefix;
 
 	unsigned int copy_with_hardlinks:1;
+	unsigned int copy_preserve_filename:1;
 	unsigned int save_size_in_filename:1;
 	unsigned int stat_dirs:1;
 };
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Dec 22 16:20:36 2006 +0200
@@ -813,6 +813,16 @@
 	return rec == NULL ? NULL : rec->filename;
 }
 
+const char *
+maildir_uidlist_get_full_filename(struct maildir_uidlist *uidlist,
+				  const char *filename)
+{
+	struct maildir_uidlist_rec *rec;
+
+	rec = hash_lookup(uidlist->files, filename);
+	return rec == NULL ? NULL : rec->filename;
+}
+
 static int maildir_time_cmp(const void *p1, const void *p2)
 {
 	const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Dec 22 16:20:36 2006 +0200
@@ -55,6 +55,10 @@
 void maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx);
 int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx **ctx);
 
+const char *
+maildir_uidlist_get_full_filename(struct maildir_uidlist *uidlist,
+				  const char *filename);
+
 void maildir_uidlist_add_flags(struct maildir_uidlist *uidlist,
 			       const char *filename,
 			       enum maildir_uidlist_rec_flag flags);
--- a/src/master/mail-process.c	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/master/mail-process.c	Fri Dec 22 16:20:36 2006 +0200
@@ -235,6 +235,8 @@
 		env_put("MAILDIR_STAT_DIRS=1");
 	if (set->maildir_copy_with_hardlinks)
 		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
+	if (set->maildir_copy_preserve_filename)
+		env_put("MAILDIR_COPY_PRESERVE_FILENAME=1");
 	if (set->mail_debug)
 		env_put("DEBUG=1");
 	if (set->mail_full_filesystem_access)
--- a/src/master/master-settings.c	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/master/master-settings.c	Fri Dec 22 16:20:36 2006 +0200
@@ -125,6 +125,7 @@
 	DEF(SET_STR, lock_method),
 	DEF(SET_BOOL, maildir_stat_dirs),
 	DEF(SET_BOOL, maildir_copy_with_hardlinks),
+	DEF(SET_BOOL, maildir_copy_preserve_filename),
 	DEF(SET_STR, mbox_read_locks),
 	DEF(SET_STR, mbox_write_locks),
 	DEF(SET_INT, mbox_lock_timeout),
@@ -338,6 +339,7 @@
 	MEMBER(lock_method) "fcntl",
 	MEMBER(maildir_stat_dirs) FALSE,
 	MEMBER(maildir_copy_with_hardlinks) FALSE,
+	MEMBER(maildir_copy_preserve_filename) FALSE,
 	MEMBER(mbox_read_locks) "fcntl",
 	MEMBER(mbox_write_locks) "dotlock fcntl",
 	MEMBER(mbox_lock_timeout) 300,
--- a/src/master/master-settings.h	Fri Dec 22 01:54:17 2006 +0200
+++ b/src/master/master-settings.h	Fri Dec 22 16:20:36 2006 +0200
@@ -84,6 +84,7 @@
 	const char *lock_method;
 	bool maildir_stat_dirs;
 	bool maildir_copy_with_hardlinks;
+	bool maildir_copy_preserve_filename;
 	const char *mbox_read_locks;
 	const char *mbox_write_locks;
 	unsigned int mbox_lock_timeout;