changeset 22919:2b16e07f8312

lib-storage: Add mail_user_home_mkdir()
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 24 Apr 2018 18:47:28 +0300
parents 6ca30380a3f5
children 02aed723d139
files src/lib-storage/mail-user.c src/lib-storage/mail-user.h
diffstat 2 files changed, 65 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/mail-user.c	Wed Apr 25 17:45:39 2018 +0300
+++ b/src/lib-storage/mail-user.c	Tue Apr 24 18:47:28 2018 +0300
@@ -8,6 +8,7 @@
 #include "module-dir.h"
 #include "home-expand.h"
 #include "file-create-locked.h"
+#include "mkdir-parents.h"
 #include "safe-mkstemp.h"
 #include "str.h"
 #include "strescape.h"
@@ -654,6 +655,65 @@
 	user->v.stats_fill(user, stats);
 }
 
+static int
+mail_user_home_mkdir_try_ns(struct mail_namespace *ns, const char *home)
+{
+	const enum mailbox_list_path_type types[] = {
+		MAILBOX_LIST_PATH_TYPE_DIR,
+		MAILBOX_LIST_PATH_TYPE_ALT_DIR,
+		MAILBOX_LIST_PATH_TYPE_CONTROL,
+		MAILBOX_LIST_PATH_TYPE_INDEX,
+		MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
+		MAILBOX_LIST_PATH_TYPE_LIST_INDEX,
+	};
+	size_t home_len = strlen(home);
+	const char *path;
+
+	for (unsigned int i = 0; i < N_ELEMENTS(types); i++) {
+		if (!mailbox_list_get_root_path(ns->list, types[i], &path))
+			continue;
+		if (strncmp(path, home, home_len) == 0 &&
+		    (path[home_len] == '\0' || path[home_len] == '/')) {
+			return mailbox_list_mkdir_root(ns->list, path,
+						       types[i]) < 0 ? -1 : 1;
+		}
+	}
+	return 0;
+}
+
+int mail_user_home_mkdir(struct mail_user *user)
+{
+	struct mail_namespace *ns;
+	const char *home;
+	int ret;
+
+	if (mail_user_get_home(user, &home) < 0)
+		return -1;
+
+	/* Try to create the home directory by creating the root directory for
+	   a namespace that exists under the home. This way we end up in the
+	   special mkdir() code in mailbox_list_try_mkdir_root_parent().
+	   Start from INBOX, since that's usually the correct place. */
+	ns = mail_namespace_find_inbox(user->namespaces);
+	if ((ret = mail_user_home_mkdir_try_ns(ns, home)) != 0)
+		return ret < 0 ? -1 : 0;
+	/* try other namespaces */
+	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
+		if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
+			/* already tried the INBOX namespace */
+			continue;
+		}
+		if ((ret = mail_user_home_mkdir_try_ns(ns, home)) != 0)
+			return ret < 0 ? -1 : 0;
+	}
+	/* fallback to a safe mkdir() with 0700 mode */
+	if (mkdir_parents(home, 0700) < 0 && errno != EEXIST) {
+		i_error("mkdir_parents(%s) failed: %m", home);
+		return -1;
+	}
+	return 0;
+}
+
 static const struct var_expand_func_table mail_user_var_expand_func_table_arr[] = {
 	{ "userdb", mail_user_var_expand_func_userdb },
 	{ NULL, NULL }
--- a/src/lib-storage/mail-user.h	Wed Apr 25 17:45:39 2018 +0300
+++ b/src/lib-storage/mail-user.h	Tue Apr 24 18:47:28 2018 +0300
@@ -196,4 +196,9 @@
    plugin must be loaded to have anything filled. */
 void mail_user_stats_fill(struct mail_user *user, struct stats *stats);
 
+/* Try to mkdir() user's home directory. Ideally this should be called only
+   after the caller tries to create a file to the home directory, but it fails
+   with ENOENT. This way it avoids unnecessary disk IO to the home. */
+int mail_user_home_mkdir(struct mail_user *user);
+
 #endif