compress.c revision 80588
1/*
2 * compress routines:
3 *	zmagic() - returns 0 if not recognized, uncompresses and prints
4 *		   information if recognized
5 *	uncompress(method, old, n, newch) - uncompress old into new,
6 *					    using method, return sizeof new
7 */
8#include "file.h"
9#include <stdio.h>
10#include <stdlib.h>
11#ifdef HAVE_UNISTD_H
12#include <unistd.h>
13#endif
14#include <string.h>
15#ifdef HAVE_SYS_WAIT_H
16#include <sys/wait.h>
17#endif
18#ifndef lint
19FILE_RCSID("@(#)$Id: compress.c,v 1.20 2001/07/22 21:04:15 christos Exp $")
20#endif
21
22
23static struct {
24	const char *magic;
25	int   maglen;
26	const char *const argv[3];
27	int	 silent;
28} compr[] = {
29	{ "\037\235", 2, { "gzip", "-cdq", NULL }, 1 },		/* compressed */
30	/* Uncompress can get stuck; so use gzip first if we have it
31	 * Idea from Damien Clark, thanks! */
32	{ "\037\235", 2, { "uncompress", "-c", NULL }, 1 },	/* compressed */
33	{ "\037\213", 2, { "gzip", "-cdq", NULL }, 1 },		/* gzipped */
34	{ "\037\236", 2, { "gzip", "-cdq", NULL }, 1 },		/* frozen */
35	{ "\037\240", 2, { "gzip", "-cdq", NULL }, 1 },		/* SCO LZH */
36	/* the standard pack utilities do not accept standard input */
37	{ "\037\036", 2, { "gzip", "-cdq", NULL }, 0 },		/* packed */
38	{ "BZh",      3, { "bzip2", "-cd", NULL }, 1 },		/* bzip2-ed */
39};
40
41static int ncompr = sizeof(compr) / sizeof(compr[0]);
42
43
44static int uncompress __P((int, const unsigned char *, unsigned char **, int));
45static int swrite __P((int, const void *, size_t));
46static int sread __P((int, void *, size_t));
47
48int
49zmagic(buf, nbytes)
50	unsigned char *buf;
51	int nbytes;
52{
53	unsigned char *newbuf;
54	int newsize;
55	int i;
56
57	for (i = 0; i < ncompr; i++) {
58		if (nbytes < compr[i].maglen)
59			continue;
60		if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
61		    (newsize = uncompress(i, buf, &newbuf, nbytes)) != 0) {
62			tryit(newbuf, newsize, 1);
63			free(newbuf);
64			printf(" (");
65			tryit(buf, nbytes, 0);
66			printf(")");
67			return 1;
68		}
69	}
70
71	if (i == ncompr)
72		return 0;
73
74	return 1;
75}
76
77/*
78 * `safe' write for sockets and pipes.
79 */
80static int
81swrite(fd, buf, n)
82	int fd;
83	const void *buf;
84	size_t n;
85{
86	int rv;
87	size_t rn = n;
88
89	do
90		switch (rv = write(fd, buf, n)) {
91		case -1:
92			if (errno == EINTR)
93				continue;
94			return -1;
95		default:
96			n -= rv;
97			buf = ((char *)buf) + rv;
98			break;
99		}
100	while (n > 0);
101	return rn;
102}
103
104
105/*
106 * `safe' read for sockets and pipes.
107 */
108static int
109sread(fd, buf, n)
110	int fd;
111	void *buf;
112	size_t n;
113{
114	int rv;
115	size_t rn = n;
116
117	do
118		switch (rv = read(fd, buf, n)) {
119		case -1:
120			if (errno == EINTR)
121				continue;
122			return -1;
123		default:
124			n -= rv;
125			buf = ((char *)buf) + rv;
126			break;
127		}
128	while (n > 0);
129	return rn;
130}
131
132static int
133uncompress(method, old, newch, n)
134	int method;
135	const unsigned char *old;
136	unsigned char **newch;
137	int n;
138{
139	int fdin[2], fdout[2];
140
141	if (pipe(fdin) == -1 || pipe(fdout) == -1) {
142		error("cannot create pipe (%s).\n", strerror(errno));
143		/*NOTREACHED*/
144	}
145	switch (fork()) {
146	case 0:	/* child */
147		(void) close(0);
148		(void) dup(fdin[0]);
149		(void) close(fdin[0]);
150		(void) close(fdin[1]);
151
152		(void) close(1);
153		(void) dup(fdout[1]);
154		(void) close(fdout[0]);
155		(void) close(fdout[1]);
156		if (compr[method].silent)
157			(void) close(2);
158
159		execvp(compr[method].argv[0],
160		       (char *const *)compr[method].argv);
161		exit(1);
162		/*NOTREACHED*/
163	case -1:
164		error("could not fork (%s).\n", strerror(errno));
165		/*NOTREACHED*/
166
167	default: /* parent */
168		(void) close(fdin[0]);
169		(void) close(fdout[1]);
170		if (swrite(fdin[1], old, n) != n) {
171			n = 0;
172			goto err;
173		}
174		(void) close(fdin[1]);
175		fdin[1] = -1;
176		if ((*newch = (unsigned char *) malloc(n)) == NULL) {
177			n = 0;
178			goto err;
179		}
180		if ((n = sread(fdout[0], *newch, n)) <= 0) {
181			free(*newch);
182			n = 0;
183			goto err;
184		}
185err:
186		if (fdin[1] != -1)
187			(void) close(fdin[1]);
188		(void) close(fdout[0]);
189		(void) wait(NULL);
190		return n;
191	}
192}
193