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

Annotation of src/usr.bin/file/funcs.c, Revision 1.5

1.5     ! chl         1: /* $OpenBSD: funcs.c,v 1.4 2007/07/09 16:39:48 dim 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: #include "file.h"
                     29: #include "magic.h"
                     30: #include <stdarg.h>
                     31: #include <stdlib.h>
                     32: #include <string.h>
                     33: #include <ctype.h>
1.5     ! chl        34: #if defined(HAVE_WCHAR_H)
        !            35: #include <wchar.h>
        !            36: #endif
        !            37: #if defined(HAVE_WCTYPE_H)
        !            38: #include <wctype.h>
        !            39: #endif
        !            40: #if defined(HAVE_LIMITS_H)
        !            41: #include <limits.h>
        !            42: #endif
        !            43: #ifndef SIZE_T_MAX
        !            44: #ifdef __LP64__
        !            45: #define SIZE_T_MAX (size_t)0xfffffffffffffffffU
        !            46: #else
        !            47: #define SIZE_T_MAX (size_t)0xffffffffU
        !            48: #endif
        !            49: #endif
1.1       tedu       50:
                     51: #ifndef        lint
1.5     ! chl        52: FILE_RCSID("@(#)$Id: funcs.c,v 1.4 2007/07/09 16:39:48 dim Exp $")
1.1       tedu       53: #endif /* lint */
1.5     ! chl        54:
        !            55: #ifndef HAVE_VSNPRINTF
        !            56: int vsnprintf(char *, size_t, const char *, va_list);
        !            57: #endif
        !            58:
1.1       tedu       59: /*
                     60:  * Like printf, only we print to a buffer and advance it.
                     61:  */
                     62: protected int
                     63: file_printf(struct magic_set *ms, const char *fmt, ...)
                     64: {
                     65:        va_list ap;
1.5     ! chl        66:        size_t len, size;
1.1       tedu       67:        char *buf;
                     68:
                     69:        va_start(ap, fmt);
                     70:
1.4       dim        71:        len = vsnprintf(ms->o.ptr, ms->o.left, fmt, ap);
                     72:        if (len == -1) {
                     73:                file_error(ms, errno, "vsnprintf failed");
                     74:                return -1;
                     75:        } else if (len >= ms->o.left) {
1.5     ! chl        76:                long diff;      /* XXX: really ptrdiff_t */
        !            77:
1.1       tedu       78:                va_end(ap);
1.4       dim        79:                size = (ms->o.size - ms->o.left) + len + 1024;
                     80:                if ((buf = realloc(ms->o.buf, size)) == NULL) {
1.5     ! chl        81:                        file_oomem(ms, size);
1.1       tedu       82:                        return -1;
                     83:                }
1.4       dim        84:                diff = ms->o.ptr - ms->o.buf;
                     85:                ms->o.ptr = buf + diff;
1.1       tedu       86:                ms->o.buf = buf;
1.4       dim        87:                ms->o.left = size - diff;
                     88:                ms->o.size = size;
1.1       tedu       89:
                     90:                va_start(ap, fmt);
1.4       dim        91:                len = vsnprintf(ms->o.ptr, ms->o.left, fmt, ap);
                     92:                if (len == -1) {
                     93:                        file_error(ms, errno, "vsnprintf failed");
                     94:                        return -1;
                     95:                }
1.1       tedu       96:        }
1.5     ! chl        97:        va_end(ap);
1.1       tedu       98:        ms->o.ptr += len;
1.4       dim        99:        ms->o.left -= len;
1.1       tedu      100:        return 0;
                    101: }
                    102:
                    103: /*
                    104:  * error - print best error message possible
                    105:  */
                    106: /*VARARGS*/
1.5     ! chl       107: private void
        !           108: file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
        !           109:     uint32_t lineno)
1.1       tedu      110: {
1.5     ! chl       111:        size_t len;
1.1       tedu      112:        /* Only the first error is ok */
                    113:        if (ms->haderr)
                    114:                return;
1.5     ! chl       115:        len = 0;
        !           116:        if (lineno != 0) {
        !           117:                (void)snprintf(ms->o.buf, ms->o.size, "line %u: ", lineno);
        !           118:                len = strlen(ms->o.buf);
        !           119:        }
        !           120:        (void)vsnprintf(ms->o.buf + len, ms->o.size - len, f, va);
1.1       tedu      121:        if (error > 0) {
1.5     ! chl       122:                len = strlen(ms->o.buf);
1.1       tedu      123:                (void)snprintf(ms->o.buf + len, ms->o.size - len, " (%s)",
                    124:                    strerror(error));
                    125:        }
                    126:        ms->haderr++;
                    127:        ms->error = error;
                    128: }
                    129:
