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
.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
@ -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

65
tar.c
View File

@ -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)
@ -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:");
@ -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);
}
@ -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];
@ -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);
@ -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
@ -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';
@ -496,7 +533,7 @@ main(int argc, char *argv[])
if (!mode)
usage();
if (mode == 'c')
if (!argc || filtermode)
if (!argc)
usage();
switch (mode) {
@ -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++)
@ -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;
}