]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
storage: Create index/control root directories using same permissions as mail root.
authorTimo Sirainen <tss@iki.fi>
Mon, 1 Jun 2009 01:26:00 +0000 (21:26 -0400)
committerTimo Sirainen <tss@iki.fi>
Mon, 1 Jun 2009 01:26:00 +0000 (21:26 -0400)
--HG--
branch : HEAD

src/lib-storage/index/index-storage.c
src/lib-storage/index/maildir/maildir-util.c
src/lib-storage/mailbox-list.c

index 9eaa887b75ce32328ba8638b75f26dba35c8d6ca..ba7340e86d2091cb56bf2159a57367d1486a4e33 100644 (file)
@@ -66,9 +66,10 @@ static void index_list_free(struct index_list *list)
 
 static int create_index_dir(struct mail_storage *storage, const char *name)
 {
-       const char *root_dir, *index_dir;
-       mode_t mode;
-       gid_t gid;
+       const char *root_dir, *index_dir, *p, *parent_dir;
+       mode_t mode, parent_mode;
+       gid_t gid, parent_gid;
+       int n = 0;
 
        root_dir = mailbox_list_get_path(storage->list, name,
                                         MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -78,13 +79,28 @@ static int create_index_dir(struct mail_storage *storage, const char *name)
                return 0;
 
        mailbox_list_get_dir_permissions(storage->list, name, &mode, &gid);
-       if (mkdir_parents_chown(index_dir, mode, (uid_t)-1, gid) < 0 &&
-           errno != EEXIST) {
-               mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
-                                         index_dir);
-               return -1;
-       }
+       while (mkdir_chown(index_dir, mode, (uid_t)-1, gid) < 0) {
+               if (errno == EEXIST)
+                       break;
 
+               p = strrchr(index_dir, '/');
+               if (errno != ENOENT || p == NULL || ++n == 2) {
+                       mail_storage_set_critical(storage,
+                               "mkdir(%s) failed: %m", index_dir);
+                       return -1;
+               }
+               /* create the parent directory first */
+               mailbox_list_get_dir_permissions(storage->list, NULL,
+                                                &parent_mode, &parent_gid);
+               parent_dir = t_strdup_until(index_dir, p);
+               if (mkdir_parents_chown(parent_dir, parent_mode,
+                                       (uid_t)-1, parent_gid) < 0 &&
+                   errno != EEXIST) {
+                       mail_storage_set_critical(storage,
+                               "mkdir(%s) failed: %m", parent_dir);
+                       return -1;
+               }
+       }
        return 0;
 }
 
index 0db32c912d19bbaae857e30ef12c0e5fa83c79e9..6646f5a834906f6e813a34d96acd330f95d875a6 100644 (file)
@@ -130,6 +130,45 @@ int maildir_file_do(struct maildir_mailbox *mbox, uint32_t uid,
        return ret == -2 ? 0 : ret;
 }
 
+static int maildir_create_path(struct mailbox *box, const char *path,
+                              bool is_mail_dir)
+{
+       const char *p, *parent;
+       mode_t parent_mode;
+       gid_t parent_gid;
+
+       if (mkdir_chown(path, box->dir_create_mode,
+                       (uid_t)-1, box->file_create_gid) == 0)
+               return 0;
+
+       switch (errno) {
+       case EEXIST:
+               return 0;
+       case ENOENT:
+               p = strrchr(path, '/');
+               if (is_mail_dir || p == NULL) {
+                       /* mailbox was being deleted just now */
+                       mailbox_set_deleted(box);
+                       return -1;
+               }
+               /* create index/control root directory */
+               parent = t_strdup_until(path, p);
+               mailbox_list_get_dir_permissions(box->storage->list, NULL,
+                                                &parent_mode, &parent_gid);
+               if (mkdir_parents_chown(parent, parent_mode, (uid_t)-1,
+                                       parent_gid) == 0 || errno == EEXIST) {
+                       /* should work now, try again */
+                       return maildir_create_path(box, path, TRUE);
+               }
+               /* fall through */
+               path = parent;
+       default:
+               mail_storage_set_critical(box->storage,
+                                         "mkdir(%s) failed: %m", path);
+               return -1;
+       }
+}
+
 static int maildir_create_subdirs(struct maildir_mailbox *mbox)
 {
        static const char *subdirs[] = { "cur", "new", "tmp" };
@@ -138,6 +177,7 @@ static int maildir_create_subdirs(struct maildir_mailbox *mbox)
        struct stat st;
        const char *path;
        unsigned int i;
+       bool is_mail_dir;
 
        /* @UNSAFE: get a list of directories we want to create */
        for (i = 0; i < N_ELEMENTS(subdirs); i++)
@@ -157,18 +197,9 @@ static int maildir_create_subdirs(struct maildir_mailbox *mbox)
                                                  "stat(%s) failed: %m", path);
                        break;
                }
