[BACK]Return to compress.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Annotation of src/usr.bin/file/compress.c, Revision 1.13

1.13    ! chl         1: /*     $OpenBSD: compress.c,v 1.12 2008/05/08 01:40:56 chl Exp $ */
1.1       deraadt     2: /*
1.7       ian         3:  * Copyright (c) Ian F. Darwin 1986-1995.
                      4:  * Software written by Ian F. Darwin and others;
                      5:  * maintained 1995-present by Christos Zoulas and others.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice immediately at the beginning of the file, without modification,
                     12:  *    this list of conditions, and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     21:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
1.1       deraadt    28:  */
1.11      tedu       29: /*
                     30:  * compress routines:
                     31:  *     zmagic() - returns 0 if not recognized, uncompresses and prints
                     32:  *                information if recognized
                     33:  *     uncompress(method, old, n, newch) - uncompress old into new,
                     34:  *                                         using method, return sizeof new
                     35:  */
1.6       ian        36: #include "file.h"
1.11      tedu       37: #include "magic.h"
                     38: #include <stdio.h>
1.6       ian        39: #include <stdlib.h>
1.11      tedu       40: #ifdef HAVE_UNISTD_H
1.6       ian        41: #include <unistd.h>
                     42: #endif
                     43: #include <string.h>
1.11      tedu       44: #include <errno.h>
                     45: #include <sys/types.h>
1.12      chl        46: #include <sys/ioctl.h>
1.11      tedu       47: #ifdef HAVE_SYS_WAIT_H
1.4       mickey     48: #include <sys/wait.h>
1.6       ian        49: #endif
1.12      chl        50: #if defined(HAVE_SYS_TIME_H)
                     51: #include <sys/time.h>
                     52: #endif
1.13    ! chl        53: #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
        !            54: #define BUILTIN_DECOMPRESS
1.6       ian        55: #include <zlib.h>
                     56: #endif
1.1       deraadt    57:
1.12      chl        58:
1.11      tedu       59: #ifndef lint
1.13    ! chl        60: FILE_RCSID("@(#)$Id: compress.c,v 1.12 2008/05/08 01:40:56 chl Exp $")
1.11      tedu       61: #endif
                     62:
1.13    ! chl        63: private const struct {
        !            64:        const char magic[8];
1.11      tedu       65:        size_t maglen;
1.13    ! chl        66:        const char *argv[3];
1.11      tedu       67:        int silent;
1.1       deraadt    68: } compr[] = {
1.11      tedu       69:        { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 },         /* compressed */
                     70:        /* Uncompress can get stuck; so use gzip first if we have it
                     71:         * Idea from Damien Clark, thanks! */
                     72:        { "\037\235", 2, { "uncompress", "-c", NULL }, 1 },     /* compressed */
                     73:        { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 },         /* gzipped */
                     74:        { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 },         /* frozen */
                     75:        { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 },         /* SCO LZH */
                     76:        /* the standard pack utilities do not accept standard input */
                     77:        { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 },         /* packed */
1.12      chl        78:        { "PK\3\4",   4, { "gzip", "-cdq", NULL }, 1 },         /* pkzipped, */
                     79:                                            /* ...only first file examined */
1.11      tedu       80:        { "BZh",      3, { "bzip2", "-cd", NULL }, 1 },         /* bzip2-ed */
1.1       deraadt    81: };
                     82:
1.12      chl        83: private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
                     84:
                     85: #define NODATA ((size_t)~0)
1.1       deraadt    86:
                     87:
1.11      tedu       88: private ssize_t swrite(int, const void *, size_t);
1.12      chl        89: private size_t uncompressbuf(struct magic_set *, int, size_t,
                     90:     const unsigned char *, unsigned char **, size_t);
1.13    ! chl        91: #ifdef BUILTIN_DECOMPRESS
1.11      tedu       92: private size_t uncompressgzipped(struct magic_set *, const unsigned char *,
                     93:     unsigned char **, size_t);
                     94: #endif
