Date: Tue, 10 Oct 2006 15:24:14 +0200 From: "Alex Unleashed" <unledev@gmail.com> To: freebsd-hackers@freebsd.org Subject: mkdir -m option POSIX compliance Message-ID: <5e4707340610100624j38ce9f8du7741bd027eb8cb1b@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
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
[-- Attachment #2 --]
--- 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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5e4707340610100624j38ce9f8du7741bd027eb8cb1b>
