xref: /PHP-7.4/ext/fileinfo/libmagic/compress.c (revision f002761e)
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 <signal.h>
49 #ifndef HAVE_SIG_T
50 typedef void (*sig_t)(int);
51 #endif /* HAVE_SIG_T */
52 #ifndef PHP_WIN32
53 #include <sys/ioctl.h>
54 #endif
55 #ifdef HAVE_SYS_WAIT_H
56 #include <sys/wait.h>
57 #endif
58 #if defined(HAVE_SYS_TIME_H)
59 #include <sys/time.h>
60 #endif
61 #if defined(HAVE_ZLIB_H) && defined(PHP_FILEINFO_UNCOMPRESS)
62 #define BUILTIN_DECOMPRESS
63 #include <zlib.h>
64 #endif
65 
66 #undef FIONREAD
67 
68 #if defined(PHP_FILEINFO_UNCOMPRESS)
69 #define BUILTIN_BZLIB
70 #include <bzlib.h>
71 #endif
72 
73 #ifdef DEBUG
74 int tty = -1;
75 #define DPRINTF(...)	do { \
76 	if (tty == -1) \
77 		tty = open("/dev/tty", O_RDWR); \
78 	if (tty == -1) \
79 		abort(); \
80 	dprintf(tty, __VA_ARGS__); \
81 } while (/*CONSTCOND*/0)
82 #else
83 #define DPRINTF(...)
84 #endif
85 
86 #ifdef ZLIBSUPPORT
87 /*
88  * The following python code is not really used because ZLIBSUPPORT is only
89  * defined if we have a built-in zlib, and the built-in zlib handles that.
90  * That is not true for android where we have zlib.h and not -lz.
91  */
92 static const char zlibcode[] =
93     "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
94 
95 static const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
96 
97 static int
zlibcmp(const unsigned char * buf)98 zlibcmp(const unsigned char *buf)
99 {
100 	unsigned short x = 1;
101 	unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
102 
103 	if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
104 		return 0;
105 	if (s[0] != 1)	/* endianness test */
106 		x = buf[0] | (buf[1] << 8);
107 	else
108 		x = buf[1] | (buf[0] << 8);
109 	if (x % 31)
110 		return 0;
111 	return 1;
112 }
113 #endif
114 
115 #define gzip_flags "-cd"
116 #define lrzip_flags "-do"
117 #define lzip_flags gzip_flags
118 #ifdef PHP_FILEINFO_UNCOMPRESS
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 private const char *methodname(size_t);
198 
199 private int
format_decompression_error(struct magic_set * ms,size_t i,unsigned char * buf)200 format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf)
201 {
202 	unsigned char *p;
203 	int mime = ms->flags & MAGIC_MIME;
204 
205 	if (!mime)
206 		return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf);
207 
208 	for (p = buf; *p; p++)
209 		if (!isalnum(*p))
210 			*p = '-';
211 
212 	return file_printf(ms, "application/x-decompression-error-%s-%s",
213 	    methodname(i), buf);
214 }
215 
216 protected int
file_zmagic(struct magic_set * ms,const struct buffer * b,const char * name)217 file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
218 {
219 	unsigned char *newbuf = NULL;
220 	size_t i, nsz;
221 	char *rbuf;
222 	file_pushbuf_t *pb;
223 	int urv, prv, rv = 0;
224 	int mime = ms->flags & MAGIC_MIME;
225 	int fd = b->fd;
226 	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
227 	size_t nbytes = b->flen;
228 	int sa_saved = 0;
229 	struct sigaction sig_act;
230 
231 	if ((ms->flags & MAGIC_COMPRESS) == 0)
232 		return 0;
233 
234 	for (i = 0; i < ncompr; i++) {
235 		int zm;
236 		if (nbytes < compr[i].maglen)
237 			continue;
238 #ifdef ZLIBSUPPORT
239 		if (compr[i].maglen == 0)
240 			zm = (RCAST(int (*)(const unsigned char *),
241 			    CCAST(void *, compr[i].magic)))(buf);
242 		else
243 #endif
244 			zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0;
245 
246 		if (!zm)
247 			continue;
248 
249 		/* Prevent SIGPIPE death if child dies unexpectedly */
250 		if (!sa_saved) {
251 			//We can use sig_act for both new and old, but
252 			struct sigaction new_act;
253 			memset(&new_act, 0, sizeof(new_act));
254 			new_act.sa_handler = SIG_IGN;
255 			sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1;
256 		}
257 
258 		nsz = nbytes;
259 		urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
260 		DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
261 		    (char *)newbuf, nsz);
262 		switch (urv) {
263 		case OKDATA:
264 		case ERRDATA:
265 			ms->flags &= ~MAGIC_COMPRESS;
266 			if (urv == ERRDATA)
267 				prv = format_decompression_error(ms, i, newbuf);
268 			else
269 				prv = file_buffer(ms, NULL, NULL, name, newbuf, nsz);
270 			if (prv == -1)
271 				goto error;
272 			rv = 1;
273 			if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
274 				goto out;
275 			if (mime != MAGIC_MIME && mime != 0)
276 				goto out;
277 			if ((file_printf(ms,
278 			    mime ? " compressed-encoding=" : " (")) == -1)
279 				goto error;
280 			if ((pb = file_push_buffer(ms)) == NULL)
281 				goto error;
282 			/*
283 			 * XXX: If file_buffer fails here, we overwrite
284 			 * the compressed text. FIXME.
285 			 */
286 			if (file_buffer(ms, NULL, NULL, NULL, buf, nbytes) == -1) {
287 				if (file_pop_buffer(ms, pb) != NULL)
288 					abort();
289 				goto error;
290 			}
291 			if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
292 				if (file_printf(ms, "%s", rbuf) == -1) {
293 					efree(rbuf);
294 					goto error;
295 				}
296 				efree(rbuf);
297 			}
298 			if (!mime && file_printf(ms, ")") == -1)
299 				goto error;
300 			/*FALLTHROUGH*/
301 		case NODATA:
302 			break;
303 		default:
304 			abort();
305 			/*NOTREACHED*/
306 		error:
307 			rv = -1;
308 			break;
309 		}
310 	}
311 out:
312 	DPRINTF("rv = %d\n", rv);
313 
314 	if (sa_saved && sig_act.sa_handler != SIG_IGN)
315 		(void)sigaction(SIGPIPE, &sig_act, NULL);
316 
317 	if (newbuf)
318 		efree(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
swrite(int fd,const void * buf,size_t n)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
sread(int fd,void * buf,size_t n,int canbepipe)353 sread(int fd, void *buf, size_t n, int canbepipe)
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 = FINFO_READ_FUNC(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
file_pipe2file(struct magic_set * ms,int fd,const void * startbuf,size_t nbytes)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 		tfd = mkstemp(buf);
438 		(void)umask(ou);
439 		te = errno;
440 		(void)unlink(buf);
441 		errno = te;
442 	}
443 #endif
444 	if (tfd == -1) {
445 		file_error(ms, errno,
446 		    "cannot create temporary file for pipe copy");
447 		return -1;
448 	}
449 
450 	if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes))
451 		r = 1;
452 	else {
453 		while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
454 			if (swrite(tfd, buf, CAST(size_t, r)) != r)
455 				break;
456 	}
457 
458 	switch (r) {
459 	case -1:
460 		file_error(ms, errno, "error copying from pipe to temp file");
461 		return -1;
462 	case 0:
463 		break;
464 	default:
465 		file_error(ms, errno, "error while writing to temp file");
466 		return -1;
467 	}
468 
469 	/*
470 	 * We duplicate the file descriptor, because fclose on a
471 	 * tmpfile will delete the file, but any open descriptors
472 	 * can still access the phantom inode.
473 	 */
474 	if ((fd = dup2(tfd, fd)) == -1) {
475 		file_error(ms, errno, "could not dup descriptor for temp file");
476 		return -1;
477 	}
478 	(void)close(tfd);
479 	if (FINFO_LSEEK_FUNC(fd, (zend_off_t)0, SEEK_SET) == (zend_off_t)-1) {
480 		file_badseek(ms);
481 		return -1;
482 	}
483 	return fd;
484 }
485 #ifdef PHP_FILEINFO_UNCOMPRESS
486 #ifdef BUILTIN_DECOMPRESS
487 
488 #define FHCRC		(1 << 1)
489 #define FEXTRA		(1 << 2)
490 #define FNAME		(1 << 3)
491 #define FCOMMENT	(1 << 4)
492 
493 
494 private int
uncompressgzipped(const unsigned char * old,unsigned char ** newch,size_t bytes_max,size_t * n)495 uncompressgzipped(const unsigned char *old, unsigned char **newch,
496     size_t bytes_max, size_t *n)
497 {
498 	unsigned char flg = old[3];
499 	size_t data_start = 10;
500 
501 	if (flg & FEXTRA) {
502 		if (data_start + 1 >= *n)
503 			goto err;
504 		data_start += 2 + old[data_start] + old[data_start + 1] * 256;
505 	}
506 	if (flg & FNAME) {
507 		while(data_start < *n && old[data_start])
508 			data_start++;
509 		data_start++;
510 	}
511 	if (flg & FCOMMENT) {
512 		while(data_start < *n && old[data_start])
513 			data_start++;
514 		data_start++;
515 	}
516 	if (flg & FHCRC)
517 		data_start += 2;
518 
519 	if (data_start >= *n)
520 		goto err;
521 
522 	*n -= data_start;
523 	old += data_start;
524 	return uncompresszlib(old, newch, bytes_max, n, 0);
525 err:
526 	return makeerror(newch, n, "File too short");
527 }
528 
529 private int
uncompresszlib(const unsigned char * old,unsigned char ** newch,size_t bytes_max,size_t * n,int zlib)530 uncompresszlib(const unsigned char *old, unsigned char **newch,
531     size_t bytes_max, size_t *n, int zlib)
532 {
533 	int rc;
534 	z_stream z;
535 
536 	if ((*newch = CAST(unsigned char *, emalloc(bytes_max + 1))) == NULL)
537 		return makeerror(newch, n, "No buffer, %s", strerror(errno));
538 
539 	z.next_in = CCAST(Bytef *, old);
540 	z.avail_in = CAST(uint32_t, *n);
541 	z.next_out = *newch;
542 	z.avail_out = CAST(unsigned int, bytes_max);
543 	z.zalloc = Z_NULL;
544 	z.zfree = Z_NULL;
545 	z.opaque = Z_NULL;
546 
547 	/* LINTED bug in header macro */
548 	rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
549 	if (rc != Z_OK)
550 		goto err;
551 
552 	rc = inflate(&z, Z_SYNC_FLUSH);
553 	if (rc != Z_OK && rc != Z_STREAM_END)
554 		goto err;
555 
556 	*n = CAST(size_t, z.total_out);
557 	rc = inflateEnd(&z);
558 	if (rc != Z_OK)
559 		goto err;
560 
561 	/* let's keep the nul-terminate tradition */
562 	(*newch)[*n] = '\0';
563 
564 	return OKDATA;
565 err:
566 	strlcpy(RCAST(char *, *newch), z.msg ? z.msg : zError(rc), bytes_max);
567 	*n = strlen(RCAST(char *, *newch));
568 	return ERRDATA;
569 }
570 #endif
571 
572 static int
makeerror(unsigned char ** buf,size_t * len,const char * fmt,...)573 makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
574 {
575 	char *msg;
576 	va_list ap;
577 	int rv;
578 
579 	va_start(ap, fmt);
580 	rv = vasprintf(&msg, fmt, ap);
581 	va_end(ap);
582 	if (rv < 0) {
583 		*buf = NULL;
584 		*len = 0;
585 		return NODATA;
586 	}
587 	*buf = RCAST(unsigned char *, msg);
588 	*len = strlen(msg);
589 	return ERRDATA;
590 }
591 
592 static void
closefd(int * fd,size_t i)593 closefd(int *fd, size_t i)
594 {
595 	if (fd[i] == -1)
596 		return;
597 	(void) close(fd[i]);
598 	fd[i] = -1;
599 }
600 
601 static void
closep(int * fd)602 closep(int *fd)
603 {
604 	size_t i;
605 	for (i = 0; i < 2; i++)
606 		closefd(fd, i);
607 }
608 
609 static int
copydesc(int i,int fd)610 copydesc(int i, int fd)
611 {
612 	if (fd == i)
613 		return 0; /* "no dup was necessary" */
614 	if (dup2(fd, i) == -1) {
615 		DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno));
616 		exit(1);
617 	}
618 	return 1;
619 }
620 
621 static pid_t
writechild(int fd,const void * old,size_t n)622 writechild(int fd, const void *old, size_t n)
623 {
624 	pid_t pid;
625 
626 	/*
627 	 * fork again, to avoid blocking because both
628 	 * pipes filled
629 	 */
630 	pid = fork();
631 	if (pid == -1) {
632 		DPRINTF("Fork failed (%s)\n", strerror(errno));
633 		exit(1);
634 	}
635 	if (pid == 0) {
636 		/* child */
637 		if (swrite(fd, old, n) != CAST(ssize_t, n)) {
638 			DPRINTF("Write failed (%s)\n", strerror(errno));
639 			exit(1);
640 		}
641 		exit(0);
642 	}
643 	/* parent */
644 	return pid;
645 }
646 
647 static ssize_t
filter_error(unsigned char * ubuf,ssize_t n)648 filter_error(unsigned char *ubuf, ssize_t n)
649 {
650 	char *p;
651 	char *buf;
652 
653 	ubuf[n] = '\0';
654 	buf = RCAST(char *, ubuf);
655 	while (isspace(CAST(unsigned char, *buf)))
656 		buf++;
657 	DPRINTF("Filter error[[[%s]]]\n", buf);
658 	if ((p = strchr(CAST(char *, buf), '\n')) != NULL)
659 		*p = '\0';
660 	if ((p = strchr(CAST(char *, buf), ';')) != NULL)
661 		*p = '\0';
662 	if ((p = strrchr(CAST(char *, buf), ':')) != NULL) {
663 		++p;
664 		while (isspace(CAST(unsigned char, *p)))
665 			p++;
666 		n = strlen(p);
667 		memmove(ubuf, p, CAST(size_t, n + 1));
668 	}
669 	DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
670 	if (islower(*ubuf))
671 		*ubuf = toupper(*ubuf);
672 	return n;
673 }
674 
675 private const char *
methodname(size_t method)676 methodname(size_t method)
677 {
678 #ifdef BUILTIN_DECOMPRESS
679         /* FIXME: This doesn't cope with bzip2 */
680 	if (method == 2 || compr[method].maglen == 0)
681 	    return "zlib";
682 #endif
683 	return compr[method].argv[0];
684 }
685 
686 private int
uncompressbuf(int fd,size_t bytes_max,size_t method,const unsigned char * old,unsigned char ** newch,size_t * n)687 uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
688     unsigned char **newch, size_t* n)
689 {
690 	int fdp[3][2];
691 	int status, rv, w;
692 	pid_t pid;
693 	pid_t writepid = -1;
694 	size_t i;
695 	ssize_t r;
696 
697 #ifdef BUILTIN_DECOMPRESS
698         /* FIXME: This doesn't cope with bzip2 */
699 	if (method == 2)
700 		return uncompressgzipped(old, newch, bytes_max, n);
701 	if (compr[method].maglen == 0)
702 		return uncompresszlib(old, newch, bytes_max, n, 1);
703 #endif
704 	(void)fflush(stdout);
705 	(void)fflush(stderr);
706 
707 	for (i = 0; i < __arraycount(fdp); i++)
708 		fdp[i][0] = fdp[i][1] = -1;
709 
710 	if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
711 	    pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
712 		closep(fdp[STDIN_FILENO]);
713 		closep(fdp[STDOUT_FILENO]);
714 		return makeerror(newch, n, "Cannot create pipe, %s",
715 		    strerror(errno));
716 	}
717 
718 	/* For processes with large mapped virtual sizes, vfork
719 	 * may be _much_ faster (10-100 times) than fork.
720 	 */
721 	pid = vfork();
722 	if (pid == -1) {
723 		return makeerror(newch, n, "Cannot vfork, %s",
724 		    strerror(errno));
725 	}
726 	if (pid == 0) {
727 		/* child */
728 		/* Note: we are after vfork, do not modify memory
729 		 * in a way which confuses parent. In particular,
730 		 * do not modify fdp[i][j].
731 		 */
732 		if (fd != -1) {
733 			(void) lseek(fd, CAST(off_t, 0), SEEK_SET);
734 			if (copydesc(STDIN_FILENO, fd))
735 				(void) close(fd);
736 		} else {
737 			if (copydesc(STDIN_FILENO, fdp[STDIN_FILENO][0]))
738 				(void) close(fdp[STDIN_FILENO][0]);
739 			if (fdp[STDIN_FILENO][1] > 2)
740 				(void) close(fdp[STDIN_FILENO][1]);
741 		}
742 ///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
743 		if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
744 			(void) close(fdp[STDOUT_FILENO][1]);
745 		if (fdp[STDOUT_FILENO][0] > 2)
746 			(void) close(fdp[STDOUT_FILENO][0]);
747 
748 		if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
749 			(void) close(fdp[STDERR_FILENO][1]);
750 		if (fdp[STDERR_FILENO][0] > 2)
751 			(void) close(fdp[STDERR_FILENO][0]);
752 
753 		(void)execvp(compr[method].argv[0],
754 		    RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
755 		dprintf(STDERR_FILENO, "exec `%s' failed, %s",
756 		    compr[method].argv[0], strerror(errno));
757 		_exit(1); /* _exit(), not exit(), because of vfork */
758 	}
759 	/* parent */
760 	/* Close write sides of child stdout/err pipes */
761 	for (i = 1; i < __arraycount(fdp); i++)
762 		closefd(fdp[i], 1);
763 	/* Write the buffer data to child stdin, if we don't have fd */
764 	if (fd == -1) {
765 		closefd(fdp[STDIN_FILENO], 0);
766 		writepid = writechild(fdp[STDIN_FILENO][1], old, *n);
767 		closefd(fdp[STDIN_FILENO], 1);
768 	}
769 
770 	*newch = CAST(unsigned char *, malloc(bytes_max + 1));
771 	if (*newch == NULL) {
772 		rv = makeerror(newch, n, "No buffer, %s",
773 		    strerror(errno));
774 		goto err;
775 	}
776 	rv = OKDATA;
777 	r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0);
778 	if (r <= 0) {
779 		DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
780 		    r != -1 ? strerror(errno) : "no data");
781 
782 		rv = ERRDATA;
783 		if (r == 0 &&
784 		    (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
785 		{
786 			r = filter_error(*newch, r);
787 			goto ok;
788 		}
789 		free(*newch);
790 		if  (r == 0)
791 			rv = makeerror(newch, n, "Read failed, %s",
792 			    strerror(errno));
793 		else
794 			rv = makeerror(newch, n, "No data");
795 		goto err;
796 	}
797 ok:
798 	*n = r;
799 	/* NUL terminate, as every buffer is handled here. */
800 	(*newch)[*n] = '\0';
801 err:
802 	closefd(fdp[STDIN_FILENO], 1);
803 	closefd(fdp[STDOUT_FILENO], 0);
804 	closefd(fdp[STDERR_FILENO], 0);
805 
806 	w = waitpid(pid, &status, 0);
807 wait_err:
808 	if (w == -1) {
809 		free(*newch);
810 		rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
811 		DPRINTF("Child wait return %#x\n", status);
812 	} else if (!WIFEXITED(status)) {
813 		DPRINTF("Child not exited (%#x)\n", status);
814 	} else if (WEXITSTATUS(status) != 0) {
815 		DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
816 	}
817 	if (writepid > 0) {
818 		/* _After_ we know decompressor has exited, our input writer
819 		 * definitely will exit now (at worst, writing fails in it,
820 		 * since output fd is closed now on the reading size).
821 		 */
822 		w = waitpid(writepid, &status, 0);
823 		writepid = -1;
824 		goto wait_err;
825 	}
826 
827 	closefd(fdp[STDIN_FILENO], 0); //why? it is already closed here!
828 	DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
829 
830 	return rv;
831 }
832 #endif
833 #endif
834