1.1       deraadt    95:
1.11      tedu       96: protected int
1.12      chl        97: file_zmagic(struct magic_set *ms, int fd, const char *name,
                     98:     const unsigned char *buf, size_t nbytes)
1.1       deraadt    99: {
1.11      tedu      100:        unsigned char *newbuf = NULL;
                    101:        size_t i, nsz;
                    102:        int rv = 0;
1.13    ! chl       103:        int mime = ms->flags & MAGIC_MIME;
1.11      tedu      104:
                    105:        if ((ms->flags & MAGIC_COMPRESS) == 0)
                    106:                return 0;
1.1       deraadt   107:
                    108:        for (i = 0; i < ncompr; i++) {
                    109:                if (nbytes < compr[i].maglen)
                    110:                        continue;
1.11      tedu      111:                if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
1.12      chl       112:                    (nsz = uncompressbuf(ms, fd, i, buf, &newbuf,
                    113:                    nbytes)) != NODATA) {
1.11      tedu      114:                        ms->flags &= ~MAGIC_COMPRESS;
                    115:                        rv = -1;
1.12      chl       116:                        if (file_buffer(ms, -1, name, newbuf, nsz) == -1)
1.11      tedu      117:                                goto error;
1.13    ! chl       118:
        !           119:                        if (mime == MAGIC_MIME || mime == 0) {
        !           120:                                if (file_printf(ms, mime ?
        !           121:                                    " compressed-encoding=" : " (") == -1)
        !           122:                                        goto error;
        !           123:                        }
        !           124:
        !           125:                        if ((mime == 0 || mime & MAGIC_MIME_ENCODING) &&
        !           126:                            file_buffer(ms, -1, NULL, buf, nbytes) == -1)
1.11      tedu      127:                                goto error;
1.13    ! chl       128:
        !           129:                        if (!mime && file_printf(ms, ")") == -1)
1.11      tedu      130:                                goto error;
                    131:                        rv = 1;
1.1       deraadt   132:                        break;
1.11      tedu      133:                }
1.1       deraadt   134:        }
1.11      tedu      135: error:
                    136:        if (newbuf)
1.1       deraadt   137:                free(newbuf);
1.11      tedu      138:        ms->flags |= MAGIC_COMPRESS;
                    139:        return rv;
1.1       deraadt   140: }
                    141:
1.6       ian       142: /*
                    143:  * `safe' write for sockets and pipes.
                    144:  */
1.11      tedu      145: private ssize_t
1.6       ian       146: swrite(int fd, const void *buf, size_t n)
                    147: {
                    148:        int rv;
                    149:        size_t rn = n;
                    150:
                    151:        do
                    152:                switch (rv = write(fd, buf, n)) {
                    153:                case -1:
                    154:                        if (errno == EINTR)
                    155:                                continue;
                    156:                        return -1;
                    157:                default:
                    158:                        n -= rv;
                    159:                        buf = ((const char *)buf) + rv;
                    160:                        break;
                    161:                }
                    162:        while (n > 0);
                    163:        return rn;
                    164: }
                    165:
1.11      tedu      166:
1.6       ian       167: /*
                    168:  * `safe' read for sockets and pipes.
                    169:  */
1.12      chl       170: protected ssize_t
                    171: sread(int fd, void *buf, size_t n, int canbepipe)
