Mercurial > hg > toybox
changeset 1217:c6c5565cc859 draft
Factor out mkpathat.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 11 Mar 2014 17:50:17 -0500 |
parents | bd4e3608ad04 |
children | fba5d8d3905c |
files | scripts/test/mkdir.test toys/posix/mkdir.c |
diffstat | 2 files changed, 36 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/test/mkdir.test Sun Mar 09 14:42:28 2014 -0500 +++ b/scripts/test/mkdir.test Tue Mar 11 17:50:17 2014 -0500 @@ -64,3 +64,10 @@ 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
--- a/toys/posix/mkdir.c Sun Mar 09 14:42:28 2014 -0500 +++ b/toys/posix/mkdir.c Tue Mar 11 17:50:17 2014 -0500 @@ -23,42 +23,49 @@ 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 (!save) { + if (flags&1) mode = lastmode; + else break; + } - if (mkdir(dir, mode)) { - if (!(toys.optflags&FLAG_p) || errno != EEXIST) return 1; - } else if (toys.optflags&FLAG_v) + 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 @@ void mkdir_main(void) { char **s; + mode_t mode = (0777&~toys.old_umask); - if(toys.optflags&FLAG_m) TT.mode = string_to_mode(TT.arg_mode, 0777); + + if (TT.arg_mode) mode = string_to_mode(TT.arg_mode, 0777); - for (s=toys.optargs; *s; s++) if (do_mkdir(*s)) perror_msg("'%s'", *s); + // Note, -p and -v flags line up with mkpathat() flags + + for (s=toys.optargs; *s; s++) + if (mkpathat(AT_FDCWD, *s, mode, toys.optflags|1)) + perror_msg("'%s'", *s); }