xref: /netbsd-src/external/bsd/file/dist/src/compress.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*	$NetBSD: compress.c,v 1.17 2018/10/19 00:24:57 christos Exp $	*/
2 
3 /*
4  * Copyright (c) Ian F. Darwin 1986-1995.
5  * Software written by Ian F. Darwin and others;
6  * maintained 1995-present by Christos Zoulas and others.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice immediately at the beginning of the file, without modification,
13  *    this list of conditions, and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*
31  * compress routines:
32  *	zmagic() - returns 0 if not recognized, uncompresses and prints
33  *		   information if recognized
34  *	uncompress(method, old, n, newch) - uncompress old into new,
35  *					    using method, return sizeof new
36  */
37 #include "file.h"
38 
39 #ifndef lint
40 #if 0
41 FILE_RCSID("@(#)$File: compress.c,v 1.113 2018/10/15 16:29:16 christos Exp $")
42 #else
43 __RCSID("$NetBSD: compress.c,v 1.17 2018/10/19 00:24:57 christos Exp $");
44 #endif
45 #endif
46 
47 #include "magic.h"
48 #include <stdlib.h>
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <string.h>
53 #include <errno.h>
54 #include <ctype.h>
55 #include <stdarg.h>
56 #include <signal.h>
57 #ifndef HAVE_SIG_T
58 typedef void (*sig_t)(int);
59 #endif /* HAVE_SIG_T */
60 #if !defined(__MINGW32__) && !defined(WIN32)
61 #include <sys/ioctl.h>
62 #endif
63 #ifdef HAVE_SYS_WAIT_H
64 #include <sys/wait.h>
65 #endif
66 #if defined(HAVE_SYS_TIME_H)
67 #include <sys/time.h>
68 #endif
69 
70 #if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT)
71 #define BUILTIN_DECOMPRESS
72 #include <zlib.h>
73 #endif
74 
75 #if defined(HAVE_BZLIB_H)
76 #define BUILTIN_BZLIB
77 #include <bzlib.h>
78 #endif
79 
80 #ifdef DEBUG
81 int tty = -1;
82 #define DPRINTF(...)	do { \
83 	if (tty == -1) \
84 		tty = open("/dev/tty", O_RDWR); \
85 	if (tty == -1) \
86 		abort(); \
87 	dprintf(tty, __VA_ARGS__); \
88 } while (/*CONSTCOND*/0)
89 #else
90 #define DPRINTF(...)
91 #endif
92 
93 #ifdef ZLIBSUPPORT
94 /*
95  * The following python code is not really used because ZLIBSUPPORT is only
96  * defined if we have a built-in zlib, and the built-in zlib handles that.
97  * That is not true for android where we have zlib.h and not -lz.
98  */
99 static const char zlibcode[] =
100     "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
101 
102 static const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
103 
104 static int
105 zlibcmp(const unsigned char *buf)
106 {
107 	unsigned short x = 1;
108 	unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
109 
110 	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
111 		return 0;
112 	if (s[0] != 1)	/* endianness test */
113 		x = buf[0] | (buf[1] << 8);
114 	else
115 		x = buf[1] | (buf[0] << 8);
116 	if (x % 31)
117 		return 0;
118 	return 1;
119 }
120 #endif
121 
122 #define gzip_flags "-cd"
123 #define lrzip_flags "-do"
124 #define lzip_flags gzip_flags
125 
126 static const char *gzip_args[] = {
127 	"gzip", gzip_flags, NULL
128 };
129 static const char *uncompress_args[] = {
130 	"uncompress", "-c", NULL
131 };
132 static const char *bzip2_args[] = {
133 	"bzip2", "-cd", NULL
134 };
135 static const char *lzip_args[] = {
136 	"lzip", lzip_flags, NULL
137 };
138 static const char *xz_args[] = {
139 	"xz", "-cd", NULL
140 };
141 static const char *lrzip_args[] = {
142 	"lrzip", lrzip_flags, NULL
143 };
144 static const char *lz4_args[] = {
145 	"lz4", "-cd", NULL
146 };
147 static const char *zstd_args[] = {
148 	"zstd", "-cd", NULL
149 };
150 
151 #define	do_zlib		NULL
152 #define	do_bzlib	NULL
153 
154 private const struct {
155 	const void *magic;
156 	size_t maglen;
157 	const char **argv;
158 	void *unused;
159 } compr[] = {
160 	{ "\037\235",	2, gzip_args, NULL },		/* compressed */
161 	/* Uncompress can get stuck; so use gzip first if we have it
162 	 * Idea from Damien Clark, thanks! */
163 	{ "\037\235",	2, uncompress_args, NULL },	/* compressed */
164 	{ "\037\213",	2, gzip_args, do_zlib },	/* gzipped */
165 	{ "\037\236",	2, gzip_args, NULL },		/* frozen */
166 	{ "\037\240",	2, gzip_args, NULL },		/* SCO LZH */
167 	/* the standard pack utilities do not accept standard input */
168 	{ "\037\036",	2, gzip_args, NULL },		/* packed */
169 	{ "PK\3\4",	4, gzip_args, NULL },		/* pkzipped, */
170 	/* ...only first file examined */
171 	{ "BZh",	3, bzip2_args, do_bzlib },	/* bzip2-ed */
172 	{ "LZIP",	4, lzip_args, NULL },		/* lzip-ed */
173  	{ "\3757zXZ\0",	6, xz_args, NULL },		/* XZ Utils */
174  	{ "LRZI",	4, lrzip_args, NULL },	/* LRZIP */
175  	{ "\004\"M\030",4, lz4_args, NULL },		/* LZ4 */
176  	{ "\x28\xB5\x2F\xFD", 4, zstd_args, NULL },	/* zstd */
177 #ifdef ZLIBSUPPORT
178 	{ RCAST(const void *, zlibcmp),	0, zlib_args, NULL },	/* zlib */
179 #endif
180 };
181 
182 #define OKDATA 	0
183 #define NODATA	1
184 #define ERRDATA	2
185 
186 private ssize_t swrite(int, const void *, size_t);
187 #if HAVE_FORK
188 private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
189 private int uncompressbuf(int, size_t, size_t, const unsigned char *,
190     unsigned char **, size_t *);
191 #ifdef BUILTIN_DECOMPRESS
192 private int uncompresszlib(const unsigned char *, unsigned char **, size_t,
193     size_t *, int);
194 private int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
195     size_t *);
196 #endif
197 #ifdef BUILTIN_BZLIB
198 private int uncompressbzlib(const unsigned char *, unsigned char **, size_t,
199     size_t *, int);
200 #endif
201 
202 static int makeerror(unsigned char **, size_t *, const char *, ...)
203     __attribute__((__format__(__printf__, 3, 4)));
204 private const char *methodname(size_t);
205 
206 private int
207 format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf)
208 {
209 	unsigned char *p;
210 	int mime = ms->flags & MAGIC_MIME;
211 
212 	if (!mime)
213 		return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf);
214 
215 	for (p = buf; *p; p++)
216 		if (!isalnum(*p))
217 			*p = '-';
218 
219 	return file_printf(ms, "application/x-decompression-error-%s-%s",
220 	    methodname(i), buf);
221 }
222 
223 protected int
224 file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
225 {
226 	unsigned char *newbuf = NULL;
227 	size_t i, nsz;
228 	char *rbuf;
229 	file_pushbuf_t *pb;
230 	int urv, prv, rv = 0;
231 	int mime = ms->flags & MAGIC_MIME;
232 	int fd = b->fd;
233 	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
234 	size_t nbytes = b->flen;
235 	sig_t osigpipe;
236 
237 	if ((ms->flags & MAGIC_COMPRESS) == 0)
238 		return 0;
239 
240 	osigpipe = signal(SIGPIPE, SIG_IGN);
241 	for (i = 0; i < ncompr; i++) {
242 		int zm;
243 		if (nbytes < compr[i].maglen)
244 			continue;
245 #ifdef ZLIBSUPPORT
246 		if (compr[i].maglen == 0)
247 			zm = (RCAST(int (*)(const unsigned char *),
248 			    CCAST(void *, compr[i].magic)))(buf);
249 		else
250 #endif
251 			zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0;
252 
253 		if (!zm)
254 			continue;
255 		nsz = nbytes;
256 		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
257 		DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
258 		    (char *)newbuf, nsz);
259 		switch (urv) {
260 		case OKDATA:
261 		case ERRDATA:
262 			ms->flags &= ~MAGIC_COMPRESS;
263 			if (urv == ERRDATA)
264 				prv = format_decompression_error(ms, i, newbuf);
265 			else
266 				prv = file_buffer(ms, -1, name, newbuf, nsz);
267 			if (prv == -1)
268 				goto error;
269 			rv = 1;
270 			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
271 				goto out;
272 			if (mime != MAGIC_MIME && mime != 0)
273 				goto out;
274 			if ((file_printf(ms,
275 			    mime ? " compressed-encoding=" : " (")) == -1)
276 				goto error;
277 			if ((pb = file_push_buffer(ms)) == NULL)
278 				goto error;
279 			/*
280 			 * XXX: If file_buffer fails here, we overwrite
281 			 * the compressed text. FIXME.
282 			 */
283 			if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) {
284 				if (file_pop_buffer(ms, pb) != NULL)
285 					abort();
286 				goto error;
287 			}
288 			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
289 				if (file_printf(ms, "%s", rbuf) == -1) {
290 					free(rbuf);
291 					goto error;
292 				}
293 				free(rbuf);
294 			}
295 			if (!mime && file_printf(ms, ")") == -1)
296 				goto error;
297 			/*FALLTHROUGH*/
298 		case NODATA:
299 			break;
300 		default:
301 			abort();
302 			/*NOTREACHED*/
303 		error:
304 			rv = -1;
305 			break;
306 		}
307 	}
308 out:
309 	DPRINTF("rv = %d\n", rv);
310 
311 	(void)signal(SIGPIPE, osigpipe);
312 	free(newbuf);
313 	ms->flags |= MAGIC_COMPRESS;
314 	DPRINTF("Zmagic returns %d\n", rv);
315 	return rv;
316 }
317 #endif
318 /*
319  * `safe' write for sockets and pipes.
320  */
321 private ssize_t
322 swrite(int fd, const void *buf, size_t n)
323 {
324 	ssize_t rv;
325 	size_t rn = n;
326 
327 	do
328 		switch (rv = write(fd, buf, n)) {
329 		case -1:
330 			if (errno == EINTR)
331 				continue;
332 			return -1;
333 		default:
334 			n -= rv;
335 			buf = CAST(const char *, buf) + rv;
336 			break;
337 		}
338 	while (n > 0);
339 	return rn;
340 }
341 
342 
343 /*
344  * `safe' read for sockets and pipes.
345  */
346 protected ssize_t
347 sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
348 {
349 	ssize_t rv;
350 #ifdef FIONREAD
351 	int t = 0;
352 #endif
353 	size_t rn = n;
354 
355 	if (fd == STDIN_FILENO)
356 		goto nocheck;
357 
358 #ifdef FIONREAD
359 	if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
360 #ifdef FD_ZERO
361 		ssize_t cnt;
362 		for (cnt = 0;; cnt++) {
363 			fd_set check;
364 			struct timeval tout = {0, 100 * 1000};
365 			int selrv;
366 
367 			FD_ZERO(&check);
368 			FD_SET(fd, &check);
369 
370 			/*
371 			 * Avoid soft deadlock: do not read if there
372 			 * is nothing to read from sockets and pipes.
373 			 */
374 			selrv = select(fd + 1, &check, NULL, NULL, &tout);
375 			if (selrv == -1) {
376 				if (errno == EINTR || errno == EAGAIN)
377 					continue;
378 			} else if (selrv == 0 && cnt >= 5) {
379 				return 0;
380 			} else
381 				break;
382 		}
383 #endif
384 		(void)ioctl(fd, FIONREAD, &t);
385 	}
386 
387 	if (t > 0 && (size_t)t < n) {
388 		n = t;
389 		rn = n;
390 	}
391 #endif
392 
393 nocheck:
394 	do
395 		switch ((rv = read(fd, buf, n))) {
396 		case -1:
397 			if (errno == EINTR)
398 				continue;
399 			return -1;
400 		case 0:
401 			return rn - n;
402 		default:
403 			n -= rv;
404 			buf = CAST(char *, CCAST(void *, buf)) + rv;
405 			break;
406 		}
407 	while (n > 0);
408 	return rn;
409 }
410 
411 protected int
412 file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
413     size_t nbytes)
414 {
415 	char buf[4096];
416 	ssize_t r;
417 	int tfd;
418 
419 	(void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
420 #ifndef HAVE_MKSTEMP
421 	{
422 		char *ptr = mktemp(buf);
423 		tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
424 		r = errno;
425 		(void)unlink(ptr);
426 		errno = r;
427 	}
428 #else
429 	{
430 		int te;
431 		mode_t ou = umask(0);
432 		tfd = mkstemp(buf);
433 		(void)umask(ou);
434 		te = errno;
435 		(void)unlink(buf);
436 		errno = te;
437 	}
438 #endif
439 	if (tfd == -1) {
440 		file_error(ms, errno,
441 		    "cannot create temporary file for pipe copy");
442 		return -1;
443 	}
444 
445 	if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
446 		r = 1;
447 	else {
448 		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
449 			if (swrite(tfd, buf, (size_t)r) != r)
450 				break;
451 	}
452 
453 	switch (r) {
454 	case -1:
455 		file_error(ms, errno, "error copying from pipe to temp file");
456 		return -1;
457 	case 0:
458 		break;
459 	default:
460 		file_error(ms, errno, "error while writing to temp file");
461 		return -1;
462 	}
463 
464 	/*
465 	 * We duplicate the file descriptor, because fclose on a
466 	 * tmpfile will delete the file, but any open descriptors
467 	 * can still access the phantom inode.
468 	 */
469 	if ((fd = dup2(tfd, fd)) == -1) {
470 		file_error(ms, errno, "could not dup descriptor for temp file");
471 		return -1;
472 	}
473 	(void)close(tfd);
474 	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
475 		file_badseek(ms);
476 		return -1;
477 	}
478 	return fd;
479 }
480 #if HAVE_FORK
481 #ifdef BUILTIN_DECOMPRESS
482 
483 #define FHCRC		(1 << 1)
484 #define FEXTRA		(1 << 2)
485 #define FNAME		(1 << 3)
486 #define FCOMMENT	(1 << 4)
487 
488 
489 private int
490 uncompressgzipped(const unsigned char *old, unsigned char **newch,
491     size_t bytes_max, size_t *n)
492 {
493 	unsigned char flg = old[3];
494 	size_t data_start = 10;
495 
496 	if (flg & FEXTRA) {
497 		if (data_start + 1 >= *n)
498 			goto err;
499 		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
500 	}
501 	if (flg & FNAME) {
502 		while(data_start < *n && old[data_start])
503 			data_start++;
504 		data_start++;
505 	}
506 	if (flg & FCOMMENT) {
507 		while(data_start < *n && old[data_start])
508 			data_start++;
509 		data_start++;
510 	}
511 	if (flg & FHCRC)
512 		data_start += 2;
513 
514 	if (data_start >= *n)
515 		goto err;
516 
517 	*n -= data_start;
518 	old += data_start;
519 	return uncompresszlib(old, newch, bytes_max, n, 0);
520 err:
521 	return makeerror(newch, n, "File too short");
522 }
523 
524 private int
525 uncompresszlib(const unsigned char *old, unsigned char **newch,
526     size_t bytes_max, size_t *n, int zlib)
527 {
528 	int rc;
529 	z_stream z;
530 
531 	if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
532 		return makeerror(newch, n, "No buffer, %s", strerror(errno));
533 
534 	z.next_in = CCAST(Bytef *, old);
535 	z.avail_in = CAST(uint32_t, *n);
536 	z.next_out = *newch;
537 	z.avail_out = CAST(unsigned int, bytes_max);
538 	z.zalloc = Z_NULL;
539 	z.zfree = Z_NULL;
540 	z.opaque = Z_NULL;
541 
542 	/* LINTED bug in header macro */
543 	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
544 	if (rc != Z_OK)
545 		goto err;
546 
547 	rc = inflate(&z, Z_SYNC_FLUSH);
548 	if (rc != Z_OK && rc != Z_STREAM_END)
549 		goto err;
550 
551 	*n = (size_t)z.total_out;
552 	rc = inflateEnd(&z);
553 	if (rc != Z_OK)
554 		goto err;
555 
556 	/* let's keep the nul-terminate tradition */
557 	(*newch)[*n] = '\0';
558 
559 	return OKDATA;
560 err:
561 	strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max);
562 	*n = strlen((char *)*newch);
563 	return ERRDATA;
564 }
565 #endif
566 
567 static int
568 makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
569 {
570 	char *msg;
571 	va_list ap;
572 	int rv;
573 
574 	va_start(ap, fmt);
575 	rv = vasprintf(&msg, fmt, ap);
576 	va_end(ap);
577 	if (rv < 0) {
578 		*buf = NULL;
579 		*len = 0;
580 		return NODATA;
581 	}
582 	*buf = (unsigned char *)msg;
583 	*len = strlen(msg);
584 	return ERRDATA;
585 }
586 
587 static void
588 closefd(int *fd, size_t i)
589 {
590 	if (fd[i] == -1)
591 		return;
592 	(void) close(fd[i]);
593 	fd[i] = -1;
594 }
595 
596 static void
597 closep(int *fd)
598 {
599 	size_t i;
600 	for (i = 0; i < 2; i++)
601 		closefd(fd, i);
602 }
603 
604 static void
605 copydesc(int i, int *fd)
606 {
607 	int j = fd[i == STDIN_FILENO ? 0 : 1];
608 	if (j == i)
609 		return;
610 	if (dup2(j, i) == -1) {
611 		DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno));
612 		exit(1);
613 	}
614 	closep(fd);
615 }
616 
617 static void
618 writechild(int fdp[3][2], const void *old, size_t n)
619 {
620 	int status;
621 
622 	closefd(fdp[STDIN_FILENO], 0);
623 	/*
624 	 * fork again, to avoid blocking because both
625 	 * pipes filled
626 	 */
627 	switch (fork()) {
628 	case 0: /* child */
629 		closefd(fdp[STDOUT_FILENO], 0);
630 		if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) {
631 			DPRINTF("Write failed (%s)\n", strerror(errno));
632 			exit(1);
633 		}
634 		exit(0);
635 		/*NOTREACHED*/
636 
637 	case -1:
638 		DPRINTF("Fork failed (%s)\n", strerror(errno));
639 		exit(1);
640 		/*NOTREACHED*/
641 
642 	default:  /* parent */
643 		if (wait(&status) == -1) {
644 			DPRINTF("Wait failed (%s)\n", strerror(errno));
645 			exit(1);
646 		}
647 		DPRINTF("Grandchild wait return %#x\n", status);
648 	}
649 	closefd(fdp[STDIN_FILENO], 1);
650 }
651 
652 static ssize_t
653 filter_error(unsigned char *ubuf, ssize_t n)
654 {
655 	char *p;
656 	char *buf;
657 
658 	ubuf[n] = '\0';
659 	buf = (char *)ubuf;
660 	while (isspace((unsigned char)*buf))
661 		buf++;
662 	DPRINTF("Filter error[[[%s]]]\n", buf);
663 	if ((p = strchr((char *)buf, '\n')) != NULL)
664 		*p = '\0';
665 	if ((p = strchr((char *)buf, ';')) != NULL)
666 		*p = '\0';
667 	if ((p = strrchr((char *)buf, ':')) != NULL) {
668 		++p;
669 		while (isspace((unsigned char)*p))
670 			p++;
671 		n = strlen(p);
672 		memmove(ubuf, p, CAST(size_t, n + 1));
673 	}
674 	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
675 	if (islower(*ubuf))
676 		*ubuf = toupper(*ubuf);
677 	return n;
678 }
679 
680 private const char *
681 methodname(size_t method)
682 {
683 #ifdef BUILTIN_DECOMPRESS
684         /* FIXME: This doesn't cope with bzip2 */
685 	if (method == 2 || compr[method].maglen == 0)
686 	    return "zlib";
687 #endif
688 	return compr[method].argv[0];
689 }
690 
691 private int
692 uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
693     unsigned char **newch, size_t* n)
694 {
695 	int fdp[3][2];
696 	int status, rv;
697 	size_t i;
698 	ssize_t r;
699 
700 #ifdef BUILTIN_DECOMPRESS
701         /* FIXME: This doesn't cope with bzip2 */
702 	if (method == 2)
703 		return uncompressgzipped(old, newch, bytes_max, n);
704 	if (compr[method].maglen == 0)
705 		return uncompresszlib(old, newch, bytes_max, n, 1);
706 #endif
707 	(void)fflush(stdout);
708 	(void)fflush(stderr);
709 
710 	for (i = 0; i < __arraycount(fdp); i++)
711 		fdp[i][0] = fdp[i][1] = -1;
712 
713 	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
714 	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
715 		closep(fdp[STDIN_FILENO]);
716 		closep(fdp[STDOUT_FILENO]);
717 		return makeerror(newch, n, "Cannot create pipe, %s",
718 		    strerror(errno));
719 	}
720 	switch (fork()) {
721 	case 0:	/* child */
722 		if (fd != -1) {
723 			fdp[STDIN_FILENO][0] = fd;
724 			(void) lseek(fd, (off_t)0, SEEK_SET);
725 		}
726 
727 		for (i = 0; i < __arraycount(fdp); i++)
728 			copydesc(CAST(int, i), fdp[i]);
729 
730 		(void)execvp(compr[method].argv[0],
731 		    (char *const *)(intptr_t)compr[method].argv);
732 		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
733 		    compr[method].argv[0], strerror(errno));
734 		exit(1);
735 		/*NOTREACHED*/
736 	case -1:
737 		return makeerror(newch, n, "Cannot fork, %s",
738 		    strerror(errno));
739 
740 	default: /* parent */
741 		for (i = 1; i < __arraycount(fdp); i++)
742 			closefd(fdp[i], 1);
743 
744 		/* Write the buffer data to the child, if we don't have fd */
745 		if (fd == -1)
746 			writechild(fdp, old, *n);
747 
748 		*newch = CAST(unsigned char *, malloc(bytes_max + 1));
749 		if (*newch == NULL) {
750 			rv = makeerror(newch, n, "No buffer, %s",
751 			    strerror(errno));
752 			goto err;
753 		}
754 		rv = OKDATA;
755 		if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0)
756 			break;
757 		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
758 		    r != -1 ? strerror(errno) : "no data");
759 
760 		rv = ERRDATA;
761 		if (r == 0 &&
762 		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
763 		{
764 			r = filter_error(*newch, r);
765 			break;
766 		}
767 		free(*newch);
768 		if  (r == 0)
769 			rv = makeerror(newch, n, "Read failed, %s",
770 			    strerror(errno));
771 		else
772 			rv = makeerror(newch, n, "No data");
773 		goto err;
774 	}
775 
776 	*n = r;
777 	/* NUL terminate, as every buffer is handled here. */
778 	(*newch)[*n] = '\0';
779 err:
780 	closefd(fdp[STDIN_FILENO], 1);
781 	closefd(fdp[STDOUT_FILENO], 0);
782 	closefd(fdp[STDERR_FILENO], 0);
783 	if (wait(&status) == -1) {
784 		free(*newch);
785 		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
786 		DPRINTF("Child wait return %#x\n", status);
787 	} else if (!WIFEXITED(status)) {
788 		DPRINTF("Child not exited (%#x)\n", status);
789 	} else if (WEXITSTATUS(status) != 0) {
790 		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
791 	}
792 
793 	closefd(fdp[STDIN_FILENO], 0);
794 	DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
795 
796 	return rv;
797 }
798 #endif
799