*
* 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);
- umask(mask & ~0300); /* Ensure intermediate dirs are wx */
+ /* Happens on bb_make_directory(dirname("no_slashes"),...) */
+ if (LONE_CHAR(path, '.'))
+ return 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. */
+ *s = '\0'; /* and replace it with nul */
break;
}
++s;
}
}
- if (!c) /* Last component uses orig umask */
- umask(mask);
+ 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
+ * 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;
}
}
* 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) */
- 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;
}