[comp.unix.sysv386] SCO UNIX tar & compress

rac@sherpa.UUCP (Roger Cornelius) (09/16/90)

A few weeks ago I posted a message regarding SCO's hacking of tar
and compress.  Below is a short program which demonstrates how tar
calls compress to decompress files restored to disk.

The program reads a list of the files in the current directory and
compresses or decompresses them (depending on the command line options).
See the comments in the source for how this is done.  By inserting the
included magic strings into /etc/magic, you can use file(C) to test
the files after running this.

You should probably create a temporary directory for playing with
this unless you're a really trusting person :-).
You will also need to change the #define for PATH to point to your
SCO compress program (probably /usr/bin/compress).

Note:  This will only work with SCO UNIX, and only if you have the
versions of tar and compress which support it.  3.2.2 does.

--
Roger A. Cornelius          rac@sherpa.UUCP         uunet!sherpa!rac

--- cut here ---
/*
 * tst.c - test compress with input via pipe
 *
 * HOW TAR DOES IT:
 * Tar writes 1 filename per 1024 byte block to a pipe which
 * is read by compress.
 * The block sent is composed of a NULL terminated filename
 * followed by space (0x20) characters padding to the end of the block.
 * (It doesn't seem to matter what the block is padded with as long
 * as it begins with a NULL terminated filename and is 1024 bytes long.)
 * compress is called with a command line of "compress -dP n" where n
 * is a fd open for reading.
 *
 * The filename is not altered by compress. ie. no .Z manipulation.
 * The file is operated on after it's been restored to the disk.
 *
 * The byte at offset 0x115 in the tar header block appears to be
 * the flag which signals tar that the file is compressed.
 * It is set to 0x31 if the file is to be decompressed.
 * It seems that if any file in the archive has this byte set, then
 * decompression is attempted on all remaining files.
 *
 * compress creates a tmp file (Comprtmp) in current directory while
 * working
 *
 * usage: tst [-d] [-x]
 * -d tells tst to decompress (the default is to compress)
 * -x debug - send the blocked filenames to stdout (ie. tst -x|hd|more)
 *            no files are changed with -x
 *
 * tst operates on all non-hidden files in the current directory.
 *
 * Here's some magic strings to add to /etc/magic so the file(C) command
 * will recognize compressed files.
0	short		0x9d1f		compressed file
>2	byte		0214		- with 12 bits
>2	byte		0215		- with 13 bits
>2	byte		0216		- with 14 bits
>2	byte		0217		- with 15 bits
>2	byte		0220		- with 16 bits
 */


#include <stdio.h>
#include <sys/wait.h>
#define BSIZE 1024
#define NAMLEN 14
/* change PATH to point to your SCO compress */
#define PATH "/usr/log/usr/bin/compress"
#define ARG1 "compress"

int debug = 0;

main(argc, argv)
int argc;
char **argv;
{
	FILE *fp, *popen();
	char arg2[10];
	char *fmt = "-P %d";					/* default is to compress */
	char buf[NAMLEN+1];
	int fd, fds[2];
	extern int optind;
	extern char *optarg;


	while ((fd = getopt(argc, argv, "dx")) != -1)
		switch (fd) {
			case 'd':	fmt = "-dP %d";		/* decompress */
						break;
			case 'x':	debug++;
						break;
			default:	exit(1);
		}

	if (pipe(fds)) {			/* create a pipe to talk with compress */
		perror("pipe");
		exit(1);
	}

	switch (fork()) {
		case -1:
			perror("fork");
			exit(1);
		case 0:
		/* child */
			close(fds[1]);
			sprintf(arg2, fmt, fds[0]);		/* pass compress the read end */
			execl(PATH, ARG1, arg2, (char *) NULL);
			perror("exec");
			exit(1);
	}
	/* parent */
	close(fds[0]);

	/* send a list of filenames through the pipe to compress */
	if ((fp = popen("ls", "r")) == (FILE *) NULL) {
		perror("popen");
		exit(1);
	}

	while (fgets((char*)buf, NAMLEN+1, fp))
		stuffit(buf, fds[1]);

	if (ferror(fp))
		perror("fgets");

	pclose(fp);
	close(fds[1]);

	wait((int*)NULL);						/* wait for compress */
	return 0;
}

stuffit(s, fd)	/* send a filename down the pipe to compress */
char *s;
int fd;
{
	static char buf[BSIZE];

	strcpy(buf,s);
	s = buf;
	do if (*s == '\n') *s = '\0'; while (*s++);
	if (debug)					/* send name to stdout */
		write(1, buf, BSIZE);
	else {
		printf("%s\n", buf);	/* list the files we operate on */
		write(fd, buf, BSIZE);	/* send name to compress */
	}
}

/* end of tst.c */
-- 
Roger A. Cornelius          rac@sherpa.UUCP         uunet!sherpa!rac