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