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