dovecot-2.0: lib-storage: Fill mailbox log with mailbox delete/r...

dovecot at dovecot.org dovecot at dovecot.org
Thu Aug 6 03:30:53 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/fd534ee2c08e
changeset: 9733:fd534ee2c08e
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Aug 05 20:29:24 2009 -0400
description:
lib-storage: Fill mailbox log with mailbox delete/rename/(un)subscribes.

diffstat:

4 files changed, 164 insertions(+), 57 deletions(-)
src/lib-storage/index/maildir/maildir-storage.c |  147 ++++++++++++++---------
src/lib-storage/mailbox-list-private.h          |    9 +
src/lib-storage/mailbox-list.c                  |   62 +++++++++
src/lib-storage/mailbox-list.h                  |    3 

diffs (truncated from 347 to 300 lines):

diff -r d21f2f0b1e11 -r fd534ee2c08e src/lib-storage/index/maildir/maildir-storage.c
--- a/src/lib-storage/index/maildir/maildir-storage.c	Wed Aug 05 20:28:50 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Wed Aug 05 20:29:24 2009 -0400
@@ -9,6 +9,7 @@
 #include "eacces-error.h"
 #include "unlink-directory.h"
 #include "unlink-old-files.h"
+#include "mailbox-log.h"
 #include "mailbox-uidvalidity.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
@@ -710,60 +711,10 @@ maildir_delete_nonrecursive(struct mailb
 }
 
 static int
