compress.c revision 337827
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 38337827SeadlerFILE_RCSID("@(#)$File: compress.c,v 1.107 2018/04/28 18:48:22 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 186337827Seadlerprivate int 187337827Seadlerformat_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf) 188337827Seadler{ 189337827Seadler unsigned char *p; 190337827Seadler int mime = ms->flags & MAGIC_MIME; 191337827Seadler 192337827Seadler if (!mime) 193337827Seadler return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf); 194337827Seadler 195337827Seadler for (p = buf; *p; p++) 196337827Seadler if (!isalnum(*p)) 197337827Seadler *p = '-'; 198337827Seadler 199337827Seadler return file_printf(ms, "application/x-decompression-error-%s-%s", 200337827Seadler methodname(i), buf); 201337827Seadler} 202337827Seadler 203133359Sobrienprotected int 204337827Seadlerfile_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) 20568349Sobrien{ 206133359Sobrien unsigned char *newbuf = NULL; 207133359Sobrien size_t i, nsz; 208298192Sdelphij char *rbuf; 209298192Sdelphij file_pushbuf_t *pb; 210299736Sdelphij int urv, prv, rv = 0; 211175296Sobrien int mime = ms->flags & MAGIC_MIME; 212337827Seadler int fd = b->fd; 213337827Seadler const unsigned char *buf = b->fbuf; 214337827Seadler size_t nbytes = b->flen; 215284237Sdelphij#ifdef HAVE_SIGNAL_H 216276577Sdelphij sig_t osigpipe; 217284237Sdelphij#endif 21868349Sobrien 219133359Sobrien if ((ms->flags & MAGIC_COMPRESS) == 0) 220133359Sobrien return 0; 221133359Sobrien 222284237Sdelphij#ifdef HAVE_SIGNAL_H 223276577Sdelphij osigpipe = signal(SIGPIPE, SIG_IGN); 224284237Sdelphij#endif 22568349Sobrien for (i = 0; i < ncompr; i++) { 226298192Sdelphij int zm; 22768349Sobrien if (nbytes < compr[i].maglen) 22868349Sobrien continue; 229298192Sdelphij#ifdef ZLIBSUPPORT 230298192Sdelphij if (compr[i].maglen == 0) 231309847Sdelphij zm = (RCAST(int (*)(const unsigned char *), 232298192Sdelphij CCAST(void *, compr[i].magic)))(buf); 233298192Sdelphij else 234298192Sdelphij#endif 235298192Sdelphij zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; 236298192Sdelphij 237298192Sdelphij if (!zm) 238298192Sdelphij continue; 239298192Sdelphij nsz = nbytes; 240299736Sdelphij urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); 241299736Sdelphij DPRINTF("uncompressbuf = %d, %s, %zu\n", urv, (char *)newbuf, 242298192Sdelphij nsz); 243299736Sdelphij switch (urv) { 244298192Sdelphij case OKDATA: 245298192Sdelphij case ERRDATA: 246133359Sobrien ms->flags &= ~MAGIC_COMPRESS; 247299736Sdelphij if (urv == ERRDATA) 248337827Seadler prv = format_decompression_error(ms, i, newbuf); 249298192Sdelphij else 250299736Sdelphij prv = file_buffer(ms, -1, name, newbuf, nsz); 251299736Sdelphij if (prv == -1) 252133359Sobrien goto error; 253299736Sdelphij rv = 1; 254298192Sdelphij if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) 255298192Sdelphij goto out; 256298192Sdelphij if (mime != MAGIC_MIME && mime != 0) 257298192Sdelphij goto out; 258298192Sdelphij if ((file_printf(ms, 259298192Sdelphij mime ? " compressed-encoding=" : " (")) == -1) 260298192Sdelphij goto error; 261298192Sdelphij if ((pb = file_push_buffer(ms)) == NULL) 262298192Sdelphij goto error; 263299736Sdelphij /* 264299736Sdelphij * XXX: If file_buffer fails here, we overwrite 265299736Sdelphij * the compressed text. FIXME. 266299736Sdelphij */ 267298192Sdelphij if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) 268298192Sdelphij goto error; 269298192Sdelphij if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 270298192Sdelphij if (file_printf(ms, "%s", rbuf) == -1) { 271298192Sdelphij free(rbuf); 272175296Sobrien goto error; 273298192Sdelphij } 274298192Sdelphij free(rbuf); 275175296Sobrien } 276298192Sdelphij if (!mime && file_printf(ms, ")") == -1) 277298192Sdelphij goto error; 278299736Sdelphij /*FALLTHROUGH*/ 279298192Sdelphij case NODATA: 280299736Sdelphij break; 281298192Sdelphij default: 282298192Sdelphij abort(); 283299736Sdelphij /*NOTREACHED*/ 284299736Sdelphij error: 285299736Sdelphij rv = -1; 286299736Sdelphij break; 28768349Sobrien } 28868349Sobrien } 289298192Sdelphijout: 290299736Sdelphij DPRINTF("rv = %d\n", rv); 291299736Sdelphij 292284237Sdelphij#ifdef HAVE_SIGNAL_H 293276577Sdelphij (void)signal(SIGPIPE, osigpipe); 294284237Sdelphij#endif 295234250Sobrien free(newbuf); 296133359Sobrien ms->flags |= MAGIC_COMPRESS; 297298192Sdelphij DPRINTF("Zmagic returns %d\n", rv); 298133359Sobrien return rv; 29968349Sobrien} 300226048Sobrien#endif 30175937Sobrien/* 30275937Sobrien * `safe' write for sockets and pipes. 30375937Sobrien */ 304133359Sobrienprivate ssize_t 305103373Sobrienswrite(int fd, const void *buf, size_t n) 30675937Sobrien{ 307226048Sobrien ssize_t rv; 30875937Sobrien size_t rn = n; 30968349Sobrien 31075937Sobrien do 31175937Sobrien switch (rv = write(fd, buf, n)) { 31275937Sobrien case -1: 31375937Sobrien if (errno == EINTR) 31475937Sobrien continue; 31575937Sobrien return -1; 31675937Sobrien default: 31775937Sobrien n -= rv; 318226048Sobrien buf = CAST(const char *, buf) + rv; 31975937Sobrien break; 32075937Sobrien } 32175937Sobrien while (n > 0); 32275937Sobrien return rn; 32375937Sobrien} 32475937Sobrien 32575937Sobrien 32675937Sobrien/* 32775937Sobrien * `safe' read for sockets and pipes. 32875937Sobrien */ 329169942Sobrienprotected ssize_t 330267843Sdelphijsread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) 33175937Sobrien{ 332226048Sobrien ssize_t rv; 333169942Sobrien#ifdef FIONREAD 334169942Sobrien int t = 0; 335169942Sobrien#endif 33675937Sobrien size_t rn = n; 33775937Sobrien 338169942Sobrien if (fd == STDIN_FILENO) 339169942Sobrien goto nocheck; 340169942Sobrien 341169942Sobrien#ifdef FIONREAD 342267843Sdelphij if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { 343169942Sobrien#ifdef FD_ZERO 344267843Sdelphij ssize_t cnt; 345169962Sobrien for (cnt = 0;; cnt++) { 346169942Sobrien fd_set check; 347169942Sobrien struct timeval tout = {0, 100 * 1000}; 348169962Sobrien int selrv; 349169942Sobrien 350169942Sobrien FD_ZERO(&check); 351169942Sobrien FD_SET(fd, &check); 352169942Sobrien 353169942Sobrien /* 354169942Sobrien * Avoid soft deadlock: do not read if there 355169942Sobrien * is nothing to read from sockets and pipes. 356169942Sobrien */ 357169962Sobrien selrv = select(fd + 1, &check, NULL, NULL, &tout); 358169962Sobrien if (selrv == -1) { 359169942Sobrien if (errno == EINTR || errno == EAGAIN) 360169942Sobrien continue; 361169962Sobrien } else if (selrv == 0 && cnt >= 5) { 362169942Sobrien return 0; 363169962Sobrien } else 364169962Sobrien break; 365169942Sobrien } 366169942Sobrien#endif 367169942Sobrien (void)ioctl(fd, FIONREAD, &t); 368169942Sobrien } 369169942Sobrien 370169942Sobrien if (t > 0 && (size_t)t < n) { 371169942Sobrien n = t; 372169942Sobrien rn = n; 373169942Sobrien } 374169942Sobrien#endif 375169942Sobrien 376169942Sobriennocheck: 37775937Sobrien do 378169942Sobrien switch ((rv = read(fd, buf, n))) { 37975937Sobrien case -1: 38075937Sobrien if (errno == EINTR) 38175937Sobrien continue; 38275937Sobrien return -1; 383103373Sobrien case 0: 384103373Sobrien return rn - n; 38575937Sobrien default: 38675937Sobrien n -= rv; 387309847Sdelphij buf = CAST(char *, CCAST(void *, buf)) + rv; 38875937Sobrien break; 38975937Sobrien } 39075937Sobrien while (n > 0); 39175937Sobrien return rn; 39275937Sobrien} 39375937Sobrien 394133359Sobrienprotected int 395133359Sobrienfile_pipe2file(struct magic_set *ms, int fd, const void *startbuf, 396133359Sobrien size_t nbytes) 397103373Sobrien{ 398103373Sobrien char buf[4096]; 399226048Sobrien ssize_t r; 400226048Sobrien int tfd; 401103373Sobrien 402191736Sobrien (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); 403103373Sobrien#ifndef HAVE_MKSTEMP 404103373Sobrien { 405103373Sobrien char *ptr = mktemp(buf); 406103373Sobrien tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); 407103373Sobrien r = errno; 408103373Sobrien (void)unlink(ptr); 409103373Sobrien errno = r; 410103373Sobrien } 411103373Sobrien#else 412267843Sdelphij { 413267843Sdelphij int te; 414267843Sdelphij tfd = mkstemp(buf); 415267843Sdelphij te = errno; 416267843Sdelphij (void)unlink(buf); 417267843Sdelphij errno = te; 418267843Sdelphij } 419103373Sobrien#endif 420103373Sobrien if (tfd == -1) { 421133359Sobrien file_error(ms, errno, 422133359Sobrien "cannot create temporary file for pipe copy"); 423133359Sobrien return -1; 424103373Sobrien } 425103373Sobrien 426133359Sobrien if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes) 427103373Sobrien r = 1; 428103373Sobrien else { 429169962Sobrien while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) 430133359Sobrien if (swrite(tfd, buf, (size_t)r) != r) 431103373Sobrien break; 432103373Sobrien } 433103373Sobrien 434103373Sobrien switch (r) { 435103373Sobrien case -1: 436133359Sobrien file_error(ms, errno, "error copying from pipe to temp file"); 437133359Sobrien return -1; 438103373Sobrien case 0: 439103373Sobrien break; 440103373Sobrien default: 441133359Sobrien file_error(ms, errno, "error while writing to temp file"); 442133359Sobrien return -1; 443103373Sobrien } 444103373Sobrien 445103373Sobrien /* 446103373Sobrien * We duplicate the file descriptor, because fclose on a 447103373Sobrien * tmpfile will delete the file, but any open descriptors 448103373Sobrien * can still access the phantom inode. 449103373Sobrien */ 450103373Sobrien if ((fd = dup2(tfd, fd)) == -1) { 451133359Sobrien file_error(ms, errno, "could not dup descriptor for temp file"); 452133359Sobrien return -1; 453103373Sobrien } 454103373Sobrien (void)close(tfd); 455103373Sobrien if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 456133359Sobrien file_badseek(ms); 457133359Sobrien return -1; 458103373Sobrien } 459103373Sobrien return fd; 460103373Sobrien} 461226048Sobrien#if HAVE_FORK 462175296Sobrien#ifdef BUILTIN_DECOMPRESS 463103373Sobrien 464103373Sobrien#define FHCRC (1 << 1) 465103373Sobrien#define FEXTRA (1 << 2) 466103373Sobrien#define FNAME (1 << 3) 467103373Sobrien#define FCOMMENT (1 << 4) 468103373Sobrien 469298192Sdelphij 470298192Sdelphijprivate int 471298192Sdelphijuncompressgzipped(const unsigned char *old, unsigned char **newch, 472298192Sdelphij size_t bytes_max, size_t *n) 47368349Sobrien{ 474103373Sobrien unsigned char flg = old[3]; 475133359Sobrien size_t data_start = 10; 476103373Sobrien 477133359Sobrien if (flg & FEXTRA) { 478298192Sdelphij if (data_start + 1 >= *n) 479298192Sdelphij goto err; 480103373Sobrien data_start += 2 + old[data_start] + old[data_start + 1] * 256; 481133359Sobrien } 482103373Sobrien if (flg & FNAME) { 483298192Sdelphij while(data_start < *n && old[data_start]) 484103373Sobrien data_start++; 485103373Sobrien data_start++; 486103373Sobrien } 487298192Sdelphij if (flg & FCOMMENT) { 488298192Sdelphij while(data_start < *n && old[data_start]) 489103373Sobrien data_start++; 490103373Sobrien data_start++; 491103373Sobrien } 492298192Sdelphij if (flg & FHCRC) 493103373Sobrien data_start += 2; 494103373Sobrien 495298192Sdelphij if (data_start >= *n) 496298192Sdelphij goto err; 497298192Sdelphij 498298192Sdelphij *n -= data_start; 499298192Sdelphij old += data_start; 500298192Sdelphij return uncompresszlib(old, newch, bytes_max, n, 0); 501298192Sdelphijerr: 502298192Sdelphij return makeerror(newch, n, "File too short"); 503298192Sdelphij} 504298192Sdelphij 505298192Sdelphijprivate int 506298192Sdelphijuncompresszlib(const unsigned char *old, unsigned char **newch, 507298192Sdelphij size_t bytes_max, size_t *n, int zlib) 508298192Sdelphij{ 509298192Sdelphij int rc; 510298192Sdelphij z_stream z; 511298192Sdelphij 512298192Sdelphij if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 513298192Sdelphij return makeerror(newch, n, "No buffer, %s", strerror(errno)); 514298192Sdelphij 515298192Sdelphij z.next_in = CCAST(Bytef *, old); 516298192Sdelphij z.avail_in = CAST(uint32_t, *n); 517103373Sobrien z.next_out = *newch; 518328874Seadler z.avail_out = CAST(unsigned int, bytes_max); 519103373Sobrien z.zalloc = Z_NULL; 520103373Sobrien z.zfree = Z_NULL; 521103373Sobrien z.opaque = Z_NULL; 522103373Sobrien 523226048Sobrien /* LINTED bug in header macro */ 524298192Sdelphij rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); 525298192Sdelphij if (rc != Z_OK) 526298192Sdelphij goto err; 527103373Sobrien 528103373Sobrien rc = inflate(&z, Z_SYNC_FLUSH); 529298192Sdelphij if (rc != Z_OK && rc != Z_STREAM_END) 530298192Sdelphij goto err; 531103373Sobrien 532298192Sdelphij *n = (size_t)z.total_out; 533298192Sdelphij rc = inflateEnd(&z); 534298192Sdelphij if (rc != Z_OK) 535298192Sdelphij goto err; 536103373Sobrien 537103373Sobrien /* let's keep the nul-terminate tradition */ 538298192Sdelphij (*newch)[*n] = '\0'; 539103373Sobrien 540298192Sdelphij return OKDATA; 541298192Sdelphijerr: 542309847Sdelphij strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max); 543298192Sdelphij *n = strlen((char *)*newch); 544298192Sdelphij return ERRDATA; 545298192Sdelphij} 546298192Sdelphij#endif 547298192Sdelphij 548298192Sdelphijstatic int 549298192Sdelphijmakeerror(unsigned char **buf, size_t *len, const char *fmt, ...) 550298192Sdelphij{ 551298192Sdelphij char *msg; 552298192Sdelphij va_list ap; 553298192Sdelphij int rv; 554298192Sdelphij 555298192Sdelphij va_start(ap, fmt); 556298192Sdelphij rv = vasprintf(&msg, fmt, ap); 557298192Sdelphij va_end(ap); 558298192Sdelphij if (rv < 0) { 559298192Sdelphij *buf = NULL; 560298192Sdelphij *len = 0; 561298192Sdelphij return NODATA; 562298192Sdelphij } 563298192Sdelphij *buf = (unsigned char *)msg; 564298192Sdelphij *len = strlen(msg); 565298192Sdelphij return ERRDATA; 566298192Sdelphij} 567298192Sdelphij 568298192Sdelphijstatic void 569298192Sdelphijclosefd(int *fd, size_t i) 570298192Sdelphij{ 571298192Sdelphij if (fd[i] == -1) 572298192Sdelphij return; 573298192Sdelphij (void) close(fd[i]); 574298192Sdelphij fd[i] = -1; 575298192Sdelphij} 576298192Sdelphij 577298192Sdelphijstatic void 578298192Sdelphijclosep(int *fd) 579298192Sdelphij{ 580298192Sdelphij size_t i; 581298192Sdelphij for (i = 0; i < 2; i++) 582298192Sdelphij closefd(fd, i); 583298192Sdelphij} 584298192Sdelphij 585298192Sdelphijstatic void 586298192Sdelphijcopydesc(int i, int *fd) 587298192Sdelphij{ 588298192Sdelphij int j = fd[i == STDIN_FILENO ? 0 : 1]; 589298192Sdelphij if (j == i) 590298192Sdelphij return; 591298192Sdelphij if (dup2(j, i) == -1) { 592298192Sdelphij DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); 593298192Sdelphij exit(1); 594298192Sdelphij } 595298192Sdelphij closep(fd); 596298192Sdelphij} 597298192Sdelphij 598298192Sdelphijstatic void 599298192Sdelphijwritechild(int fdp[3][2], const void *old, size_t n) 600298192Sdelphij{ 601298192Sdelphij int status; 602298192Sdelphij 603298192Sdelphij closefd(fdp[STDIN_FILENO], 0); 604298192Sdelphij /* 605298192Sdelphij * fork again, to avoid blocking because both 606298192Sdelphij * pipes filled 607298192Sdelphij */ 608298192Sdelphij switch (fork()) { 609298192Sdelphij case 0: /* child */ 610298192Sdelphij closefd(fdp[STDOUT_FILENO], 0); 611298192Sdelphij if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { 612298192Sdelphij DPRINTF("Write failed (%s)\n", strerror(errno)); 613298192Sdelphij exit(1); 614298192Sdelphij } 615298192Sdelphij exit(0); 616298192Sdelphij /*NOTREACHED*/ 617298192Sdelphij 618298192Sdelphij case -1: 619298192Sdelphij DPRINTF("Fork failed (%s)\n", strerror(errno)); 620298192Sdelphij exit(1); 621298192Sdelphij /*NOTREACHED*/ 622298192Sdelphij 623298192Sdelphij default: /* parent */ 624298192Sdelphij if (wait(&status) == -1) { 625298192Sdelphij DPRINTF("Wait failed (%s)\n", strerror(errno)); 626298192Sdelphij exit(1); 627298192Sdelphij } 628298192Sdelphij DPRINTF("Grandchild wait return %#x\n", status); 629298192Sdelphij } 630298192Sdelphij closefd(fdp[STDIN_FILENO], 1); 631298192Sdelphij} 632298192Sdelphij 633298192Sdelphijstatic ssize_t 634298192Sdelphijfilter_error(unsigned char *ubuf, ssize_t n) 635298192Sdelphij{ 636298192Sdelphij char *p; 637298192Sdelphij char *buf; 638298192Sdelphij 639298192Sdelphij ubuf[n] = '\0'; 640298192Sdelphij buf = (char *)ubuf; 641298192Sdelphij while (isspace((unsigned char)*buf)) 642298192Sdelphij buf++; 643298192Sdelphij DPRINTF("Filter error[[[%s]]]\n", buf); 644298192Sdelphij if ((p = strchr((char *)buf, '\n')) != NULL) 645298192Sdelphij *p = '\0'; 646298192Sdelphij if ((p = strchr((char *)buf, ';')) != NULL) 647298192Sdelphij *p = '\0'; 648298192Sdelphij if ((p = strrchr((char *)buf, ':')) != NULL) { 649298192Sdelphij ++p; 650298192Sdelphij while (isspace((unsigned char)*p)) 651298192Sdelphij p++; 652298192Sdelphij n = strlen(p); 653328874Seadler memmove(ubuf, p, CAST(size_t, n + 1)); 654298192Sdelphij } 655298192Sdelphij DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); 656298192Sdelphij if (islower(*ubuf)) 657298192Sdelphij *ubuf = toupper(*ubuf); 658103373Sobrien return n; 659103373Sobrien} 660298192Sdelphij 661298192Sdelphijprivate const char * 662298192Sdelphijmethodname(size_t method) 663298192Sdelphij{ 664298192Sdelphij#ifdef BUILTIN_DECOMPRESS 665298192Sdelphij /* FIXME: This doesn't cope with bzip2 */ 666298192Sdelphij if (method == 2 || compr[method].maglen == 0) 667298192Sdelphij return "zlib"; 668103373Sobrien#endif 669298192Sdelphij return compr[method].argv[0]; 670298192Sdelphij} 671103373Sobrien 672298192Sdelphijprivate int 673298192Sdelphijuncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, 674298192Sdelphij unsigned char **newch, size_t* n) 675103373Sobrien{ 676298192Sdelphij int fdp[3][2]; 677298192Sdelphij int status, rv; 678298192Sdelphij size_t i; 679226048Sobrien ssize_t r; 68068349Sobrien 681175296Sobrien#ifdef BUILTIN_DECOMPRESS 682186690Sobrien /* FIXME: This doesn't cope with bzip2 */ 683103373Sobrien if (method == 2) 684298192Sdelphij return uncompressgzipped(old, newch, bytes_max, n); 685298192Sdelphij if (compr[method].maglen == 0) 686298192Sdelphij return uncompresszlib(old, newch, bytes_max, n, 1); 687103373Sobrien#endif 688159764Sobrien (void)fflush(stdout); 689159764Sobrien (void)fflush(stderr); 690103373Sobrien 691298192Sdelphij for (i = 0; i < __arraycount(fdp); i++) 692298192Sdelphij fdp[i][0] = fdp[i][1] = -1; 693298192Sdelphij 694298192Sdelphij if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || 695298192Sdelphij pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { 696298192Sdelphij closep(fdp[STDIN_FILENO]); 697298192Sdelphij closep(fdp[STDOUT_FILENO]); 698298192Sdelphij return makeerror(newch, n, "Cannot create pipe, %s", 699298192Sdelphij strerror(errno)); 70068349Sobrien } 701284237Sdelphij switch (fork()) { 70268349Sobrien case 0: /* child */ 703159764Sobrien if (fd != -1) { 704298192Sdelphij fdp[STDIN_FILENO][0] = fd; 705298192Sdelphij (void) lseek(fd, (off_t)0, SEEK_SET); 706159764Sobrien } 707298192Sdelphij 708298192Sdelphij for (i = 0; i < __arraycount(fdp); i++) 709328874Seadler copydesc(CAST(int, i), fdp[i]); 71068349Sobrien 711169962Sobrien (void)execvp(compr[method].argv[0], 712169962Sobrien (char *const *)(intptr_t)compr[method].argv); 713298192Sdelphij dprintf(STDERR_FILENO, "exec `%s' failed, %s", 714159764Sobrien compr[method].argv[0], strerror(errno)); 71568349Sobrien exit(1); 71668349Sobrien /*NOTREACHED*/ 71768349Sobrien case -1: 718298192Sdelphij return makeerror(newch, n, "Cannot fork, %s", 719298192Sdelphij strerror(errno)); 72068349Sobrien 72168349Sobrien default: /* parent */ 722298192Sdelphij for (i = 1; i < __arraycount(fdp); i++) 723298192Sdelphij closefd(fdp[i], 1); 724159764Sobrien 725298192Sdelphij /* Write the buffer data to the child, if we don't have fd */ 726298192Sdelphij if (fd == -1) 727298192Sdelphij writechild(fdp, old, *n); 728133359Sobrien 729298192Sdelphij *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 730298192Sdelphij if (*newch == NULL) { 731298192Sdelphij rv = makeerror(newch, n, "No buffer, %s", 732159764Sobrien strerror(errno)); 73375937Sobrien goto err; 73475937Sobrien } 735298192Sdelphij rv = OKDATA; 736298192Sdelphij if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) 737298192Sdelphij break; 738298192Sdelphij DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], 739298192Sdelphij r != -1 ? strerror(errno) : "no data"); 740298192Sdelphij 741298192Sdelphij rv = ERRDATA; 742298192Sdelphij if (r == 0 && 743298192Sdelphij (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) 744298192Sdelphij { 745298192Sdelphij r = filter_error(*newch, r); 746298192Sdelphij break; 74768349Sobrien } 748298192Sdelphij free(*newch); 749298192Sdelphij if (r == 0) 750298192Sdelphij rv = makeerror(newch, n, "Read failed, %s", 751275698Sdelphij strerror(errno)); 752298192Sdelphij else 753298192Sdelphij rv = makeerror(newch, n, "No data"); 754298192Sdelphij goto err; 755298192Sdelphij } 756275698Sdelphij 757298192Sdelphij *n = r; 758298192Sdelphij /* NUL terminate, as every buffer is handled here. */ 759298192Sdelphij (*newch)[*n] = '\0'; 760298192Sdelphijerr: 761298192Sdelphij closefd(fdp[STDIN_FILENO], 1); 762298192Sdelphij closefd(fdp[STDOUT_FILENO], 0); 763298192Sdelphij closefd(fdp[STDERR_FILENO], 0); 764298192Sdelphij if (wait(&status) == -1) { 765298192Sdelphij free(*newch); 766298192Sdelphij rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); 767298192Sdelphij DPRINTF("Child wait return %#x\n", status); 768298192Sdelphij } else if (!WIFEXITED(status)) { 769328874Seadler DPRINTF("Child not exited (%#x)\n", status); 770298192Sdelphij } else if (WEXITSTATUS(status) != 0) { 771328874Seadler DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status)); 77268349Sobrien } 773298192Sdelphij 774298192Sdelphij closefd(fdp[STDIN_FILENO], 0); 775298192Sdelphij DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); 776298192Sdelphij 777298192Sdelphij return rv; 77868349Sobrien} 779226048Sobrien#endif 780