1.5     ! chl       130: /*VARARGS*/
        !           131: protected void
        !           132: file_error(struct magic_set *ms, int error, const char *f, ...)
        !           133: {
        !           134:        va_list va;
        !           135:        va_start(va, f);
        !           136:        file_error_core(ms, error, f, va, 0);
        !           137:        va_end(va);
        !           138: }
        !           139:
        !           140: /*
        !           141:  * Print an error with magic line number.
        !           142:  */
        !           143: /*VARARGS*/
        !           144: protected void
        !           145: file_magerror(struct magic_set *ms, const char *f, ...)
        !           146: {
        !           147:        va_list va;
        !           148:        va_start(va, f);
        !           149:        file_error_core(ms, 0, f, va, ms->line);
        !           150:        va_end(va);
        !           151: }
1.1       tedu      152:
                    153: protected void
1.5     ! chl       154: file_oomem(struct magic_set *ms, size_t len)
1.1       tedu      155: {
1.5     ! chl       156:        file_error(ms, errno, "cannot allocate %zu bytes", len);
1.1       tedu      157: }
                    158:
                    159: protected void
                    160: file_badseek(struct magic_set *ms)
                    161: {
                    162:        file_error(ms, errno, "error seeking");
                    163: }
                    164:
                    165: protected void
                    166: file_badread(struct magic_set *ms)
                    167: {
                    168:        file_error(ms, errno, "error reading");
                    169: }
                    170:
1.5     ! chl       171: #ifndef COMPILE_ONLY
1.1       tedu      172: protected int
1.5     ! chl       173: file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
        !           174:     size_t nb)
1.1       tedu      175: {
                    176:     int m;
1.5     ! chl       177:
        !           178: #ifdef __EMX__
        !           179:     if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
        !           180:        switch (file_os2_apptype(ms, inname, buf, nb)) {
        !           181:        case -1:
        !           182:            return -1;
        !           183:        case 0:
        !           184:            break;
        !           185:        default:
        !           186:            return 1;
        !           187:        }
        !           188:     }
        !           189: #endif
        !           190:
1.1       tedu      191:     /* try compression stuff */
1.5     ! chl       192:     if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) != 0 ||
        !           193:         (m = file_zmagic(ms, fd, inname, buf, nb)) == 0) {
1.1       tedu      194:        /* Check if we have a tar file */
1.5     ! chl       195:        if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 ||
        !           196:            (m = file_is_tar(ms, buf, nb)) == 0) {
1.1       tedu      197:            /* try tests in /etc/magic (or surrogate magic file) */
1.5     ! chl       198:            if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 ||
        !           199:                (m = file_softmagic(ms, buf, nb)) == 0) {
1.1       tedu      200:                /* try known keywords, check whether it is ASCII */
1.5     ! chl       201:                if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 ||
        !           202:                    (m = file_ascmagic(ms, buf, nb)) == 0) {
1.1       tedu      203:                    /* abandon hope, all ye who remain here */
                    204:                    if (file_printf(ms, ms->flags & MAGIC_MIME ?
1.5     ! chl       205:                        (nb ? "application/octet-stream" :
        !           206:                            "application/empty") :
        !           207:                        (nb ? "data" :
        !           208:                            "empty")) == -1)
1.1       tedu      209:                            return -1;
                    210:                    m = 1;
                    211:                }
                    212:            }
                    213:        }
                    214:     }
1.5     ! chl       215: #ifdef BUILTIN_ELF
        !           216:     if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 && nb > 5 && fd != -1) {
        !           217:        /*
        !           218:         * We matched something in the file, so this *might*
        !           219:         * be an ELF file, and the file is at least 5 bytes
        !           220:         * long, so if it's an ELF file it has at least one
        !           221:         * byte past the ELF magic number - try extracting
        !           222:         * information from the ELF headers that cannot easily
        !           223:         * be extracted with rules in the magic file.
        !           224:         */
        !           225:        (void)file_tryelf(ms, fd, buf, nb);
        !           226:     }
        !           227: #endif
1.1       tedu      228:     return m;
                    229: }
1.5     ! chl       230: #endif
1.1       tedu      231:
                    232: protected int
                    233: file_reset(struct magic_set *ms)
                    234: {
                    235:        if (ms->mlist == NULL) {
                    236:                file_error(ms, 0, "no magic files loaded");
                    237:                return -1;
                    238:        }
                    239:        ms->o.ptr = ms->o.buf;
1.5     ! chl       240:        ms->o.left = ms->o.size;
1.1       tedu      241:        ms->haderr = 0;
                    242:        ms->error = -1;
                    243:        return 0;
                    244: }
                    245:
1.5     ! chl       246: #define OCTALIFY(n, o) \
        !           247:        /*LINTED*/ \
        !           248:        (void)(*(n)++ = '\\', \
        !           249:        *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
        !           250:        *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
        !           251:        *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
        !           252:        (o)++)
        !           253:
