compress.c revision 328874
168349Sobrien/* 2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 3133359Sobrien * Software written by Ian F. Darwin and others; 4133359Sobrien * maintained 1995-present by Christos Zoulas and others. 5133359Sobrien * 6133359Sobrien * Redistribution and use in source and binary forms, with or without 7133359Sobrien * modification, are permitted provided that the following conditions 8133359Sobrien * are met: 9133359Sobrien * 1. Redistributions of source code must retain the above copyright 10133359Sobrien * notice immediately at the beginning of the file, without modification, 11133359Sobrien * this list of conditions, and the following disclaimer. 12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13133359Sobrien * notice, this list of conditions and the following disclaimer in the 14133359Sobrien * documentation and/or other materials provided with the distribution. 15133359Sobrien * 16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26133359Sobrien * SUCH DAMAGE. 27133359Sobrien */ 28133359Sobrien/* 2968349Sobrien * compress routines: 3068349Sobrien * zmagic() - returns 0 if not recognized, uncompresses and prints 3168349Sobrien * information if recognized 3268349Sobrien * uncompress(method, old, n, newch) - uncompress old into new, 3368349Sobrien * using method, return sizeof new 3468349Sobrien */ 3568349Sobrien#include "file.h" 36191736Sobrien 37191736Sobrien#ifndef lint 38328874SeadlerFILE_RCSID("@(#)$File: compress.c,v 1.105 2017/05/25 00:13:03 christos Exp $") 39191736Sobrien#endif 40191736Sobrien 41133359Sobrien#include "magic.h" 4268349Sobrien#include <stdlib.h> 4368349Sobrien#ifdef HAVE_UNISTD_H 4468349Sobrien#include <unistd.h> 4568349Sobrien#endif 4668349Sobrien#include <string.h> 47133359Sobrien#include <errno.h> 48298192Sdelphij#include <ctype.h> 49298192Sdelphij#include <stdarg.h> 50284237Sdelphij#ifdef HAVE_SIGNAL_H 51276577Sdelphij#include <signal.h> 52284237Sdelphij# ifndef HAVE_SIG_T 53284237Sdelphijtypedef void (*sig_t)(int); 54284237Sdelphij# endif /* HAVE_SIG_T */ 55284237Sdelphij#endif 56275698Sdelphij#if !defined(__MINGW32__) && !defined(WIN32) 57169942Sobrien#include <sys/ioctl.h> 58226048Sobrien#endif 5968349Sobrien#ifdef HAVE_SYS_WAIT_H 6068349Sobrien#include <sys/wait.h> 6168349Sobrien#endif 62169962Sobrien#if defined(HAVE_SYS_TIME_H) 63169962Sobrien#include <sys/time.h> 64169962Sobrien#endif 65328874Seadler#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) 66175296Sobrien#define BUILTIN_DECOMPRESS 67103373Sobrien#include <zlib.h> 68103373Sobrien#endif 69298192Sdelphij#ifdef DEBUG 70298192Sdelphijint tty = -1; 71298192Sdelphij#define DPRINTF(...) do { \ 72298192Sdelphij if (tty == -1) \ 73298192Sdelphij tty = open("/dev/tty", O_RDWR); \ 74298192Sdelphij if (tty == -1) \ 75298192Sdelphij abort(); \ 76298192Sdelphij dprintf(tty, __VA_ARGS__); \ 77298192Sdelphij} while (/*CONSTCOND*/0) 78298192Sdelphij#else 79298192Sdelphij#define DPRINTF(...) 80298192Sdelphij#endif 81103373Sobrien 82298192Sdelphij#ifdef ZLIBSUPPORT 83298192Sdelphij/* 84298192Sdelphij * The following python code is not really used because ZLIBSUPPORT is only 85298192Sdelphij * defined if we have a built-in zlib, and the built-in zlib handles that. 86328874Seadler * That is not true for android where we have zlib.h and not -lz. 87298192Sdelphij */ 88298192Sdelphijstatic const char zlibcode[] = 89298192Sdelphij "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; 90298192Sdelphij 91298192Sdelphijstatic const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; 92298192Sdelphij 93298192Sdelphijstatic int 94298192Sdelphijzlibcmp(const unsigned char *buf) 95298192Sdelphij{ 96298192Sdelphij unsigned short x = 1; 97328874Seadler unsigned char *s = CAST(unsigned char *, CAST(void *, &x)); 98298192Sdelphij 99298192Sdelphij if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) 100298192Sdelphij return 0; 101298192Sdelphij if (s[0] != 1) /* endianness test */ 102298192Sdelphij x = buf[0] | (buf[1] << 8); 103298192Sdelphij else 104298192Sdelphij x = buf[1] | (buf[0] << 8); 105298192Sdelphij if (x % 31) 106298192Sdelphij return 0; 107298192Sdelphij return 1; 108298192Sdelphij} 109298192Sdelphij#endif 110298192Sdelphij 111298192Sdelphij#define gzip_flags "-cd" 112298192Sdelphij#define lrzip_flags "-do" 113298192Sdelphij#define lzip_flags gzip_flags 114298192Sdelphij 115298192Sdelphijstatic const char *gzip_args[] = { 116298192Sdelphij "gzip", gzip_flags, NULL 117298192Sdelphij}; 118298192Sdelphijstatic const char *uncompress_args[] = { 119298192Sdelphij "uncompress", "-c", NULL 120298192Sdelphij}; 121298192Sdelphijstatic const char *bzip2_args[] = { 122298192Sdelphij "bzip2", "-cd", NULL 123298192Sdelphij}; 124298192Sdelphijstatic const char *lzip_args[] = { 125298192Sdelphij "lzip", lzip_flags, NULL 126298192Sdelphij}; 127298192Sdelphijstatic const char *xz_args[] = { 128298192Sdelphij "xz", "-cd", NULL 129298192Sdelphij}; 130298192Sdelphijstatic const char *lrzip_args[] = { 131298192Sdelphij "lrzip", lrzip_flags, NULL 132298192Sdelphij}; 133298192Sdelphijstatic const char *lz4_args[] = { 134298192Sdelphij "lz4", "-cd", NULL 135298192Sdelphij}; 136309847Sdelphijstatic const char *zstd_args[] = { 137309847Sdelphij "zstd", "-cd", NULL 138309847Sdelphij}; 139298192Sdelphij 140186690Sobrienprivate const struct { 141298192Sdelphij const void *magic; 142133359Sobrien size_t maglen; 143298192Sdelphij const char **argv; 14468349Sobrien} compr[] = { 145298192Sdelphij { "\037\235", 2, gzip_args }, /* compressed */ 14675937Sobrien /* Uncompress can get stuck; so use gzip first if we have it 14775937Sobrien * Idea from Damien Clark, thanks! */ 148298192Sdelphij { "\037\235", 2, uncompress_args }, /* compressed */ 149298192Sdelphij { "\037\213", 2, gzip_args }, /* gzipped */ 150298192Sdelphij { "\037\236", 2, gzip_args }, /* frozen */ 151298192Sdelphij { "\037\240", 2, gzip_args }, /* SCO LZH */ 15268349Sobrien /* the standard pack utilities do not accept standard input */ 153298192Sdelphij { "\037\036", 2, gzip_args }, /* packed */ 154298192Sdelphij { "PK\3\4", 4, gzip_args }, /* pkzipped, */ 155298192Sdelphij /* ...only first file examined */ 156298192Sdelphij { "BZh", 3, bzip2_args }, /* bzip2-ed */ 157298192Sdelphij { "LZIP", 4, lzip_args }, /* lzip-ed */ 158298192Sdelphij { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ 159298192Sdelphij { "LRZI", 4, lrzip_args }, /* LRZIP */ 160298192Sdelphij { "\004\"M\030",4, lz4_args }, /* LZ4 */ 161309847Sdelphij { "\x28\xB5\x2F\xFD", 4, zstd_args }, /* zstd */ 162298192Sdelphij#ifdef ZLIBSUPPORT 163309847Sdelphij { RCAST(const void *, zlibcmp), 0, zlib_args }, /* zlib */ 164298192Sdelphij#endif 16568349Sobrien}; 16668349Sobrien 167298192Sdelphij#define OKDATA 0 168298192Sdelphij#define NODATA 1 169298192Sdelphij#define ERRDATA 2 17068349Sobrien 171133359Sobrienprivate ssize_t swrite(int, const void *, size_t); 172226048Sobrien#if HAVE_FORK 173226048Sobrienprivate size_t ncompr = sizeof(compr) / sizeof(compr[0]); 174298192Sdelphijprivate int uncompressbuf(int, size_t, size_t, const unsigned char *, 175298192Sdelphij unsigned char **, size_t *); 176175296Sobrien#ifdef BUILTIN_DECOMPRESS 177298192Sdelphijprivate int uncompresszlib(const unsigned char *, unsigned char **, size_t, 178298192Sdelphij size_t *, int); 179298192Sdelphijprivate int uncompressgzipped(const unsigned char *, unsigned char **, size_t, 180298192Sdelphij size_t *); 181103373Sobrien#endif 182298192Sdelphijstatic int makeerror(unsigned char **, size_t *, const char *, ...) 183298192Sdelphij __attribute__((__format__(__printf__, 3, 4))); 184298192Sdelphijprivate const char *methodname(size_t); 18568349Sobrien 186133359Sobrienprotected int 187169962Sobrienfile_zmagic(struct magic_set *ms, int fd, const char *name, 188169962Sobrien const unsigned char *buf, size_t nbytes) 18968349Sobrien{ 190133359Sobrien unsigned char *newbuf = NULL; 191133359Sobrien size_t i, nsz; 192298192Sdelphij char *rbuf; 193298192Sdelphij file_pushbuf_t *pb; 194299736Sdelphij int urv, prv, rv = 0; 195175296Sobrien int mime = ms->flags & MAGIC_MIME; 196284237Sdelphij#ifdef HAVE_SIGNAL_H 197276577Sdelphij sig_t osigpipe; 198284237Sdelphij#endif 19968349Sobrien 200133359Sobrien if ((ms->flags & MAGIC_COMPRESS) == 0) 201133359Sobrien return 0; 202133359Sobrien 203284237Sdelphij#ifdef HAVE_SIGNAL_H 204276577Sdelphij osigpipe = signal(SIGPIPE, SIG_IGN); 205284237Sdelphij#endif 20668349Sobrien for (i = 0; i < ncompr; i++) { 207298192Sdelphij int zm; 20868349Sobrien if (nbytes < compr[i].maglen) 20968349Sobrien continue; 210298192Sdelphij#ifdef ZLIBSUPPORT 211298192Sdelphij if (compr[i].maglen == 0) 212309847Sdelphij zm = (RCAST(int (*)(const unsigned char *), 213298192Sdelphij CCAST(void *, compr[i].magic)))(buf); 214298192Sdelphij else 215298192Sdelphij#endif 216298192Sdelphij zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; 217298192Sdelphij 218298192Sdelphij if (!zm) 219298192Sdelphij continue; 220298192Sdelphij nsz = nbytes; 221299736Sdelphij urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); 222299736Sdelphij DPRINTF("uncompressbuf = %d, %s, %zu\n", urv, (char *)newbuf, 223298192Sdelphij nsz); 224299736Sdelphij switch (urv) { 225298192Sdelphij case OKDATA: 226298192Sdelphij case ERRDATA: 227298192Sdelphij 228133359Sobrien ms->flags &= ~MAGIC_COMPRESS; 229299736Sdelphij if (urv == ERRDATA) 230299736Sdelphij prv = file_printf(ms, "%s ERROR: %s", 231298192Sdelphij methodname(i), newbuf); 232298192Sdelphij else 233299736Sdelphij prv = file_buffer(ms, -1, name, newbuf, nsz); 234299736Sdelphij if (prv == -1) 235133359Sobrien goto error; 236299736Sdelphij rv = 1; 237298192Sdelphij if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) 238298192Sdelphij goto out; 239298192Sdelphij if (mime != MAGIC_MIME && mime != 0) 240298192Sdelphij goto out; 241298192Sdelphij if ((file_printf(ms, 242298192Sdelphij mime ? " compressed-encoding=" : " (")) == -1) 243298192Sdelphij goto error; 244298192Sdelphij if ((pb = file_push_buffer(ms)) == NULL) 245298192Sdelphij goto error; 246299736Sdelphij /* 247299736Sdelphij * XXX: If file_buffer fails here, we overwrite 248299736Sdelphij * the compressed text. FIXME. 249299736Sdelphij */ 250298192Sdelphij if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 251298192Sdelphij goto error; 252298192Sdelphij if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 253298192Sdelphij if (file_printf(ms, "%s", rbuf) == -1) { 254298192Sdelphij free(rbuf); 255175296Sobrien goto error; 256298192Sdelphij } 257298192Sdelphij free(rbuf); 258175296Sobrien } 259298192Sdelphij if (!mime && file_printf(ms, ")") == -1) 260298192Sdelphij goto error; 261299736Sdelphij /*FALLTHROUGH*/ 262298192Sdelphij case NODATA: 263299736Sdelphij break; 264298192Sdelphij default: 265298192Sdelphij abort(); 266299736Sdelphij /*NOTREACHED*/ 267299736Sdelphij error: 268299736Sdelphij rv = -1; 269299736Sdelphij break; 27068349Sobrien } 27168349Sobrien } 272298192Sdelphijout: 273299736Sdelphij DPRINTF("rv = %d\n", rv); 274299736Sdelphij 275284237Sdelphij#ifdef HAVE_SIGNAL_H 276276577Sdelphij (void)signal(SIGPIPE, osigpipe); 277284237Sdelphij#endif 278234250Sobrien free(newbuf); 279133359Sobrien ms->flags |= MAGIC_COMPRESS; 280298192Sdelphij DPRINTF("Zmagic returns %d\n", rv); 281133359Sobrien return rv; 28268349Sobrien} 283226048Sobrien#endif 28475937Sobrien/* 28575937Sobrien * `safe' write for sockets and pipes. 28675937Sobrien */ 287133359Sobrienprivate ssize_t 288103373Sobrienswrite(int fd, const void *buf, size_t n) 28975937Sobrien{ 290226048Sobrien ssize_t rv; 29175937Sobrien size_t rn = n; 29268349Sobrien 29375937Sobrien do 29475937Sobrien switch (rv = write(fd, buf, n)) { 29575937Sobrien case -1: 29675937Sobrien if (errno == EINTR) 29775937Sobrien continue; 29875937Sobrien return -1; 29975937Sobrien default: 30075937Sobrien n -= rv; 301226048Sobrien buf = CAST(const char *, buf) + rv; 30275937Sobrien break; 30375937Sobrien } 30475937Sobrien while (n > 0); 30575937Sobrien return rn; 30675937Sobrien} 30775937Sobrien 30875937Sobrien 30975937Sobrien/* 31075937Sobrien * `safe' read for sockets and pipes. 31175937Sobrien */ 312169942Sobrienprotected ssize_t 313267843Sdelphijsread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 31475937Sobrien{ 315226048Sobrien ssize_t rv; 316169942Sobrien#ifdef FIONREAD 317169942Sobrien int t = 0; 318169942Sobrien#endif 31975937Sobrien size_t rn = n; 32075937Sobrien 321169942Sobrien if (fd == STDIN_FILENO) 322169942Sobrien goto nocheck; 323169942Sobrien 324169942Sobrien#ifdef FIONREAD 325267843Sdelphij if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 326169942Sobrien#ifdef FD_ZERO 327267843Sdelphij ssize_t cnt; 328169962Sobrien for (cnt = 0;; cnt++) { 329169942Sobrien fd_set check; 330169942Sobrien struct timeval tout = {0, 100 * 1000}; 331169962Sobrien int selrv; 332169942Sobrien 333169942Sobrien FD_ZERO(&check); 334169942Sobrien FD_SET(fd, &check); 335169942Sobrien 336169942Sobrien /* 337169942Sobrien * Avoid soft deadlock: do not read if there 338169942Sobrien * is nothing to read from sockets and pipes. 339169942Sobrien */ 340169962Sobrien selrv = select(fd + 1, &check, NULL, NULL, &tout); 341169962Sobrien if (selrv == -1) { 342169942Sobrien if (errno == EINTR || errno == EAGAIN) 343169942Sobrien continue; 344169962Sobrien } else if (selrv == 0 && cnt >= 5) { 345169942Sobrien return 0; 346169962Sobrien } else 347169962Sobrien break; 348169942Sobrien } 349169942Sobrien#endif 350169942Sobrien (void)ioctl(fd, FIONREAD, &t); 351169942Sobrien } 352169942Sobrien 353169942Sobrien if (t > 0 && (size_t)t < n) { 354169942Sobrien n = t; 355169942Sobrien rn = n; 356169942Sobrien } 357169942Sobrien#endif 358169942Sobrien 359169942Sobriennocheck: 36075937Sobrien do 361169942Sobrien switch ((rv = read(fd, buf, n))) { 36275937Sobrien case -1: 36375937Sobrien if (errno == EINTR) 36475937Sobrien continue; 36575937Sobrien return -1; 366103373Sobrien case 0: 367103373Sobrien return rn - n; 36875937Sobrien default: 36975937Sobrien n -= rv; 370309847Sdelphij buf = CAST(char *, CCAST(void *, buf)) + rv; 37175937Sobrien break; 37275937Sobrien } 37375937Sobrien while (n > 0); 37475937Sobrien return rn; 37575937Sobrien} 37675937Sobrien 377133359Sobrienprotected int 378133359Sobrienfile_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 379133359Sobrien size_t nbytes) 380103373Sobrien{ 381103373Sobrien char buf[4096]; 382226048Sobrien ssize_t r; 383226048Sobrien int tfd; 384103373Sobrien 385191736Sobrien (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 386103373Sobrien#ifndef HAVE_MKSTEMP 387103373Sobrien { 388103373Sobrien char *ptr = mktemp(buf); 389103373Sobrien tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 390103373Sobrien r = errno; 391103373Sobrien (void)unlink(ptr); 392103373Sobrien errno = r; 393103373Sobrien } 394103373Sobrien#else 395267843Sdelphij { 396267843Sdelphij int te; 397267843Sdelphij tfd = mkstemp(buf); 398267843Sdelphij te = errno; 399267843Sdelphij (void)unlink(buf); 400267843Sdelphij errno = te; 401267843Sdelphij } 402103373Sobrien#endif 403103373Sobrien if (tfd == -1) { 404133359Sobrien file_error(ms, errno, 405133359Sobrien "cannot create temporary file for pipe copy"); 406133359Sobrien return -1; 407103373Sobrien } 408103373Sobrien 409133359Sobrien if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 410103373Sobrien r = 1; 411103373Sobrien else { 412169962Sobrien while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 413133359Sobrien if (swrite(tfd, buf, (size_t)r) != r) 414103373Sobrien break; 415103373Sobrien } 416103373Sobrien 417103373Sobrien switch (r) { 418103373Sobrien case -1: 419133359Sobrien file_error(ms, errno, "error copying from pipe to temp file"); 420133359Sobrien return -1; 421103373Sobrien case 0: 422103373Sobrien break; 423103373Sobrien default: 424133359Sobrien file_error(ms, errno, "error while writing to temp file"); 425133359Sobrien return -1; 426103373Sobrien } 427103373Sobrien 428103373Sobrien /* 429103373Sobrien * We duplicate the file descriptor, because fclose on a 430103373Sobrien * tmpfile will delete the file, but any open descriptors 431103373Sobrien * can still access the phantom inode. 432103373Sobrien */ 433103373Sobrien if ((fd = dup2(tfd, fd)) == -1) { 434133359Sobrien file_error(ms, errno, "could not dup descriptor for temp file"); 435133359Sobrien return -1; 436103373Sobrien } 437103373Sobrien (void)close(tfd); 438103373Sobrien if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 439133359Sobrien file_badseek(ms); 440133359Sobrien return -1; 441103373Sobrien } 442103373Sobrien return fd; 443103373Sobrien} 444226048Sobrien#if HAVE_FORK 445175296Sobrien#ifdef BUILTIN_DECOMPRESS 446103373Sobrien 447103373Sobrien#define FHCRC (1 << 1) 448103373Sobrien#define FEXTRA (1 << 2) 449103373Sobrien#define FNAME (1 << 3) 450103373Sobrien#define FCOMMENT (1 << 4) 451103373Sobrien 452298192Sdelphij 453298192Sdelphijprivate int 454298192Sdelphijuncompressgzipped(const unsigned char *old, unsigned char **newch, 455298192Sdelphij size_t bytes_max, size_t *n) 45668349Sobrien{ 457103373Sobrien unsigned char flg = old[3]; 458133359Sobrien size_t data_start = 10; 459103373Sobrien 460133359Sobrien if (flg & FEXTRA) { 461298192Sdelphij if (data_start + 1 >= *n) 462298192Sdelphij goto err; 463103373Sobrien data_start += 2 + old[data_start] + old[data_start + 1] * 256; 464133359Sobrien } 465103373Sobrien if (flg & FNAME) { 466298192Sdelphij while(data_start < *n && old[data_start]) 467103373Sobrien data_start++; 468103373Sobrien data_start++; 469103373Sobrien } 470298192Sdelphij if (flg & FCOMMENT) { 471298192Sdelphij while(data_start < *n && old[data_start]) 472103373Sobrien data_start++; 473103373Sobrien data_start++; 474103373Sobrien } 475298192Sdelphij if (flg & FHCRC) 476103373Sobrien data_start += 2; 477103373Sobrien 478298192Sdelphij if (data_start >= *n) 479298192Sdelphij goto err; 480298192Sdelphij 481298192Sdelphij *n -= data_start; 482298192Sdelphij old += data_start; 483298192Sdelphij return uncompresszlib(old, newch, bytes_max, n, 0); 484298192Sdelphijerr: 485298192Sdelphij return makeerror(newch, n, "File too short"); 486298192Sdelphij} 487298192Sdelphij 488298192Sdelphijprivate int 489298192Sdelphijuncompresszlib(const unsigned char *old, unsigned char **newch, 490298192Sdelphij size_t bytes_max, size_t *n, int zlib) 491298192Sdelphij{ 492298192Sdelphij int rc; 493298192Sdelphij z_stream z; 494298192Sdelphij 495298192Sdelphij if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 496298192Sdelphij return makeerror(newch, n, "No buffer, %s", strerror(errno)); 497298192Sdelphij 498298192Sdelphij z.next_in = CCAST(Bytef *, old); 499298192Sdelphij z.avail_in = CAST(uint32_t, *n); 500103373Sobrien z.next_out = *newch; 501328874Seadler z.avail_out = CAST(unsigned int, bytes_max); 502103373Sobrien z.zalloc = Z_NULL; 503103373Sobrien z.zfree = Z_NULL; 504103373Sobrien z.opaque = Z_NULL; 505103373Sobrien 506226048Sobrien /* LINTED bug in header macro */ 507298192Sdelphij rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); 508298192Sdelphij if (rc != Z_OK) 509298192Sdelphij goto err; 510103373Sobrien 511103373Sobrien rc = inflate(&z, Z_SYNC_FLUSH); 512298192Sdelphij if (rc != Z_OK && rc != Z_STREAM_END) 513298192Sdelphij goto err; 514103373Sobrien 515298192Sdelphij *n = (size_t)z.total_out; 516298192Sdelphij rc = inflateEnd(&z); 517298192Sdelphij if (rc != Z_OK) 518298192Sdelphij goto err; 519103373Sobrien 520103373Sobrien /* let's keep the nul-terminate tradition */ 521298192Sdelphij (*newch)[*n] = '\0'; 522103373Sobrien 523298192Sdelphij return OKDATA; 524298192Sdelphijerr: 525309847Sdelphij strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max); 526298192Sdelphij *n = strlen((char *)*newch); 527298192Sdelphij return ERRDATA; 528298192Sdelphij} 529298192Sdelphij#endif 530298192Sdelphij 531298192Sdelphijstatic int 532298192Sdelphijmakeerror(unsigned char **buf, size_t *len, const char *fmt, ...) 533298192Sdelphij{ 534298192Sdelphij char *msg; 535298192Sdelphij va_list ap; 536298192Sdelphij int rv; 537298192Sdelphij 538298192Sdelphij va_start(ap, fmt); 539298192Sdelphij rv = vasprintf(&msg, fmt, ap); 540298192Sdelphij va_end(ap); 541298192Sdelphij if (rv < 0) { 542298192Sdelphij *buf = NULL; 543298192Sdelphij *len = 0; 544298192Sdelphij return NODATA; 545298192Sdelphij } 546298192Sdelphij *buf = (unsigned char *)msg; 547298192Sdelphij *len = strlen(msg); 548298192Sdelphij return ERRDATA; 549298192Sdelphij} 550298192Sdelphij 551298192Sdelphijstatic void 552298192Sdelphijclosefd(int *fd, size_t i) 553298192Sdelphij{ 554298192Sdelphij if (fd[i] == -1) 555298192Sdelphij return; 556298192Sdelphij (void) close(fd[i]); 557298192Sdelphij fd[i] = -1; 558298192Sdelphij} 559298192Sdelphij 560298192Sdelphijstatic void 561298192Sdelphijclosep(int *fd) 562298192Sdelphij{ 563298192Sdelphij size_t i; 564298192Sdelphij for (i = 0; i < 2; i++) 565298192Sdelphij closefd(fd, i); 566298192Sdelphij} 567298192Sdelphij 568298192Sdelphijstatic void 569298192Sdelphijcopydesc(int i, int *fd) 570298192Sdelphij{ 571298192Sdelphij int j = fd[i == STDIN_FILENO ? 0 : 1]; 572298192Sdelphij if (j == i) 573298192Sdelphij return; 574298192Sdelphij if (dup2(j, i) == -1) { 575298192Sdelphij DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); 576298192Sdelphij exit(1); 577298192Sdelphij } 578298192Sdelphij closep(fd); 579298192Sdelphij} 580298192Sdelphij 581298192Sdelphijstatic void 582298192Sdelphijwritechild(int fdp[3][2], const void *old, size_t n) 583298192Sdelphij{ 584298192Sdelphij int status; 585298192Sdelphij 586298192Sdelphij closefd(fdp[STDIN_FILENO], 0); 587298192Sdelphij /* 588298192Sdelphij * fork again, to avoid blocking because both 589298192Sdelphij * pipes filled 590298192Sdelphij */ 591298192Sdelphij switch (fork()) { 592298192Sdelphij case 0: /* child */ 593298192Sdelphij closefd(fdp[STDOUT_FILENO], 0); 594298192Sdelphij if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { 595298192Sdelphij DPRINTF("Write failed (%s)\n", strerror(errno)); 596298192Sdelphij exit(1); 597298192Sdelphij } 598298192Sdelphij exit(0); 599298192Sdelphij /*NOTREACHED*/ 600298192Sdelphij 601298192Sdelphij case -1: 602298192Sdelphij DPRINTF("Fork failed (%s)\n", strerror(errno)); 603298192Sdelphij exit(1); 604298192Sdelphij /*NOTREACHED*/ 605298192Sdelphij 606298192Sdelphij default: /* parent */ 607298192Sdelphij if (wait(&status) == -1) { 608298192Sdelphij DPRINTF("Wait failed (%s)\n", strerror(errno)); 609298192Sdelphij exit(1); 610298192Sdelphij } 611298192Sdelphij DPRINTF("Grandchild wait return %#x\n", status); 612298192Sdelphij } 613298192Sdelphij closefd(fdp[STDIN_FILENO], 1); 614298192Sdelphij} 615298192Sdelphij 616298192Sdelphijstatic ssize_t 617298192Sdelphijfilter_error(unsigned char *ubuf, ssize_t n) 618298192Sdelphij{ 619298192Sdelphij char *p; 620298192Sdelphij char *buf; 621298192Sdelphij 622298192Sdelphij ubuf[n] = '\0'; 623298192Sdelphij buf = (char *)ubuf; 624298192Sdelphij while (isspace((unsigned char)*buf)) 625298192Sdelphij buf++; 626298192Sdelphij DPRINTF("Filter error[[[%s]]]\n", buf); 627298192Sdelphij if ((p = strchr((char *)buf, '\n')) != NULL) 628298192Sdelphij *p = '\0'; 629298192Sdelphij if ((p = strchr((char *)buf, ';')) != NULL) 630298192Sdelphij *p = '\0'; 631298192Sdelphij if ((p = strrchr((char *)buf, ':')) != NULL) { 632298192Sdelphij ++p; 633298192Sdelphij while (isspace((unsigned char)*p)) 634298192Sdelphij p++; 635298192Sdelphij n = strlen(p); 636328874Seadler memmove(ubuf, p, CAST(size_t, n + 1)); 637298192Sdelphij } 638298192Sdelphij DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); 639298192Sdelphij if (islower(*ubuf)) 640298192Sdelphij *ubuf = toupper(*ubuf); 641103373Sobrien return n; 642103373Sobrien} 643298192Sdelphij 644298192Sdelphijprivate const char * 645298192Sdelphijmethodname(size_t method) 646298192Sdelphij{ 647298192Sdelphij#ifdef BUILTIN_DECOMPRESS 648298192Sdelphij /* FIXME: This doesn't cope with bzip2 */ 649298192Sdelphij if (method == 2 || compr[method].maglen == 0) 650298192Sdelphij return "zlib"; 651103373Sobrien#endif 652298192Sdelphij return compr[method].argv[0]; 653298192Sdelphij} 654103373Sobrien 655298192Sdelphijprivate int 656298192Sdelphijuncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, 657298192Sdelphij unsigned char **newch, size_t* n) 658103373Sobrien{ 659298192Sdelphij int fdp[3][2]; 660298192Sdelphij int status, rv; 661298192Sdelphij size_t i; 662226048Sobrien ssize_t r; 66368349Sobrien 664175296Sobrien#ifdef BUILTIN_DECOMPRESS 665186690Sobrien /* FIXME: This doesn't cope with bzip2 */ 666103373Sobrien if (method == 2) 667298192Sdelphij return uncompressgzipped(old, newch, bytes_max, n); 668298192Sdelphij if (compr[method].maglen == 0) 669298192Sdelphij return uncompresszlib(old, newch, bytes_max, n, 1); 670103373Sobrien#endif 671159764Sobrien (void)fflush(stdout); 672159764Sobrien (void)fflush(stderr); 673103373Sobrien 674298192Sdelphij for (i = 0; i < __arraycount(fdp); i++) 675298192Sdelphij fdp[i][0] = fdp[i][1] = -1; 676298192Sdelphij 677298192Sdelphij if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || 678298192Sdelphij pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { 679298192Sdelphij closep(fdp[STDIN_FILENO]); 680298192Sdelphij closep(fdp[STDOUT_FILENO]); 681298192Sdelphij return makeerror(newch, n, "Cannot create pipe, %s", 682298192Sdelphij strerror(errno)); 68368349Sobrien } 684284237Sdelphij switch (fork()) { 68568349Sobrien case 0: /* child */ 686159764Sobrien if (fd != -1) { 687298192Sdelphij fdp[STDIN_FILENO][0] = fd; 688298192Sdelphij (void) lseek(fd, (off_t)0, SEEK_SET); 689159764Sobrien } 690298192Sdelphij 691298192Sdelphij for (i = 0; i < __arraycount(fdp); i++) 692328874Seadler copydesc(CAST(int, i), fdp[i]); 69368349Sobrien 694169962Sobrien (void)execvp(compr[method].argv[0], 695169962Sobrien (char *const *)(intptr_t)compr[method].argv); 696298192Sdelphij dprintf(STDERR_FILENO, "exec `%s' failed, %s", 697159764Sobrien compr[method].argv[0], strerror(errno)); 69868349Sobrien exit(1); 69968349Sobrien /*NOTREACHED*/ 70068349Sobrien case -1: 701298192Sdelphij return makeerror(newch, n, "Cannot fork, %s", 702298192Sdelphij strerror(errno)); 70368349Sobrien 70468349Sobrien default: /* parent */ 705298192Sdelphij for (i = 1; i < __arraycount(fdp); i++) 706298192Sdelphij closefd(fdp[i], 1); 707159764Sobrien 708298192Sdelphij /* Write the buffer data to the child, if we don't have fd */ 709298192Sdelphij if (fd == -1) 710298192Sdelphij writechild(fdp, old, *n); 711133359Sobrien 712298192Sdelphij *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 713298192Sdelphij if (*newch == NULL) { 714298192Sdelphij rv = makeerror(newch, n, "No buffer, %s", 715159764Sobrien strerror(errno)); 71675937Sobrien goto err; 71775937Sobrien } 718298192Sdelphij rv = OKDATA; 719298192Sdelphij if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) 720298192Sdelphij break; 721298192Sdelphij DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], 722298192Sdelphij r != -1 ? strerror(errno) : "no data"); 723298192Sdelphij 724298192Sdelphij rv = ERRDATA; 725298192Sdelphij if (r == 0 && 726298192Sdelphij (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) 727298192Sdelphij { 728298192Sdelphij r = filter_error(*newch, r); 729298192Sdelphij break; 73068349Sobrien } 731298192Sdelphij free(*newch); 732298192Sdelphij if (r == 0) 733298192Sdelphij rv = makeerror(newch, n, "Read failed, %s", 734275698Sdelphij strerror(errno)); 735298192Sdelphij else 736298192Sdelphij rv = makeerror(newch, n, "No data"); 737298192Sdelphij goto err; 738298192Sdelphij } 739275698Sdelphij 740298192Sdelphij *n = r; 741298192Sdelphij /* NUL terminate, as every buffer is handled here. */ 742298192Sdelphij (*newch)[*n] = '\0'; 743298192Sdelphijerr: 744298192Sdelphij closefd(fdp[STDIN_FILENO], 1); 745298192Sdelphij closefd(fdp[STDOUT_FILENO], 0); 746298192Sdelphij closefd(fdp[STDERR_FILENO], 0); 747298192Sdelphij if (wait(&status) == -1) { 748298192Sdelphij free(*newch); 749298192Sdelphij rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); 750298192Sdelphij DPRINTF("Child wait return %#x\n", status); 751298192Sdelphij } else if (!WIFEXITED(status)) { 752328874Seadler DPRINTF("Child not exited (%#x)\n", status); 753298192Sdelphij } else if (WEXITSTATUS(status) != 0) { 754328874Seadler DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status)); 75568349Sobrien } 756298192Sdelphij 757298192Sdelphij closefd(fdp[STDIN_FILENO], 0); 758298192Sdelphij DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); 759298192Sdelphij 760298192Sdelphij return rv; 76168349Sobrien} 762226048Sobrien#endif 763