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