Hi all, "mkdir -m mode -p /some/directory" calls chmod() on /some/directory even if it already exists, effectively changing the mode. POSIX specifies that this mode may only be applied to newly created directories. Patch attached. Please look at the URLs referenced in the patch for further information.
Thanks, Alex
--- bin/mkdir/mkdir.c 2006-10-10 13:58:53.000000000 +0200 +++ bin/mkdir/mkdir.c 2006-10-10 15:09:32.000000000 +0200 @@ -61,12 +61,12 @@ int main(int argc, char *argv[]) { - int ch, exitval, success, pflag; + int ch, exitval, success, pflag, olddirflag; mode_t omode; void *set = NULL; char *mode; - omode = pflag = 0; + omode = pflag = olddirflag = 0; mode = NULL; while ((ch = getopt(argc, argv, "m:pv")) != -1) switch(ch) { @@ -101,8 +101,11 @@ for (exitval = 0; *argv != NULL; ++argv) { success = 1; if (pflag) { - if (build(*argv, omode)) - success = 0; + if ((success = build(*argv, omode)) == 2) { + /* the directory existed */ + olddirflag = 1; + success = 1; + } } else if (mkdir(*argv, omode) < 0) { if (errno == ENOTDIR || errno == ENOENT) warn("%s", dirname(*argv)); @@ -120,8 +123,16 @@ * sticky, setuid, setgid bits you lose them. Don't do * this unless the user has specifically requested a mode, * as chmod will (obviously) ignore the umask. + * + * Do this only on _newly-created_ directories, not those + * already existing. See -m option for mkdir in: + * + * http://www.opengroup.org/onlinepubs/009695399/utilities/mkdir.html + * + * Read http://lists.gnu.org/archive/html/bug-autoconf/2006-10/msg00012.html + * mailing list thread for further details. */ - if (success && mode != NULL && chmod(*argv, omode) == -1) { + if (success && mode != NULL && !olddirflag && chmod(*argv, omode) == -1) { warn("%s", *argv); exitval = 1; } @@ -129,6 +140,17 @@ exit(exitval); } +/* + * The build() function returns 0 when failed, + * 1 on success, and 2 when the target directory + * did already exist. + * + * This is because we need to differentiate the + * cases in which the directory has been created + * from those in which it hasn't to provide + * POSIX compliance when specifying a mode. + */ + int build(char *path, mode_t omode) { @@ -139,7 +161,7 @@ p = path; oumask = 0; - retval = 0; + retval = 1; if (p[0] == '/') /* Skip leading '/'. */ ++p; for (first = 1, last = 0; !last ; ++p) { @@ -174,7 +196,7 @@ if (errno == EEXIST || errno == EISDIR) { if (stat(path, &sb) < 0) { warn("%s", path); - retval = 1; + retval = 0; break; } else if (!S_ISDIR(sb.st_mode)) { if (last) @@ -182,12 +204,15 @@ else errno = ENOTDIR; warn("%s", path); - retval = 1; + retval = 0; break; } + /* It's a directory, and we didn't create it */ + if (last) + retval = 2; } else { warn("%s", path); - retval = 1; + retval = 0; break; } } else if (vflag)
_______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"