commit 3233d4dcc91a9e4cadb90392f1dfa6f3543f3757
Author: sin <[email protected]>
Date:   Mon Jan 26 15:07:42 2015 +0000

    tar: Add support for -z and -j by invoking external programs
    
    Only extraction is supported at the moment.

diff --git a/tar.c b/tar.c
index 65898d5..39147f2 100644
--- a/tar.c
+++ b/tar.c
@@ -1,13 +1,14 @@
 /* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
 #include <grp.h>
 #include <limits.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include "util.h"
@@ -52,104 +53,40 @@ static FILE *tarfile;
 static ino_t tarinode;
 static dev_t tardev;
 
-static int mflag = 0;
-
-static void
-usage(void)
-{
-       eprintf("usage: tar [-f tarfile] [-C dir] [-]x[m]|t\n"
-               "       tar [-f tarfile] [-C dir] [-]c dir\n"
-               "       tar [-C dir] cf tarfile dir\n"
-               "       tar [-C dir] x[m]|tf tarfile\n");
-}
+static int mflag;
+static char filtermode;
 
-int
-main(int argc, char *argv[])
+static FILE *
+decomp(FILE *fp)
 {
-       struct stat st;
-       char *file = NULL, *dir = ".", *ap;
-       char mode = '\0';
-
-       ARGBEGIN {
-       case 'x':
-       case 'c':
-       case 't':
-               if (mode)
-                       usage();
-               mode = ARGC();
-               break;
-       case 'C':
-               dir = EARGF(usage());
-               break;
-       case 'f':
-               file = EARGF(usage());
-               break;
-       case 'm':
-               mflag = 1;
-               break;
-       default:
-               usage();
-       } ARGEND;
-
-       if (!mode) {
-               if (argc < 1)
-                       usage();
-
-               for (ap = argv[0]; *ap; ap++) {
-                       switch (*ap) {
-                       case 'x':
-                       case 'c':
-                       case 't':
-                               if (mode)
-                                       usage();
-                               mode = *ap;
-                               break;
-                       case 'f':
-                               if (argc < 2)
-                                       usage();
-                               argc--, argv++;
-                               file = argv[0];
-                               break;
-                       case 'C':
-                               if (argc < 2)
-                                       usage();
-                               argc--, argv++;
-                               dir = argv[0];
-                               break;
-                       case 'm':
-                               mflag = 1;
-                               break;
-                       default:
-                               usage();
-                       }
+       int   fds[2];
+       pid_t pid;
+
+       if (pipe(fds) < 0)
+               eprintf("pipe:");
+
+       pid = fork();
+       if (pid < 0) {
+               eprintf("fork:");
+       } else if (!pid) {
+               dup2(fileno(fp), 0);
+               dup2(fds[1], 1);
+               close(fds[0]);
+               close(fds[1]);
+
+               switch (filtermode) {
+               case 'j':
+                       execlp("bzip2", "bzip2", "-cd", (char *)0);
+                       eprintf("execlp bzip2:");
+               case 'z':
+                       execlp("gzip", "gzip", "-cdf", (char *)0);
+                       eprintf("execlp gzip:");
+                       break;
                }
-               argc--, argv++;
-       }
-
-       if (!mode || argc != (mode == 'c'))
-               usage();
-
-       if (file) {
-               tarfile = fopen(file, (mode == 'c') ? "wb" : "rb");
-               if (!tarfile)
-                       eprintf("tar: open '%s':", file);
-               if (lstat(file, &st) < 0)
-                       eprintf("tar: stat '%s':", file);
-               tarinode = st.st_ino;
-               tardev = st.st_dev;
-       } else {
-               tarfile = (mode == 'c') ? stdout : stdin;
-       }
-
-       chdir(dir);
-
-       if (mode == 'c') {
-               c(argv[0]);
-       } else {
-               xt((mode == 'x') ? unarchive : print);
        }
 
-       return 0;
+       close(fds[1]);
+       return fdopen(fds[0], "r");
 }
 
 static void
@@ -330,3 +267,134 @@ xt(int (*fn)(char*, int, char[Blksiz]))
                fn(fname, strtol(h->size, 0, 8), b);
        }
 }
+
+static void
+usage(void)
+{
+       eprintf("usage: tar [-f tarfile] [-C dir] [-]j|z [-]x[m]|t\n"
+               "       tar [-f tarfile] [-C dir] [-]c dir\n"
+               "       tar [-C dir] cf tarfile dir\n"
+               "       tar [-C dir] j|z x[m]|tf tarfile\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct stat st;
+       char *file = NULL, *dir = ".", *ap;
+       char mode = '\0';
+       FILE *fp;
+
+       ARGBEGIN {
+       case 'x':
+       case 'c':
+       case 't':
+               if (mode)
+                       usage();
+               mode = ARGC();
+               break;
+       case 'C':
+               dir = EARGF(usage());
+               break;
+       case 'f':
+               file = EARGF(usage());
+               break;
+       case 'm':
+               mflag = 1;
+               break;
+       case 'j':
+       case 'z':
+               if (filtermode)
+                       usage();
+               filtermode = ARGC();
+               break;
+       default:
+               usage();
+       } ARGEND;
+
+       if (!mode) {
+               if (argc < 1)
+                       usage();
+
+               for (ap = argv[0]; *ap; ap++) {
+                       switch (*ap) {
+                       case 'x':
+                       case 'c':
+                       case 't':
+                               if (mode)
+                                       usage();
+                               mode = *ap;
+                               break;
+                       case 'f':
+                               if (argc < 2)
+                                       usage();
+                               argc--, argv++;
+                               file = argv[0];
+                               break;
+                       case 'C':
+                               if (argc < 2)
+                                       usage();
+                               argc--, argv++;
+                               dir = argv[0];
+                               break;
+                       case 'm':
+                               mflag = 1;
+                               break;
+                       case 'j':
+                       case 'z':
+                               if (filtermode)
+                                       usage();
+                               filtermode = *ap;
+                               break;
+                       default:
+                               usage();
+                       }
+               }
+               argc--, argv++;
+       }
+
+       if (!mode || argc != (mode == 'c'))
+               usage();
+
+       switch (mode) {
+       case 'c':
+               if (file) {
+                       if (!(fp = fopen(file, "wb")))
+                               eprintf("fopen %s:", file);
+                       if (lstat(file, &st) < 0)
+                               eprintf("tar: stat '%s':", file);
+                       tarinode = st.st_ino;
+                       tardev = st.st_dev;
+                       tarfile = fp;
+               } else {
+                       tarfile = stdout;
+               }
+               chdir(dir);
+               c(argv[0]);
+               break;
+       case 't':
+       case 'x':
+               if (file) {
+                       if (!(fp = fopen(file, "rb")))
+                               eprintf("fopen %s:", file);
+               } else {
+                       fp = stdin;
+               }
+
+               switch (filtermode) {
+               case 'j':
+               case 'z':
+                       tarfile = decomp(fp);
+                       break;
+               default:
+                       tarfile = fp;
+                       break;
+               }
+
+               chdir(dir);
+               xt(mode == 'x' ? unarchive : print);
+               break;
+       }
+
+       return 0;
+}

Reply via email to