1.1       tedu      254: protected const char *
                    255: file_getbuffer(struct magic_set *ms)
                    256: {
1.4       dim       257:        char *pbuf, *op, *np;
                    258:        size_t psize, len;
1.1       tedu      259:
                    260:        if (ms->haderr)
                    261:                return NULL;
                    262:
                    263:        if (ms->flags & MAGIC_RAW)
                    264:                return ms->o.buf;
                    265:
1.4       dim       266:        len = ms->o.size - ms->o.left;
1.5     ! chl       267:        /* * 4 is for octal representation, + 1 is for NUL */
1.4       dim       268:        if (len > (SIZE_T_MAX - 1) / 4) {
1.5     ! chl       269:                file_oomem(ms, len);
1.4       dim       270:                return NULL;
                    271:        }
                    272:        psize = len * 4 + 1;
                    273:        if (ms->o.psize < psize) {
                    274:                if ((pbuf = realloc(ms->o.pbuf, psize)) == NULL) {
1.5     ! chl       275:                        file_oomem(ms, psize);
1.1       tedu      276:                        return NULL;
                    277:                }
1.4       dim       278:                ms->o.psize = psize;
                    279:                ms->o.pbuf = pbuf;
1.1       tedu      280:        }
                    281:
1.5     ! chl       282: #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
        !           283:        {
        !           284:                mbstate_t state;
        !           285:                wchar_t nextchar;
        !           286:                int mb_conv = 1;
        !           287:                size_t bytesconsumed;
        !           288:                char *eop;
        !           289:                (void)memset(&state, 0, sizeof(mbstate_t));
        !           290:
        !           291:                np = ms->o.pbuf;
        !           292:                op = ms->o.buf;
        !           293:                eop = op + strlen(ms->o.buf);
        !           294:
        !           295:                while (op < eop) {
        !           296:                        bytesconsumed = mbrtowc(&nextchar, op,
        !           297:                            (size_t)(eop - op), &state);
        !           298:                        if (bytesconsumed == (size_t)(-1) ||
        !           299:                            bytesconsumed == (size_t)(-2)) {
        !           300:                                mb_conv = 0;
        !           301:                                break;
        !           302:                        }
        !           303:
        !           304:                        if (iswprint(nextchar)) {
        !           305:                                (void)memcpy(np, op, bytesconsumed);
        !           306:                                op += bytesconsumed;
        !           307:                                np += bytesconsumed;
        !           308:                        } else {
        !           309:                                while (bytesconsumed-- > 0)
        !           310:                                        OCTALIFY(np, op);
        !           311:                        }
        !           312:                }
        !           313:                *np = '\0';
        !           314:
        !           315:                /* Parsing succeeded as a multi-byte sequence */
        !           316:                if (mb_conv != 0)
        !           317:                        return ms->o.pbuf;
        !           318:        }
        !           319: #endif
        !           320:
1.1       tedu      321:        for (np = ms->o.pbuf, op = ms->o.buf; *op; op++) {
                    322:                if (isprint((unsigned char)*op)) {
                    323:                        *np++ = *op;
                    324:                } else {
1.5     ! chl       325:                        OCTALIFY(np, op);
1.1       tedu      326:                }
                    327:        }
                    328:        *np = '\0';
                    329:        return ms->o.pbuf;
                    330: }
1.5     ! chl       331:
        !           332: protected int
        !           333: file_check_mem(struct magic_set *ms, unsigned int level)
        !           334: {
        !           335:        size_t len;
        !           336:
        !           337:        if (level >= ms->c.len) {
        !           338:                len = (ms->c.len += 20) * sizeof(*ms->c.li);
        !           339:                ms->c.li = (ms->c.li == NULL) ? malloc(len) :
        !           340:                    realloc(ms->c.li, len);
        !           341:                if (ms->c.li == NULL) {
        !           342:                        file_oomem(ms, len);
        !           343:                        return -1;
        !           344:                }
        !           345:        }
        !           346:        ms->c.li[level].got_match = 0;
        !           347: #ifdef ENABLE_CONDITIONALS
        !           348:        ms->c.li[level].last_match = 0;
        !           349:        ms->c.li[level].last_cond = COND_NONE;
        !           350: #endif /* ENABLE_CONDITIONALS */
        !           351:        return 0;
        !           352: }
        !           353: /*
        !           354:  * Yes these wrappers suffer from buffer overflows, but if your OS does not
        !           355:  * have the real functions, maybe you should consider replacing your OS?
        !           356:  */
        !           357: #ifndef HAVE_VSNPRINTF
        !           358: int
        !           359: vsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
        !           360: {
        !           361:        return vsprintf(buf, fmt, ap);
        !           362: }
        !           363: #endif
        !           364:
        !           365: #ifndef HAVE_SNPRINTF
        !           366: /*ARGSUSED*/
        !           367: int
        !           368: snprintf(char *buf, size_t len, const char *fmt, ...)
        !           369: {
        !           370:        int rv;
        !           371:        va_list ap;
        !           372:        va_start(ap, fmt);
        !           373:        rv = vsprintf(buf, fmt, ap);
        !           374:        va_end(ap);
        !           375:        return rv;
        !           376: }
        !           377: #endif