-maildir_list_delete_mailbox(struct mailbox_list *list, const char *name)
-{
-	union mailbox_list_module_context *mlist = MAILDIR_LIST_CONTEXT(list);
-	struct stat st;
-	const char *src, *dest, *base;
-	int count;
-
-	/* Make sure the indexes are closed before trying to delete the
-	   directory that contains them. It can still fail with some NFS
-	   implementations if indexes are opened by another session, but
-	   that can't really be helped. */
-	index_storage_destroy_unrefed();
-
-	/* delete the index and control directories */
-	if (mlist->super.delete_mailbox(list, name) < 0)
-		return -1;
-
-	/* check if the mailbox actually exists */
-	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
-	if (lstat(src, &st) != 0 && errno == ENOENT) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
-			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
-		return -1;
-	}
-
-	if (!S_ISDIR(st.st_mode)) {
-		/* a symlink most likely */
-		if (unlink(src) < 0 && errno != ENOENT) {
-			mailbox_list_set_critical(list,
-				"unlink(%s) failed: %m", src);
-			return -1;
-		}
-		return 0;
-	}
-
-	if (strcmp(name, "INBOX") == 0) {
-		/* we shouldn't get this far if this is the actual INBOX.
-		   more likely we're just deleting a namespace/INBOX.
-		   be anyway sure that we don't accidentally delete the entire
-		   maildir (INBOX explicitly configured to maildir root). */
-		base = mailbox_list_get_path(list, NULL,
-					     MAILBOX_LIST_PATH_TYPE_MAILBOX);
-		if (strcmp(base, src) == 0) {
-			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
-					       "INBOX can't be deleted.");
-			return -1;
-		}
-	}
-
-	dest = maildir_get_unlink_dest(list, name);
-	if (dest == NULL) {
-		/* delete the directory directly without any renaming */
-		return maildir_delete_nonrecursive(list, src, name);
-	}
+maildir_delete_with_trash(struct mailbox_list *list, const char *src,
+			  const char *dest, const char *name)
+{
+	unsigned int count;
 
 	/* rename the .maildir into ..DOVECOT-TRASH which atomically
 	   marks it as being deleted. If we die before deleting the
@@ -801,6 +752,94 @@ maildir_list_delete_mailbox(struct mailb
 		/* it's already renamed to ..dir, which means it's
 		   deleted as far as the client is concerned. Report
 		   success. */
+	}
+	return 0;
+}
+
+static void mailbox_get_guid(struct mailbox_list *list, const char *name,
+			     uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
+{
+	struct mailbox *box;
+	struct mailbox_status status;
+
+	box = mailbox_alloc(list, name, NULL, MAILBOX_FLAG_KEEP_RECENT);
+	if (mailbox_open(box) < 0)
+		memset(mailbox_guid, 0, MAIL_GUID_128_SIZE);
+	else {
+		mailbox_get_status(box, STATUS_GUID, &status);
+		memcpy(mailbox_guid, status.mailbox_guid, MAIL_GUID_128_SIZE);
+	}
+	mailbox_close(&box);
+}
+
+static int
+maildir_list_delete_mailbox(struct mailbox_list *list, const char *name)
+{
+	union mailbox_list_module_context *mlist = MAILDIR_LIST_CONTEXT(list);
+	uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
+	uint8_t dir_guid[MAIL_GUID_128_SIZE];
+	struct stat st;
+	const char *src, *dest, *base;
+	int ret;
+
+	mailbox_get_guid(list, name, mailbox_guid);
+	(void)mailbox_list_get_guid(list, name, dir_guid);
+
+	/* Make sure the indexes are closed before trying to delete the
+	   directory that contains them. It can still fail with some NFS
+	   implementations if indexes are opened by another session, but
+	   that can't really be helped. */
+	index_storage_destroy_unrefed();
+
+	/* delete the index and control directories */
+	if (mlist->super.delete_mailbox(list, name) < 0)
+		return -1;
+
+	/* check if the mailbox actually exists */
+	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
+	if (lstat(src, &st) != 0 && errno == ENOENT) {
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+		return -1;
+	}
+
+	if (!S_ISDIR(st.st_mode)) {
+		/* a symlink most likely */
+		if (unlink(src) < 0 && errno != ENOENT) {
+			mailbox_list_set_critical(list,
+				"unlink(%s) failed: %m", src);
+			return -1;
+		}
+		return 0;
+	}
+
+	if (strcmp(name, "INBOX") == 0) {
+		/* we shouldn't get this far if this is the actual INBOX.
+		   more likely we're just deleting a namespace/INBOX.
+		   be anyway sure that we don't accidentally delete the entire
+		   maildir (INBOX explicitly configured to maildir root). */
+		base = mailbox_list_get_path(list, NULL,
+					     MAILBOX_LIST_PATH_TYPE_MAILBOX);
+		if (strcmp(base, src) == 0) {
+			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+					       "INBOX can't be deleted.");
+			return -1;
+		}
+	}
+
+	dest = maildir_get_unlink_dest(list, name);
+	if (dest == NULL) {
+		/* delete the directory directly without any renaming */
+		ret = maildir_delete_nonrecursive(list, src, name);
+	} else {
+		ret = maildir_delete_with_trash(list, src, dest, name);
+	}
+
+	if (ret == 0) {
+		mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_MAILBOX,
+					mailbox_guid);
+		mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_DIR,
+					dir_guid);
 	}
 	return 0;
 }
diff -r d21f2f0b1e11 -r fd534ee2c08e src/lib-storage/mailbox-list-private.h
--- a/src/lib-storage/mailbox-list-private.h	Wed Aug 05 20:28:50 2009 -0400
+++ b/src/lib-storage/mailbox-list-private.h	Wed Aug 05 20:29:24 2009 -0400
@@ -9,6 +9,9 @@
 #define MAILBOX_LIST_NAME_IMAPDIR "imapdir"
 #define MAILBOX_LIST_NAME_FS "fs"
 
+#define MAILBOX_LOG_FILE_NAME "dovecot.mailbox.log"
+
+enum mailbox_log_record_type;
 struct dirent;
 struct imap_match_glob;
 struct mailbox_tree_context;