1.6       ian       172: {
1.12      chl       173:        int rv, cnt;
                    174: #ifdef FIONREAD
                    175:        int t = 0;
                    176: #endif
1.6       ian       177:        size_t rn = n;
                    178:
1.12      chl       179:        if (fd == STDIN_FILENO)
                    180:                goto nocheck;
                    181:
                    182: #ifdef FIONREAD
                    183:        if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) {
                    184: #ifdef FD_ZERO
                    185:                for (cnt = 0;; cnt++) {
                    186:                        fd_set check;
                    187:                        struct timeval tout = {0, 100 * 1000};
                    188:                        int selrv;
                    189:
                    190:                        FD_ZERO(&check);
                    191:                        FD_SET(fd, &check);
                    192:
                    193:                        /*
                    194:                         * Avoid soft deadlock: do not read if there
                    195:                         * is nothing to read from sockets and pipes.
                    196:                         */
                    197:                        selrv = select(fd + 1, &check, NULL, NULL, &tout);
                    198:                        if (selrv == -1) {
                    199:                                if (errno == EINTR || errno == EAGAIN)
                    200:                                        continue;
                    201:                        } else if (selrv == 0 && cnt >= 5) {
                    202:                                return 0;
                    203:                        } else
                    204:                                break;
                    205:                }
                    206: #endif
                    207:                (void)ioctl(fd, FIONREAD, &t);
                    208:        }
                    209:
                    210:        if (t > 0 && (size_t)t < n) {
                    211:                n = t;
                    212:                rn = n;
                    213:        }
                    214: #endif
                    215:
                    216: nocheck:
1.6       ian       217:        do
1.12      chl       218:                switch ((rv = read(fd, buf, n))) {
1.6       ian       219:                case -1:
                    220:                        if (errno == EINTR)
                    221:                                continue;
                    222:                        return -1;
                    223:                case 0:
                    224:                        return rn - n;
                    225:                default:
                    226:                        n -= rv;
                    227:                        buf = ((char *)buf) + rv;
                    228:                        break;
                    229:                }
                    230:        while (n > 0);
                    231:        return rn;
                    232: }
                    233:
1.11      tedu      234: protected int
                    235: file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
                    236:     size_t nbytes)
1.6       ian       237: {
                    238:        char buf[4096];
                    239:        int r, tfd;
                    240:
1.11      tedu      241:        (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
1.6       ian       242: #ifndef HAVE_MKSTEMP
                    243:        {
                    244:                char *ptr = mktemp(buf);
                    245:                tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
                    246:                r = errno;
                    247:                (void)unlink(ptr);
                    248:                errno = r;
                    249:        }
                    250: #else
                    251:        tfd = mkstemp(buf);
                    252:        r = errno;
                    253:        (void)unlink(buf);
                    254:        errno = r;
                    255: #endif
                    256:        if (tfd == -1) {
1.11      tedu      257:                file_error(ms, errno,
                    258:                    "cannot create temporary file for pipe copy");
                    259:                return -1;
1.6       ian       260:        }
                    261:
1.11      tedu      262:        if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
1.6       ian       263:                r = 1;
                    264:        else {
1.12      chl       265:                while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
1.11      tedu      266:                        if (swrite(tfd, buf, (size_t)r) != r)
1.6       ian       267:                                break;
                    268:        }
                    269:
                    270:        switch (r) {
                    271:        case -1:
1.11      tedu      272:                file_error(ms, errno, "error copying from pipe to temp file");
                    273:                return -1;
1.6       ian       274:        case 0:
                    275:                break;
                    276:        default:
1.11      tedu      277:                file_error(ms, errno, "error while writing to temp file");
                    278:                return -1;
1.6       ian       279:        }
                    280:
                    281:        /*
                    282:         * We duplicate the file descriptor, because fclose on a
                    283:         * tmpfile will delete the file, but any open descriptors
                    284:         * can still access the phantom inode.
                    285:         */
                    286:        if ((fd = dup2(tfd, fd)) == -1) {
1.11      tedu      287:                file_error(ms, errno, "could not dup descriptor for temp file");
                    288:                return -1;
1.6       ian       289:        }
                    290:        (void)close(tfd);
                    291:        if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
1.11      tedu      292:                file_badseek(ms);
                    293:                return -1;
1.6       ian       294:        }
                    295:        return fd;
                    296: }
