aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2014-03-11 17:50:17 -0500
committerRob Landley <rob@landley.net>2014-03-11 17:50:17 -0500
commitfad38c7d1675a34a350fb1d99fb6b66728cad8a7 (patch)
tree7a6dd814d35b933e7f6a6440b7a5f8014d4cbb41
parent69664c24a11e8bba39890ec52aefa5654aab60bd (diff)
downloadtoybox-fad38c7d1675a34a350fb1d99fb6b66728cad8a7.tar.gz
Factor out mkpathat.
-rwxr-xr-x[-rw-r--r--]scripts/test/mkdir.test7
-rw-r--r--toys/posix/mkdir.c47
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);
}