Support cpio -d.
cpio -d is similar in logic to mkdir -p, so split out the relevant code.

--
r_mkdir should probably go in one or another of the headers, and
r_mkdir.c should go in pending.c or lib.c; but I wasn't sure how to
proceed on that front.

Thanks,
Isaac Dunham
diff --git a/lib/r_mkdir.c b/lib/r_mkdir.c
new file mode 100644
index 0000000..e004b6c
--- /dev/null
+++ b/lib/r_mkdir.c
@@ -0,0 +1,43 @@
+#include "toys.h"
+
+// 0 if we end up with the path existing as a directory; 1 otherwise
+// flags is a bitwise OR of 1 for "recurse", 2 for "verbose"
+int r_mkdir(char *dir, mode_t mode, 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
+  // 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)) {
+    errno = EEXIST;
+    return 1;
+  }
+
+  for (s=dir; ; s++) {
+    char save=0;
+    mode_t lmode = mode;
+    //mode_t mode = 0777&~toys.old_umask;
+
+    // Skip leading / of absolute paths.
+    if (s!=dir && *s == '/' && (flags & 1)) {
+      save = *s;
+      *s = 0;
+    } else if (*s) continue;
+
+    // Use the mode from the -m option only for the last directory.
+    if (save == '/') lmode |= 0300;
+
+    if (mkdir(dir, lmode)) {
+      if (!(flags & 1) || errno != EEXIST) return 1;
+    } else if (flags & 2)
+      fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
+    
+    if (!(*s = save)) break;
+  }
+
+  return 0;
+}
diff --git a/toys/pending/cpio.c b/toys/pending/cpio.c
index e0ed8e8..bf63d90 100644
--- a/toys/pending/cpio.c
+++ b/toys/pending/cpio.c
@@ -7,19 +7,20 @@
  *
  * http://pubs.opengroup.org/onlinepubs/7908799/xcu/cpio.html
 
-USE_CPIO(NEWTOY(cpio, "H:iotuF:", TOYFLAG_BIN))
+USE_CPIO(NEWTOY(cpio, "H:diotuF:", TOYFLAG_BIN))
 
 config CPIO
   bool "cpio"
   default n
   help
-    usage: cpio { -iu | -o | -t } [-H FMT] [-F ARCHIVE]
+    usage: cpio { -i[du] | -o | -t } [-H FMT] [-F ARCHIVE]
 
     copy files into and out of an archive
+    -d  create leading directories when extracting an archive
     -i  extract from archive into file system (stdin is an archive)
     -o  create archive (stdin is a list of files, stdout is an archive)
     -t  list files (stdin is an archive, stdout is a list of files)
-    -u  always overwrite files (current default)
+    -u  always overwrite files (default)
     -H FMT   write archive in specified format:
     newc  SVR4 new character format (default)
     -F ARCHIVE  read from or write to ARCHIVE
@@ -27,6 +28,7 @@ config CPIO
 
 #define FOR_cpio
 #include "toys.h"
+int r_mkdir(char*, mode_t, int);
 
 GLOBALS(
   char *archive;
@@ -49,7 +51,8 @@ void loopfiles_stdin(void (*function)(int fd, char *name, struct stat st))
     if (name) {
       if (toybuf[strlen(name) - 1] == '\n' ) { 
         toybuf[strlen(name) - 1 ] = '\0';
-        if (lstat(name, &st) == -1) continue;
+        if (lstat(name, &st) == -1) verror_msg(name, errno, NULL);
+	if (errno) continue;
 	fd = open(name, O_RDONLY);
 	if (fd > 0 || !S_ISREG(st.st_mode)) {
           function(fd, name, st);
@@ -158,7 +161,7 @@ int read_cpio_member(int fd, int how)
   mode_t mode = 0;
   int pad, ofd = 0; 
   struct newc_header hdr;
-  char *name;
+  char *name, *lastdir;
   dev_t dev = 0;
 
   xreadall(fd, &hdr, sizeof(struct newc_header));
@@ -171,6 +174,12 @@ int read_cpio_member(int fd, int how)
   if (pad < 4) xreadall(fd, toybuf, pad);
   pad = 4 - (fsize % 4);
 
+  if ((toys.optflags&FLAG_d) && (lastdir = strrchr(name, '/'))) {
+    *lastdir = 0;
+    r_mkdir(name, 0777, 1);
+    *lastdir = '/';
+  }
+
   if (how & 1) {
     if (S_ISDIR(mode)) ofd = mkdir(name, mode);
     else if (S_ISLNK(mode)) {
diff --git a/toys/posix/mkdir.c b/toys/posix/mkdir.c
index 0094638..c86d582 100644
--- a/toys/posix/mkdir.c
+++ b/toys/posix/mkdir.c
@@ -20,6 +20,7 @@ config MKDIR
 
 #define FOR_mkdir
 #include "toys.h"
+int r_mkdir(char*, mode_t, int);
 
 GLOBALS(
   char *arg_mode;
@@ -29,41 +30,13 @@ GLOBALS(
 
 static int do_mkdir(char *dir)
 {
-  struct stat buf;
-  char *s;
+  mode_t mode = (toys.optflags&FLAG_m ? TT.mode : 0777&~toys.old_umask);
+  int flags = 0;
 
-  // 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
-  // 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)) {
-    errno = EEXIST;
+  if (toys.optflags & FLAG_p) flags |= 1;
+  if (toys.optflags & FLAG_v) flags |= 2;
+  if (r_mkdir(dir,mode,flags))
     return 1;
-  }
-
-  for (s=dir; ; s++) {
-    char save=0;
-    mode_t mode = 0777&~toys.old_umask;
-
-    // Skip leading / of absolute paths.
-    if (s!=dir && *s == '/' && (toys.optflags&FLAG_p)) {
-      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)
-      fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
-    
-    if (!(*s = save)) break;
-  }
-
   return 0;
 }
 
_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to