1.1       deraadt   297:
1.13    ! chl       298: #ifdef BUILTIN_DECOMPRESS
1.11      tedu      299:
                    300: #define FHCRC          (1 << 1)
                    301: #define FEXTRA         (1 << 2)
                    302: #define FNAME          (1 << 3)
                    303: #define FCOMMENT       (1 << 4)
                    304:
                    305: private size_t
                    306: uncompressgzipped(struct magic_set *ms, const unsigned char *old,
                    307:     unsigned char **newch, size_t n)
                    308: {
                    309:        unsigned char flg = old[3];
                    310:        size_t data_start = 10;
                    311:        z_stream z;
                    312:        int rc;
                    313:
                    314:        if (flg & FEXTRA) {
                    315:                if (data_start+1 >= n)
                    316:                        return 0;
                    317:                data_start += 2 + old[data_start] + old[data_start + 1] * 256;
                    318:        }
                    319:        if (flg & FNAME) {
                    320:                while(data_start < n && old[data_start])
                    321:                        data_start++;
                    322:                data_start++;
                    323:        }
                    324:        if(flg & FCOMMENT) {
                    325:                while(data_start < n && old[data_start])
                    326:                        data_start++;
                    327:                data_start++;
                    328:        }
                    329:        if(flg & FHCRC)
                    330:                data_start += 2;
                    331:
                    332:        if (data_start >= n)
                    333:                return 0;
                    334:        if ((*newch = (unsigned char *)malloc(HOWMANY + 1)) == NULL) {
                    335:                return 0;
                    336:        }
                    337:
                    338:        /* XXX: const castaway, via strchr */
                    339:        z.next_in = (Bytef *)strchr((const char *)old + data_start,
                    340:            old[data_start]);
                    341:        z.avail_in = n - data_start;
                    342:        z.next_out = *newch;
                    343:        z.avail_out = HOWMANY;
                    344:        z.zalloc = Z_NULL;
                    345:        z.zfree = Z_NULL;
                    346:        z.opaque = Z_NULL;
                    347:
                    348:        rc = inflateInit2(&z, -15);
                    349:        if (rc != Z_OK) {
                    350:                file_error(ms, 0, "zlib: %s", z.msg);
                    351:                return 0;
                    352:        }
                    353:
                    354:        rc = inflate(&z, Z_SYNC_FLUSH);
                    355:        if (rc != Z_OK && rc != Z_STREAM_END) {
                    356:                file_error(ms, 0, "zlib: %s", z.msg);
                    357:                return 0;
                    358:        }
                    359:
                    360:        n = (size_t)z.total_out;
1.12      chl       361:        (void)inflateEnd(&z);
1.11      tedu      362:
                    363:        /* let's keep the nul-terminate tradition */
1.12      chl       364:        (*newch)[n] = '\0';
1.11      tedu      365:
                    366:        return n;
                    367: }
                    368: #endif
                    369:
                    370: private size_t
1.12      chl       371: uncompressbuf(struct magic_set *ms, int fd, size_t method,
                    372:     const unsigned char *old, unsigned char **newch, size_t n)
