"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/funcs.c" (1 Oct 2018, 14168 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "funcs.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

    1 /*
    2  * Copyright (c) Christos Zoulas 2003.
    3  * All Rights Reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice immediately at the beginning of the file, without modification,
   10  *    this list of conditions, and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 #include "file.h"
   28 
   29 #ifndef lint
   30 FILE_RCSID("@(#)$File: funcs.c,v 1.100 2018/10/01 18:45:39 christos Exp $")
   31 #endif  /* lint */
   32 
   33 #include "magic.h"
   34 #include <assert.h>
   35 #include <stdarg.h>
   36 #include <stdlib.h>
   37 #include <string.h>
   38 #include <ctype.h>
   39 #if defined(HAVE_WCHAR_H)
   40 #include <wchar.h>
   41 #endif
   42 #if defined(HAVE_WCTYPE_H)
   43 #include <wctype.h>
   44 #endif
   45 #include <limits.h>
   46 
   47 #ifndef SIZE_MAX
   48 #define SIZE_MAX    ((size_t)~0)
   49 #endif
   50 
   51 /*
   52  * Like printf, only we append to a buffer.
   53  */
   54 protected int
   55 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap)
   56 {
   57     int len;
   58     char *buf, *newstr;
   59 
   60     if (ms->event_flags & EVENT_HAD_ERR)
   61         return 0;
   62     len = vasprintf(&buf, fmt, ap);
   63     if (len < 0)
   64         goto out;
   65 
   66     if (ms->o.buf != NULL) {
   67         len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
   68         free(buf);
   69         if (len < 0)
   70             goto out;
   71         free(ms->o.buf);
   72         buf = newstr;
   73     }
   74     ms->o.buf = buf;
   75     return 0;
   76 out:
   77     fprintf(stderr, "vasprintf failed (%s)", strerror(errno));
   78     return -1;
   79 }
   80 
   81 protected int
   82 file_printf(struct magic_set *ms, const char *fmt, ...)
   83 {
   84     int rv;
   85     va_list ap;
   86 
   87     va_start(ap, fmt);
   88     rv = file_vprintf(ms, fmt, ap);
   89     va_end(ap);
   90     return rv;
   91 }
   92 
   93 /*
   94  * error - print best error message possible
   95  */
   96 /*VARARGS*/
   97 __attribute__((__format__(__printf__, 3, 0)))
   98 private void
   99 file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
  100     size_t lineno)
  101 {
  102     /* Only the first error is ok */
  103     if (ms->event_flags & EVENT_HAD_ERR)
  104         return;
  105     if (lineno != 0) {
  106         free(ms->o.buf);
  107         ms->o.buf = NULL;
  108         (void)file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno);
  109     }
  110     if (ms->o.buf && *ms->o.buf)
  111         (void)file_printf(ms, " ");
  112     (void)file_vprintf(ms, f, va);
  113     if (error > 0)
  114         (void)file_printf(ms, " (%s)", strerror(error));
  115     ms->event_flags |= EVENT_HAD_ERR;
  116     ms->error = error;
  117 }
  118 
  119 /*VARARGS*/
  120 protected void
  121 file_error(struct magic_set *ms, int error, const char *f, ...)
  122 {
  123     va_list va;
  124     va_start(va, f);
  125     file_error_core(ms, error, f, va, 0);
  126     va_end(va);
  127 }
  128 
  129 /*
  130  * Print an error with magic line number.
  131  */
  132 /*VARARGS*/
  133 protected void
  134 file_magerror(struct magic_set *ms, const char *f, ...)
  135 {
  136     va_list va;
  137     va_start(va, f);
  138     file_error_core(ms, 0, f, va, ms->line);
  139     va_end(va);
  140 }
  141 
  142 protected void
  143 file_oomem(struct magic_set *ms, size_t len)
  144 {
  145     file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
  146         len);
  147 }
  148 
  149 protected void
  150 file_badseek(struct magic_set *ms)
  151 {
  152     file_error(ms, errno, "error seeking");
  153 }
  154 
  155 protected void
  156 file_badread(struct magic_set *ms)
  157 {
  158     file_error(ms, errno, "error reading");
  159 }
  160 
  161 #ifndef COMPILE_ONLY
  162 
  163 static int
  164 checkdone(struct magic_set *ms, int *rv)
  165 {
  166     if ((ms->flags & MAGIC_CONTINUE) == 0)
  167         return 1;
  168     if (file_printf(ms, "\n- ") == -1)
  169         *rv = -1;
  170     return 0;
  171 }
  172 
  173 protected int
  174 file_default(struct magic_set *ms, size_t nb)
  175 {
  176     if (ms->flags & MAGIC_MIME) {
  177         if ((ms->flags & MAGIC_MIME_TYPE) &&
  178             file_printf(ms, "application/%s",
  179             nb ? "octet-stream" : "x-empty") == -1)
  180             return -1;
  181         return 1;
  182     }
  183     if (ms->flags & MAGIC_APPLE) {
  184         if (file_printf(ms, "UNKNUNKN") == -1)
  185             return -1;
  186         return 1;
  187     }
  188     if (ms->flags & MAGIC_EXTENSION) {
  189         if (file_printf(ms, "???") == -1)
  190             return -1;
  191         return 1;
  192     }
  193     return 0;
  194 }
  195 
  196 /*
  197  * The magic detection functions return:
  198  *   1: found
  199  *   0: not found
  200  *  -1: error
  201  */
  202 /*ARGSUSED*/
  203 protected int
  204 file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__unused__)),
  205     const void *buf, size_t nb)
  206 {
  207     int m = 0, rv = 0, looks_text = 0;
  208     const char *code = NULL;
  209     const char *code_mime = "binary";
  210     const char *def = "data";
  211     const char *ftype = NULL;
  212     char *rbuf = NULL;
  213     struct buffer b;
  214 
  215     buffer_init(&b, fd, buf, nb);
  216     ms->mode = b.st.st_mode;
  217 
  218     if (nb == 0) {
  219         def = "empty";
  220         goto simple;
  221     } else if (nb == 1) {
  222         def = "very short file (no magic)";
  223         goto simple;
  224     }
  225 
  226     if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
  227         looks_text = file_encoding(ms, &b, NULL, 0,
  228             &code, &code_mime, &ftype);
  229     }
  230 
  231 #ifdef __EMX__
  232     if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
  233         m = file_os2_apptype(ms, inname, &b);
  234         if ((ms->flags & MAGIC_DEBUG) != 0)
  235             (void)fprintf(stderr, "[try os2_apptype %d]\n", m);
  236         switch (m) {
  237         case -1:
  238             return -1;
  239         case 0:
  240             break;
  241         default:
  242             return 1;
  243         }
  244     }
  245 #endif
  246 #if HAVE_FORK
  247     /* try compression stuff */
  248     if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) {
  249         m = file_zmagic(ms, &b, inname);
  250         if ((ms->flags & MAGIC_DEBUG) != 0)
  251             (void)fprintf(stderr, "[try zmagic %d]\n", m);
  252         if (m) {
  253             goto done_encoding;
  254         }
  255     }
  256 #endif
  257     /* Check if we have a tar file */
  258     if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) {
  259         m = file_is_tar(ms, &b);
  260         if ((ms->flags & MAGIC_DEBUG) != 0)
  261             (void)fprintf(stderr, "[try tar %d]\n", m);
  262         if (m) {
  263             if (checkdone(ms, &rv))
  264                 goto done;
  265         }
  266     }
  267 
  268     /* Check if we have a JSON file */
  269     if ((ms->flags & MAGIC_NO_CHECK_JSON) == 0) {
  270         m = file_is_json(ms, &b);
  271         if ((ms->flags & MAGIC_DEBUG) != 0)
  272             (void)fprintf(stderr, "[try json %d]\n", m);
  273         if (m) {
  274             if (checkdone(ms, &rv))
  275                 goto done;
  276         }
  277     }
  278 
  279     /* Check if we have a CDF file */
  280     if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
  281         m = file_trycdf(ms, &b);
  282         if ((ms->flags & MAGIC_DEBUG) != 0)
  283             (void)fprintf(stderr, "[try cdf %d]\n", m);
  284         if (m) {
  285             if (checkdone(ms, &rv))
  286                 goto done;
  287         }
  288     }
  289 #ifdef BUILTIN_ELF
  290     if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) {
  291         file_pushbuf_t *pb;
  292         /*
  293          * We matched something in the file, so this
  294          * *might* be an ELF file, and the file is at
  295          * least 5 bytes long, so if it's an ELF file
  296          * it has at least one byte past the ELF magic
  297          * number - try extracting information from the
  298          * ELF headers that cannot easily be  extracted
  299          * with rules in the magic file. We we don't
  300          * print the information yet.
  301          */
  302         if ((pb = file_push_buffer(ms)) == NULL)
  303             return -1;
  304 
  305         rv = file_tryelf(ms, &b);
  306         rbuf = file_pop_buffer(ms, pb);
  307         if (rv == -1) {
  308             free(rbuf);
  309             rbuf = NULL;
  310         }
  311         if ((ms->flags & MAGIC_DEBUG) != 0)
  312             (void)fprintf(stderr, "[try elf %d]\n", m);
  313     }
  314 #endif
  315 
  316     /* try soft magic tests */
  317     if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
  318         m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text);
  319         if ((ms->flags & MAGIC_DEBUG) != 0)
  320             (void)fprintf(stderr, "[try softmagic %d]\n", m);
  321         if (m == 1 && rbuf) {
  322             if (file_printf(ms, "%s", rbuf) == -1)
  323                 goto done;
  324         }
  325         if (m) {
  326             if (checkdone(ms, &rv))
  327                 goto done;
  328         }
  329     }
  330 
  331     /* try text properties */
  332     if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
  333 
  334         m = file_ascmagic(ms, &b, looks_text);
  335         if ((ms->flags & MAGIC_DEBUG) != 0)
  336             (void)fprintf(stderr, "[try ascmagic %d]\n", m);
  337         if (m) {
  338             if (checkdone(ms, &rv))
  339                 goto done;
  340         }
  341     }
  342 
  343 simple:
  344     /* give up */
  345     if (m == 0) {
  346         m = 1;
  347         rv = file_default(ms, nb);
  348         if (rv == 0)
  349             if (file_printf(ms, "%s", def) == -1)
  350                 rv = -1;
  351     }
  352  done:
  353     if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
  354         if (ms->flags & MAGIC_MIME_TYPE)
  355             if (file_printf(ms, "; charset=") == -1)
  356                 rv = -1;
  357         if (file_printf(ms, "%s", code_mime) == -1)
  358             rv = -1;
  359     }
  360 #if HAVE_FORK
  361  done_encoding:
  362 #endif
  363     free(rbuf);
  364     buffer_fini(&b);
  365     if (rv)
  366         return rv;
  367 
  368     return m;
  369 }
  370 #endif
  371 
  372 protected int
  373 file_reset(struct magic_set *ms, int checkloaded)
  374 {
  375     if (checkloaded && ms->mlist[0] == NULL) {
  376         file_error(ms, 0, "no magic files loaded");
  377         return -1;
  378     }
  379     if (ms->o.buf) {
  380         free(ms->o.buf);
  381         ms->o.buf = NULL;
  382     }
  383     if (ms->o.pbuf) {
  384         free(ms->o.pbuf);
  385         ms->o.pbuf = NULL;
  386     }
  387     ms->event_flags &= ~EVENT_HAD_ERR;
  388     ms->error = -1;
  389     return 0;
  390 }
  391 
  392 #define OCTALIFY(n, o)  \
  393     /*LINTED*/ \
  394     (void)(*(n)++ = '\\', \
  395     *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
  396     *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
  397     *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
  398     (o)++)
  399 
  400 protected const char *
  401 file_getbuffer(struct magic_set *ms)
  402 {
  403     char *pbuf, *op, *np;
  404     size_t psize, len;
  405 
  406     if (ms->event_flags & EVENT_HAD_ERR)
  407         return NULL;
  408 
  409     if (ms->flags & MAGIC_RAW)
  410         return ms->o.buf;
  411 
  412     if (ms->o.buf == NULL)
  413         return NULL;
  414 
  415     /* * 4 is for octal representation, + 1 is for NUL */
  416     len = strlen(ms->o.buf);
  417     if (len > (SIZE_MAX - 1) / 4) {
  418         file_oomem(ms, len);
  419         return NULL;
  420     }
  421     psize = len * 4 + 1;
  422     if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) {
  423         file_oomem(ms, psize);
  424         return NULL;
  425     }
  426     ms->o.pbuf = pbuf;
  427 
  428 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
  429     {
  430         mbstate_t state;
  431         wchar_t nextchar;
  432         int mb_conv = 1;
  433         size_t bytesconsumed;
  434         char *eop;
  435         (void)memset(&state, 0, sizeof(mbstate_t));
  436 
  437         np = ms->o.pbuf;
  438         op = ms->o.buf;
  439         eop = op + len;
  440 
  441         while (op < eop) {
  442             bytesconsumed = mbrtowc(&nextchar, op,
  443                 (size_t)(eop - op), &state);
  444             if (bytesconsumed == (size_t)(-1) ||
  445                 bytesconsumed == (size_t)(-2)) {
  446                 mb_conv = 0;
  447                 break;
  448             }
  449 
  450             if (iswprint(nextchar)) {
  451                 (void)memcpy(np, op, bytesconsumed);
  452                 op += bytesconsumed;
  453                 np += bytesconsumed;
  454             } else {
  455                 while (bytesconsumed-- > 0)
  456                     OCTALIFY(np, op);
  457             }
  458         }
  459         *np = '\0';
  460 
  461         /* Parsing succeeded as a multi-byte sequence */
  462         if (mb_conv != 0)
  463             return ms->o.pbuf;
  464     }
  465 #endif
  466 
  467     for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
  468         if (isprint((unsigned char)*op)) {
  469             *np++ = *op++;
  470         } else {
  471             OCTALIFY(np, op);
  472         }
  473     }
  474     *np = '\0';
  475     return ms->o.pbuf;
  476 }
  477 
  478 protected int
  479 file_check_mem(struct magic_set *ms, unsigned int level)
  480 {
  481     size_t len;
  482 
  483     if (level >= ms->c.len) {
  484         len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
  485         ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
  486             malloc(len) :
  487             realloc(ms->c.li, len));
  488         if (ms->c.li == NULL) {
  489             file_oomem(ms, len);
  490             return -1;
  491         }
  492     }
  493     ms->c.li[level].got_match = 0;
  494 #ifdef ENABLE_CONDITIONALS
  495     ms->c.li[level].last_match = 0;
  496     ms->c.li[level].last_cond = COND_NONE;
  497 #endif /* ENABLE_CONDITIONALS */
  498     return 0;
  499 }
  500 
  501 protected size_t
  502 file_printedlen(const struct magic_set *ms)
  503 {
  504     return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
  505 }
  506 
  507 protected int
  508 file_replace(struct magic_set *ms, const char *pat, const char *rep)
  509 {
  510     file_regex_t rx;
  511     int rc, rv = -1;
  512 
  513     rc = file_regcomp(&rx, pat, REG_EXTENDED);
  514     if (rc) {
  515         file_regerror(&rx, rc, ms);
  516     } else {
  517         regmatch_t rm;
  518         int nm = 0;
  519         while (file_regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) {
  520             ms->o.buf[rm.rm_so] = '\0';
  521             if (file_printf(ms, "%s%s", rep,
  522                 rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1)
  523                 goto out;
  524             nm++;
  525         }
  526         rv = nm;
  527     }
  528 out:
  529     file_regfree(&rx);
  530     return rv;
  531 }
  532 
  533 protected int
  534 file_regcomp(file_regex_t *rx, const char *pat, int flags)
  535 {
  536 #ifdef USE_C_LOCALE
  537     rx->c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
  538     assert(rx->c_lc_ctype != NULL);
  539     rx->old_lc_ctype = uselocale(rx->c_lc_ctype);
  540     assert(rx->old_lc_ctype != NULL);
  541 #else
  542     rx->old_lc_ctype = setlocale(LC_CTYPE, "C");
  543 #endif
  544     rx->pat = pat;
  545 
  546     return rx->rc = regcomp(&rx->rx, pat, flags);
  547 }
  548 
  549 protected int
  550 file_regexec(file_regex_t *rx, const char *str, size_t nmatch,
  551     regmatch_t* pmatch, int eflags)
  552 {
  553     assert(rx->rc == 0);
  554     /* XXX: force initialization because glibc does not always do this */
  555     memset(pmatch, 0, nmatch * sizeof(*pmatch));
  556     return regexec(&rx->rx, str, nmatch, pmatch, eflags);
  557 }
  558 
  559 protected void
  560 file_regfree(file_regex_t *rx)
  561 {
  562     if (rx->rc == 0)
  563         regfree(&rx->rx);
  564 #ifdef USE_C_LOCALE
  565     (void)uselocale(rx->old_lc_ctype);
  566     freelocale(rx->c_lc_ctype);
  567 #else
  568     (void)setlocale(LC_CTYPE, rx->old_lc_ctype);
  569 #endif
  570 }
  571 
  572 protected void
  573 file_regerror(file_regex_t *rx, int rc, struct magic_set *ms)
  574 {
  575     char errmsg[512];
  576 
  577     (void)regerror(rc, &rx->rx, errmsg, sizeof(errmsg));
  578     file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat,
  579         errmsg);
  580 }
  581 
  582 protected file_pushbuf_t *
  583 file_push_buffer(struct magic_set *ms)
  584 {
  585     file_pushbuf_t *pb;
  586 
  587     if (ms->event_flags & EVENT_HAD_ERR)
  588         return NULL;
  589 
  590     if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
  591         return NULL;
  592 
  593     pb->buf = ms->o.buf;
  594     pb->offset = ms->offset;
  595 
  596     ms->o.buf = NULL;
  597     ms->offset = 0;
  598 
  599     return pb;
  600 }
  601 
  602 protected char *
  603 file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
  604 {
  605     char *rbuf;
  606 
  607     if (ms->event_flags & EVENT_HAD_ERR) {
  608         free(pb->buf);
  609         free(pb);
  610         return NULL;
  611     }
  612 
  613     rbuf = ms->o.buf;
  614 
  615     ms->o.buf = pb->buf;
  616     ms->offset = pb->offset;
  617 
  618     free(pb);
  619     return rbuf;
  620 }
  621 
  622 /*
  623  * convert string to ascii printable format.
  624  */
  625 protected char *
  626 file_printable(char *buf, size_t bufsiz, const char *str)
  627 {
  628     char *ptr, *eptr;
  629     const unsigned char *s = (const unsigned char *)str;
  630 
  631     for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
  632         if (isprint(*s)) {
  633             *ptr++ = *s;
  634             continue;
  635         }
  636         if (ptr >= eptr - 3)
  637             break;
  638         *ptr++ = '\\';
  639         *ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
  640         *ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
  641         *ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
  642     }
  643     *ptr = '\0';
  644     return buf;
  645 }