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

Annotation of src/usr.bin/file/magic.c, Revision 1.6

1.6     ! chl         1: /* $OpenBSD: magic.c,v 1.5 2008/05/08 01:40:56 chl Exp $ */
1.1       tedu        2: /*
                      3:  * Copyright (c) Christos Zoulas 2003.
                      4:  * All Rights Reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice immediately at the beginning of the file, without modification,
                     11:  *    this list of conditions, and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28:
                     29: #include "file.h"
                     30: #include "magic.h"
                     31:
                     32: #include <stdio.h>
                     33: #include <stdlib.h>
                     34: #include <unistd.h>
                     35: #include <string.h>
                     36: #include <sys/types.h>
                     37: #include <sys/param.h> /* for MAXPATHLEN */
                     38: #include <sys/stat.h>
                     39: #ifdef QUICK
                     40: #include <sys/mman.h>
                     41: #endif
1.5       chl        42: #include <limits.h>    /* for PIPE_BUF */
1.1       tedu       43:
1.5       chl        44: #if defined(HAVE_UTIMES)
                     45: # include <sys/time.h>
                     46: #elif defined(HAVE_UTIME)
1.1       tedu       47: # if defined(HAVE_SYS_UTIME_H)
                     48: #  include <sys/utime.h>
                     49: # elif defined(HAVE_UTIME_H)
                     50: #  include <utime.h>
                     51: # endif
                     52: #endif
                     53:
                     54: #ifdef HAVE_UNISTD_H
                     55: #include <unistd.h>    /* for read() */
                     56: #endif
                     57:
                     58: #ifdef HAVE_LOCALE_H
                     59: #include <locale.h>
                     60: #endif
                     61:
                     62: #include <netinet/in.h>                /* for byte swapping */
                     63:
                     64: #include "patchlevel.h"
                     65:
                     66: #ifndef        lint
1.6     ! chl        67: FILE_RCSID("@(#)$Id: magic.c,v 1.5 2008/05/08 01:40:56 chl Exp $")
1.1       tedu       68: #endif /* lint */
                     69:
1.6     ! chl        70: #ifndef PIPE_BUF
        !            71: /* Get the PIPE_BUF from pathconf */
        !            72: #ifdef _PC_PIPE_BUF
        !            73: #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
        !            74: #else
        !            75: #define PIPE_BUF 512
        !            76: #endif
        !            77: #endif
        !            78:
1.1       tedu       79: #ifdef __EMX__
                     80: private char *apptypeName = NULL;
                     81: protected int file_os2_apptype(struct magic_set *ms, const char *fn,
                     82:     const void *buf, size_t nb);
                     83: #endif /* __EMX__ */
                     84:
                     85: private void free_mlist(struct mlist *);
                     86: private void close_and_restore(const struct magic_set *, const char *, int,
                     87:     const struct stat *);
1.5       chl        88: private int info_from_stat(struct magic_set *, mode_t);
1.6     ! chl        89: #ifndef COMPILE_ONLY
        !            90: private const char *file_or_fd(struct magic_set *, const char *, int);
        !            91: #endif
1.5       chl        92:
                     93: #ifndef        STDIN_FILENO
                     94: #define        STDIN_FILENO    0
                     95: #endif
1.1       tedu       96:
                     97: public struct magic_set *
                     98: magic_open(int flags)
                     99: {
                    100:        struct magic_set *ms;
                    101:
1.5       chl       102:        if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL)
1.1       tedu      103:                return NULL;
                    104:
                    105:        if (magic_setflags(ms, flags) == -1) {
                    106:                errno = EINVAL;
1.6     ! chl       107:                goto free;
1.1       tedu      108:        }
                    109:
1.6     ! chl       110:        ms->o.buf = ms->o.pbuf = NULL;
1.5       chl       111:
                    112:        ms->c.li = malloc((ms->c.len = 10) * sizeof(*ms->c.li));
                    113:        if (ms->c.li == NULL)
1.6     ! chl       114:                goto free;
1.5       chl       115:
1.1       tedu      116:        ms->haderr = 0;
                    117:        ms->error = -1;
                    118:        ms->mlist = NULL;
1.5       chl       119:        ms->file = "unknown";
                    120:        ms->line = 0;
1.1       tedu      121:        return ms;
1.6     ! chl       122: free:
1.5       chl       123:        free(ms);
                    124:        return NULL;
1.1       tedu      125: }
                    126:
                    127: private void
                    128: free_mlist(struct mlist *mlist)
                    129: {
                    130:        struct mlist *ml;
                    131:
                    132:        if (mlist == NULL)
                    133:                return;
                    134:
                    135:        for (ml = mlist->next; ml != mlist;) {
                    136:                struct mlist *next = ml->next;
                    137:                struct magic *mg = ml->magic;
                    138:                file_delmagic(mg, ml->mapped, ml->nmagic);
                    139:                free(ml);
                    140:                ml = next;
                    141:        }
                    142:        free(ml);
                    143: }
                    144:
