*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/* Mar 5, 2003 Manuel Novoa III
int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
{
- mode_t mask;
+ mode_t cur_mask;
+ mode_t org_mask;
const char *fail_msg;
- char *s = path;
+ char *s;
char c;
struct stat st;
- mask = umask(0);
- if (mode == -1) {
- umask(mask);
- mode = (S_IXUSR | S_IXGRP | S_IXOTH |
- S_IWUSR | S_IWGRP | S_IWOTH |
- S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
- } else {
- umask(mask & ~0300);
- }
+ /* Happens on bb_make_directory(dirname("no_slashes"),...) */
+ if (LONE_CHAR(path, '.'))
+ return 0;
- do {
- c = 0;
+ org_mask = cur_mask = (mode_t)-1L;
+ s = path;
+ while (1) {
+ c = '\0';
- if (flags & FILEUTILS_RECUR) { /* Get the parent. */
- /* Bypass leading non-'/'s and then subsequent '/'s. */
+ if (flags & FILEUTILS_RECUR) { /* Get the parent */
+ /* Bypass leading non-'/'s and then subsequent '/'s */
while (*s) {
if (*s == '/') {
do {
++s;
} while (*s == '/');
- c = *s; /* Save the current char */
- *s = 0; /* and replace it with nul. */
+ c = *s; /* Save the current char */
+ *s = '\0'; /* and replace it with nul */
break;
}
++s;
}
}
+ if (c != '\0') {
+ /* Intermediate dirs: must have wx for user */
+ if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */
+ mode_t new_mask;
+ org_mask = umask(0);
+ cur_mask = 0;
+ /* Clear u=wx in umask - this ensures
+ * they won't be cleared on mkdir */
+ new_mask = (org_mask & ~(mode_t)0300);
+ //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask);
+ if (new_mask != cur_mask) {
+ cur_mask = new_mask;
+ umask(new_mask);
+ }
+ }
+ } else {
+ /* Last component: uses original umask */
+ //bb_error_msg("1 org_mask:%o", org_mask);
+ if (org_mask != cur_mask) {
+ cur_mask = org_mask;
+ umask(org_mask);
+ }
+ }
+
if (mkdir(path, 0777) < 0) {
/* If we failed for any other reason than the directory
- * already exists, output a diagnostic and return -1.*/
- if (errno != EEXIST
- || !(flags & FILEUTILS_RECUR)
- || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
+ * already exists, output a diagnostic and return -1 */
+ if ((errno != EEXIST && errno != EISDIR)
+ || !(flags & FILEUTILS_RECUR)
+ || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode))
+ ) {
fail_msg = "create";
- umask(mask);
break;
}
/* Since the directory exists, don't attempt to change
* permissions if it was the full target. Note that
- * this is not an error conditon. */
+ * this is not an error condition. */
if (!c) {
- umask(mask);
- return 0;
+ goto ret0;
}
}
if (!c) {
- /* Done. If necessary, updated perms on the newly
+ /* Done. If necessary, update perms on the newly
* created directory. Failure to update here _is_
- * an error.*/
- umask(mask);
- if ((mode != -1) && (chmod(path, mode) < 0)){
+ * an error. */
+ if ((mode != -1) && (chmod(path, mode) < 0)) {
fail_msg = "set permissions of";
+ if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
+ flags = 0;
+ goto print_err;
+ }
break;
}
- return 0;
+ goto ret0;
}
- /* Remove any inserted nul from the path (recursive mode). */
+ /* Remove any inserted nul from the path (recursive mode) */
*s = c;
+ } /* while (1) */
- } while (1);
-
- bb_perror_msg("cannot %s directory '%s'", fail_msg, path);
- return -1;
+ flags = -1;
+ print_err:
+ bb_perror_msg("can't %s directory '%s'", fail_msg, path);
+ goto ret;
+ ret0:
+ flags = 0;
+ ret:
+ //bb_error_msg("2 org_mask:%o", org_mask);
+ if (org_mask != cur_mask)
+ umask(org_mask);
+ return flags;
}