diff options
-rwxr-xr-x[-rw-r--r--] | scripts/test/mkdir.test | 7 | ||||
-rw-r--r-- | toys/posix/mkdir.c | 47 |
2 files changed, 37 insertions, 17 deletions
diff --git a/scripts/test/mkdir.test b/scripts/test/mkdir.test index 583b4c0d..8b2f99f5 100644..100755 --- a/scripts/test/mkdir.test +++ b/scripts/test/mkdir.test @@ -64,3 +64,10 @@ testing "mkdir -vp" "mkdir -vp walrus 2>&1" \ testing "mkdir -vp exists" "mkdir -vp walrus 2>&1" \ "" "" "" +rm -rf walrus + +touch two +testing "mkdir continue after fail" \ + "mkdir -m 777 one two three 2>/dev/null || stat -c %a three" \ + "777\n" "" "" +rm -rf one two three diff --git a/toys/posix/mkdir.c b/toys/posix/mkdir.c index 00946389..25dfb0de 100644 --- a/toys/posix/mkdir.c +++ b/toys/posix/mkdir.c @@ -23,42 +23,49 @@ config MKDIR GLOBALS( char *arg_mode; - - mode_t mode; ) -static int do_mkdir(char *dir) +// flags: 1=make last dir (with mode lastmode, otherwise skips last component) +// 2=make path (already exists is ok) +// 4=verbose +// returns 0 = path ok, 1 = error +int mkpathat(int atfd, char *dir, mode_t lastmode, int flags) { struct stat buf; char *s; // mkdir -p one/two/three is not an error if the path already exists, - // but is if "three" is a file. The others we dereference and catch + // but is if "three" is a file. The others we dereference and catch // not-a-directory along the way, but the last one we must explicitly // test for. Might as well do it up front. - if (!stat(dir, &buf) && !S_ISDIR(buf.st_mode)) { + if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) { errno = EEXIST; return 1; } - for (s=dir; ; s++) { - char save=0; - mode_t mode = 0777&~toys.old_umask; + // Skip leading / of absolute paths + while (*dir == '/') dir++; + + for (s=dir; ;s++) { + char save = 0; + mode_t mode = (0777&~toys.old_umask)|0300; // Skip leading / of absolute paths. - if (s!=dir && *s == '/' && (toys.optflags&FLAG_p)) { + if (*s == '/' && (flags&2)) { save = *s; *s = 0; } else if (*s) continue; // Use the mode from the -m option only for the last directory. - if (save == '/') mode |= 0300; - else if (toys.optflags&FLAG_m) mode = TT.mode; - - if (mkdir(dir, mode)) { - if (!(toys.optflags&FLAG_p) || errno != EEXIST) return 1; - } else if (toys.optflags&FLAG_v) + if (!save) { + if (flags&1) mode = lastmode; + else break; + } + + if (mkdirat(atfd, dir, mode)) { + if (!(flags&2) || errno != EEXIST) return 1; + } else if (flags&4) fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir); if (!(*s = save)) break; @@ -70,8 +77,14 @@ static int do_mkdir(char *dir) void mkdir_main(void) { char **s; + mode_t mode = (0777&~toys.old_umask); + + + if (TT.arg_mode) mode = string_to_mode(TT.arg_mode, 0777); - if(toys.optflags&FLAG_m) TT.mode = string_to_mode(TT.arg_mode, 0777); + // Note, -p and -v flags line up with mkpathat() flags - for (s=toys.optargs; *s; s++) if (do_mkdir(*s)) perror_msg("'%s'", *s); + for (s=toys.optargs; *s; s++) + if (mkpathat(AT_FDCWD, *s, mode, toys.optflags|1)) + perror_msg("'%s'", *s); } |