tar: add support for compressing with an external tool
... and add xz, compress and lzma as options
This commit is contained in:
		
							
								
								
									
										13
									
								
								tar.1
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tar.1
									
									
									
									
									
								
							@@ -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
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								tar.c
									
									
									
									
									
								
							@@ -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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user