1.1       deraadt   373: {
                    374:        int fdin[2], fdout[2];
1.11      tedu      375:        int r;
                    376:
1.13    ! chl       377: #ifdef BUILTIN_DECOMPRESS
        !           378:         /* FIXME: This doesn't cope with bzip2 */
1.11      tedu      379:        if (method == 2)
                    380:                return uncompressgzipped(ms, old, newch, n);
                    381: #endif
1.12      chl       382:        (void)fflush(stdout);
                    383:        (void)fflush(stderr);
1.1       deraadt   384:
1.12      chl       385:        if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) {
1.11      tedu      386:                file_error(ms, errno, "cannot create pipe");
1.12      chl       387:                return NODATA;
1.1       deraadt   388:        }
                    389:        switch (fork()) {
                    390:        case 0: /* child */
                    391:                (void) close(0);
1.12      chl       392:                if (fd != -1) {
                    393:                    (void) dup(fd);
                    394:                    (void) lseek(0, (off_t)0, SEEK_SET);
                    395:                } else {
                    396:                    (void) dup(fdin[0]);
                    397:                    (void) close(fdin[0]);
                    398:                    (void) close(fdin[1]);
                    399:                }
1.1       deraadt   400:
                    401:                (void) close(1);
                    402:                (void) dup(fdout[1]);
                    403:                (void) close(fdout[0]);
                    404:                (void) close(fdout[1]);
1.12      chl       405: #ifndef DEBUG
1.1       deraadt   406:                if (compr[method].silent)
1.12      chl       407:                        (void)close(2);
                    408: #endif
1.1       deraadt   409:
1.12      chl       410:                (void)execvp(compr[method].argv[0],
                    411:                    (char *const *)(intptr_t)compr[method].argv);
                    412: #ifdef DEBUG
                    413:                (void)fprintf(stderr, "exec `%s' failed (%s)\n",
                    414:                    compr[method].argv[0], strerror(errno));
                    415: #endif
1.11      tedu      416:                exit(1);
1.1       deraadt   417:                /*NOTREACHED*/
                    418:        case -1:
1.11      tedu      419:                file_error(ms, errno, "could not fork");
1.12      chl       420:                return NODATA;
1.1       deraadt   421:
                    422:        default: /* parent */
                    423:                (void) close(fdout[1]);
1.12      chl       424:                if (fd == -1) {
                    425:                        (void) close(fdin[0]);
                    426:                        /*
                    427:                         * fork again, to avoid blocking because both
                    428:                         * pipes filled
                    429:                         */
                    430:                        switch (fork()) {
                    431:                        case 0: /* child */
                    432:                                (void)close(fdout[0]);
                    433:                                if (swrite(fdin[1], old, n) != (ssize_t)n) {
                    434: #ifdef DEBUG
                    435:                                        (void)fprintf(stderr,
                    436:                                            "Write failed (%s)\n",
                    437:                                            strerror(errno));
                    438: #endif
                    439:                                        exit(1);
                    440:                                }
                    441:                                exit(0);
                    442:                                /*NOTREACHED*/
                    443:
                    444:                        case -1:
                    445: #ifdef DEBUG
                    446:                                (void)fprintf(stderr, "Fork failed (%s)\n",
                    447:                                    strerror(errno));
                    448: #endif
1.11      tedu      449:                                exit(1);
1.12      chl       450:                                /*NOTREACHED*/
1.11      tedu      451:
1.12      chl       452:                        default:  /* parent */
                    453:                                break;
                    454:                        }
                    455:                        (void) close(fdin[1]);
                    456:                        fdin[1] = -1;
                    457:                }
1.11      tedu      458:
                    459:                if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) {
1.12      chl       460: #ifdef DEBUG
                    461:                        (void)fprintf(stderr, "Malloc failed (%s)\n",
                    462:                            strerror(errno));
                    463: #endif
1.11      tedu      464:                        n = 0;
                    465:                        goto err;
1.1       deraadt   466:                }
1.12      chl       467:                if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) {
                    468: #ifdef DEBUG
                    469:                        (void)fprintf(stderr, "Read failed (%s)\n",
                    470:                            strerror(errno));
                    471: #endif
1.1       deraadt   472:                        free(*newch);
1.11      tedu      473:                        n = 0;
                    474:                        newch[0] = '\0';
                    475:                        goto err;
                    476:                } else {
                    477:                        n = r;
1.1       deraadt   478:                }
1.11      tedu      479:                /* NUL terminate, as every buffer is handled here. */
1.12      chl       480:                (*newch)[n] = '\0';
1.11      tedu      481: err:
                    482:                if (fdin[1] != -1)
                    483:                        (void) close(fdin[1]);
1.1       deraadt   484:                (void) close(fdout[0]);
1.11      tedu      485: #ifdef WNOHANG
                    486:                while (waitpid(-1, NULL, WNOHANG) != -1)
                    487:                        continue;
                    488: #else
                    489:                (void)wait(NULL);
                    490: #endif
1.1       deraadt   491:                return n;
                    492:        }
                    493: }