1b6cee71dSXin LI /* 2b6cee71dSXin LI * Copyright (c) Ian F. Darwin 1986-1995. 3b6cee71dSXin LI * Software written by Ian F. Darwin and others; 4b6cee71dSXin LI * maintained 1995-present by Christos Zoulas and others. 5b6cee71dSXin LI * 6b6cee71dSXin LI * Redistribution and use in source and binary forms, with or without 7b6cee71dSXin LI * modification, are permitted provided that the following conditions 8b6cee71dSXin LI * are met: 9b6cee71dSXin LI * 1. Redistributions of source code must retain the above copyright 10b6cee71dSXin LI * notice immediately at the beginning of the file, without modification, 11b6cee71dSXin LI * this list of conditions, and the following disclaimer. 12b6cee71dSXin LI * 2. Redistributions in binary form must reproduce the above copyright 13b6cee71dSXin LI * notice, this list of conditions and the following disclaimer in the 14b6cee71dSXin LI * documentation and/or other materials provided with the distribution. 15b6cee71dSXin LI * 16b6cee71dSXin LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17b6cee71dSXin LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b6cee71dSXin LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b6cee71dSXin LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20b6cee71dSXin LI * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b6cee71dSXin LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22b6cee71dSXin LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23b6cee71dSXin LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24b6cee71dSXin LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25b6cee71dSXin LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26b6cee71dSXin LI * SUCH DAMAGE. 27b6cee71dSXin LI */ 28b6cee71dSXin LI /* 29b6cee71dSXin LI * compress routines: 30b6cee71dSXin LI * zmagic() - returns 0 if not recognized, uncompresses and prints 31b6cee71dSXin LI * information if recognized 32b6cee71dSXin LI * uncompress(method, old, n, newch) - uncompress old into new, 33b6cee71dSXin LI * using method, return sizeof new 34b6cee71dSXin LI */ 35b6cee71dSXin LI #include "file.h" 36b6cee71dSXin LI 37b6cee71dSXin LI #ifndef lint 38*58a0f0d0SEitan Adler FILE_RCSID("@(#)$File: compress.c,v 1.106 2017/11/02 20:25:39 christos Exp $") 39b6cee71dSXin LI #endif 40b6cee71dSXin LI 41b6cee71dSXin LI #include "magic.h" 42b6cee71dSXin LI #include <stdlib.h> 43b6cee71dSXin LI #ifdef HAVE_UNISTD_H 44b6cee71dSXin LI #include <unistd.h> 45b6cee71dSXin LI #endif 46b6cee71dSXin LI #include <string.h> 47b6cee71dSXin LI #include <errno.h> 483e41d09dSXin LI #include <ctype.h> 493e41d09dSXin LI #include <stdarg.h> 505f0216bdSXin LI #ifdef HAVE_SIGNAL_H 514460e5b0SXin LI #include <signal.h> 525f0216bdSXin LI # ifndef HAVE_SIG_T 535f0216bdSXin LI typedef void (*sig_t)(int); 545f0216bdSXin LI # endif /* HAVE_SIG_T */ 555f0216bdSXin LI #endif 56c2931133SXin LI #if !defined(__MINGW32__) && !defined(WIN32) 57b6cee71dSXin LI #include <sys/ioctl.h> 58b6cee71dSXin LI #endif 59b6cee71dSXin LI #ifdef HAVE_SYS_WAIT_H 60b6cee71dSXin LI #include <sys/wait.h> 61b6cee71dSXin LI #endif 62b6cee71dSXin LI #if defined(HAVE_SYS_TIME_H) 63b6cee71dSXin LI #include <sys/time.h> 64b6cee71dSXin LI #endif 6540427ccaSGordon Tetlow #if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) 66b6cee71dSXin LI #define BUILTIN_DECOMPRESS 67b6cee71dSXin LI #include <zlib.h> 683e41d09dSXin LI #endif 693e41d09dSXin LI #ifdef DEBUG 703e41d09dSXin LI int tty = -1; 713e41d09dSXin LI #define DPRINTF(...) do { \ 723e41d09dSXin LI if (tty == -1) \ 733e41d09dSXin LI tty = open("/dev/tty", O_RDWR); \ 743e41d09dSXin LI if (tty == -1) \ 753e41d09dSXin LI abort(); \ 763e41d09dSXin LI dprintf(tty, __VA_ARGS__); \ 773e41d09dSXin LI } while (/*CONSTCOND*/0) 783e41d09dSXin LI #else 793e41d09dSXin LI #define DPRINTF(...) 80b6cee71dSXin LI #endif 81b6cee71dSXin LI 823e41d09dSXin LI #ifdef ZLIBSUPPORT 833e41d09dSXin LI /* 843e41d09dSXin LI * The following python code is not really used because ZLIBSUPPORT is only 853e41d09dSXin LI * defined if we have a built-in zlib, and the built-in zlib handles that. 8640427ccaSGordon Tetlow * That is not true for android where we have zlib.h and not -lz. 873e41d09dSXin LI */ 883e41d09dSXin LI static const char zlibcode[] = 893e41d09dSXin LI "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; 903e41d09dSXin LI 913e41d09dSXin LI static const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; 923e41d09dSXin LI 933e41d09dSXin LI static int 943e41d09dSXin LI zlibcmp(const unsigned char *buf) 953e41d09dSXin LI { 963e41d09dSXin LI unsigned short x = 1; 9740427ccaSGordon Tetlow unsigned char *s = CAST(unsigned char *, CAST(void *, &x)); 983e41d09dSXin LI 993e41d09dSXin LI if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) 1003e41d09dSXin LI return 0; 1013e41d09dSXin LI if (s[0] != 1) /* endianness test */ 1023e41d09dSXin LI x = buf[0] | (buf[1] << 8); 1033e41d09dSXin LI else 1043e41d09dSXin LI x = buf[1] | (buf[0] << 8); 1053e41d09dSXin LI if (x % 31) 1063e41d09dSXin LI return 0; 1073e41d09dSXin LI return 1; 1083e41d09dSXin LI } 1093e41d09dSXin LI #endif 1103e41d09dSXin LI 1113e41d09dSXin LI #define gzip_flags "-cd" 1123e41d09dSXin LI #define lrzip_flags "-do" 1133e41d09dSXin LI #define lzip_flags gzip_flags 1143e41d09dSXin LI 1153e41d09dSXin LI static const char *gzip_args[] = { 1163e41d09dSXin LI "gzip", gzip_flags, NULL 1173e41d09dSXin LI }; 1183e41d09dSXin LI static const char *uncompress_args[] = { 1193e41d09dSXin LI "uncompress", "-c", NULL 1203e41d09dSXin LI }; 1213e41d09dSXin LI static const char *bzip2_args[] = { 1223e41d09dSXin LI "bzip2", "-cd", NULL 1233e41d09dSXin LI }; 1243e41d09dSXin LI static const char *lzip_args[] = { 1253e41d09dSXin LI "lzip", lzip_flags, NULL 1263e41d09dSXin LI }; 1273e41d09dSXin LI static const char *xz_args[] = { 1283e41d09dSXin LI "xz", "-cd", NULL 1293e41d09dSXin LI }; 1303e41d09dSXin LI static const char *lrzip_args[] = { 1313e41d09dSXin LI "lrzip", lrzip_flags, NULL 1323e41d09dSXin LI }; 1333e41d09dSXin LI static const char *lz4_args[] = { 1343e41d09dSXin LI "lz4", "-cd", NULL 135b6cee71dSXin LI }; 136a5d223e6SXin LI static const char *zstd_args[] = { 137a5d223e6SXin LI "zstd", "-cd", NULL 138a5d223e6SXin LI }; 139b6cee71dSXin LI 1403e41d09dSXin LI private const struct { 1413e41d09dSXin LI const void *magic; 1423e41d09dSXin LI size_t maglen; 1433e41d09dSXin LI const char **argv; 1443e41d09dSXin LI } compr[] = { 1453e41d09dSXin LI { "\037\235", 2, gzip_args }, /* compressed */ 1463e41d09dSXin LI /* Uncompress can get stuck; so use gzip first if we have it 1473e41d09dSXin LI * Idea from Damien Clark, thanks! */ 1483e41d09dSXin LI { "\037\235", 2, uncompress_args }, /* compressed */ 1493e41d09dSXin LI { "\037\213", 2, gzip_args }, /* gzipped */ 1503e41d09dSXin LI { "\037\236", 2, gzip_args }, /* frozen */ 1513e41d09dSXin LI { "\037\240", 2, gzip_args }, /* SCO LZH */ 1523e41d09dSXin LI /* the standard pack utilities do not accept standard input */ 1533e41d09dSXin LI { "\037\036", 2, gzip_args }, /* packed */ 1543e41d09dSXin LI { "PK\3\4", 4, gzip_args }, /* pkzipped, */ 1553e41d09dSXin LI /* ...only first file examined */ 1563e41d09dSXin LI { "BZh", 3, bzip2_args }, /* bzip2-ed */ 1573e41d09dSXin LI { "LZIP", 4, lzip_args }, /* lzip-ed */ 1583e41d09dSXin LI { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ 1593e41d09dSXin LI { "LRZI", 4, lrzip_args }, /* LRZIP */ 1603e41d09dSXin LI { "\004\"M\030",4, lz4_args }, /* LZ4 */ 161a5d223e6SXin LI { "\x28\xB5\x2F\xFD", 4, zstd_args }, /* zstd */ 1623e41d09dSXin LI #ifdef ZLIBSUPPORT 163a5d223e6SXin LI { RCAST(const void *, zlibcmp), 0, zlib_args }, /* zlib */ 1643e41d09dSXin LI #endif 1653e41d09dSXin LI }; 1663e41d09dSXin LI 1673e41d09dSXin LI #define OKDATA 0 1683e41d09dSXin LI #define NODATA 1 1693e41d09dSXin LI #define ERRDATA 2 170b6cee71dSXin LI 171b6cee71dSXin LI private ssize_t swrite(int, const void *, size_t); 172b6cee71dSXin LI #if HAVE_FORK 173b6cee71dSXin LI private size_t ncompr = sizeof(compr) / sizeof(compr[0]); 1743e41d09dSXin LI private int uncompressbuf(int, size_t, size_t, const unsigned char *, 1753e41d09dSXin LI unsigned char **, size_t *); 176b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 1773e41d09dSXin LI private int uncompresszlib(const unsigned char *, unsigned char **, size_t, 1783e41d09dSXin LI size_t *, int); 1793e41d09dSXin LI private int uncompressgzipped(const unsigned char *, unsigned char **, size_t, 1803e41d09dSXin LI size_t *); 181b6cee71dSXin LI #endif 1823e41d09dSXin LI static int makeerror(unsigned char **, size_t *, const char *, ...) 1833e41d09dSXin LI __attribute__((__format__(__printf__, 3, 4))); 1843e41d09dSXin LI private const char *methodname(size_t); 185b6cee71dSXin LI 186b6cee71dSXin LI protected int 187*58a0f0d0SEitan Adler file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) 188b6cee71dSXin LI { 189b6cee71dSXin LI unsigned char *newbuf = NULL; 190b6cee71dSXin LI size_t i, nsz; 1913e41d09dSXin LI char *rbuf; 1923e41d09dSXin LI file_pushbuf_t *pb; 19320f8619dSXin LI int urv, prv, rv = 0; 194b6cee71dSXin LI int mime = ms->flags & MAGIC_MIME; 195*58a0f0d0SEitan Adler int fd = b->fd; 196*58a0f0d0SEitan Adler const unsigned char *buf = b->fbuf; 197*58a0f0d0SEitan Adler size_t nbytes = b->flen; 1985f0216bdSXin LI #ifdef HAVE_SIGNAL_H 1994460e5b0SXin LI sig_t osigpipe; 2005f0216bdSXin LI #endif 201b6cee71dSXin LI 202b6cee71dSXin LI if ((ms->flags & MAGIC_COMPRESS) == 0) 203b6cee71dSXin LI return 0; 204b6cee71dSXin LI 2055f0216bdSXin LI #ifdef HAVE_SIGNAL_H 2064460e5b0SXin LI osigpipe = signal(SIGPIPE, SIG_IGN); 2075f0216bdSXin LI #endif 208b6cee71dSXin LI for (i = 0; i < ncompr; i++) { 2093e41d09dSXin LI int zm; 210b6cee71dSXin LI if (nbytes < compr[i].maglen) 211b6cee71dSXin LI continue; 2123e41d09dSXin LI #ifdef ZLIBSUPPORT 2133e41d09dSXin LI if (compr[i].maglen == 0) 214a5d223e6SXin LI zm = (RCAST(int (*)(const unsigned char *), 2153e41d09dSXin LI CCAST(void *, compr[i].magic)))(buf); 2163e41d09dSXin LI else 2173e41d09dSXin LI #endif 2183e41d09dSXin LI zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; 219b6cee71dSXin LI 2203e41d09dSXin LI if (!zm) 2213e41d09dSXin LI continue; 2223e41d09dSXin LI nsz = nbytes; 22320f8619dSXin LI urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); 22420f8619dSXin LI DPRINTF("uncompressbuf = %d, %s, %zu\n", urv, (char *)newbuf, 2253e41d09dSXin LI nsz); 22620f8619dSXin LI switch (urv) { 2273e41d09dSXin LI case OKDATA: 2283e41d09dSXin LI case ERRDATA: 2293e41d09dSXin LI 2303e41d09dSXin LI ms->flags &= ~MAGIC_COMPRESS; 23120f8619dSXin LI if (urv == ERRDATA) 23220f8619dSXin LI prv = file_printf(ms, "%s ERROR: %s", 2333e41d09dSXin LI methodname(i), newbuf); 2343e41d09dSXin LI else 23520f8619dSXin LI prv = file_buffer(ms, -1, name, newbuf, nsz); 23620f8619dSXin LI if (prv == -1) 2373e41d09dSXin LI goto error; 23820f8619dSXin LI rv = 1; 2393e41d09dSXin LI if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) 2403e41d09dSXin LI goto out; 2413e41d09dSXin LI if (mime != MAGIC_MIME && mime != 0) 2423e41d09dSXin LI goto out; 2433e41d09dSXin LI if ((file_printf(ms, 2443e41d09dSXin LI mime ? " compressed-encoding=" : " (")) == -1) 2453e41d09dSXin LI goto error; 2463e41d09dSXin LI if ((pb = file_push_buffer(ms)) == NULL) 247b6cee71dSXin LI goto error; 24820f8619dSXin LI /* 24920f8619dSXin LI * XXX: If file_buffer fails here, we overwrite 25020f8619dSXin LI * the compressed text. FIXME. 25120f8619dSXin LI */ 252b6cee71dSXin LI if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 253b6cee71dSXin LI goto error; 2543e41d09dSXin LI if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 2553e41d09dSXin LI if (file_printf(ms, "%s", rbuf) == -1) { 2563e41d09dSXin LI free(rbuf); 257b6cee71dSXin LI goto error; 258b6cee71dSXin LI } 2593e41d09dSXin LI free(rbuf); 2603e41d09dSXin LI } 2613e41d09dSXin LI if (!mime && file_printf(ms, ")") == -1) 2623e41d09dSXin LI goto error; 26320f8619dSXin LI /*FALLTHROUGH*/ 2643e41d09dSXin LI case NODATA: 26520f8619dSXin LI break; 2663e41d09dSXin LI default: 2673e41d09dSXin LI abort(); 26820f8619dSXin LI /*NOTREACHED*/ 26920f8619dSXin LI error: 27020f8619dSXin LI rv = -1; 27120f8619dSXin LI break; 2723e41d09dSXin LI } 2733e41d09dSXin LI } 2743e41d09dSXin LI out: 27520f8619dSXin LI DPRINTF("rv = %d\n", rv); 27620f8619dSXin LI 2775f0216bdSXin LI #ifdef HAVE_SIGNAL_H 2784460e5b0SXin LI (void)signal(SIGPIPE, osigpipe); 2795f0216bdSXin LI #endif 280b6cee71dSXin LI free(newbuf); 281b6cee71dSXin LI ms->flags |= MAGIC_COMPRESS; 2823e41d09dSXin LI DPRINTF("Zmagic returns %d\n", rv); 283b6cee71dSXin LI return rv; 284b6cee71dSXin LI } 285b6cee71dSXin LI #endif 286b6cee71dSXin LI /* 287b6cee71dSXin LI * `safe' write for sockets and pipes. 288b6cee71dSXin LI */ 289b6cee71dSXin LI private ssize_t 290b6cee71dSXin LI swrite(int fd, const void *buf, size_t n) 291b6cee71dSXin LI { 292b6cee71dSXin LI ssize_t rv; 293b6cee71dSXin LI size_t rn = n; 294b6cee71dSXin LI 295b6cee71dSXin LI do 296b6cee71dSXin LI switch (rv = write(fd, buf, n)) { 297b6cee71dSXin LI case -1: 298b6cee71dSXin LI if (errno == EINTR) 299b6cee71dSXin LI continue; 300b6cee71dSXin LI return -1; 301b6cee71dSXin LI default: 302b6cee71dSXin LI n -= rv; 303b6cee71dSXin LI buf = CAST(const char *, buf) + rv; 304b6cee71dSXin LI break; 305b6cee71dSXin LI } 306b6cee71dSXin LI while (n > 0); 307b6cee71dSXin LI return rn; 308b6cee71dSXin LI } 309b6cee71dSXin LI 310b6cee71dSXin LI 311b6cee71dSXin LI /* 312b6cee71dSXin LI * `safe' read for sockets and pipes. 313b6cee71dSXin LI */ 314b6cee71dSXin LI protected ssize_t 315b6cee71dSXin LI sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 316b6cee71dSXin LI { 317b6cee71dSXin LI ssize_t rv; 318b6cee71dSXin LI #ifdef FIONREAD 319b6cee71dSXin LI int t = 0; 320b6cee71dSXin LI #endif 321b6cee71dSXin LI size_t rn = n; 322b6cee71dSXin LI 323b6cee71dSXin LI if (fd == STDIN_FILENO) 324b6cee71dSXin LI goto nocheck; 325b6cee71dSXin LI 326b6cee71dSXin LI #ifdef FIONREAD 327b6cee71dSXin LI if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 328b6cee71dSXin LI #ifdef FD_ZERO 329b6cee71dSXin LI ssize_t cnt; 330b6cee71dSXin LI for (cnt = 0;; cnt++) { 331b6cee71dSXin LI fd_set check; 332b6cee71dSXin LI struct timeval tout = {0, 100 * 1000}; 333b6cee71dSXin LI int selrv; 334b6cee71dSXin LI 335b6cee71dSXin LI FD_ZERO(&check); 336b6cee71dSXin LI FD_SET(fd, &check); 337b6cee71dSXin LI 338b6cee71dSXin LI /* 339b6cee71dSXin LI * Avoid soft deadlock: do not read if there 340b6cee71dSXin LI * is nothing to read from sockets and pipes. 341b6cee71dSXin LI */ 342b6cee71dSXin LI selrv = select(fd + 1, &check, NULL, NULL, &tout); 343b6cee71dSXin LI if (selrv == -1) { 344b6cee71dSXin LI if (errno == EINTR || errno == EAGAIN) 345b6cee71dSXin LI continue; 346b6cee71dSXin LI } else if (selrv == 0 && cnt >= 5) { 347b6cee71dSXin LI return 0; 348b6cee71dSXin LI } else 349b6cee71dSXin LI break; 350b6cee71dSXin LI } 351b6cee71dSXin LI #endif 352b6cee71dSXin LI (void)ioctl(fd, FIONREAD, &t); 353b6cee71dSXin LI } 354b6cee71dSXin LI 355b6cee71dSXin LI if (t > 0 && (size_t)t < n) { 356b6cee71dSXin LI n = t; 357b6cee71dSXin LI rn = n; 358b6cee71dSXin LI } 359b6cee71dSXin LI #endif 360b6cee71dSXin LI 361b6cee71dSXin LI nocheck: 362b6cee71dSXin LI do 363b6cee71dSXin LI switch ((rv = read(fd, buf, n))) { 364b6cee71dSXin LI case -1: 365b6cee71dSXin LI if (errno == EINTR) 366b6cee71dSXin LI continue; 367b6cee71dSXin LI return -1; 368b6cee71dSXin LI case 0: 369b6cee71dSXin LI return rn - n; 370b6cee71dSXin LI default: 371b6cee71dSXin LI n -= rv; 372a5d223e6SXin LI buf = CAST(char *, CCAST(void *, buf)) + rv; 373b6cee71dSXin LI break; 374b6cee71dSXin LI } 375b6cee71dSXin LI while (n > 0); 376b6cee71dSXin LI return rn; 377b6cee71dSXin LI } 378b6cee71dSXin LI 379b6cee71dSXin LI protected int 380b6cee71dSXin LI file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 381b6cee71dSXin LI size_t nbytes) 382b6cee71dSXin LI { 383b6cee71dSXin LI char buf[4096]; 384b6cee71dSXin LI ssize_t r; 385b6cee71dSXin LI int tfd; 386b6cee71dSXin LI 387b6cee71dSXin LI (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 388b6cee71dSXin LI #ifndef HAVE_MKSTEMP 389b6cee71dSXin LI { 390b6cee71dSXin LI char *ptr = mktemp(buf); 391b6cee71dSXin LI tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 392b6cee71dSXin LI r = errno; 393b6cee71dSXin LI (void)unlink(ptr); 394b6cee71dSXin LI errno = r; 395b6cee71dSXin LI } 396b6cee71dSXin LI #else 397b6cee71dSXin LI { 398b6cee71dSXin LI int te; 399b6cee71dSXin LI tfd = mkstemp(buf); 400b6cee71dSXin LI te = errno; 401b6cee71dSXin LI (void)unlink(buf); 402b6cee71dSXin LI errno = te; 403b6cee71dSXin LI } 404b6cee71dSXin LI #endif 405b6cee71dSXin LI if (tfd == -1) { 406b6cee71dSXin LI file_error(ms, errno, 407b6cee71dSXin LI "cannot create temporary file for pipe copy"); 408b6cee71dSXin LI return -1; 409b6cee71dSXin LI } 410b6cee71dSXin LI 411b6cee71dSXin LI if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 412b6cee71dSXin LI r = 1; 413b6cee71dSXin LI else { 414b6cee71dSXin LI while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 415b6cee71dSXin LI if (swrite(tfd, buf, (size_t)r) != r) 416b6cee71dSXin LI break; 417b6cee71dSXin LI } 418b6cee71dSXin LI 419b6cee71dSXin LI switch (r) { 420b6cee71dSXin LI case -1: 421b6cee71dSXin LI file_error(ms, errno, "error copying from pipe to temp file"); 422b6cee71dSXin LI return -1; 423b6cee71dSXin LI case 0: 424b6cee71dSXin LI break; 425b6cee71dSXin LI default: 426b6cee71dSXin LI file_error(ms, errno, "error while writing to temp file"); 427b6cee71dSXin LI return -1; 428b6cee71dSXin LI } 429b6cee71dSXin LI 430b6cee71dSXin LI /* 431b6cee71dSXin LI * We duplicate the file descriptor, because fclose on a 432b6cee71dSXin LI * tmpfile will delete the file, but any open descriptors 433b6cee71dSXin LI * can still access the phantom inode. 434b6cee71dSXin LI */ 435b6cee71dSXin LI if ((fd = dup2(tfd, fd)) == -1) { 436b6cee71dSXin LI file_error(ms, errno, "could not dup descriptor for temp file"); 437b6cee71dSXin LI return -1; 438b6cee71dSXin LI } 439b6cee71dSXin LI (void)close(tfd); 440b6cee71dSXin LI if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 441b6cee71dSXin LI file_badseek(ms); 442b6cee71dSXin LI return -1; 443b6cee71dSXin LI } 444b6cee71dSXin LI return fd; 445b6cee71dSXin LI } 446b6cee71dSXin LI #if HAVE_FORK 447b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 448b6cee71dSXin LI 449b6cee71dSXin LI #define FHCRC (1 << 1) 450b6cee71dSXin LI #define FEXTRA (1 << 2) 451b6cee71dSXin LI #define FNAME (1 << 3) 452b6cee71dSXin LI #define FCOMMENT (1 << 4) 453b6cee71dSXin LI 4543e41d09dSXin LI 4553e41d09dSXin LI private int 4563e41d09dSXin LI uncompressgzipped(const unsigned char *old, unsigned char **newch, 4573e41d09dSXin LI size_t bytes_max, size_t *n) 458b6cee71dSXin LI { 459b6cee71dSXin LI unsigned char flg = old[3]; 460b6cee71dSXin LI size_t data_start = 10; 461b6cee71dSXin LI 462b6cee71dSXin LI if (flg & FEXTRA) { 4633e41d09dSXin LI if (data_start + 1 >= *n) 4643e41d09dSXin LI goto err; 465b6cee71dSXin LI data_start += 2 + old[data_start] + old[data_start + 1] * 256; 466b6cee71dSXin LI } 467b6cee71dSXin LI if (flg & FNAME) { 4683e41d09dSXin LI while(data_start < *n && old[data_start]) 469b6cee71dSXin LI data_start++; 470b6cee71dSXin LI data_start++; 471b6cee71dSXin LI } 472b6cee71dSXin LI if (flg & FCOMMENT) { 4733e41d09dSXin LI while(data_start < *n && old[data_start]) 474b6cee71dSXin LI data_start++; 475b6cee71dSXin LI data_start++; 476b6cee71dSXin LI } 477b6cee71dSXin LI if (flg & FHCRC) 478b6cee71dSXin LI data_start += 2; 479b6cee71dSXin LI 4803e41d09dSXin LI if (data_start >= *n) 4813e41d09dSXin LI goto err; 4823e41d09dSXin LI 4833e41d09dSXin LI *n -= data_start; 4843e41d09dSXin LI old += data_start; 4853e41d09dSXin LI return uncompresszlib(old, newch, bytes_max, n, 0); 4863e41d09dSXin LI err: 4873e41d09dSXin LI return makeerror(newch, n, "File too short"); 488b6cee71dSXin LI } 489b6cee71dSXin LI 4903e41d09dSXin LI private int 4913e41d09dSXin LI uncompresszlib(const unsigned char *old, unsigned char **newch, 4923e41d09dSXin LI size_t bytes_max, size_t *n, int zlib) 4933e41d09dSXin LI { 4943e41d09dSXin LI int rc; 4953e41d09dSXin LI z_stream z; 4963e41d09dSXin LI 4973e41d09dSXin LI if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 4983e41d09dSXin LI return makeerror(newch, n, "No buffer, %s", strerror(errno)); 4993e41d09dSXin LI 5003e41d09dSXin LI z.next_in = CCAST(Bytef *, old); 5013e41d09dSXin LI z.avail_in = CAST(uint32_t, *n); 502b6cee71dSXin LI z.next_out = *newch; 50340427ccaSGordon Tetlow z.avail_out = CAST(unsigned int, bytes_max); 504b6cee71dSXin LI z.zalloc = Z_NULL; 505b6cee71dSXin LI z.zfree = Z_NULL; 506b6cee71dSXin LI z.opaque = Z_NULL; 507b6cee71dSXin LI 508b6cee71dSXin LI /* LINTED bug in header macro */ 5093e41d09dSXin LI rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); 5103e41d09dSXin LI if (rc != Z_OK) 5113e41d09dSXin LI goto err; 512b6cee71dSXin LI 513b6cee71dSXin LI rc = inflate(&z, Z_SYNC_FLUSH); 5143e41d09dSXin LI if (rc != Z_OK && rc != Z_STREAM_END) 5153e41d09dSXin LI goto err; 516b6cee71dSXin LI 5173e41d09dSXin LI *n = (size_t)z.total_out; 5183e41d09dSXin LI rc = inflateEnd(&z); 5193e41d09dSXin LI if (rc != Z_OK) 5203e41d09dSXin LI goto err; 521b6cee71dSXin LI 522b6cee71dSXin LI /* let's keep the nul-terminate tradition */ 5233e41d09dSXin LI (*newch)[*n] = '\0'; 524b6cee71dSXin LI 5253e41d09dSXin LI return OKDATA; 5263e41d09dSXin LI err: 527a5d223e6SXin LI strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max); 5283e41d09dSXin LI *n = strlen((char *)*newch); 5293e41d09dSXin LI return ERRDATA; 530b6cee71dSXin LI } 531b6cee71dSXin LI #endif 532b6cee71dSXin LI 5333e41d09dSXin LI static int 5343e41d09dSXin LI makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) 535b6cee71dSXin LI { 5363e41d09dSXin LI char *msg; 5373e41d09dSXin LI va_list ap; 5383e41d09dSXin LI int rv; 539b6cee71dSXin LI 5403e41d09dSXin LI va_start(ap, fmt); 5413e41d09dSXin LI rv = vasprintf(&msg, fmt, ap); 5423e41d09dSXin LI va_end(ap); 5433e41d09dSXin LI if (rv < 0) { 5443e41d09dSXin LI *buf = NULL; 5453e41d09dSXin LI *len = 0; 546b6cee71dSXin LI return NODATA; 547b6cee71dSXin LI } 5483e41d09dSXin LI *buf = (unsigned char *)msg; 5493e41d09dSXin LI *len = strlen(msg); 5503e41d09dSXin LI return ERRDATA; 551b6cee71dSXin LI } 552b6cee71dSXin LI 5533e41d09dSXin LI static void 5543e41d09dSXin LI closefd(int *fd, size_t i) 5553e41d09dSXin LI { 5563e41d09dSXin LI if (fd[i] == -1) 5573e41d09dSXin LI return; 5583e41d09dSXin LI (void) close(fd[i]); 5593e41d09dSXin LI fd[i] = -1; 5603e41d09dSXin LI } 561b6cee71dSXin LI 5623e41d09dSXin LI static void 5633e41d09dSXin LI closep(int *fd) 5643e41d09dSXin LI { 5653e41d09dSXin LI size_t i; 5663e41d09dSXin LI for (i = 0; i < 2; i++) 5673e41d09dSXin LI closefd(fd, i); 5683e41d09dSXin LI } 5693e41d09dSXin LI 5703e41d09dSXin LI static void 5713e41d09dSXin LI copydesc(int i, int *fd) 5723e41d09dSXin LI { 5733e41d09dSXin LI int j = fd[i == STDIN_FILENO ? 0 : 1]; 5743e41d09dSXin LI if (j == i) 5753e41d09dSXin LI return; 5763e41d09dSXin LI if (dup2(j, i) == -1) { 5773e41d09dSXin LI DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); 578b6cee71dSXin LI exit(1); 5793e41d09dSXin LI } 5803e41d09dSXin LI closep(fd); 5813e41d09dSXin LI } 582b6cee71dSXin LI 5833e41d09dSXin LI static void 5843e41d09dSXin LI writechild(int fdp[3][2], const void *old, size_t n) 5853e41d09dSXin LI { 5863e41d09dSXin LI int status; 5873e41d09dSXin LI 5883e41d09dSXin LI closefd(fdp[STDIN_FILENO], 0); 589b6cee71dSXin LI /* 590b6cee71dSXin LI * fork again, to avoid blocking because both 591b6cee71dSXin LI * pipes filled 592b6cee71dSXin LI */ 593b6cee71dSXin LI switch (fork()) { 594b6cee71dSXin LI case 0: /* child */ 5953e41d09dSXin LI closefd(fdp[STDOUT_FILENO], 0); 5963e41d09dSXin LI if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { 5973e41d09dSXin LI DPRINTF("Write failed (%s)\n", strerror(errno)); 598b6cee71dSXin LI exit(1); 599b6cee71dSXin LI } 600b6cee71dSXin LI exit(0); 601b6cee71dSXin LI /*NOTREACHED*/ 602b6cee71dSXin LI 603b6cee71dSXin LI case -1: 6043e41d09dSXin LI DPRINTF("Fork failed (%s)\n", strerror(errno)); 605b6cee71dSXin LI exit(1); 606b6cee71dSXin LI /*NOTREACHED*/ 607b6cee71dSXin LI 608b6cee71dSXin LI default: /* parent */ 609c2931133SXin LI if (wait(&status) == -1) { 6103e41d09dSXin LI DPRINTF("Wait failed (%s)\n", strerror(errno)); 611c2931133SXin LI exit(1); 612c2931133SXin LI } 6133e41d09dSXin LI DPRINTF("Grandchild wait return %#x\n", status); 614b6cee71dSXin LI } 6153e41d09dSXin LI closefd(fdp[STDIN_FILENO], 1); 616b6cee71dSXin LI } 617b6cee71dSXin LI 6183e41d09dSXin LI static ssize_t 6193e41d09dSXin LI filter_error(unsigned char *ubuf, ssize_t n) 6203e41d09dSXin LI { 6213e41d09dSXin LI char *p; 6223e41d09dSXin LI char *buf; 623c2931133SXin LI 6243e41d09dSXin LI ubuf[n] = '\0'; 6253e41d09dSXin LI buf = (char *)ubuf; 6263e41d09dSXin LI while (isspace((unsigned char)*buf)) 6273e41d09dSXin LI buf++; 6283e41d09dSXin LI DPRINTF("Filter error[[[%s]]]\n", buf); 6293e41d09dSXin LI if ((p = strchr((char *)buf, '\n')) != NULL) 6303e41d09dSXin LI *p = '\0'; 6313e41d09dSXin LI if ((p = strchr((char *)buf, ';')) != NULL) 6323e41d09dSXin LI *p = '\0'; 6333e41d09dSXin LI if ((p = strrchr((char *)buf, ':')) != NULL) { 6343e41d09dSXin LI ++p; 6353e41d09dSXin LI while (isspace((unsigned char)*p)) 6363e41d09dSXin LI p++; 6373e41d09dSXin LI n = strlen(p); 63840427ccaSGordon Tetlow memmove(ubuf, p, CAST(size_t, n + 1)); 6393e41d09dSXin LI } 6403e41d09dSXin LI DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); 6413e41d09dSXin LI if (islower(*ubuf)) 6423e41d09dSXin LI *ubuf = toupper(*ubuf); 643b6cee71dSXin LI return n; 644b6cee71dSXin LI } 6453e41d09dSXin LI 6463e41d09dSXin LI private const char * 6473e41d09dSXin LI methodname(size_t method) 6483e41d09dSXin LI { 6493e41d09dSXin LI #ifdef BUILTIN_DECOMPRESS 6503e41d09dSXin LI /* FIXME: This doesn't cope with bzip2 */ 6513e41d09dSXin LI if (method == 2 || compr[method].maglen == 0) 6523e41d09dSXin LI return "zlib"; 6533e41d09dSXin LI #endif 6543e41d09dSXin LI return compr[method].argv[0]; 6553e41d09dSXin LI } 6563e41d09dSXin LI 6573e41d09dSXin LI private int 6583e41d09dSXin LI uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, 6593e41d09dSXin LI unsigned char **newch, size_t* n) 6603e41d09dSXin LI { 6613e41d09dSXin LI int fdp[3][2]; 6623e41d09dSXin LI int status, rv; 6633e41d09dSXin LI size_t i; 6643e41d09dSXin LI ssize_t r; 6653e41d09dSXin LI 6663e41d09dSXin LI #ifdef BUILTIN_DECOMPRESS 6673e41d09dSXin LI /* FIXME: This doesn't cope with bzip2 */ 6683e41d09dSXin LI if (method == 2) 6693e41d09dSXin LI return uncompressgzipped(old, newch, bytes_max, n); 6703e41d09dSXin LI if (compr[method].maglen == 0) 6713e41d09dSXin LI return uncompresszlib(old, newch, bytes_max, n, 1); 6723e41d09dSXin LI #endif 6733e41d09dSXin LI (void)fflush(stdout); 6743e41d09dSXin LI (void)fflush(stderr); 6753e41d09dSXin LI 6763e41d09dSXin LI for (i = 0; i < __arraycount(fdp); i++) 6773e41d09dSXin LI fdp[i][0] = fdp[i][1] = -1; 6783e41d09dSXin LI 6793e41d09dSXin LI if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || 6803e41d09dSXin LI pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { 6813e41d09dSXin LI closep(fdp[STDIN_FILENO]); 6823e41d09dSXin LI closep(fdp[STDOUT_FILENO]); 6833e41d09dSXin LI return makeerror(newch, n, "Cannot create pipe, %s", 6843e41d09dSXin LI strerror(errno)); 6853e41d09dSXin LI } 6863e41d09dSXin LI switch (fork()) { 6873e41d09dSXin LI case 0: /* child */ 6883e41d09dSXin LI if (fd != -1) { 6893e41d09dSXin LI fdp[STDIN_FILENO][0] = fd; 6903e41d09dSXin LI (void) lseek(fd, (off_t)0, SEEK_SET); 6913e41d09dSXin LI } 6923e41d09dSXin LI 6933e41d09dSXin LI for (i = 0; i < __arraycount(fdp); i++) 69440427ccaSGordon Tetlow copydesc(CAST(int, i), fdp[i]); 6953e41d09dSXin LI 6963e41d09dSXin LI (void)execvp(compr[method].argv[0], 6973e41d09dSXin LI (char *const *)(intptr_t)compr[method].argv); 6983e41d09dSXin LI dprintf(STDERR_FILENO, "exec `%s' failed, %s", 6993e41d09dSXin LI compr[method].argv[0], strerror(errno)); 7003e41d09dSXin LI exit(1); 7013e41d09dSXin LI /*NOTREACHED*/ 7023e41d09dSXin LI case -1: 7033e41d09dSXin LI return makeerror(newch, n, "Cannot fork, %s", 7043e41d09dSXin LI strerror(errno)); 7053e41d09dSXin LI 7063e41d09dSXin LI default: /* parent */ 7073e41d09dSXin LI for (i = 1; i < __arraycount(fdp); i++) 7083e41d09dSXin LI closefd(fdp[i], 1); 7093e41d09dSXin LI 7103e41d09dSXin LI /* Write the buffer data to the child, if we don't have fd */ 7113e41d09dSXin LI if (fd == -1) 7123e41d09dSXin LI writechild(fdp, old, *n); 7133e41d09dSXin LI 7143e41d09dSXin LI *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 7153e41d09dSXin LI if (*newch == NULL) { 7163e41d09dSXin LI rv = makeerror(newch, n, "No buffer, %s", 7173e41d09dSXin LI strerror(errno)); 7183e41d09dSXin LI goto err; 7193e41d09dSXin LI } 7203e41d09dSXin LI rv = OKDATA; 7213e41d09dSXin LI if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) 7223e41d09dSXin LI break; 7233e41d09dSXin LI DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], 7243e41d09dSXin LI r != -1 ? strerror(errno) : "no data"); 7253e41d09dSXin LI 7263e41d09dSXin LI rv = ERRDATA; 7273e41d09dSXin LI if (r == 0 && 7283e41d09dSXin LI (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) 7293e41d09dSXin LI { 7303e41d09dSXin LI r = filter_error(*newch, r); 7313e41d09dSXin LI break; 7323e41d09dSXin LI } 7333e41d09dSXin LI free(*newch); 7343e41d09dSXin LI if (r == 0) 7353e41d09dSXin LI rv = makeerror(newch, n, "Read failed, %s", 7363e41d09dSXin LI strerror(errno)); 7373e41d09dSXin LI else 7383e41d09dSXin LI rv = makeerror(newch, n, "No data"); 7393e41d09dSXin LI goto err; 7403e41d09dSXin LI } 7413e41d09dSXin LI 7423e41d09dSXin LI *n = r; 7433e41d09dSXin LI /* NUL terminate, as every buffer is handled here. */ 7443e41d09dSXin LI (*newch)[*n] = '\0'; 7453e41d09dSXin LI err: 7463e41d09dSXin LI closefd(fdp[STDIN_FILENO], 1); 7473e41d09dSXin LI closefd(fdp[STDOUT_FILENO], 0); 7483e41d09dSXin LI closefd(fdp[STDERR_FILENO], 0); 7493e41d09dSXin LI if (wait(&status) == -1) { 7503e41d09dSXin LI free(*newch); 7513e41d09dSXin LI rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); 7523e41d09dSXin LI DPRINTF("Child wait return %#x\n", status); 7533e41d09dSXin LI } else if (!WIFEXITED(status)) { 75440427ccaSGordon Tetlow DPRINTF("Child not exited (%#x)\n", status); 7553e41d09dSXin LI } else if (WEXITSTATUS(status) != 0) { 75640427ccaSGordon Tetlow DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status)); 7573e41d09dSXin LI } 7583e41d09dSXin LI 7593e41d09dSXin LI closefd(fdp[STDIN_FILENO], 0); 7603e41d09dSXin LI DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); 7613e41d09dSXin LI 7623e41d09dSXin LI return rv; 763b6cee71dSXin LI } 764b6cee71dSXin LI #endif 765