[hackers] [sbase] tar: add support for compressing with an external tool || Hiltjo Posthuma

From: <git_AT_suckless.org>
Date: Fri, 8 May 2015 16:56:25 +0200 (CEST)

commit 1d9d17eba2f151996a01218cd16d45d8cd702f97
Author: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
Date: Fri May 8 12:43:33 2015 +0200

    tar: add support for compressing with an external tool
    
    ... and add xz, compress and lzma as options

diff --git a/tar.1 b/tar.1
index 3339fb0..3df23ee 100644
--- a/tar.1
+++ b/tar.1
_AT_@ -7,12 +7,13 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl C Ar dir
-.Op Fl j | Fl z
+.Op Fl J | Fl Z | Fl a | Fl j | Fl z
 .Fl x Op Fl m | Fl t
 .Op Fl f Ar file
 .Op Ar file ...
 .Nm
 .Op Fl C Ar dir
+.Op Fl J | Fl Z | Fl a | Fl j | Fl z
 .Op Fl h
 .Fl c Ar path ...
 .Op Fl f Ar file
_AT_@ -40,16 +41,14 @@ List all files in the archive.
 Extract archive.
 .It Fl h
 Always dereference symbolic links while recursively traversing directories.
-.It Fl j | Fl z
-Use bzip2 | gzip decompression. The
-.Xr bzip2 1 |
-.Xr gzip 1
+.It Fl J | Fl Z | Fl a | Fl j | Fl z
+Use xz | compress | lzma | bzip2 | gzip decompression. These
 utilities must be installed separately.
 Using these flags is discouraged in favour of the flexibility
 and clarity of pipes:
 .Bd -literal -offset indent
-$ bzcat archive.tar.bz2 | tar -x
-$ zcat archive.tar.gz | tar -x
+$ bzip2 -cd archive.tar.bz2 | tar -x
+$ gzip -cd archive.tar.gz | tar -x
 .Ed
 .Bd -literal -offset indent
 $ tar -c file ... | bzip2 > archive.tar.bz2
diff --git a/tar.c b/tar.c
index 307e177..2162423 100644
--- a/tar.c
+++ b/tar.c
_AT_@ -67,6 +67,15 @@ static dev_t tardev;
 
 static int mflag, vflag;
 static int filtermode;
+static const char *filtertool;
+
+static const char *filtertools[] = {
+ ['J'] = "xz",
+ ['Z'] = "compress",
+ ['a'] = "lzma",
+ ['j'] = "bzip2",
+ ['z'] = "gzip",
+};
 
 static void
 pushent(char *name, time_t mtime)
_AT_@ -88,10 +97,34 @@ popent(void)
 }
 
 static int
-decomp(int fd)
+comp(int fd, const char *tool, const char *flags)
+{
+ int fds[2];
+
+ if (pipe(fds) < 0)
+ eprintf("pipe:");
+
+ switch (fork()) {
+ case -1:
+ eprintf("fork:");
+ case 0:
+ dup2(fd, 1);
+ dup2(fds[0], 0);
+ close(fds[0]);
+ close(fds[1]);
+
+ execlp(tool, tool, flags, NULL);
+ weprintf("execlp %s:", tool);
+ _exit(1);
+ }
+ close(fds[0]);
+ return fds[1];
+}
+
+static int
+decomp(int fd, const char *tool, const char *flags)
 {
         int fds[2];
- char *tool;
 
         if (pipe(fds) < 0)
                 eprintf("pipe:");
_AT_@ -105,8 +138,7 @@ decomp(int fd)
                 close(fds[0]);
                 close(fds[1]);
 
- tool = (filtermode == 'j') ? "bzip2" : "gzip";
- execlp(tool, tool, "-cd", NULL);
+ execlp(tool, tool, flags, NULL);
                 weprintf("execlp %s:", tool);
                 _exit(1);
         }
_AT_@ -390,7 +422,7 @@ bad:
 }
 
 static void
-xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
+xt(int argc, char *argv[], int mode)
 {
         char b[BLKSIZ], fname[256 + 1], *p;
         struct timeval times[2];
_AT_@ -398,6 +430,7 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
         struct ent *ent;
         long size;
         int i, n;
+ int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print;
 
         while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) {
                 chktar(h);
_AT_@ -451,8 +484,8 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
 static void
 usage(void)
 {
- eprintf("usage: %s [-C dir] [-j | -z] -x [-m | -t] [-f file] [file ...]\n"
- " %s [-C dir] [-h] -c path ... [-f file]\n", argv0, argv0);
+ eprintf("usage: %s [-C dir] [-J | -Z | -a | -j | -z] -x [-m | -t] [-f file] [file ...]\n"
+ " %s [-C dir] [-J | -Z | -a | -j | -z] [-h] -c path ... [-f file]\n", argv0, argv0);
 }
 
 int
_AT_@ -479,9 +512,13 @@ main(int argc, char *argv[])
         case 'm':
                 mflag = 1;
                 break;
+ case 'J':
+ case 'Z':
+ case 'a':
         case 'j':
         case 'z':
                 filtermode = ARGC();
+ filtertool = filtertools[filtermode];
                 break;
         case 'h':
                 r.follow = 'L';
_AT_@ -496,7 +533,7 @@ main(int argc, char *argv[])
         if (!mode)
                 usage();
         if (mode == 'c')
- if (!argc || filtermode)
+ if (!argc)
                         usage();
 
         switch (mode) {
_AT_@ -512,6 +549,9 @@ main(int argc, char *argv[])
                         tardev = st.st_dev;
                 }
 
+ if (filtertool)
+ tarfd = comp(tarfd, filtertool, "-cf");
+
                 if (chdir(dir) < 0)
                         eprintf("chdir %s:", dir);
                 for (; *argv; argc--, argv++)
_AT_@ -526,18 +566,15 @@ main(int argc, char *argv[])
                                 eprintf("open %s:", file);
                 }
 
- switch (filtermode) {
- case 'j':
- case 'z':
+ if (filtertool) {
                         fd = tarfd;
- tarfd = decomp(tarfd);
+ tarfd = decomp(tarfd, filtertool, "-cd");
                         close(fd);
- break;
                 }
 
                 if (chdir(dir) < 0)
                         eprintf("chdir %s:", dir);
- xt(argc, argv, (mode == 'x') ? unarchive : print);
+ xt(argc, argv, mode);
                 break;
         }
 
Received on Fri May 08 2015 - 16:56:25 CEST

This archive was generated by hypermail 2.3.0 : Fri May 08 2015 - 17:00:15 CEST