changeset 22302:55d796ab90d8

dbox: Check mailbox existence from index directory with ITERINDEX
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 26 Jun 2017 19:06:26 +0300
parents d86a691543b4
children 15823e373013
files src/lib-storage/index/dbox-common/dbox-storage.c
diffstat 1 files changed, 47 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/dbox-common/dbox-storage.c	Wed Jun 28 19:46:01 2017 +0300
+++ b/src/lib-storage/index/dbox-common/dbox-storage.c	Mon Jun 26 19:06:26 2017 +0300
@@ -15,6 +15,7 @@
 #include <stdio.h>
 #include <dirent.h>
 #include <unistd.h>
+#include <utime.h>
 
 void dbox_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
 				    struct mailbox_list_settings *set)
@@ -178,10 +179,25 @@
 		/* not the time to scan it yet */
 		return FALSE;
 	} else {
+		bool stated = FALSE;
+		if (last_change_time == (time_t)-1) {
+			/* Don't know the ctime yet - look it up. */
+			struct stat st;
+
+			if (stat(path, &st) < 0) {
+				if (errno == ENOENT)
+					i_error("stat(%s) failed: %m", path);
+				return FALSE;
+			}
+			last_change_time = st.st_ctime;
+			stated = TRUE;
+		}
 		if (last_scan_time > last_change_time + DBOX_TMP_DELETE_SECS) {
 			/* there haven't been any changes to this directory
-			   since we last checked it. */
-			return FALSE;
+			   since we last checked it. If we did an extra stat(),
+			   we need to update the last_scan_time to avoid
+			   stat()ing the next time. */
+			return stated;
 		}
 		const char *prefix =
 			mailbox_list_get_global_temp_prefix(list);
@@ -189,15 +205,41 @@
 				       ioloop_time - DBOX_TMP_DELETE_SECS);
 		return TRUE;
 	}
+	return FALSE;
 }
 
 int dbox_mailbox_check_existence(struct mailbox *box, time_t *path_ctime_r)
 {
-	const char *box_path = mailbox_get_path(box);
+	const char *index_path, *box_path = mailbox_get_path(box);
 	struct stat st;
+	int ret = -1;
+
+	*path_ctime_r = (time_t)-1;
 
-	if (stat(box_path, &st) == 0) {
-		*path_ctime_r = st.st_ctime;
+	if (box->list->set.iter_from_index_dir) {
+		/* Just because the index directory exists, it doesn't mean
+		   that the mailbox is selectable. Check that by seeing if
+		   dovecot.index.log exists. If it doesn't, fallback to
+		   checking for the dbox-Mails in the mail root directory.
+		   So this also means that if a mailbox is \NoSelect, listing
+		   it will always do a stat() for dbox-Mails in the mail root
+		   directory. That's not ideal, but this makes the behavior
+		   safer and \NoSelect mailboxes are somewhat rare. */
+		if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX,
+					&index_path) < 0)
+			return -1;
+		i_assert(index_path != NULL);
+		index_path = t_strconcat(index_path, "/", box->index_prefix,
+					 ".log", NULL);
+		ret = stat(index_path, &st);
+	}
+	if (ret < 0) {
+		ret = stat(box_path, &st);
+		if (ret == 0)
+			*path_ctime_r = st.st_ctime;
+	}
+
+	if (ret == 0) {
 		return 0;
 	} else if (errno == ENOENT || errno == ENAMETOOLONG) {
 		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,