tar: add support for compressing with an external tool

... and add xz, compress and lzma as options
This commit is contained in:
Hiltjo Posthuma 2015-05-08 12:43:33 +02:00 committed by sin
parent 7dff7d4c83
commit 1d9d17eba2
2 changed files with 57 additions and 21 deletions

13
tar.1
View File

@ -7,12 +7,13 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl C Ar dir .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 .Fl x Op Fl m | Fl t
.Op Fl f Ar file .Op Fl f Ar file
.Op Ar file ... .Op Ar file ...
.Nm .Nm
.Op Fl C Ar dir .Op Fl C Ar dir
.Op Fl J | Fl Z | Fl a | Fl j | Fl z
.Op Fl h .Op Fl h
.Fl c Ar path ... .Fl c Ar path ...
.Op Fl f Ar file .Op Fl f Ar file
@ -40,16 +41,14 @@ List all files in the archive.
Extract archive. Extract archive.
.It Fl h .It Fl h
Always dereference symbolic links while recursively traversing directories. Always dereference symbolic links while recursively traversing directories.
.It Fl j | Fl z .It Fl J | Fl Z | Fl a | Fl j | Fl z
Use bzip2 | gzip decompression. The Use xz | compress | lzma | bzip2 | gzip decompression. These
.Xr bzip2 1 |
.Xr gzip 1
utilities must be installed separately. utilities must be installed separately.
Using these flags is discouraged in favour of the flexibility Using these flags is discouraged in favour of the flexibility
and clarity of pipes: and clarity of pipes:
.Bd -literal -offset indent .Bd -literal -offset indent
$ bzcat archive.tar.bz2 | tar -x $ bzip2 -cd archive.tar.bz2 | tar -x
$ zcat archive.tar.gz | tar -x $ gzip -cd archive.tar.gz | tar -x
.Ed .Ed
.Bd -literal -offset indent .Bd -literal -offset indent
$ tar -c file ... | bzip2 > archive.tar.bz2 $ tar -c file ... | bzip2 > archive.tar.bz2

65
tar.c
View File

@ -67,6 +67,15 @@ static dev_t tardev;
static int mflag, vflag; static int mflag, vflag;
static int filtermode; static int filtermode;
static const char *filtertool;
static const char *filtertools[] = {
['J'] = "xz",
['Z'] = "compress",
['a'] = "lzma",
['j'] = "bzip2",
['z'] = "gzip",
};
static void static void
pushent(char *name, time_t mtime) pushent(char *name, time_t mtime)
@ -88,10 +97,34 @@ popent(void)
} }
static int 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]; int fds[2];
char *tool;
if (pipe(fds) < 0) if (pipe(fds) < 0)
eprintf("pipe:"); eprintf("pipe:");
@ -105,8 +138,7 @@ decomp(int fd)
close(fds[0]); close(fds[0]);
close(fds[1]); close(fds[1]);
tool = (filtermode == 'j') ? "bzip2" : "gzip"; execlp(tool, tool, flags, NULL);
execlp(tool, tool, "-cd", NULL);
weprintf("execlp %s:", tool); weprintf("execlp %s:", tool);
_exit(1); _exit(1);
} }
@ -390,7 +422,7 @@ bad:
} }
static void 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; char b[BLKSIZ], fname[256 + 1], *p;
struct timeval times[2]; struct timeval times[2];
@ -398,6 +430,7 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
struct ent *ent; struct ent *ent;
long size; long size;
int i, n; int i, n;
int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print;
while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) { while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) {
chktar(h); chktar(h);
@ -451,8 +484,8 @@ xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
static void static void
usage(void) usage(void)
{ {
eprintf("usage: %s [-C dir] [-j | -z] -x [-m | -t] [-f file] [file ...]\n" eprintf("usage: %s [-C dir] [-J | -Z | -a | -j | -z] -x [-m | -t] [-f file] [file ...]\n"
" %s [-C dir] [-h] -c path ... [-f file]\n", argv0, argv0); " %s [-C dir] [-J | -Z | -a | -j | -z] [-h] -c path ... [-f file]\n", argv0, argv0);
} }
int int
@ -479,9 +512,13 @@ main(int argc, char *argv[])
case 'm': case 'm':
mflag = 1; mflag = 1;
break; break;
case 'J':
case 'Z':
case 'a':
case 'j': case 'j':
case 'z': case 'z':
filtermode = ARGC(); filtermode = ARGC();
filtertool = filtertools[filtermode];
break; break;
case 'h': case 'h':
r.follow = 'L'; r.follow = 'L';
@ -496,7 +533,7 @@ main(int argc, char *argv[])
if (!mode) if (!mode)
usage(); usage();
if (mode == 'c') if (mode == 'c')
if (!argc || filtermode) if (!argc)
usage(); usage();
switch (mode) { switch (mode) {
@ -512,6 +549,9 @@ main(int argc, char *argv[])
tardev = st.st_dev; tardev = st.st_dev;
} }
if (filtertool)
tarfd = comp(tarfd, filtertool, "-cf");
if (chdir(dir) < 0) if (chdir(dir) < 0)
eprintf("chdir %s:", dir); eprintf("chdir %s:", dir);
for (; *argv; argc--, argv++) for (; *argv; argc--, argv++)
@ -526,18 +566,15 @@ main(int argc, char *argv[])
eprintf("open %s:", file); eprintf("open %s:", file);
} }
switch (filtermode) { if (filtertool) {
case 'j':
case 'z':
fd = tarfd; fd = tarfd;
tarfd = decomp(tarfd); tarfd = decomp(tarfd, filtertool, "-cd");
close(fd); close(fd);
break;
} }
if (chdir(dir) < 0) if (chdir(dir) < 0)
eprintf("chdir %s:", dir); eprintf("chdir %s:", dir);
xt(argc, argv, (mode == 'x') ? unarchive : print); xt(argc, argv, mode);
break; break;
} }