# HG changeset patch # User Timo Sirainen # Date 1243819560 14400 # Node ID 2f2a907f11320251437bbb5b70364d795ff051bc # Parent 3870069faea34018eeccf1af3cdf0df93d5046a0 storage: Create index/control root directories using same permissions as mail root. diff -r 3870069faea3 -r 2f2a907f1132 src/lib-storage/index/index-storage.c --- a/src/lib-storage/index/index-storage.c Sun May 31 21:24:50 2009 -0400 +++ b/src/lib-storage/index/index-storage.c Sun May 31 21:26:00 2009 -0400 @@ -69,9 +69,10 @@ 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); @@ -81,13 +82,28 @@ 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; } diff -r 3870069faea3 -r 2f2a907f1132 src/lib-storage/index/maildir/maildir-util.c --- a/src/lib-storage/index/maildir/maildir-util.c Sun May 31 21:24:50 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-util.c Sun May 31 21:26:00 2009 -0400 @@ -130,6 +130,45 @@ 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 @@ 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 @@ "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; } diff -r 3870069faea3 -r 2f2a907f1132 src/lib-storage/mailbox-list.c --- a/src/lib-storage/mailbox-list.c Sun May 31 21:24:50 2009 -0400 +++ b/src/lib-storage/mailbox-list.c Sun May 31 21:26:00 2009 -0400 @@ -283,18 +283,14 @@ return mode; } -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)) { @@ -305,35 +301,39 @@ 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; + + 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); + } - *mode_r = list->file_create_mode; - *gid_r = list->file_create_gid; - return; + 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; + } } - 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 */ - 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->flags & MAILBOX_LIST_FLAG_DEBUG) != 0 && name == NULL) { @@ -343,19 +343,36 @@ list->file_create_gid == (gid_t)-1 ? -1L : (long)list->file_create_gid); } +} - *mode_r = list->file_create_mode; - *gid_r = 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; + } + + 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; - mailbox_list_get_permissions(list, name, &mode, gid_r); - *mode_r = list->dir_create_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_full(list, name, &file_mode, + mode_r, gid_r); } bool mailbox_list_is_valid_pattern(struct mailbox_list *list,