-               if (mkdir_parents_chown(path, box->dir_create_mode,
-                                       (uid_t)-1, box->file_create_gid) < 0 &&
-                   errno != EEXIST) {
-                       if (errno == ENOENT) {
-                               /* mailbox was being deleted just now */
-                               mailbox_set_deleted(box);
-                               break;
-                       }
-                       mail_storage_set_critical(box->storage,
-                                                 "mkdir(%s) failed: %m", path);
+               is_mail_dir = i < N_ELEMENTS(subdirs);
+               if (maildir_create_path(box, path, is_mail_dir) < 0)
                        break;
-               }
        }
        return i == N_ELEMENTS(dirs) ? 0 : -1;
 }
index d4f1785616d02bf9d76871a9dfc43128be565f67..8eef12394013196583ad366d4ee626a34253982f 100644 (file)
@@ -293,18 +293,14 @@ mailbox_list_get_user(const struct mailbox_list *list)
        return list->ns->user;
 }
 
-void mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
-                                 mode_t *mode_r, gid_t *gid_r)
+static void
+mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
+                                 mode_t *file_mode_r, mode_t *dir_mode_r,
+                                 gid_t *gid_r)
 {
        const char *path;
        struct stat st;
 
-       if (list->file_create_mode != (mode_t)-1 && name == NULL) {
-               *mode_r = list->file_create_mode;
-               *gid_r = list->file_create_gid;
-               return;
-       }
-
        path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
        if (stat(path, &st) < 0) {
                if (!ENOTFOUND(errno)) {
@@ -315,35 +311,39 @@ void mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
                               list->ns->prefix, path);
                }
                /* return safe defaults */
-               list->file_create_mode = 0600;
-               list->dir_create_mode = 0700;
-               list->file_create_gid = (gid_t)-1;
+               *file_mode_r = 0600;
+               *dir_mode_r = 0700;
+               *gid_r = (gid_t)-1;
+       } else {
+               *file_mode_r = st.st_mode & 0666;
+               *dir_mode_r = st.st_mode & 0777;
 
-               *mode_r = list->file_create_mode;
-               *gid_r = list->file_create_gid;
-               return;
-       }
+               if (!S_ISDIR(st.st_mode)) {
+                       /* we're getting permissions from a file.
+                          apply +x modes as necessary. */
+                       *dir_mode_r = get_dir_mode(*dir_mode_r);
+               }
 
-       list->file_create_mode = st.st_mode & 0666;
-       list->dir_create_mode = st.st_mode & 0777;
-       if (!S_ISDIR(st.st_mode)) {
-               /* we're getting permissions from a file.
-                  apply +x modes as necessary. */
-               list->dir_create_mode = get_dir_mode(list->dir_create_mode);
+               if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
+                       /* directory's GID is used automatically for new
+                          files */
+                       *gid_r = (gid_t)-1;
+               } else if ((st.st_mode & 0070) == 0) {
+                       /* group doesn't have any permissions, so don't bother
+                          changing it */
+                       *gid_r = (gid_t)-1;
+               } else if (getegid() == st.st_gid) {
+                       /* using our own gid, no need to change it */
+                       *gid_r = (gid_t)-1;
+               } else {
+                       *gid_r = st.st_gid;
+               }
        }
 
-       if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
-               /* directory's GID is used automatically for new files */
-               list->file_create_gid = (gid_t)-1;
-       } else if ((st.st_mode & 0070) == 0) {
-               /* group doesn't have any permissions, so don't bother
-                  changing it */
-               list->file_create_gid = (gid_t)-1;
-       } else if (getegid() == st.st_gid) {
-               /* using our own gid, no need to change it */
-               list->file_create_gid = (gid_t)-1;
-       } else {
-               list->file_create_gid = st.st_gid;
+       if (name == NULL) {
+               list->file_create_mode = *file_mode_r;
+               list->dir_create_mode = *dir_mode_r;
+               list->file_create_gid = *gid_r;
        }
 
        if (list->mail_set->mail_debug && name == NULL) {
@@ -353,19 +353,36 @@ void mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
                       list->file_create_gid == (gid_t)-1 ? -1L :
                       (long)list->file_create_gid);
        }
+}
+
+void mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
+                                 mode_t *mode_r, gid_t *gid_r)
+{
+       mode_t dir_mode;
+
+       if (list->file_create_mode != (mode_t)-1 && name == NULL) {
+               *mode_r = list->file_create_mode;
+               *gid_r = list->file_create_gid;
+               return;
+       }
 
-       *mode_r = list->file_create_mode;
-       *gid_r = list->file_create_gid;
+       mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r);
 }
 
 void mailbox_list_get_dir_permissions(struct mailbox_list *list,
                                      const char *name,
                                      mode_t *mode_r, gid_t *gid_r)
 {
-       mode_t mode;
+       mode_t file_mode;
+
+       if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
+               *mode_r = list->dir_create_mode;
+               *gid_r = list->file_create_gid;
+               return;
+       }
 
-       mailbox_list_get_permissions(list, name, &mode, gid_r);
-       *mode_r = list->dir_create_mode;
+       mailbox_list_get_permissions_full(list, name, &file_mode,
+                                         mode_r, gid_r);
 }
 
 bool mailbox_list_is_valid_pattern(struct mailbox_list *list,