1.5       chl       145: private int
                    146: info_from_stat(struct magic_set *ms, mode_t md)
                    147: {
                    148:        /* We cannot open it, but we were able to stat it. */
                    149:        if (md & 0222)
                    150:                if (file_printf(ms, "writable, ") == -1)
                    151:                        return -1;
                    152:        if (md & 0111)
                    153:                if (file_printf(ms, "executable, ") == -1)
                    154:                        return -1;
                    155:        if (S_ISREG(md))
                    156:                if (file_printf(ms, "regular file, ") == -1)
                    157:                        return -1;
                    158:        if (file_printf(ms, "no read permission") == -1)
                    159:                return -1;
                    160:        return 0;
                    161: }
                    162:
1.1       tedu      163: public void
1.5       chl       164: magic_close(struct magic_set *ms)
1.1       tedu      165: {
                    166:        free_mlist(ms->mlist);
1.5       chl       167:        free(ms->o.pbuf);
1.1       tedu      168:        free(ms->o.buf);
1.5       chl       169:        free(ms->c.li);
1.1       tedu      170:        free(ms);
                    171: }
                    172:
                    173: /*
                    174:  * load a magic file
                    175:  */
                    176: public int
                    177: magic_load(struct magic_set *ms, const char *magicfile)
                    178: {
                    179:        struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
                    180:        if (ml) {
                    181:                free_mlist(ms->mlist);
                    182:                ms->mlist = ml;
                    183:                return 0;
                    184:        }
                    185:        return -1;
                    186: }
                    187:
                    188: public int
                    189: magic_compile(struct magic_set *ms, const char *magicfile)
                    190: {
                    191:        struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
                    192:        free_mlist(ml);
                    193:        return ml ? 0 : -1;
                    194: }
                    195:
                    196: public int
                    197: magic_check(struct magic_set *ms, const char *magicfile)
                    198: {
                    199:        struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
                    200:        free_mlist(ml);
                    201:        return ml ? 0 : -1;
                    202: }
                    203:
                    204: private void
                    205: close_and_restore(const struct magic_set *ms, const char *name, int fd,
                    206:     const struct stat *sb)
                    207: {
1.5       chl       208:        if (fd == STDIN_FILENO)
                    209:                return;
1.1       tedu      210:        (void) close(fd);
1.5       chl       211:
                    212:        if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
1.1       tedu      213:                /*
                    214:                 * Try to restore access, modification times if read it.
                    215:                 * This is really *bad* because it will modify the status
                    216:                 * time of the file... And of course this will affect
                    217:                 * backup programs
                    218:                 */
                    219: #ifdef HAVE_UTIMES
                    220:                struct timeval  utsbuf[2];
1.6     ! chl       221:                (void)memset(utsbuf, 0, sizeof(utsbuf));
1.1       tedu      222:                utsbuf[0].tv_sec = sb->st_atime;
                    223:                utsbuf[1].tv_sec = sb->st_mtime;
                    224:
                    225:                (void) utimes(name, utsbuf); /* don't care if loses */
                    226: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
                    227:                struct utimbuf  utbuf;
                    228:
1.6     ! chl       229:                (void)memset(utbuf, 0, sizeof(utbuf));
1.1       tedu      230:                utbuf.actime = sb->st_atime;
                    231:                utbuf.modtime = sb->st_mtime;
                    232:                (void) utime(name, &utbuf); /* don't care if loses */
                    233: #endif
                    234:        }
                    235: }
                    236:
1.5       chl       237: #ifndef COMPILE_ONLY
1.6     ! chl       238:
        !           239: /*
        !           240:  * find type of descriptor
        !           241:  */
        !           242: public const char *
        !           243: magic_descriptor(struct magic_set *ms, int fd)
        !           244: {
        !           245:        return file_or_fd(ms, NULL, fd);
        !           246: }
        !           247:
