changeset 1217:c6c5565cc859

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);
 
-  for (s=toys.optargs; *s; s++) if (do_mkdir(*s)) perror_msg("'%s'", *s);
+  if (TT.arg_mode) 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 (mkpathat(AT_FDCWD, *s, mode, toys.optflags|1))
+      perror_msg("'%s'", *s);
 }