@@ -95,6 +98,8 @@ struct mailbox_list {
 	/* origin (e.g. path) where the file_create_gid was got from */
 	const char *file_create_gid_origin;
 
+	struct mailbox_log *changelog;
+
 	char *error_string;
 	enum mail_error error;
 	bool temporary_error;
@@ -144,6 +149,10 @@ bool mailbox_list_try_get_absolute_path(
 bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
 					const char **name);
 
+void mailbox_list_add_change(struct mailbox_list *list,
+			     enum mailbox_log_record_type type,
+			     const uint8_t mailbox_guid[MAIL_GUID_128_SIZE]);
+
 void mailbox_list_clear_error(struct mailbox_list *list);
 void mailbox_list_set_error(struct mailbox_list *list,
 			    enum mail_error error, const char *string);
diff -r d21f2f0b1e11 -r fd534ee2c08e src/lib-storage/mailbox-list.c
--- a/src/lib-storage/mailbox-list.c	Wed Aug 05 20:28:50 2009 -0400
+++ b/src/lib-storage/mailbox-list.c	Wed Aug 05 20:29:24 2009 -0400
@@ -5,10 +5,17 @@
 #include "ioloop.h"
 #include "mkdir-parents.h"
 #include "str.h"
+#include "sha1.h"
 #include "home-expand.h"
+#include "close-keep-errno.h"
+#include "eacces-error.h"
+#include "read-full.h"
+#include "write-full.h"
+#include "safe-mkstemp.h"
 #include "unlink-directory.h"
 #include "imap-match.h"
 #include "imap-utf7.h"
+#include "mailbox-log.h"
 #include "mailbox-tree.h"
 #include "mail-storage-private.h"
 #include "mailbox-list-private.h"
@@ -94,6 +101,7 @@ int mailbox_list_create(const char *driv
 {
 	const struct mailbox_list *const *class_p;
 	struct mailbox_list *list;
+	const char *path;
 	unsigned int idx;
 
 	i_assert(ns->list == NULL);
@@ -161,6 +169,12 @@ int mailbox_list_create(const char *driv
 	}
 
 	mail_namespace_finish_list_init(ns, list);
+
+	path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
+	if (path != NULL) {
+		path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
+		list->changelog = mailbox_log_alloc(path);
+	}
 
 	if (hook_mailbox_list_created != NULL)
 		hook_mailbox_list_created(list);
@@ -281,6 +295,8 @@ void mailbox_list_destroy(struct mailbox
 	*_list = NULL;
 	i_free_and_null(list->error_string);
 
+	if (list->changelog != NULL)
+		mailbox_log_free(&list->changelog);
 	list->v.deinit(list);
 }
 
@@ -661,12 +677,42 @@ int mailbox_list_mailbox(struct mailbox_
 				       flags_r);
 }
 
+void mailbox_list_add_change(struct mailbox_list *list,
+			     enum mailbox_log_record_type type,
+			     const uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
+{
+	struct mailbox_log_record rec;
+
+	if (list->changelog == NULL || mail_guid_128_is_empty(mailbox_guid))
+		return;
+
+	memset(&rec, 0, sizeof(rec));
+	rec.type = type;
+	memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
+	mailbox_log_record_set_timestamp(&rec, ioloop_time);
+	(void)mailbox_log_append(list->changelog, &rec);
+}
+
 int mailbox_list_set_subscribed(struct mailbox_list *list,
 				const char *name, bool set)
 {
+	uint8_t guid[MAIL_GUID_128_SIZE];
+	unsigned char sha[SHA1_RESULTLEN];
+
 	mailbox_list_clear_error(list);
 
-	return list->v.set_subscribed(list, name, set);
+	if (list->v.set_subscribed(list, name, set) < 0)
+		return -1;
+
+	/* subscriptions are about names, not about mailboxes. it's possible
+	   to have a subscription to non-existing mailbox. renames also don't
+	   change subscriptions. so instead of using actual GUIDs, we'll use
+	   hash of the name. */
+	sha1_get_digest(name, strlen(name), sha);
+	memcpy(guid, sha, I_MIN(sizeof(guid), sizeof(sha)));
+	mailbox_list_add_change(list, set ? MAILBOX_LOG_RECORD_SUBSCRIBE :
+				MAILBOX_LOG_RECORD_UNSUBSCRIBE, guid);
+	return 0;
 }
 
 int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
@@ -697,6 +743,7 @@ int mailbox_list_rename_mailbox(struct m


More information about the dovecot-cvs mailing list