dovecot-2.0: lib-storage: Mailbox deletion via trash directory w...

dovecot at dovecot.org dovecot at dovecot.org
Fri Apr 16 17:53:44 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/c2f00a85a177
changeset: 11167:c2f00a85a177
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Apr 16 17:53:41 2010 +0300
description:
lib-storage: Mailbox deletion via trash directory works now better with NFS.

diffstat:

 src/lib-storage/list/mailbox-list-delete.c |  49 ++++++++++++++++++++----
 1 files changed, 40 insertions(+), 9 deletions(-)

diffs (91 lines):

diff -r 960c6936ba6a -r c2f00a85a177 src/lib-storage/list/mailbox-list-delete.c
--- a/src/lib-storage/list/mailbox-list-delete.c	Fri Apr 16 17:23:43 2010 +0300
+++ b/src/lib-storage/list/mailbox-list-delete.c	Fri Apr 16 17:53:41 2010 +0300
@@ -2,6 +2,9 @@
 
 #include "lib.h"
 #include "str.h"
+#include "hex-binary.h"
+#include "hostpid.h"
+#include "randgen.h"
 #include "unlink-directory.h"
 #include "mailbox-list-private.h"
 #include "mailbox-list-delete.h"
@@ -32,11 +35,21 @@
 	return -1;
 }
 
+static const char *unique_fname(void)
+{
+	unsigned char randbuf[8];
+
+	random_fill_weak(randbuf, sizeof(randbuf));
+	return t_strdup_printf("%s.%s.%s", my_hostname, my_pid,
+			       binary_to_hex(randbuf, sizeof(randbuf)));
+
+}
+
 int mailbox_list_delete_maildir_via_trash(struct mailbox_list *list,
 					  const char *name,
 					  const char *trash_dir)
 {
-	const char *src;
+	const char *src, *trash_dest;
 	unsigned int count;
 
 	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -45,9 +58,15 @@
 
 	/* rename the mailbox dir to trash dir, which atomically
 	   marks it as being deleted. */
-	count = 0;
-	while (rename(src, trash_dir) < 0) {
+	count = 0; trash_dest = trash_dir;
+	for (; rename(src, trash_dest) < 0; count++) {
 		if (ENOTFOUND(errno)) {
+			if (trash_dest != trash_dir && count < 5) {
+				/* either the source was just deleted or
+				   the trash dir was deleted. */
+				trash_dest = trash_dir;
+				continue;
+			}
 			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 			return -1;
@@ -60,18 +79,30 @@
 			if (mailbox_list_set_error_from_errno(list))
 				return -1;
 			mailbox_list_set_critical(list,
-				"rename(%s, %s) failed: %m", src, trash_dir);
+				"rename(%s, %s) failed: %m", src, trash_dest);
 			return -1;
 		}
 
-		/* already existed, delete it and try again */
-		if (unlink_directory(trash_dir, TRUE) < 0 &&
-		    (errno != ENOTEMPTY || count >= 5)) {
+		/* trash dir already exists. the reasons for this are:
+
+		   a) another process is in the middle of deleting it
+		   b) previous process crashed and didn't delete it
+		   c) NFS: mailbox was recently deleted, but some connection
+		      still has that mailbox open. the directory contains .nfs*
+		      files that can't be deleted until the mailbox is closed.
+
+		   Because of c) we'll first try to rename the mailbox under
+		   the trash directory and only later try to delete the entire
+		   trash directory. */
+		if (trash_dir == trash_dest) {
+			trash_dest = t_strconcat(trash_dir, "/",
+						 unique_fname(), NULL);
+		} else if (unlink_directory(trash_dest, TRUE) < 0 &&
+			   (errno != ENOTEMPTY || count >= 5)) {
 			mailbox_list_set_critical(list,
-				"unlink_directory(%s) failed: %m", trash_dir);
+				"unlink_directory(%s) failed: %m", trash_dest);
 			return -1;
 		}
-		count++;
 	}
 
 	if (unlink_directory(trash_dir, TRUE) < 0 && errno != ENOTEMPTY) {


More information about the dovecot-cvs mailing list