compress.c revision 298920
1141104Sharti/*
294589Sobrien * Copyright (c) Ian F. Darwin 1986-1995.
394589Sobrien * Software written by Ian F. Darwin and others;
45814Sjkh * maintained 1995-present by Christos Zoulas and others.
51590Srgrimes *
61590Srgrimes * Redistribution and use in source and binary forms, with or without
71590Srgrimes * modification, are permitted provided that the following conditions
81590Srgrimes * are met:
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice immediately at the beginning of the file, without modification,
111590Srgrimes *    this list of conditions, and the following disclaimer.
121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer in the
141590Srgrimes *    documentation and/or other materials provided with the distribution.
151590Srgrimes *
161590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
201590Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261590Srgrimes * SUCH DAMAGE.
271590Srgrimes */
281590Srgrimes/*
291590Srgrimes * compress routines:
301590Srgrimes *	zmagic() - returns 0 if not recognized, uncompresses and prints
311590Srgrimes *		   information if recognized
321590Srgrimes *	uncompress(method, old, n, newch) - uncompress old into new,
331590Srgrimes *					    using method, return sizeof new
341590Srgrimes */
351590Srgrimes#include "file.h"
361590Srgrimes
371590Srgrimes#ifndef lint
3862833SwsanchezFILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 christos Exp $")
3962833Swsanchez#endif
401590Srgrimes
411590Srgrimes#include "magic.h"
4262833Swsanchez#include <stdlib.h>
4394587Sobrien#ifdef HAVE_UNISTD_H
441590Srgrimes#include <unistd.h>
4535483Simp#endif
46103503Sjmallett#include <string.h>
4735483Simp#include <errno.h>
4835483Simp#include <ctype.h>
491590Srgrimes#include <stdarg.h>
501590Srgrimes#ifdef HAVE_SIGNAL_H
511590Srgrimes#include <signal.h>
521590Srgrimes# ifndef HAVE_SIG_T
531590Srgrimestypedef void (*sig_t)(int);
54144467Sharti# endif /* HAVE_SIG_T */
551590Srgrimes#endif
56144467Sharti#if !defined(__MINGW32__) && !defined(WIN32)
57144467Sharti#include <sys/ioctl.h>
58144467Sharti#endif
59144467Sharti#ifdef HAVE_SYS_WAIT_H
60144467Sharti#include <sys/wait.h>
61144467Sharti#endif
62144467Sharti#if defined(HAVE_SYS_TIME_H)
631590Srgrimes#include <sys/time.h>
64144467Sharti#endif
65144467Sharti#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
66144467Sharti#define BUILTIN_DECOMPRESS
67144467Sharti#include <zlib.h>
68144467Sharti#define ZLIBSUPPORT
691590Srgrimes#endif
70144467Sharti#ifdef DEBUG
71144467Shartiint tty = -1;
72144467Sharti#define DPRINTF(...)	do { \
73144467Sharti	if (tty == -1) \
741590Srgrimes		tty = open("/dev/tty", O_RDWR); \
75144467Sharti	if (tty == -1) \
761590Srgrimes		abort(); \
77144467Sharti	dprintf(tty, __VA_ARGS__); \
781590Srgrimes} while (/*CONSTCOND*/0)
79144467Sharti#else
80144467Sharti#define DPRINTF(...)
81144467Sharti#endif
821590Srgrimes
83144467Sharti#ifdef ZLIBSUPPORT
84144467Sharti/*
85144467Sharti * The following python code is not really used because ZLIBSUPPORT is only
86144467Sharti * defined if we have a built-in zlib, and the built-in zlib handles that.
871590Srgrimes */
88144467Shartistatic const char zlibcode[] =
89144467Sharti    "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
90144467Sharti
911590Srgrimesstatic const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
92144467Sharti
93144467Shartistatic int
94144467Shartizlibcmp(const unsigned char *buf)
951590Srgrimes{
96144467Sharti	unsigned short x = 1;
971590Srgrimes	unsigned char *s = (unsigned char *)&x;
98144467Sharti
99146132Sharti	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
100146132Sharti		return 0;
101146132Sharti	if (s[0] != 1)	/* endianness test */
102146132Sharti		x = buf[0] | (buf[1] << 8);
103146132Sharti	else
104146132Sharti		x = buf[1] | (buf[0] << 8);
105146132Sharti	if (x % 31)
106146132Sharti		return 0;
107146132Sharti	return 1;
108146132Sharti}
109146132Sharti#endif
1101590Srgrimes
1111590Srgrimes#define gzip_flags "-cd"
112144494Sharti#define lrzip_flags "-do"
1131590Srgrimes#define lzip_flags gzip_flags
114141104Sharti
1151590Srgrimesstatic const char *gzip_args[] = {
116107447Sru	"gzip", gzip_flags, NULL
117104475Sphk};
118107447Srustatic const char *uncompress_args[] = {
1191590Srgrimes	"uncompress", "-c", NULL
120141104Sharti};
12194506Scharnierstatic const char *bzip2_args[] = {
1225814Sjkh	"bzip2", "-cd", NULL
123144665Sharti};
1241590Srgrimesstatic const char *lzip_args[] = {
1255814Sjkh	"lzip", lzip_flags, NULL
126141104Sharti};
12780381Ssheldonhstatic const char *xz_args[] = {
12894506Scharnier	"xz", "-cd", NULL
129141104Sharti};
130141104Shartistatic const char *lrzip_args[] = {
131142457Sharti	"lrzip", lrzip_flags, NULL
132146056Sharti};
1331590Srgrimesstatic const char *lz4_args[] = {
134141104Sharti	"lz4", "-cd", NULL
135141104Sharti};
1361590Srgrimes
137141104Shartiprivate const struct {
138141104Sharti	const void *magic;
1391590Srgrimes	size_t maglen;
140141104Sharti	const char **argv;
141146056Sharti} compr[] = {
142141104Sharti	{ "\037\235",	2, gzip_args },		/* compressed */
143141104Sharti	/* Uncompress can get stuck; so use gzip first if we have it
144141104Sharti	 * Idea from Damien Clark, thanks! */
1451590Srgrimes	{ "\037\235",	2, uncompress_args },	/* compressed */
146146057Sharti	{ "\037\213",	2, gzip_args },		/* gzipped */
147146057Sharti	{ "\037\236",	2, gzip_args },		/* frozen */
148146057Sharti	{ "\037\240",	2, gzip_args },		/* SCO LZH */
1491590Srgrimes	/* the standard pack utilities do not accept standard input */
150146057Sharti	{ "\037\036",	2, gzip_args },		/* packed */
151146057Sharti	{ "PK\3\4",	4, gzip_args },		/* pkzipped, */
152146057Sharti	/* ...only first file examined */
153146057Sharti	{ "BZh",	3, bzip2_args },	/* bzip2-ed */
154146057Sharti	{ "LZIP",	4, lzip_args },		/* lzip-ed */
155146057Sharti 	{ "\3757zXZ\0",	6, xz_args },		/* XZ Utils */
156146057Sharti 	{ "LRZI",	4, lrzip_args },	/* LRZIP */
157146057Sharti 	{ "\004\"M\030",4, lz4_args },		/* LZ4 */
158146057Sharti#ifdef ZLIBSUPPORT
159144483Sharti	{ zlibcmp,	0, zlib_args },		/* zlib */
160144483Sharti#endif
161144483Sharti};
162144483Sharti
163144483Sharti#define OKDATA 	0
164144483Sharti#define NODATA	1
165144483Sharti#define ERRDATA	2
166144483Sharti
167144483Shartiprivate ssize_t swrite(int, const void *, size_t);
168144483Sharti#if HAVE_FORK
169144483Shartiprivate size_t ncompr = sizeof(compr) / sizeof(compr[0]);
170144483Shartiprivate int uncompressbuf(int, size_t, size_t, const unsigned char *,
171144665Sharti    unsigned char **, size_t *);
172144483Sharti#ifdef BUILTIN_DECOMPRESS
173144483Shartiprivate int uncompresszlib(const unsigned char *, unsigned char **, size_t,
174144483Sharti    size_t *, int);
175144483Shartiprivate int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
176144483Sharti    size_t *);
177144483Sharti#endif
178144483Shartistatic int makeerror(unsigned char **, size_t *, const char *, ...)
179144483Sharti    __attribute__((__format__(__printf__, 3, 4)));
180144483Shartiprivate const char *methodname(size_t);
181144483Sharti
182144483Shartiprotected int
183144483Shartifile_zmagic(struct magic_set *ms, int fd, const char *name,
184144483Sharti    const unsigned char *buf, size_t nbytes)
185144483Sharti{
186144483Sharti	unsigned char *newbuf = NULL;
187144483Sharti	size_t i, nsz;
188144483Sharti	char *rbuf;
189144483Sharti	file_pushbuf_t *pb;
190144483Sharti	int rv = 0;
191144483Sharti	int mime = ms->flags & MAGIC_MIME;
192144483Sharti#ifdef HAVE_SIGNAL_H
193144483Sharti	sig_t osigpipe;
194144483Sharti#endif
195144483Sharti
196146061Sharti	if ((ms->flags & MAGIC_COMPRESS) == 0)
197144483Sharti		return 0;
198144483Sharti
199144483Sharti#ifdef HAVE_SIGNAL_H
200144483Sharti	osigpipe = signal(SIGPIPE, SIG_IGN);
201144483Sharti#endif
202144483Sharti	for (i = 0; i < ncompr; i++) {
203144483Sharti		int zm;
204144483Sharti		if (nbytes < compr[i].maglen)
205144483Sharti			continue;
206144483Sharti#ifdef ZLIBSUPPORT
207144483Sharti		if (compr[i].maglen == 0)
208144483Sharti			zm = (CAST(int (*)(const unsigned char *),
209144483Sharti			    CCAST(void *, compr[i].magic)))(buf);
210146061Sharti		else
211144483Sharti#endif
212144483Sharti			zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0;
213144483Sharti
214144483Sharti		if (!zm)
215144483Sharti			continue;
216144483Sharti		nsz = nbytes;
217144483Sharti		rv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
218144483Sharti		DPRINTF("uncompressbuf = %d, %s, %zu\n", rv, (char *)newbuf,
219144483Sharti		    nsz);
220144483Sharti		switch (rv) {
221144483Sharti		case OKDATA:
222144483Sharti		case ERRDATA:
223144483Sharti
224144483Sharti			ms->flags &= ~MAGIC_COMPRESS;
225144483Sharti			if (rv == ERRDATA)
226144483Sharti				rv = file_printf(ms, "%s ERROR: %s",
227144483Sharti				    methodname(i), newbuf);
228144483Sharti			else
229144483Sharti				rv = file_buffer(ms, -1, name, newbuf, nsz);
230144483Sharti			if (rv == -1)
231144483Sharti				goto error;
232144483Sharti			DPRINTF("rv = %d\n", rv);
233144483Sharti			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
234144483Sharti				goto out;
235144483Sharti			if (mime != MAGIC_MIME && mime != 0)
236144483Sharti				goto out;
237144483Sharti			if ((file_printf(ms,
238144483Sharti			    mime ? " compressed-encoding=" : " (")) == -1)
239144483Sharti				goto error;
240144483Sharti			if ((pb = file_push_buffer(ms)) == NULL)
241144483Sharti				goto error;
242144483Sharti			if (file_buffer(ms, -1, NULL, buf, nbytes) == -1)
243144483Sharti				goto error;
244144483Sharti			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
245144483Sharti				if (file_printf(ms, "%s", rbuf) == -1) {
246144483Sharti					free(rbuf);
247144483Sharti					goto error;
248144483Sharti				}
249144483Sharti				free(rbuf);
250144483Sharti			}
251144483Sharti			if (!mime && file_printf(ms, ")") == -1)
252144483Sharti				goto error;
253144483Sharti			goto out;
254144483Sharti		case NODATA:
255144483Sharti			goto out;
256144494Sharti		default:
257144494Sharti			abort();
258144483Sharti		}
259144483Sharti	}
260146061Shartiout:
261146061Sharti	rv = 1;
262144483Shartierror:
263144483Sharti#ifdef HAVE_SIGNAL_H
264144483Sharti	(void)signal(SIGPIPE, osigpipe);
265146061Sharti#endif
266144483Sharti	free(newbuf);
267144494Sharti	ms->flags |= MAGIC_COMPRESS;
268144494Sharti	DPRINTF("Zmagic returns %d\n", rv);
269144483Sharti	return rv;
270144483Sharti}
271144483Sharti#endif
272144483Sharti/*
273144483Sharti * `safe' write for sockets and pipes.
274144483Sharti */
275144483Shartiprivate ssize_t
276144483Shartiswrite(int fd, const void *buf, size_t n)
277144483Sharti{
278144483Sharti	ssize_t rv;
279144483Sharti	size_t rn = n;
280144483Sharti
281144483Sharti	do
282144483Sharti		switch (rv = write(fd, buf, n)) {
283144483Sharti		case -1:
284144483Sharti			if (errno == EINTR)
285144483Sharti				continue;
286144483Sharti			return -1;
287144483Sharti		default:
288144483Sharti			n -= rv;
289144483Sharti			buf = CAST(const char *, buf) + rv;
290144483Sharti			break;
291144483Sharti		}
292144483Sharti	while (n > 0);
293144483Sharti	return rn;
294144483Sharti}
295144483Sharti
296144483Sharti
297144483Sharti/*
298144483Sharti * `safe' read for sockets and pipes.
299144483Sharti */
300144483Shartiprotected ssize_t
301144483Shartisread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
302144483Sharti{
303144483Sharti	ssize_t rv;
304144483Sharti#ifdef FIONREAD
305144483Sharti	int t = 0;
306144483Sharti#endif
307144483Sharti	size_t rn = n;
308144483Sharti
309144483Sharti	if (fd == STDIN_FILENO)
310144483Sharti		goto nocheck;
311144483Sharti
312144483Sharti#ifdef FIONREAD
313144483Sharti	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
314144483Sharti#ifdef FD_ZERO
315144483Sharti		ssize_t cnt;
316144483Sharti		for (cnt = 0;; cnt++) {
317144483Sharti			fd_set check;
318144483Sharti			struct timeval tout = {0, 100 * 1000};
319144483Sharti			int selrv;
3208874Srgrimes
3211590Srgrimes			FD_ZERO(&check);
322144467Sharti			FD_SET(fd, &check);
323144467Sharti
324144467Sharti			/*
325144467Sharti			 * Avoid soft deadlock: do not read if there
326144467Sharti			 * is nothing to read from sockets and pipes.
3271590Srgrimes			 */
32818730Ssteve			selrv = select(fd + 1, &check, NULL, NULL, &tout);
32918730Ssteve			if (selrv == -1) {
33018730Ssteve				if (errno == EINTR || errno == EAGAIN)
33118730Ssteve					continue;
332138232Sharti			} else if (selrv == 0 && cnt >= 5) {
3331590Srgrimes				return 0;
3341590Srgrimes			} else
3351590Srgrimes				break;
3361590Srgrimes		}
3371590Srgrimes#endif
3381590Srgrimes		(void)ioctl(fd, FIONREAD, &t);
339144467Sharti	}
3401590Srgrimes
3411590Srgrimes	if (t > 0 && (size_t)t < n) {
342144467Sharti		n = t;
343144467Sharti		rn = n;
344144467Sharti	}
345144467Sharti#endif
346144467Sharti
347144467Shartinocheck:
3481590Srgrimes	do
3491590Srgrimes		switch ((rv = read(fd, buf, n))) {
350144467Sharti		case -1:
351146061Sharti			if (errno == EINTR)
352144467Sharti				continue;
353144467Sharti			return -1;
3541590Srgrimes		case 0:
3551590Srgrimes			return rn - n;
3561590Srgrimes		default:
3571590Srgrimes			n -= rv;
358144483Sharti			buf = ((char *)buf) + rv;
359144467Sharti			break;
360144467Sharti		}
361144467Sharti	while (n > 0);
362144467Sharti	return rn;
363144467Sharti}
364144467Sharti
365144467Shartiprotected int
366144741Shartifile_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
367144467Sharti    size_t nbytes)
368144467Sharti{
369144467Sharti	char buf[4096];
370144467Sharti	ssize_t r;
371144467Sharti	int tfd;
372144467Sharti
373144467Sharti	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
374144467Sharti#ifndef HAVE_MKSTEMP
375144467Sharti	{
376144741Sharti		char *ptr = mktemp(buf);
377144467Sharti		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
37818730Ssteve		r = errno;
379144467Sharti		(void)unlink(ptr);
38018730Ssteve		errno = r;
381144467Sharti	}
382144467Sharti#else
383144467Sharti	{
384144467Sharti		int te;
385144467Sharti		tfd = mkstemp(buf);
386144467Sharti		te = errno;
387144467Sharti		(void)unlink(buf);
388144467Sharti		errno = te;
389144741Sharti	}
390144467Sharti#endif
391144467Sharti	if (tfd == -1) {
392144467Sharti		file_error(ms, errno,
3931590Srgrimes		    "cannot create temporary file for pipe copy");
3941590Srgrimes		return -1;
395144467Sharti	}
396144467Sharti
397144467Sharti	if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
398144467Sharti		r = 1;
399144483Sharti	else {
400146059Sharti		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
401146059Sharti			if (swrite(tfd, buf, (size_t)r) != r)
4021590Srgrimes				break;
403146140Sharti	}
404146140Sharti
405146140Sharti	switch (r) {
406146140Sharti	case -1:
407146140Sharti		file_error(ms, errno, "error copying from pipe to temp file");
408146140Sharti		return -1;
409144656Sharti	case 0:
410138916Sharti		break;
411138916Sharti	default:
412144494Sharti		file_error(ms, errno, "error while writing to temp file");
413138916Sharti		return -1;
414146061Sharti	}
4151590Srgrimes
416137572Sphk	/*
417104475Sphk	 * We duplicate the file descriptor, because fclose on a
418104475Sphk	 * tmpfile will delete the file, but any open descriptors
419104475Sphk	 * can still access the phantom inode.
420146061Sharti	 */
4211590Srgrimes	if ((fd = dup2(tfd, fd)) == -1) {
4221590Srgrimes		file_error(ms, errno, "could not dup descriptor for temp file");
4231590Srgrimes		return -1;
424146061Sharti	}
4251590Srgrimes	(void)close(tfd);
426146061Sharti	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
4271590Srgrimes		file_badseek(ms);
4281590Srgrimes		return -1;
4291590Srgrimes	}
430137202Sharti	return fd;
431137202Sharti}
432138232Sharti#if HAVE_FORK
43318730Ssteve#ifdef BUILTIN_DECOMPRESS
4341590Srgrimes
435137252Sharti#define FHCRC		(1 << 1)
436137252Sharti#define FEXTRA		(1 << 2)
437137252Sharti#define FNAME		(1 << 3)
4388874Srgrimes#define FCOMMENT	(1 << 4)
439138916Sharti
440138916Sharti
441138916Shartiprivate int
4421590Srgrimesuncompressgzipped(const unsigned char *old, unsigned char **newch,
443144494Sharti    size_t bytes_max, size_t *n)
4441590Srgrimes{
445144656Sharti	unsigned char flg = old[3];
446144656Sharti	size_t data_start = 10;
447144656Sharti
4481590Srgrimes	if (flg & FEXTRA) {
449137605Sharti		if (data_start + 1 >= *n)
450137605Sharti			goto err;
451137605Sharti		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
4521590Srgrimes	}
45318730Ssteve	if (flg & FNAME) {
4541590Srgrimes		while(data_start < *n && old[data_start])
4551590Srgrimes			data_start++;
45618730Ssteve		data_start++;
4571590Srgrimes	}
45818730Ssteve	if (flg & FCOMMENT) {
4591590Srgrimes		while(data_start < *n && old[data_start])
4601590Srgrimes			data_start++;
4611590Srgrimes		data_start++;
46218730Ssteve	}
46318730Ssteve	if (flg & FHCRC)
46418730Ssteve		data_start += 2;
46518730Ssteve
46618730Ssteve	if (data_start >= *n)
46718730Ssteve		goto err;
468103503Sjmallett
46918730Ssteve	*n -= data_start;
470138232Sharti	old += data_start;
47118730Ssteve	return uncompresszlib(old, newch, bytes_max, n, 0);
47218730Ssteveerr:
47318730Ssteve	return makeerror(newch, n, "File too short");
47418730Ssteve}
47518730Ssteve
47618730Ssteveprivate int
47718730Ssteveuncompresszlib(const unsigned char *old, unsigned char **newch,
478103503Sjmallett    size_t bytes_max, size_t *n, int zlib)
479103503Sjmallett{
48018730Ssteve	int rc;
481146129Sharti	z_stream z;
482146129Sharti
483146129Sharti	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
484146129Sharti		return makeerror(newch, n, "No buffer, %s", strerror(errno));
485146129Sharti
486146129Sharti	z.next_in = CCAST(Bytef *, old);
487146129Sharti	z.avail_in = CAST(uint32_t, *n);
488146129Sharti	z.next_out = *newch;
489146129Sharti	z.avail_out = bytes_max;
490146129Sharti	z.zalloc = Z_NULL;
491146129Sharti	z.zfree = Z_NULL;
492146129Sharti	z.opaque = Z_NULL;
493146129Sharti
494146130Sharti	/* LINTED bug in header macro */
495146130Sharti	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
496146129Sharti	if (rc != Z_OK)
497146129Sharti		goto err;
49892921Simp
49992921Simp	rc = inflate(&z, Z_SYNC_FLUSH);
50092921Simp	if (rc != Z_OK && rc != Z_STREAM_END)
501144483Sharti		goto err;
50292921Simp
50392921Simp	*n = (size_t)z.total_out;
504146129Sharti	rc = inflateEnd(&z);
505146142Sharti	if (rc != Z_OK)
5061590Srgrimes		goto err;
507146132Sharti
508146132Sharti	/* let's keep the nul-terminate tradition */
509146132Sharti	(*newch)[*n] = '\0';
510146132Sharti
511146132Sharti	return OKDATA;
512146132Shartierr:
513146132Sharti	strlcpy((char *)*newch, z.msg, bytes_max);
514146132Sharti	*n = strlen((char *)*newch);
515146132Sharti	return ERRDATA;
516146132Sharti}
517146132Sharti#endif
518146132Sharti
519146132Shartistatic int
520146132Shartimakeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
521146132Sharti{
522146132Sharti	char *msg;
523146132Sharti	va_list ap;
524146132Sharti	int rv;
525144467Sharti
526146129Sharti	va_start(ap, fmt);
527146129Sharti	rv = vasprintf(&msg, fmt, ap);
528146129Sharti	va_end(ap);
529146129Sharti	if (rv < 0) {
530146129Sharti		*buf = NULL;
531146129Sharti		*len = 0;
532146129Sharti		return NODATA;
533146129Sharti	}
534146129Sharti	*buf = (unsigned char *)msg;
535146129Sharti	*len = strlen(msg);
536146129Sharti	return ERRDATA;
537146129Sharti}
538146129Sharti
539146129Shartistatic void
540146129Sharticlosefd(int *fd, size_t i)
541146129Sharti{
542146129Sharti	if (fd[i] == -1)
543146129Sharti		return;
544146129Sharti	(void) close(fd[i]);
545146129Sharti	fd[i] = -1;
546146129Sharti}
547146129Sharti
548146129Shartistatic void
549146129Sharticlosep(int *fd)
550146129Sharti{
551146129Sharti	size_t i;
552146129Sharti	for (i = 0; i < 2; i++)
553146129Sharti		closefd(fd, i);
554146129Sharti}
555146129Sharti
556146129Shartistatic void
557146129Sharticopydesc(int i, int *fd)
558146129Sharti{
559146129Sharti	int j = fd[i == STDIN_FILENO ? 0 : 1];
560146129Sharti	if (j == i)
561146129Sharti		return;
562146129Sharti	if (dup2(j, i) == -1) {
563146129Sharti		DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno));
564146129Sharti		exit(1);
565146129Sharti	}
566146129Sharti	closep(fd);
567146129Sharti}
568146129Sharti
569146129Shartistatic void
570146129Shartiwritechild(int fdp[3][2], const void *old, size_t n)
571146129Sharti{
572146129Sharti	int status;
573146129Sharti
574146129Sharti	closefd(fdp[STDIN_FILENO], 0);
575146129Sharti	/*
576146129Sharti	 * fork again, to avoid blocking because both
577146129Sharti	 * pipes filled
578146129Sharti	 */
579146129Sharti	switch (fork()) {
580146129Sharti	case 0: /* child */
581146129Sharti		closefd(fdp[STDOUT_FILENO], 0);
582146129Sharti		if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) {
583146129Sharti			DPRINTF("Write failed (%s)\n", strerror(errno));
584146129Sharti			exit(1);
585146129Sharti		}
586146129Sharti		exit(0);
587146129Sharti		/*NOTREACHED*/
588146129Sharti
589146129Sharti	case -1:
590146129Sharti		DPRINTF("Fork failed (%s)\n", strerror(errno));
591146129Sharti		exit(1);
592146129Sharti		/*NOTREACHED*/
593146129Sharti
594146129Sharti	default:  /* parent */
595146129Sharti		if (wait(&status) == -1) {
596146129Sharti			DPRINTF("Wait failed (%s)\n", strerror(errno));
597146129Sharti			exit(1);
598146129Sharti		}
599146129Sharti		DPRINTF("Grandchild wait return %#x\n", status);
600146129Sharti	}
601146129Sharti	closefd(fdp[STDIN_FILENO], 1);
602146129Sharti}
603146129Sharti
604146129Shartistatic ssize_t
605146129Shartifilter_error(unsigned char *ubuf, ssize_t n)
606146129Sharti{
607146129Sharti	char *p;
608146129Sharti	char *buf;
609146129Sharti
610146129Sharti	ubuf[n] = '\0';
611146129Sharti	buf = (char *)ubuf;
612146129Sharti	while (isspace((unsigned char)*buf))
613146129Sharti		buf++;
614146129Sharti	DPRINTF("Filter error[[[%s]]]\n", buf);
615146129Sharti	if ((p = strchr((char *)buf, '\n')) != NULL)
616146129Sharti		*p = '\0';
617146129Sharti	if ((p = strchr((char *)buf, ';')) != NULL)
618146131Sharti		*p = '\0';
619146130Sharti	if ((p = strrchr((char *)buf, ':')) != NULL) {
620146130Sharti		++p;
621146130Sharti		while (isspace((unsigned char)*p))
622146130Sharti			p++;
623146130Sharti		n = strlen(p);
624146130Sharti		memmove(ubuf, p, n + 1);
625146130Sharti	}
626146130Sharti	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
627146130Sharti	if (islower(*ubuf))
628146130Sharti		*ubuf = toupper(*ubuf);
629146131Sharti	return n;
630146131Sharti}
631146131Sharti
632146131Shartiprivate const char *
633146131Shartimethodname(size_t method)
634146131Sharti{
635146131Sharti#ifdef BUILTIN_DECOMPRESS
636146131Sharti        /* FIXME: This doesn't cope with bzip2 */
637146131Sharti	if (method == 2 || compr[method].maglen == 0)
638146131Sharti	    return "zlib";
639146131Sharti#endif
640146131Sharti	return compr[method].argv[0];
641146130Sharti}
642146130Sharti
643146130Shartiprivate int
644146130Shartiuncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
645146130Sharti    unsigned char **newch, size_t* n)
646146130Sharti{
647137605Sharti	int fdp[3][2];
648144467Sharti	int status, rv;
649144467Sharti	size_t i;
650137605Sharti	ssize_t r;
651137605Sharti
652137605Sharti#ifdef BUILTIN_DECOMPRESS
653137605Sharti        /* FIXME: This doesn't cope with bzip2 */
654137605Sharti	if (method == 2)
655137605Sharti		return uncompressgzipped(old, newch, bytes_max, n);
656137605Sharti	if (compr[method].maglen == 0)
657137605Sharti		return uncompresszlib(old, newch, bytes_max, n, 1);
658144467Sharti#endif
6591590Srgrimes	(void)fflush(stdout);
660137252Sharti	(void)fflush(stderr);
6611590Srgrimes
6621590Srgrimes	for (i = 0; i < __arraycount(fdp); i++)
6631590Srgrimes		fdp[i][0] = fdp[i][1] = -1;
6641590Srgrimes
6651590Srgrimes	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
6661590Srgrimes	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
667104696Sjmallett		closep(fdp[STDIN_FILENO]);
6681590Srgrimes		closep(fdp[STDOUT_FILENO]);
669144741Sharti		return makeerror(newch, n, "Cannot create pipe, %s",
670144467Sharti		    strerror(errno));
671144467Sharti	}
6728874Srgrimes	switch (fork()) {
673144467Sharti	case 0:	/* child */
674144467Sharti		if (fd != -1) {
675144467Sharti			fdp[STDIN_FILENO][0] = fd;
676137605Sharti			(void) lseek(fd, (off_t)0, SEEK_SET);
677144467Sharti		}
678144741Sharti
679144741Sharti		for (i = 0; i < __arraycount(fdp); i++)
680144741Sharti			copydesc(i, fdp[i]);
681144741Sharti
682144741Sharti		(void)execvp(compr[method].argv[0],
6831590Srgrimes		    (char *const *)(intptr_t)compr[method].argv);
684144467Sharti		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
685144467Sharti		    compr[method].argv[0], strerror(errno));
686144467Sharti		exit(1);
687144467Sharti		/*NOTREACHED*/
688144467Sharti	case -1:
689144467Sharti		return makeerror(newch, n, "Cannot fork, %s",
690144467Sharti		    strerror(errno));
691144467Sharti
692144657Sharti	default: /* parent */
693144467Sharti		for (i = 1; i < __arraycount(fdp); i++)
694144467Sharti			closefd(fdp[i], 1);
6958874Srgrimes
696144467Sharti		/* Write the buffer data to the child, if we don't have fd */
697144467Sharti		if (fd == -1)
698144467Sharti			writechild(fdp, old, *n);
699144467Sharti
700144467Sharti		*newch = CAST(unsigned char *, malloc(bytes_max + 1));
701144467Sharti		if (*newch == NULL) {
7028874Srgrimes			rv = makeerror(newch, n, "No buffer, %s",
703144467Sharti			    strerror(errno));
704144467Sharti			goto err;
705144467Sharti		}
706144467Sharti		rv = OKDATA;
707144467Sharti		if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0)
708144467Sharti			break;
709144467Sharti		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
710144467Sharti		    r != -1 ? strerror(errno) : "no data");
711144467Sharti
712144467Sharti		rv = ERRDATA;
713144467Sharti		if (r == 0 &&
7141590Srgrimes		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
715144467Sharti		{
716144467Sharti			r = filter_error(*newch, r);
717144467Sharti			break;
7181590Srgrimes		}
719144467Sharti		free(*newch);
72018730Ssteve		if  (r == 0)
721144467Sharti			rv = makeerror(newch, n, "Read failed, %s",
722144741Sharti			    strerror(errno));
723144741Sharti		else
724144741Sharti			rv = makeerror(newch, n, "No data");
725144741Sharti		goto err;
726144741Sharti	}
7271590Srgrimes
728144467Sharti	*n = r;
729144467Sharti	/* NUL terminate, as every buffer is handled here. */
730144467Sharti	(*newch)[*n] = '\0';
731144467Shartierr:
7321590Srgrimes	closefd(fdp[STDIN_FILENO], 1);
7331590Srgrimes	closefd(fdp[STDOUT_FILENO], 0);
734144467Sharti	closefd(fdp[STDERR_FILENO], 0);
7351590Srgrimes	if (wait(&status) == -1) {
7361590Srgrimes		free(*newch);
7371590Srgrimes		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
7381590Srgrimes		DPRINTF("Child wait return %#x\n", status);
7391590Srgrimes	} else if (!WIFEXITED(status)) {
7401590Srgrimes		DPRINTF("Child not exited (0x%x)\n", status);
7411590Srgrimes	} else if (WEXITSTATUS(status) != 0) {
7421590Srgrimes		DPRINTF("Child exited (0x%d)\n", WEXITSTATUS(status));
7431590Srgrimes	}
7441590Srgrimes
7451590Srgrimes	closefd(fdp[STDIN_FILENO], 0);
74694594Sobrien	DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv);
747142993Sharti
7481590Srgrimes	return rv;
7491590Srgrimes}
7501590Srgrimes#endif
7511590Srgrimes