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*3e41d09dSXin LI FILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 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> 48*3e41d09dSXin LI #include <ctype.h> 49*3e41d09dSXin 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 65b6cee71dSXin LI #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) 66b6cee71dSXin LI #define BUILTIN_DECOMPRESS 67b6cee71dSXin LI #include <zlib.h> 68*3e41d09dSXin LI #define ZLIBSUPPORT 69*3e41d09dSXin LI #endif 70*3e41d09dSXin LI #ifdef DEBUG 71*3e41d09dSXin LI int tty = -1; 72*3e41d09dSXin LI #define DPRINTF(...) do { \ 73*3e41d09dSXin LI if (tty == -1) \ 74*3e41d09dSXin LI tty = open("/dev/tty", O_RDWR); \ 75*3e41d09dSXin LI if (tty == -1) \ 76*3e41d09dSXin LI abort(); \ 77*3e41d09dSXin LI dprintf(tty, __VA_ARGS__); \ 78*3e41d09dSXin LI } while (/*CONSTCOND*/0) 79*3e41d09dSXin LI #else 80*3e41d09dSXin LI #define DPRINTF(...) 81b6cee71dSXin LI #endif 82b6cee71dSXin LI 83*3e41d09dSXin LI #ifdef ZLIBSUPPORT 84*3e41d09dSXin LI /* 85*3e41d09dSXin LI * The following python code is not really used because ZLIBSUPPORT is only 86*3e41d09dSXin LI * defined if we have a built-in zlib, and the built-in zlib handles that. 87*3e41d09dSXin LI */ 88*3e41d09dSXin LI static const char zlibcode[] = 89*3e41d09dSXin LI "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; 90*3e41d09dSXin LI 91*3e41d09dSXin LI static const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; 92*3e41d09dSXin LI 93*3e41d09dSXin LI static int 94*3e41d09dSXin LI zlibcmp(const unsigned char *buf) 95*3e41d09dSXin LI { 96*3e41d09dSXin LI unsigned short x = 1; 97*3e41d09dSXin LI unsigned char *s = (unsigned char *)&x; 98*3e41d09dSXin LI 99*3e41d09dSXin LI if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) 100*3e41d09dSXin LI return 0; 101*3e41d09dSXin LI if (s[0] != 1) /* endianness test */ 102*3e41d09dSXin LI x = buf[0] | (buf[1] << 8); 103*3e41d09dSXin LI else 104*3e41d09dSXin LI x = buf[1] | (buf[0] << 8); 105*3e41d09dSXin LI if (x % 31) 106*3e41d09dSXin LI return 0; 107*3e41d09dSXin LI return 1; 108*3e41d09dSXin LI } 109*3e41d09dSXin LI #endif 110*3e41d09dSXin LI 111*3e41d09dSXin LI #define gzip_flags "-cd" 112*3e41d09dSXin LI #define lrzip_flags "-do" 113*3e41d09dSXin LI #define lzip_flags gzip_flags 114*3e41d09dSXin LI 115*3e41d09dSXin LI static const char *gzip_args[] = { 116*3e41d09dSXin LI "gzip", gzip_flags, NULL 117*3e41d09dSXin LI }; 118*3e41d09dSXin LI static const char *uncompress_args[] = { 119*3e41d09dSXin LI "uncompress", "-c", NULL 120*3e41d09dSXin LI }; 121*3e41d09dSXin LI static const char *bzip2_args[] = { 122*3e41d09dSXin LI "bzip2", "-cd", NULL 123*3e41d09dSXin LI }; 124*3e41d09dSXin LI static const char *lzip_args[] = { 125*3e41d09dSXin LI "lzip", lzip_flags, NULL 126*3e41d09dSXin LI }; 127*3e41d09dSXin LI static const char *xz_args[] = { 128*3e41d09dSXin LI "xz", "-cd", NULL 129*3e41d09dSXin LI }; 130*3e41d09dSXin LI static const char *lrzip_args[] = { 131*3e41d09dSXin LI "lrzip", lrzip_flags, NULL 132*3e41d09dSXin LI }; 133*3e41d09dSXin LI static const char *lz4_args[] = { 134*3e41d09dSXin LI "lz4", "-cd", NULL 135b6cee71dSXin LI }; 136b6cee71dSXin LI 137*3e41d09dSXin LI private const struct { 138*3e41d09dSXin LI const void *magic; 139*3e41d09dSXin LI size_t maglen; 140*3e41d09dSXin LI const char **argv; 141*3e41d09dSXin LI } compr[] = { 142*3e41d09dSXin LI { "\037\235", 2, gzip_args }, /* compressed */ 143*3e41d09dSXin LI /* Uncompress can get stuck; so use gzip first if we have it 144*3e41d09dSXin LI * Idea from Damien Clark, thanks! */ 145*3e41d09dSXin LI { "\037\235", 2, uncompress_args }, /* compressed */ 146*3e41d09dSXin LI { "\037\213", 2, gzip_args }, /* gzipped */ 147*3e41d09dSXin LI { "\037\236", 2, gzip_args }, /* frozen */ 148*3e41d09dSXin LI { "\037\240", 2, gzip_args }, /* SCO LZH */ 149*3e41d09dSXin LI /* the standard pack utilities do not accept standard input */ 150*3e41d09dSXin LI { "\037\036", 2, gzip_args }, /* packed */ 151*3e41d09dSXin LI { "PK\3\4", 4, gzip_args }, /* pkzipped, */ 152*3e41d09dSXin LI /* ...only first file examined */ 153*3e41d09dSXin LI { "BZh", 3, bzip2_args }, /* bzip2-ed */ 154*3e41d09dSXin LI { "LZIP", 4, lzip_args }, /* lzip-ed */ 155*3e41d09dSXin LI { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ 156*3e41d09dSXin LI { "LRZI", 4, lrzip_args }, /* LRZIP */ 157*3e41d09dSXin LI { "\004\"M\030",4, lz4_args }, /* LZ4 */ 158*3e41d09dSXin LI #ifdef ZLIBSUPPORT 159*3e41d09dSXin LI { zlibcmp, 0, zlib_args }, /* zlib */ 160*3e41d09dSXin LI #endif 161*3e41d09dSXin LI }; 162*3e41d09dSXin LI 163*3e41d09dSXin LI #define OKDATA 0 164*3e41d09dSXin LI #define NODATA 1 165*3e41d09dSXin LI #define ERRDATA 2 166b6cee71dSXin LI 167b6cee71dSXin LI private ssize_t swrite(int, const void *, size_t); 168b6cee71dSXin LI #if HAVE_FORK 169b6cee71dSXin LI private size_t ncompr = sizeof(compr) / sizeof(compr[0]); 170*3e41d09dSXin LI private int uncompressbuf(int, size_t, size_t, const unsigned char *, 171*3e41d09dSXin LI unsigned char **, size_t *); 172b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 173*3e41d09dSXin LI private int uncompresszlib(const unsigned char *, unsigned char **, size_t, 174*3e41d09dSXin LI size_t *, int); 175*3e41d09dSXin LI private int uncompressgzipped(const unsigned char *, unsigned char **, size_t, 176*3e41d09dSXin LI size_t *); 177b6cee71dSXin LI #endif 178*3e41d09dSXin LI static int makeerror(unsigned char **, size_t *, const char *, ...) 179*3e41d09dSXin LI __attribute__((__format__(__printf__, 3, 4))); 180*3e41d09dSXin LI private const char *methodname(size_t); 181b6cee71dSXin LI 182b6cee71dSXin LI protected int 183b6cee71dSXin LI file_zmagic(struct magic_set *ms, int fd, const char *name, 184b6cee71dSXin LI const unsigned char *buf, size_t nbytes) 185b6cee71dSXin LI { 186b6cee71dSXin LI unsigned char *newbuf = NULL; 187b6cee71dSXin LI size_t i, nsz; 188*3e41d09dSXin LI char *rbuf; 189*3e41d09dSXin LI file_pushbuf_t *pb; 190b6cee71dSXin LI int rv = 0; 191b6cee71dSXin LI int mime = ms->flags & MAGIC_MIME; 1925f0216bdSXin LI #ifdef HAVE_SIGNAL_H 1934460e5b0SXin LI sig_t osigpipe; 1945f0216bdSXin LI #endif 195b6cee71dSXin LI 196b6cee71dSXin LI if ((ms->flags & MAGIC_COMPRESS) == 0) 197b6cee71dSXin LI return 0; 198b6cee71dSXin LI 1995f0216bdSXin LI #ifdef HAVE_SIGNAL_H 2004460e5b0SXin LI osigpipe = signal(SIGPIPE, SIG_IGN); 2015f0216bdSXin LI #endif 202b6cee71dSXin LI for (i = 0; i < ncompr; i++) { 203*3e41d09dSXin LI int zm; 204b6cee71dSXin LI if (nbytes < compr[i].maglen) 205b6cee71dSXin LI continue; 206*3e41d09dSXin LI #ifdef ZLIBSUPPORT 207*3e41d09dSXin LI if (compr[i].maglen == 0) 208*3e41d09dSXin LI zm = (CAST(int (*)(const unsigned char *), 209*3e41d09dSXin LI CCAST(void *, compr[i].magic)))(buf); 210*3e41d09dSXin LI else 211*3e41d09dSXin LI #endif 212*3e41d09dSXin LI zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; 213b6cee71dSXin LI 214*3e41d09dSXin LI if (!zm) 215*3e41d09dSXin LI continue; 216*3e41d09dSXin LI nsz = nbytes; 217*3e41d09dSXin LI rv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); 218*3e41d09dSXin LI DPRINTF("uncompressbuf = %d, %s, %zu\n", rv, (char *)newbuf, 219*3e41d09dSXin LI nsz); 220*3e41d09dSXin LI switch (rv) { 221*3e41d09dSXin LI case OKDATA: 222*3e41d09dSXin LI case ERRDATA: 223*3e41d09dSXin LI 224*3e41d09dSXin LI ms->flags &= ~MAGIC_COMPRESS; 225*3e41d09dSXin LI if (rv == ERRDATA) 226*3e41d09dSXin LI rv = file_printf(ms, "%s ERROR: %s", 227*3e41d09dSXin LI methodname(i), newbuf); 228*3e41d09dSXin LI else 229*3e41d09dSXin LI rv = file_buffer(ms, -1, name, newbuf, nsz); 230*3e41d09dSXin LI if (rv == -1) 231*3e41d09dSXin LI goto error; 232*3e41d09dSXin LI DPRINTF("rv = %d\n", rv); 233*3e41d09dSXin LI if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) 234*3e41d09dSXin LI goto out; 235*3e41d09dSXin LI if (mime != MAGIC_MIME && mime != 0) 236*3e41d09dSXin LI goto out; 237*3e41d09dSXin LI if ((file_printf(ms, 238*3e41d09dSXin LI mime ? " compressed-encoding=" : " (")) == -1) 239*3e41d09dSXin LI goto error; 240*3e41d09dSXin LI if ((pb = file_push_buffer(ms)) == NULL) 241b6cee71dSXin LI goto error; 242b6cee71dSXin LI if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 243b6cee71dSXin LI goto error; 244*3e41d09dSXin LI if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 245*3e41d09dSXin LI if (file_printf(ms, "%s", rbuf) == -1) { 246*3e41d09dSXin LI free(rbuf); 247b6cee71dSXin LI goto error; 248b6cee71dSXin LI } 249*3e41d09dSXin LI free(rbuf); 250*3e41d09dSXin LI } 251*3e41d09dSXin LI if (!mime && file_printf(ms, ")") == -1) 252*3e41d09dSXin LI goto error; 253*3e41d09dSXin LI goto out; 254*3e41d09dSXin LI case NODATA: 255*3e41d09dSXin LI goto out; 256*3e41d09dSXin LI default: 257*3e41d09dSXin LI abort(); 258*3e41d09dSXin LI } 259*3e41d09dSXin LI } 260*3e41d09dSXin LI out: 261b6cee71dSXin LI rv = 1; 262b6cee71dSXin LI error: 2635f0216bdSXin LI #ifdef HAVE_SIGNAL_H 2644460e5b0SXin LI (void)signal(SIGPIPE, osigpipe); 2655f0216bdSXin LI #endif 266b6cee71dSXin LI free(newbuf); 267b6cee71dSXin LI ms->flags |= MAGIC_COMPRESS; 268*3e41d09dSXin LI DPRINTF("Zmagic returns %d\n", rv); 269b6cee71dSXin LI return rv; 270b6cee71dSXin LI } 271b6cee71dSXin LI #endif 272b6cee71dSXin LI /* 273b6cee71dSXin LI * `safe' write for sockets and pipes. 274b6cee71dSXin LI */ 275b6cee71dSXin LI private ssize_t 276b6cee71dSXin LI swrite(int fd, const void *buf, size_t n) 277b6cee71dSXin LI { 278b6cee71dSXin LI ssize_t rv; 279b6cee71dSXin LI size_t rn = n; 280b6cee71dSXin LI 281b6cee71dSXin LI do 282b6cee71dSXin LI switch (rv = write(fd, buf, n)) { 283b6cee71dSXin LI case -1: 284b6cee71dSXin LI if (errno == EINTR) 285b6cee71dSXin LI continue; 286b6cee71dSXin LI return -1; 287b6cee71dSXin LI default: 288b6cee71dSXin LI n -= rv; 289b6cee71dSXin LI buf = CAST(const char *, buf) + rv; 290b6cee71dSXin LI break; 291b6cee71dSXin LI } 292b6cee71dSXin LI while (n > 0); 293b6cee71dSXin LI return rn; 294b6cee71dSXin LI } 295b6cee71dSXin LI 296b6cee71dSXin LI 297b6cee71dSXin LI /* 298b6cee71dSXin LI * `safe' read for sockets and pipes. 299b6cee71dSXin LI */ 300b6cee71dSXin LI protected ssize_t 301b6cee71dSXin LI sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 302b6cee71dSXin LI { 303b6cee71dSXin LI ssize_t rv; 304b6cee71dSXin LI #ifdef FIONREAD 305b6cee71dSXin LI int t = 0; 306b6cee71dSXin LI #endif 307b6cee71dSXin LI size_t rn = n; 308b6cee71dSXin LI 309b6cee71dSXin LI if (fd == STDIN_FILENO) 310b6cee71dSXin LI goto nocheck; 311b6cee71dSXin LI 312b6cee71dSXin LI #ifdef FIONREAD 313b6cee71dSXin LI if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 314b6cee71dSXin LI #ifdef FD_ZERO 315b6cee71dSXin LI ssize_t cnt; 316b6cee71dSXin LI for (cnt = 0;; cnt++) { 317b6cee71dSXin LI fd_set check; 318b6cee71dSXin LI struct timeval tout = {0, 100 * 1000}; 319b6cee71dSXin LI int selrv; 320b6cee71dSXin LI 321b6cee71dSXin LI FD_ZERO(&check); 322b6cee71dSXin LI FD_SET(fd, &check); 323b6cee71dSXin LI 324b6cee71dSXin LI /* 325b6cee71dSXin LI * Avoid soft deadlock: do not read if there 326b6cee71dSXin LI * is nothing to read from sockets and pipes. 327b6cee71dSXin LI */ 328b6cee71dSXin LI selrv = select(fd + 1, &check, NULL, NULL, &tout); 329b6cee71dSXin LI if (selrv == -1) { 330b6cee71dSXin LI if (errno == EINTR || errno == EAGAIN) 331b6cee71dSXin LI continue; 332b6cee71dSXin LI } else if (selrv == 0 && cnt >= 5) { 333b6cee71dSXin LI return 0; 334b6cee71dSXin LI } else 335b6cee71dSXin LI break; 336b6cee71dSXin LI } 337b6cee71dSXin LI #endif 338b6cee71dSXin LI (void)ioctl(fd, FIONREAD, &t); 339b6cee71dSXin LI } 340b6cee71dSXin LI 341b6cee71dSXin LI if (t > 0 && (size_t)t < n) { 342b6cee71dSXin LI n = t; 343b6cee71dSXin LI rn = n; 344b6cee71dSXin LI } 345b6cee71dSXin LI #endif 346b6cee71dSXin LI 347b6cee71dSXin LI nocheck: 348b6cee71dSXin LI do 349b6cee71dSXin LI switch ((rv = read(fd, buf, n))) { 350b6cee71dSXin LI case -1: 351b6cee71dSXin LI if (errno == EINTR) 352b6cee71dSXin LI continue; 353b6cee71dSXin LI return -1; 354b6cee71dSXin LI case 0: 355b6cee71dSXin LI return rn - n; 356b6cee71dSXin LI default: 357b6cee71dSXin LI n -= rv; 358b6cee71dSXin LI buf = ((char *)buf) + rv; 359b6cee71dSXin LI break; 360b6cee71dSXin LI } 361b6cee71dSXin LI while (n > 0); 362b6cee71dSXin LI return rn; 363b6cee71dSXin LI } 364b6cee71dSXin LI 365b6cee71dSXin LI protected int 366b6cee71dSXin LI file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 367b6cee71dSXin LI size_t nbytes) 368b6cee71dSXin LI { 369b6cee71dSXin LI char buf[4096]; 370b6cee71dSXin LI ssize_t r; 371b6cee71dSXin LI int tfd; 372b6cee71dSXin LI 373b6cee71dSXin LI (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 374b6cee71dSXin LI #ifndef HAVE_MKSTEMP 375b6cee71dSXin LI { 376b6cee71dSXin LI char *ptr = mktemp(buf); 377b6cee71dSXin LI tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 378b6cee71dSXin LI r = errno; 379b6cee71dSXin LI (void)unlink(ptr); 380b6cee71dSXin LI errno = r; 381b6cee71dSXin LI } 382b6cee71dSXin LI #else 383b6cee71dSXin LI { 384b6cee71dSXin LI int te; 385b6cee71dSXin LI tfd = mkstemp(buf); 386b6cee71dSXin LI te = errno; 387b6cee71dSXin LI (void)unlink(buf); 388b6cee71dSXin LI errno = te; 389b6cee71dSXin LI } 390b6cee71dSXin LI #endif 391b6cee71dSXin LI if (tfd == -1) { 392b6cee71dSXin LI file_error(ms, errno, 393b6cee71dSXin LI "cannot create temporary file for pipe copy"); 394b6cee71dSXin LI return -1; 395b6cee71dSXin LI } 396b6cee71dSXin LI 397b6cee71dSXin LI if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 398b6cee71dSXin LI r = 1; 399b6cee71dSXin LI else { 400b6cee71dSXin LI while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 401b6cee71dSXin LI if (swrite(tfd, buf, (size_t)r) != r) 402b6cee71dSXin LI break; 403b6cee71dSXin LI } 404b6cee71dSXin LI 405b6cee71dSXin LI switch (r) { 406b6cee71dSXin LI case -1: 407b6cee71dSXin LI file_error(ms, errno, "error copying from pipe to temp file"); 408b6cee71dSXin LI return -1; 409b6cee71dSXin LI case 0: 410b6cee71dSXin LI break; 411b6cee71dSXin LI default: 412b6cee71dSXin LI file_error(ms, errno, "error while writing to temp file"); 413b6cee71dSXin LI return -1; 414b6cee71dSXin LI } 415b6cee71dSXin LI 416b6cee71dSXin LI /* 417b6cee71dSXin LI * We duplicate the file descriptor, because fclose on a 418b6cee71dSXin LI * tmpfile will delete the file, but any open descriptors 419b6cee71dSXin LI * can still access the phantom inode. 420b6cee71dSXin LI */ 421b6cee71dSXin LI if ((fd = dup2(tfd, fd)) == -1) { 422b6cee71dSXin LI file_error(ms, errno, "could not dup descriptor for temp file"); 423b6cee71dSXin LI return -1; 424b6cee71dSXin LI } 425b6cee71dSXin LI (void)close(tfd); 426b6cee71dSXin LI if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 427b6cee71dSXin LI file_badseek(ms); 428b6cee71dSXin LI return -1; 429b6cee71dSXin LI } 430b6cee71dSXin LI return fd; 431b6cee71dSXin LI } 432b6cee71dSXin LI #if HAVE_FORK 433b6cee71dSXin LI #ifdef BUILTIN_DECOMPRESS 434b6cee71dSXin LI 435b6cee71dSXin LI #define FHCRC (1 << 1) 436b6cee71dSXin LI #define FEXTRA (1 << 2) 437b6cee71dSXin LI #define FNAME (1 << 3) 438b6cee71dSXin LI #define FCOMMENT (1 << 4) 439b6cee71dSXin LI 440*3e41d09dSXin LI 441*3e41d09dSXin LI private int 442*3e41d09dSXin LI uncompressgzipped(const unsigned char *old, unsigned char **newch, 443*3e41d09dSXin LI size_t bytes_max, size_t *n) 444b6cee71dSXin LI { 445b6cee71dSXin LI unsigned char flg = old[3]; 446b6cee71dSXin LI size_t data_start = 10; 447b6cee71dSXin LI 448b6cee71dSXin LI if (flg & FEXTRA) { 449*3e41d09dSXin LI if (data_start + 1 >= *n) 450*3e41d09dSXin LI goto err; 451b6cee71dSXin LI data_start += 2 + old[data_start] + old[data_start + 1] * 256; 452b6cee71dSXin LI } 453b6cee71dSXin LI if (flg & FNAME) { 454*3e41d09dSXin LI while(data_start < *n && old[data_start]) 455b6cee71dSXin LI data_start++; 456b6cee71dSXin LI data_start++; 457b6cee71dSXin LI } 458b6cee71dSXin LI if (flg & FCOMMENT) { 459*3e41d09dSXin LI while(data_start < *n && old[data_start]) 460b6cee71dSXin LI data_start++; 461b6cee71dSXin LI data_start++; 462b6cee71dSXin LI } 463b6cee71dSXin LI if (flg & FHCRC) 464b6cee71dSXin LI data_start += 2; 465b6cee71dSXin LI 466*3e41d09dSXin LI if (data_start >= *n) 467*3e41d09dSXin LI goto err; 468*3e41d09dSXin LI 469*3e41d09dSXin LI *n -= data_start; 470*3e41d09dSXin LI old += data_start; 471*3e41d09dSXin LI return uncompresszlib(old, newch, bytes_max, n, 0); 472*3e41d09dSXin LI err: 473*3e41d09dSXin LI return makeerror(newch, n, "File too short"); 474b6cee71dSXin LI } 475b6cee71dSXin LI 476*3e41d09dSXin LI private int 477*3e41d09dSXin LI uncompresszlib(const unsigned char *old, unsigned char **newch, 478*3e41d09dSXin LI size_t bytes_max, size_t *n, int zlib) 479*3e41d09dSXin LI { 480*3e41d09dSXin LI int rc; 481*3e41d09dSXin LI z_stream z; 482*3e41d09dSXin LI 483*3e41d09dSXin LI if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 484*3e41d09dSXin LI return makeerror(newch, n, "No buffer, %s", strerror(errno)); 485*3e41d09dSXin LI 486*3e41d09dSXin LI z.next_in = CCAST(Bytef *, old); 487*3e41d09dSXin LI z.avail_in = CAST(uint32_t, *n); 488b6cee71dSXin LI z.next_out = *newch; 489*3e41d09dSXin LI z.avail_out = bytes_max; 490b6cee71dSXin LI z.zalloc = Z_NULL; 491b6cee71dSXin LI z.zfree = Z_NULL; 492b6cee71dSXin LI z.opaque = Z_NULL; 493b6cee71dSXin LI 494b6cee71dSXin LI /* LINTED bug in header macro */ 495*3e41d09dSXin LI rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); 496*3e41d09dSXin LI if (rc != Z_OK) 497*3e41d09dSXin LI goto err; 498b6cee71dSXin LI 499b6cee71dSXin LI rc = inflate(&z, Z_SYNC_FLUSH); 500*3e41d09dSXin LI if (rc != Z_OK && rc != Z_STREAM_END) 501*3e41d09dSXin LI goto err; 502b6cee71dSXin LI 503*3e41d09dSXin LI *n = (size_t)z.total_out; 504*3e41d09dSXin LI rc = inflateEnd(&z); 505*3e41d09dSXin LI if (rc != Z_OK) 506*3e41d09dSXin LI goto err; 507b6cee71dSXin LI 508b6cee71dSXin LI /* let's keep the nul-terminate tradition */ 509*3e41d09dSXin LI (*newch)[*n] = '\0'; 510b6cee71dSXin LI 511*3e41d09dSXin LI return OKDATA; 512*3e41d09dSXin LI err: 513*3e41d09dSXin LI strlcpy((char *)*newch, z.msg, bytes_max); 514*3e41d09dSXin LI *n = strlen((char *)*newch); 515*3e41d09dSXin LI return ERRDATA; 516b6cee71dSXin LI } 517b6cee71dSXin LI #endif 518b6cee71dSXin LI 519*3e41d09dSXin LI static int 520*3e41d09dSXin LI makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) 521b6cee71dSXin LI { 522*3e41d09dSXin LI char *msg; 523*3e41d09dSXin LI va_list ap; 524*3e41d09dSXin LI int rv; 525b6cee71dSXin LI 526*3e41d09dSXin LI va_start(ap, fmt); 527*3e41d09dSXin LI rv = vasprintf(&msg, fmt, ap); 528*3e41d09dSXin LI va_end(ap); 529*3e41d09dSXin LI if (rv < 0) { 530*3e41d09dSXin LI *buf = NULL; 531*3e41d09dSXin LI *len = 0; 532b6cee71dSXin LI return NODATA; 533b6cee71dSXin LI } 534*3e41d09dSXin LI *buf = (unsigned char *)msg; 535*3e41d09dSXin LI *len = strlen(msg); 536*3e41d09dSXin LI return ERRDATA; 537b6cee71dSXin LI } 538b6cee71dSXin LI 539*3e41d09dSXin LI static void 540*3e41d09dSXin LI closefd(int *fd, size_t i) 541*3e41d09dSXin LI { 542*3e41d09dSXin LI if (fd[i] == -1) 543*3e41d09dSXin LI return; 544*3e41d09dSXin LI (void) close(fd[i]); 545*3e41d09dSXin LI fd[i] = -1; 546*3e41d09dSXin LI } 547b6cee71dSXin LI 548*3e41d09dSXin LI static void 549*3e41d09dSXin LI closep(int *fd) 550*3e41d09dSXin LI { 551*3e41d09dSXin LI size_t i; 552*3e41d09dSXin LI for (i = 0; i < 2; i++) 553*3e41d09dSXin LI closefd(fd, i); 554*3e41d09dSXin LI } 555*3e41d09dSXin LI 556*3e41d09dSXin LI static void 557*3e41d09dSXin LI copydesc(int i, int *fd) 558*3e41d09dSXin LI { 559*3e41d09dSXin LI int j = fd[i == STDIN_FILENO ? 0 : 1]; 560*3e41d09dSXin LI if (j == i) 561*3e41d09dSXin LI return; 562*3e41d09dSXin LI if (dup2(j, i) == -1) { 563*3e41d09dSXin LI DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); 564b6cee71dSXin LI exit(1); 565*3e41d09dSXin LI } 566*3e41d09dSXin LI closep(fd); 567*3e41d09dSXin LI } 568b6cee71dSXin LI 569*3e41d09dSXin LI static void 570*3e41d09dSXin LI writechild(int fdp[3][2], const void *old, size_t n) 571*3e41d09dSXin LI { 572*3e41d09dSXin LI int status; 573*3e41d09dSXin LI 574*3e41d09dSXin LI closefd(fdp[STDIN_FILENO], 0); 575b6cee71dSXin LI /* 576b6cee71dSXin LI * fork again, to avoid blocking because both 577b6cee71dSXin LI * pipes filled 578b6cee71dSXin LI */ 579b6cee71dSXin LI switch (fork()) { 580b6cee71dSXin LI case 0: /* child */ 581*3e41d09dSXin LI closefd(fdp[STDOUT_FILENO], 0); 582*3e41d09dSXin LI if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { 583*3e41d09dSXin LI DPRINTF("Write failed (%s)\n", strerror(errno)); 584b6cee71dSXin LI exit(1); 585b6cee71dSXin LI } 586b6cee71dSXin LI exit(0); 587b6cee71dSXin LI /*NOTREACHED*/ 588b6cee71dSXin LI 589b6cee71dSXin LI case -1: 590*3e41d09dSXin LI DPRINTF("Fork failed (%s)\n", strerror(errno)); 591b6cee71dSXin LI exit(1); 592b6cee71dSXin LI /*NOTREACHED*/ 593b6cee71dSXin LI 594b6cee71dSXin LI default: /* parent */ 595c2931133SXin LI if (wait(&status) == -1) { 596*3e41d09dSXin LI DPRINTF("Wait failed (%s)\n", strerror(errno)); 597c2931133SXin LI exit(1); 598c2931133SXin LI } 599*3e41d09dSXin LI DPRINTF("Grandchild wait return %#x\n", status); 600b6cee71dSXin LI } 601*3e41d09dSXin LI closefd(fdp[STDIN_FILENO], 1); 602b6cee71dSXin LI } 603b6cee71dSXin LI 604*3e41d09dSXin LI static ssize_t 605*3e41d09dSXin LI filter_error(unsigned char *ubuf, ssize_t n) 606*3e41d09dSXin LI { 607*3e41d09dSXin LI char *p; 608*3e41d09dSXin LI char *buf; 609c2931133SXin LI 610*3e41d09dSXin LI ubuf[n] = '\0'; 611*3e41d09dSXin LI buf = (char *)ubuf; 612*3e41d09dSXin LI while (isspace((unsigned char)*buf)) 613*3e41d09dSXin LI buf++; 614*3e41d09dSXin LI DPRINTF("Filter error[[[%s]]]\n", buf); 615*3e41d09dSXin LI if ((p = strchr((char *)buf, '\n')) != NULL) 616*3e41d09dSXin LI *p = '\0'; 617*3e41d09dSXin LI if ((p = strchr((char *)buf, ';')) != NULL) 618*3e41d09dSXin LI *p = '\0'; 619*3e41d09dSXin LI if ((p = strrchr((char *)buf, ':')) != NULL) { 620*3e41d09dSXin LI ++p; 621*3e41d09dSXin LI while (isspace((unsigned char)*p)) 622*3e41d09dSXin LI p++; 623*3e41d09dSXin LI n = strlen(p); 624*3e41d09dSXin LI memmove(ubuf, p, n + 1); 625*3e41d09dSXin LI } 626*3e41d09dSXin LI DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); 627*3e41d09dSXin LI if (islower(*ubuf)) 628*3e41d09dSXin LI *ubuf = toupper(*ubuf); 629b6cee71dSXin LI return n; 630b6cee71dSXin LI } 631*3e41d09dSXin LI 632*3e41d09dSXin LI private const char * 633*3e41d09dSXin LI methodname(size_t method) 634*3e41d09dSXin LI { 635*3e41d09dSXin LI #ifdef BUILTIN_DECOMPRESS 636*3e41d09dSXin LI /* FIXME: This doesn't cope with bzip2 */ 637*3e41d09dSXin LI if (method == 2 || compr[method].maglen == 0) 638*3e41d09dSXin LI return "zlib"; 639*3e41d09dSXin LI #endif 640*3e41d09dSXin LI return compr[method].argv[0]; 641*3e41d09dSXin LI } 642*3e41d09dSXin LI 643*3e41d09dSXin LI private int 644*3e41d09dSXin LI uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, 645*3e41d09dSXin LI unsigned char **newch, size_t* n) 646*3e41d09dSXin LI { 647*3e41d09dSXin LI int fdp[3][2]; 648*3e41d09dSXin LI int status, rv; 649*3e41d09dSXin LI size_t i; 650*3e41d09dSXin LI ssize_t r; 651*3e41d09dSXin LI 652*3e41d09dSXin LI #ifdef BUILTIN_DECOMPRESS 653*3e41d09dSXin LI /* FIXME: This doesn't cope with bzip2 */ 654*3e41d09dSXin LI if (method == 2) 655*3e41d09dSXin LI return uncompressgzipped(old, newch, bytes_max, n); 656*3e41d09dSXin LI if (compr[method].maglen == 0) 657*3e41d09dSXin LI return uncompresszlib(old, newch, bytes_max, n, 1); 658*3e41d09dSXin LI #endif 659*3e41d09dSXin LI (void)fflush(stdout); 660*3e41d09dSXin LI (void)fflush(stderr); 661*3e41d09dSXin LI 662*3e41d09dSXin LI for (i = 0; i < __arraycount(fdp); i++) 663*3e41d09dSXin LI fdp[i][0] = fdp[i][1] = -1; 664*3e41d09dSXin LI 665*3e41d09dSXin LI if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || 666*3e41d09dSXin LI pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { 667*3e41d09dSXin LI closep(fdp[STDIN_FILENO]); 668*3e41d09dSXin LI closep(fdp[STDOUT_FILENO]); 669*3e41d09dSXin LI return makeerror(newch, n, "Cannot create pipe, %s", 670*3e41d09dSXin LI strerror(errno)); 671*3e41d09dSXin LI } 672*3e41d09dSXin LI switch (fork()) { 673*3e41d09dSXin LI case 0: /* child */ 674*3e41d09dSXin LI if (fd != -1) { 675*3e41d09dSXin LI fdp[STDIN_FILENO][0] = fd; 676*3e41d09dSXin LI (void) lseek(fd, (off_t)0, SEEK_SET); 677*3e41d09dSXin LI } 678*3e41d09dSXin LI 679*3e41d09dSXin LI for (i = 0; i < __arraycount(fdp); i++) 680*3e41d09dSXin LI copydesc(i, fdp[i]); 681*3e41d09dSXin LI 682*3e41d09dSXin LI (void)execvp(compr[method].argv[0], 683*3e41d09dSXin LI (char *const *)(intptr_t)compr[method].argv); 684*3e41d09dSXin LI dprintf(STDERR_FILENO, "exec `%s' failed, %s", 685*3e41d09dSXin LI compr[method].argv[0], strerror(errno)); 686*3e41d09dSXin LI exit(1); 687*3e41d09dSXin LI /*NOTREACHED*/ 688*3e41d09dSXin LI case -1: 689*3e41d09dSXin LI return makeerror(newch, n, "Cannot fork, %s", 690*3e41d09dSXin LI strerror(errno)); 691*3e41d09dSXin LI 692*3e41d09dSXin LI default: /* parent */ 693*3e41d09dSXin LI for (i = 1; i < __arraycount(fdp); i++) 694*3e41d09dSXin LI closefd(fdp[i], 1); 695*3e41d09dSXin LI 696*3e41d09dSXin LI /* Write the buffer data to the child, if we don't have fd */ 697*3e41d09dSXin LI if (fd == -1) 698*3e41d09dSXin LI writechild(fdp, old, *n); 699*3e41d09dSXin LI 700*3e41d09dSXin LI *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 701*3e41d09dSXin LI if (*newch == NULL) { 702*3e41d09dSXin LI rv = makeerror(newch, n, "No buffer, %s", 703*3e41d09dSXin LI strerror(errno)); 704*3e41d09dSXin LI goto err; 705*3e41d09dSXin LI } 706*3e41d09dSXin LI rv = OKDATA; 707*3e41d09dSXin LI if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) 708*3e41d09dSXin LI break; 709*3e41d09dSXin LI DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], 710*3e41d09dSXin LI r != -1 ? strerror(errno) : "no data"); 711*3e41d09dSXin LI 712*3e41d09dSXin LI rv = ERRDATA; 713*3e41d09dSXin LI if (r == 0 && 714*3e41d09dSXin LI (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) 715*3e41d09dSXin LI { 716*3e41d09dSXin LI r = filter_error(*newch, r); 717*3e41d09dSXin LI break; 718*3e41d09dSXin LI } 719*3e41d09dSXin LI free(*newch); 720*3e41d09dSXin LI if (r == 0) 721*3e41d09dSXin LI rv = makeerror(newch, n, "Read failed, %s", 722*3e41d09dSXin LI strerror(errno)); 723*3e41d09dSXin LI else 724*3e41d09dSXin LI rv = makeerror(newch, n, "No data"); 725*3e41d09dSXin LI goto err; 726*3e41d09dSXin LI } 727*3e41d09dSXin LI 728*3e41d09dSXin LI *n = r; 729*3e41d09dSXin LI /* NUL terminate, as every buffer is handled here. */ 730*3e41d09dSXin LI (*newch)[*n] = '\0'; 731*3e41d09dSXin LI err: 732*3e41d09dSXin LI closefd(fdp[STDIN_FILENO], 1); 733*3e41d09dSXin LI closefd(fdp[STDOUT_FILENO], 0); 734*3e41d09dSXin LI closefd(fdp[STDERR_FILENO], 0); 735*3e41d09dSXin LI if (wait(&status) == -1) { 736*3e41d09dSXin LI free(*newch); 737*3e41d09dSXin LI rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); 738*3e41d09dSXin LI DPRINTF("Child wait return %#x\n", status); 739*3e41d09dSXin LI } else if (!WIFEXITED(status)) { 740*3e41d09dSXin LI DPRINTF("Child not exited (0x%x)\n", status); 741*3e41d09dSXin LI } else if (WEXITSTATUS(status) != 0) { 742*3e41d09dSXin LI DPRINTF("Child exited (0x%d)\n", WEXITSTATUS(status)); 743*3e41d09dSXin LI } 744*3e41d09dSXin LI 745*3e41d09dSXin LI closefd(fdp[STDIN_FILENO], 0); 746*3e41d09dSXin LI DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); 747*3e41d09dSXin LI 748*3e41d09dSXin LI return rv; 749b6cee71dSXin LI } 750b6cee71dSXin LI #endif 751