]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/src/compress.c
MFV r357635: imnport v1.9 of the O_SEARCH tests
[FreeBSD/FreeBSD.git] / contrib / file / src / compress.c
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