]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Add mail_user_home_mkdir()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 24 Apr 2018 15:47:28 +0000 (18:47 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 24 Apr 2018 15:48:49 +0000 (18:48 +0300)
src/lib-storage/mail-user.c
src/lib-storage/mail-user.h

index 947e26cee4a9867d3a576f853cf979d887af9d0e..a15ed353ff97f03359fd939aac6c38a15518d4c8 100644 (file)
@@ -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"
@@ -716,6 +717,66 @@ void mail_user_stats_fill(struct mail_user *user, struct stats *stats)
        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_INDEX_CACHE,
+               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 }
index b97514df75cb1cdb4c8d8378d714430af39d3895..1627e34fe1843ee545db3ba06426ba9d30e8d568 100644 (file)
@@ -210,4 +210,9 @@ void mail_user_init_fs_settings(struct mail_user *user,
    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