1.1       tedu      248: /*
                    249:  * find type of named file
                    250:  */
                    251: public const char *
                    252: magic_file(struct magic_set *ms, const char *inname)
                    253: {
1.6     ! chl       254:        return file_or_fd(ms, inname, STDIN_FILENO);
        !           255: }
        !           256:
        !           257: private const char *
        !           258: file_or_fd(struct magic_set *ms, const char *inname, int fd)
        !           259: {
1.5       chl       260:        int     rv = -1;
                    261:        unsigned char *buf;
1.1       tedu      262:        struct stat     sb;
                    263:        ssize_t nbytes = 0;     /* number of bytes read from a datafile */
1.5       chl       264:        int     ispipe = 0;
                    265:
                    266:        /*
                    267:         * one extra for terminating '\0', and
                    268:         * some overlapping space for matches near EOF
                    269:         */
                    270: #define SLOP (1 + sizeof(union VALUETYPE))
                    271:        if ((buf = malloc(HOWMANY + SLOP)) == NULL)
                    272:                return NULL;
1.1       tedu      273:
                    274:        if (file_reset(ms) == -1)
1.5       chl       275:                goto done;
1.1       tedu      276:
                    277:        switch (file_fsmagic(ms, inname, &sb)) {
1.5       chl       278:        case -1:                /* error */
                    279:                goto done;
                    280:        case 0:                 /* nothing found */
1.1       tedu      281:                break;
1.5       chl       282:        default:                /* matched it and printed type */
                    283:                rv = 0;
                    284:                goto done;
1.1       tedu      285:        }
                    286:
1.5       chl       287:        if (inname == NULL) {
                    288:                if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
                    289:                        ispipe = 1;
                    290:        } else {
                    291:                int flags = O_RDONLY|O_BINARY;
                    292:
                    293:                if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
                    294:                        flags |= O_NONBLOCK;
                    295:                        ispipe = 1;
                    296:                }
                    297:
                    298:                errno = 0;
                    299:                if ((fd = open(inname, flags)) < 0) {
                    300: #ifdef __CYGWIN__
1.6     ! chl       301:                        /* FIXME: Do this with EXEEXT from autotools */
        !           302:                        char *tmp = alloca(strlen(inname) + 5);
        !           303:                        (void)strcat(strcpy(tmp, inname), ".exe");
        !           304:                        if ((fd = open(tmp, flags)) < 0) {
1.5       chl       305: #endif
1.6     ! chl       306:                                fprintf(stderr, "couldn't open file\n");
        !           307:                                if (info_from_stat(ms, sb.st_mode) == -1)
        !           308:                                        goto done;
        !           309:                                rv = 0;
        !           310:                                goto done;
1.5       chl       311: #ifdef __CYGWIN__
1.6     ! chl       312:                        }
1.5       chl       313: #endif
                    314:                }
                    315: #ifdef O_NONBLOCK
                    316:                if ((flags = fcntl(fd, F_GETFL)) != -1) {
                    317:                        flags &= ~O_NONBLOCK;
                    318:                        (void)fcntl(fd, F_SETFL, flags);
                    319:                }
1.1       tedu      320: #endif
                    321:        }
                    322:
                    323:        /*
                    324:         * try looking at the first HOWMANY bytes
                    325:         */
1.5       chl       326:        if (ispipe) {
                    327:                ssize_t r = 0;
                    328:
                    329:                while ((r = sread(fd, (void *)&buf[nbytes],
                    330:                    (size_t)(HOWMANY - nbytes), 1)) > 0) {
                    331:                        nbytes += r;
                    332:                        if (r < PIPE_BUF) break;
                    333:                }
                    334:
                    335:                if (nbytes == 0) {
                    336:                        /* We can not read it, but we were able to stat it. */
                    337:                        if (info_from_stat(ms, sb.st_mode) == -1)
                    338:                                goto done;
                    339:                        rv = 0;
                    340:                        goto done;
                    341:                }
                    342:
                    343:        } else {
                    344:                if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
                    345:                        file_error(ms, errno, "cannot read `%s'", inname);
                    346:                        goto done;
                    347:                }
1.1       tedu      348:        }
                    349:
1.6     ! chl       350:        (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
        !           351:        if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
        !           352:                goto done;
1.5       chl       353:        rv = 0;
1.1       tedu      354: done:
1.5       chl       355:        free(buf);
1.1       tedu      356:        close_and_restore(ms, inname, fd, &sb);
1.5       chl       357:        return rv == 0 ? file_getbuffer(ms) : NULL;
1.1       tedu      358: }
                    359:
                    360:
                    361: public const char *
                    362: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
                    363: {
                    364:        if (file_reset(ms) == -1)
                    365:                return NULL;
                    366:        /*
                    367:         * The main work is done here!
                    368:         * We have the file name and/or the data buffer to be identified.
                    369:         */
1.5       chl       370:        if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
1.1       tedu      371:                return NULL;
                    372:        }
                    373:        return file_getbuffer(ms);
                    374: }
1.5       chl       375: #endif
1.1       tedu      376:
                    377: public const char *
                    378: magic_error(struct magic_set *ms)
                    379: {
                    380:        return ms->haderr ? ms->o.buf : NULL;
                    381: }
                    382:
                    383: public int
                    384: magic_errno(struct magic_set *ms)
                    385: {
                    386:        return ms->haderr ? ms->error : 0;
                    387: }
                    388:
                    389: public int
                    390: magic_setflags(struct magic_set *ms, int flags)
                    391: {
                    392: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
                    393:        if (flags & MAGIC_PRESERVE_ATIME)
                    394:                return -1;
                    395: #endif
                    396:        ms->flags = flags;
                    397:        return 0;
                    398: }