"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/compress.c" (15 Oct 2018, 18485 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "compress.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

    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.113 2018/10/15 16:29:16 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 = sizeof(compr) / sizeof(compr[0]);
  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     sig_t osigpipe;
  230 
  231     if ((ms->flags & MAGIC_COMPRESS) == 0)
  232         return 0;
  233 
  234     osigpipe = signal(SIGPIPE, SIG_IGN);
  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         nsz = nbytes;
  250         urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
  251         DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv,
  252             (char *)newbuf, nsz);
  253         switch (urv) {
  254         case OKDATA:
  255         case ERRDATA:
  256             ms->flags &= ~MAGIC_COMPRESS;
  257             if (urv == ERRDATA)
  258                 prv = format_decompression_error(ms, i, newbuf);
  259             else
  260                 prv = file_buffer(ms, -1, name, newbuf, nsz);
  261             if (prv == -1)
  262                 goto error;
  263             rv = 1;
  264             if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
  265                 goto out;
  266             if (mime != MAGIC_MIME && mime != 0)
  267                 goto out;
  268             if ((file_printf(ms,
  269                 mime ? " compressed-encoding=" : " (")) == -1)
  270                 goto error;
  271             if ((pb = file_push_buffer(ms)) == NULL)
  272                 goto error;
  273             /*
  274              * XXX: If file_buffer fails here, we overwrite
  275              * the compressed text. FIXME.
  276              */
  277             if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) {
  278                 if (file_pop_buffer(ms, pb) != NULL)
  279                     abort();
  280                 goto error;
  281             }
  282             if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
  283                 if (file_printf(ms, "%s", rbuf) == -1) {
  284                     free(rbuf);
  285                     goto error;
  286                 }
  287                 free(rbuf);
  288             }
  289             if (!mime && file_printf(ms, ")") == -1)
  290                 goto error;
  291             /*FALLTHROUGH*/
  292         case NODATA:
  293             break;
  294         default:
  295             abort();
  296             /*NOTREACHED*/
  297         error:
  298             rv = -1;
  299             break;
  300         }
  301     }
  302 out:
  303     DPRINTF("rv = %d\n", rv);
  304 
  305     (void)signal(SIGPIPE, osigpipe);
  306     free(newbuf);
  307     ms->flags |= MAGIC_COMPRESS;
  308     DPRINTF("Zmagic returns %d\n", rv);
  309     return rv;
  310 }
  311 #endif
  312 /*
  313  * `safe' write for sockets and pipes.
  314  */
  315 private ssize_t
  316 swrite(int fd, const void *buf, size_t n)
  317 {
  318     ssize_t rv;
  319     size_t rn = n;
  320 
  321     do
  322         switch (rv = write(fd, buf, n)) {
  323         case -1:
  324             if (errno == EINTR)
  325                 continue;
  326             return -1;
  327         default:
  328             n -= rv;
  329             buf = CAST(const char *, buf) + rv;
  330             break;
  331         }
  332     while (n > 0);
  333     return rn;
  334 }
  335 
  336 
  337 /*
  338  * `safe' read for sockets and pipes.
  339  */
  340 protected ssize_t
  341 sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
  342 {
  343     ssize_t rv;
  344 #ifdef FIONREAD
  345     int t = 0;
  346 #endif
  347     size_t rn = n;
  348 
  349     if (fd == STDIN_FILENO)
  350         goto nocheck;
  351 
  352 #ifdef FIONREAD
  353     if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
  354 #ifdef FD_ZERO
  355         ssize_t cnt;
  356         for (cnt = 0;; cnt++) {
  357             fd_set check;
  358             struct timeval tout = {0, 100 * 1000};
  359             int selrv;
  360 
  361             FD_ZERO(&check);
  362             FD_SET(fd, &check);
  363 
  364             /*
  365              * Avoid soft deadlock: do not read if there
  366              * is nothing to read from sockets and pipes.
  367              */
  368             selrv = select(fd + 1, &check, NULL, NULL, &tout);
  369             if (selrv == -1) {
  370                 if (errno == EINTR || errno == EAGAIN)
  371                     continue;
  372             } else if (selrv == 0 && cnt >= 5) {
  373                 return 0;
  374             } else
  375                 break;
  376         }
  377 #endif
  378         (void)ioctl(fd, FIONREAD, &t);
  379     }
  380 
  381     if (t > 0 && (size_t)t < n) {
  382         n = t;
  383         rn = n;
  384     }
  385 #endif
  386 
  387 nocheck:
  388     do
  389         switch ((rv = read(fd, buf, n))) {
  390         case -1:
  391             if (errno == EINTR)
  392                 continue;
  393             return -1;
  394         case 0:
  395             return rn - n;
  396         default:
  397             n -= rv;
  398             buf = CAST(char *, CCAST(void *, buf)) + rv;
  399             break;
  400         }
  401     while (n > 0);
  402     return rn;
  403 }
  404 
  405 protected int
  406 file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
  407     size_t nbytes)
  408 {
  409     char buf[4096];
  410     ssize_t r;
  411     int tfd;
  412 
  413     (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
  414 #ifndef HAVE_MKSTEMP
  415     {
  416         char *ptr = mktemp(buf);
  417         tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
  418         r = errno;
  419         (void)unlink(ptr);
  420         errno = r;
  421     }
  422 #else
  423     {
  424         int te;
  425         int ou = umask(0);
  426         tfd = mkstemp(buf);
  427         (void)umask(ou);
  428         te = errno;
  429         (void)unlink(buf);
  430         errno = te;
  431     }
  432 #endif
  433     if (tfd == -1) {
  434         file_error(ms, errno,
  435             "cannot create temporary file for pipe copy");
  436         return -1;
  437     }
  438 
  439     if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
  440         r = 1;
  441     else {
  442         while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
  443             if (swrite(tfd, buf, (size_t)r) != r)
  444                 break;
  445     }
  446 
  447     switch (r) {
  448     case -1:
  449         file_error(ms, errno, "error copying from pipe to temp file");
  450         return -1;
  451     case 0:
  452         break;
  453     default:
  454         file_error(ms, errno, "error while writing to temp file");
  455         return -1;
  456     }
  457 
  458     /*
  459      * We duplicate the file descriptor, because fclose on a
  460      * tmpfile will delete the file, but any open descriptors
  461      * can still access the phantom inode.
  462      */
  463     if ((fd = dup2(tfd, fd)) == -1) {
  464         file_error(ms, errno, "could not dup descriptor for temp file");
  465         return -1;
  466     }
  467     (void)close(tfd);
  468     if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
  469         file_badseek(ms);
  470         return -1;
  471     }
  472     return fd;
  473 }
  474 #if HAVE_FORK
  475 #ifdef BUILTIN_DECOMPRESS
  476 
  477 #define FHCRC       (1 << 1)
  478 #define FEXTRA      (1 << 2)
  479 #define FNAME       (1 << 3)
  480 #define FCOMMENT    (1 << 4)
  481 
  482 
  483 private int
  484 uncompressgzipped(const unsigned char *old, unsigned char **newch,
  485     size_t bytes_max, size_t *n)
  486 {
  487     unsigned char flg = old[3];
  488     size_t data_start = 10;
  489 
  490     if (flg & FEXTRA) {
  491         if (data_start + 1 >= *n)
  492             goto err;
  493         data_start += 2 + old[data_start] + old[data_start + 1] * 256;
  494     }
  495     if (flg & FNAME) {
  496         while(data_start < *n && old[data_start])
  497             data_start++;
  498         data_start++;
  499     }
  500     if (flg & FCOMMENT) {
  501         while(data_start < *n && old[data_start])
  502             data_start++;
  503         data_start++;
  504     }
  505     if (flg & FHCRC)
  506         data_start += 2;
  507 
  508     if (data_start >= *n)
  509         goto err;
  510 
  511     *n -= data_start;
  512     old += data_start;
  513     return uncompresszlib(old, newch, bytes_max, n, 0);
  514 err:
  515     return makeerror(newch, n, "File too short");
  516 }
  517 
  518 private int
  519 uncompresszlib(const unsigned char *old, unsigned char **newch,
  520     size_t bytes_max, size_t *n, int zlib)
  521 {
  522     int rc;
  523     z_stream z;
  524 
  525     if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
  526         return makeerror(newch, n, "No buffer, %s", strerror(errno));
  527 
  528     z.next_in = CCAST(Bytef *, old);
  529     z.avail_in = CAST(uint32_t, *n);
  530     z.next_out = *newch;
  531     z.avail_out = CAST(unsigned int, bytes_max);
  532     z.zalloc = Z_NULL;
  533     z.zfree = Z_NULL;
  534     z.opaque = Z_NULL;
  535 
  536     /* LINTED bug in header macro */
  537     rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
  538     if (rc != Z_OK)
  539         goto err;
  540 
  541     rc = inflate(&z, Z_SYNC_FLUSH);
  542     if (rc != Z_OK && rc != Z_STREAM_END)
  543         goto err;
  544 
  545     *n = (size_t)z.total_out;
  546     rc = inflateEnd(&z);
  547     if (rc != Z_OK)
  548         goto err;
  549 
  550     /* let's keep the nul-terminate tradition */
  551     (*newch)[*n] = '\0';
  552 
  553     return OKDATA;
  554 err:
  555     strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max);
  556     *n = strlen((char *)*newch);
  557     return ERRDATA;
  558 }
  559 #endif
  560 
  561 static int
  562 makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
  563 {
  564     char *msg;
  565     va_list ap;
  566     int rv;
  567 
  568     va_start(ap, fmt);
  569     rv = vasprintf(&msg, fmt, ap);
  570     va_end(ap);
  571     if (rv < 0) {
  572         *buf = NULL;
  573         *len = 0;
  574         return NODATA;
  575     }
  576     *buf = (unsigned char *)msg;
  577     *len = strlen(msg);
  578     return ERRDATA;
  579 }
  580 
  581 static void
  582 closefd(int *fd, size_t i)
  583 {
  584     if (fd[i] == -1)
  585         return;
  586     (void) close(fd[i]);
  587     fd[i] = -1;
  588 }
  589 
  590 static void
  591 closep(int *fd)
  592 {
  593     size_t i;
  594     for (i = 0; i < 2; i++)
  595         closefd(fd, i);
  596 }
  597 
  598 static void
  599 copydesc(int i, int *fd)
  600 {
  601     int j = fd[i == STDIN_FILENO ? 0 : 1];
  602     if (j == i)
  603         return;
  604     if (dup2(j, i) == -1) {
  605         DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno));
  606         exit(1);
  607     }
  608     closep(fd);
  609 }
  610 
  611 static void
  612 writechild(int fdp[3][2], const void *old, size_t n)
  613 {
  614     int status;
  615 
  616     closefd(fdp[STDIN_FILENO], 0);
  617     /*
  618      * fork again, to avoid blocking because both
  619      * pipes filled
  620      */
  621     switch (fork()) {
  622     case 0: /* child */
  623         closefd(fdp[STDOUT_FILENO], 0);
  624         if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) {
  625             DPRINTF("Write failed (%s)\n", strerror(errno));
  626             exit(1);
  627         }
  628         exit(0);
  629         /*NOTREACHED*/
  630 
  631     case -1:
  632         DPRINTF("Fork failed (%s)\n", strerror(errno));
  633         exit(1);
  634         /*NOTREACHED*/
  635 
  636     default:  /* parent */
  637         if (wait(&status) == -1) {
  638             DPRINTF("Wait failed (%s)\n", strerror(errno));
  639             exit(1);
  640         }
  641         DPRINTF("Grandchild wait return %#x\n", status);
  642     }
  643     closefd(fdp[STDIN_FILENO], 1);
  644 }
  645 
  646 static ssize_t
  647 filter_error(unsigned char *ubuf, ssize_t n)
  648 {
  649     char *p;
  650     char *buf;
  651 
  652     ubuf[n] = '\0';
  653     buf = (char *)ubuf;
  654     while (isspace((unsigned char)*buf))
  655         buf++;
  656     DPRINTF("Filter error[[[%s]]]\n", buf);
  657     if ((p = strchr((char *)buf, '\n')) != NULL)
  658         *p = '\0';
  659     if ((p = strchr((char *)buf, ';')) != NULL)
  660         *p = '\0';
  661     if ((p = strrchr((char *)buf, ':')) != NULL) {
  662         ++p;
  663         while (isspace((unsigned char)*p))
  664             p++;
  665         n = strlen(p);
  666         memmove(ubuf, p, CAST(size_t, n + 1));
  667     }
  668     DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
  669     if (islower(*ubuf))
  670         *ubuf = toupper(*ubuf);
  671     return n;
  672 }
  673 
  674 private const char *
  675 methodname(size_t method)
  676 {
  677 #ifdef BUILTIN_DECOMPRESS
  678         /* FIXME: This doesn't cope with bzip2 */
  679     if (method == 2 || compr[method].maglen == 0)
  680         return "zlib";
  681 #endif
  682     return compr[method].argv[0];
  683 }
  684 
  685 private int
  686 uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
  687     unsigned char **newch, size_t* n)
  688 {
  689     int fdp[3][2];
  690     int status, rv;
  691     size_t i;
  692     ssize_t r;
  693 
  694 #ifdef BUILTIN_DECOMPRESS
  695         /* FIXME: This doesn't cope with bzip2 */
  696     if (method == 2)
  697         return uncompressgzipped(old, newch, bytes_max, n);
  698     if (compr[method].maglen == 0)
  699         return uncompresszlib(old, newch, bytes_max, n, 1);
  700 #endif
  701     (void)fflush(stdout);
  702     (void)fflush(stderr);
  703 
  704     for (i = 0; i < __arraycount(fdp); i++)
  705         fdp[i][0] = fdp[i][1] = -1;
  706 
  707     if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
  708         pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
  709         closep(fdp[STDIN_FILENO]);
  710         closep(fdp[STDOUT_FILENO]);
  711         return makeerror(newch, n, "Cannot create pipe, %s",
  712             strerror(errno));
  713     }
  714     switch (fork()) {
  715     case 0: /* child */
  716         if (fd != -1) {
  717             fdp[STDIN_FILENO][0] = fd;
  718             (void) lseek(fd, (off_t)0, SEEK_SET);
  719         }
  720 
  721         for (i = 0; i < __arraycount(fdp); i++)
  722             copydesc(CAST(int, i), fdp[i]);
  723 
  724         (void)execvp(compr[method].argv[0],
  725             (char *const *)(intptr_t)compr[method].argv);
  726         dprintf(STDERR_FILENO, "exec `%s' failed, %s",
  727             compr[method].argv[0], strerror(errno));
  728         exit(1);
  729         /*NOTREACHED*/
  730     case -1:
  731         return makeerror(newch, n, "Cannot fork, %s",
  732             strerror(errno));
  733 
  734     default: /* parent */
  735         for (i = 1; i < __arraycount(fdp); i++)
  736             closefd(fdp[i], 1);
  737 
  738         /* Write the buffer data to the child, if we don't have fd */
  739         if (fd == -1)
  740             writechild(fdp, old, *n);
  741 
  742         *newch = CAST(unsigned char *, malloc(bytes_max + 1));
  743         if (*newch == NULL) {
  744             rv = makeerror(newch, n, "No buffer, %s",
  745                 strerror(errno));
  746             goto err;
  747         }
  748         rv = OKDATA;
  749         if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0)
  750             break;
  751         DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
  752             r != -1 ? strerror(errno) : "no data");
  753 
  754         rv = ERRDATA;
  755         if (r == 0 &&
  756             (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
  757         {
  758             r = filter_error(*newch, r);
  759             break;
  760         }
  761         free(*newch);
  762         if  (r == 0)
  763             rv = makeerror(newch, n, "Read failed, %s",
  764                 strerror(errno));
  765         else
  766             rv = makeerror(newch, n, "No data");
  767         goto err;
  768     }
  769 
  770     *n = r;
  771     /* NUL terminate, as every buffer is handled here. */
  772     (*newch)[*n] = '\0';
  773 err:
  774     closefd(fdp[STDIN_FILENO], 1);
  775     closefd(fdp[STDOUT_FILENO], 0);
  776     closefd(fdp[STDERR_FILENO], 0);
  777     if (wait(&status) == -1) {
  778         free(*newch);
  779         rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
  780         DPRINTF("Child wait return %#x\n", status);
  781     } else if (!WIFEXITED(status)) {
  782         DPRINTF("Child not exited (%#x)\n", status);
  783     } else if (WEXITSTATUS(status) != 0) {
  784         DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
  785     }
  786 
  787     closefd(fdp[STDIN_FILENO], 0);
  788     DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv);
  789 
  790     return rv;
  791 }
  792 #endif