Annotation of embedaddon/php/ext/fileinfo/libmagic/apprentice.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) Ian F. Darwin 1986-1995.
! 3: * Software written by Ian F. Darwin and others;
! 4: * maintained 1995-present by Christos Zoulas and others.
! 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: * apprentice - make one pass through /etc/magic, learning its secrets.
! 30: */
! 31:
! 32: #include "php.h"
! 33:
! 34: #include "file.h"
! 35:
! 36: #ifndef lint
! 37: FILE_RCSID("@(#)$File: apprentice.c,v 1.151 2009/03/18 15:19:23 christos Exp $")
! 38: #endif /* lint */
! 39:
! 40: #include "magic.h"
! 41: #include "patchlevel.h"
! 42: #include <stdlib.h>
! 43:
! 44: #if defined(__hpux) && !defined(HAVE_STRTOULL)
! 45: #if SIZEOF_LONG == 8
! 46: # define strtoull strtoul
! 47: #else
! 48: # define strtoull __strtoull
! 49: #endif
! 50: #endif
! 51:
! 52: #ifdef PHP_WIN32
! 53: #include "win32/unistd.h"
! 54: #if _MSC_VER <= 1300
! 55: # include "win32/php_strtoi64.h"
! 56: #endif
! 57: #define strtoull _strtoui64
! 58: #else
! 59: #include <unistd.h>
! 60: #endif
! 61:
! 62: #include <string.h>
! 63: #include <assert.h>
! 64: #include <ctype.h>
! 65: #include <fcntl.h>
! 66: #ifndef PHP_WIN32
! 67: #include <dirent.h>
! 68: #endif
! 69:
! 70: #define EATAB {while (isascii((unsigned char) *l) && \
! 71: isspace((unsigned char) *l)) ++l;}
! 72: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
! 73: tolower((unsigned char) (l)) : (l))
! 74: /*
! 75: * Work around a bug in headers on Digital Unix.
! 76: * At least confirmed for: OSF1 V4.0 878
! 77: */
! 78: #if defined(__osf__) && defined(__DECC)
! 79: #ifdef MAP_FAILED
! 80: #undef MAP_FAILED
! 81: #endif
! 82: #endif
! 83:
! 84: #ifndef MAP_FAILED
! 85: #define MAP_FAILED (void *) -1
! 86: #endif
! 87:
! 88: #ifndef MAP_FILE
! 89: #define MAP_FILE 0
! 90: #endif
! 91:
! 92: #ifndef MAXPATHLEN
! 93: #define MAXPATHLEN 1024
! 94: #endif
! 95:
! 96: struct magic_entry {
! 97: struct magic *mp;
! 98: uint32_t cont_count;
! 99: uint32_t max_count;
! 100: };
! 101:
! 102: int file_formats[FILE_NAMES_SIZE];
! 103: const size_t file_nformats = FILE_NAMES_SIZE;
! 104: const char *file_names[FILE_NAMES_SIZE];
! 105: const size_t file_nnames = FILE_NAMES_SIZE;
! 106:
! 107: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
! 108: private int hextoint(int);
! 109: private const char *getstr(struct magic_set *, struct magic *, const char *,
! 110: int);
! 111: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
! 112: const char *, size_t, int);
! 113: private void eatsize(const char **);
! 114: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
! 115: private size_t apprentice_magic_strength(const struct magic *);
! 116: private int apprentice_sort(const void *, const void *);
! 117: private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
! 118: const char *, int);
! 119: private void byteswap(struct magic *, uint32_t);
! 120: private void bs1(struct magic *);
! 121: private uint16_t swap2(uint16_t);
! 122: private uint32_t swap4(uint32_t);
! 123: private uint64_t swap8(uint64_t);
! 124: private char *mkdbname(struct magic_set *, const char *, int);
! 125: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
! 126: const char *);
! 127: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
! 128: const char *);
! 129: private int check_format_type(const char *, int);
! 130: private int check_format(struct magic_set *, struct magic *);
! 131: private int get_op(char);
! 132: private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
! 133: private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
! 134: private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
! 135:
! 136: private size_t maxmagic = 0;
! 137: private size_t magicsize = sizeof(struct magic);
! 138:
! 139: private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
! 140: private struct {
! 141: const char *name;
! 142: size_t len;
! 143: int (*fun)(struct magic_set *, struct magic_entry *, const char *);
! 144: } bang[] = {
! 145: #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
! 146: DECLARE_FIELD(mime),
! 147: DECLARE_FIELD(apple),
! 148: DECLARE_FIELD(strength),
! 149: #undef DECLARE_FIELD
! 150: { NULL, 0, NULL }
! 151: };
! 152:
! 153: #include "../data_file.c"
! 154:
! 155: static const struct type_tbl_s {
! 156: const char name[16];
! 157: const size_t len;
! 158: const int type;
! 159: const int format;
! 160: } type_tbl[] = {
! 161: # define XX(s) s, (sizeof(s) - 1)
! 162: # define XX_NULL "", 0
! 163: { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
! 164: { XX("short"), FILE_SHORT, FILE_FMT_NUM },
! 165: { XX("default"), FILE_DEFAULT, FILE_FMT_STR },
! 166: { XX("long"), FILE_LONG, FILE_FMT_NUM },
! 167: { XX("string"), FILE_STRING, FILE_FMT_STR },
! 168: { XX("date"), FILE_DATE, FILE_FMT_STR },
! 169: { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
! 170: { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
! 171: { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
! 172: { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
! 173: { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
! 174: { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
! 175: { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
! 176: { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
! 177: { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
! 178: { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
! 179: { XX("regex"), FILE_REGEX, FILE_FMT_STR },
! 180: { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
! 181: { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
! 182: { XX("search"), FILE_SEARCH, FILE_FMT_STR },
! 183: { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
! 184: { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
! 185: { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
! 186: { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
! 187: { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
! 188: { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
! 189: { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
! 190: { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
! 191: { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
! 192: { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
! 193: { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
! 194: { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
! 195: { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT },
! 196: { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT },
! 197: { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT },
! 198: { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE },
! 199: { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE },
! 200: { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE },
! 201: { XX("leid3"), FILE_LEID3, FILE_FMT_NUM },
! 202: { XX("beid3"), FILE_BEID3, FILE_FMT_NUM },
! 203: { XX("indirect"), FILE_INDIRECT, FILE_FMT_NONE },
! 204: { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
! 205: # undef XX
! 206: # undef XX_NULL
! 207: };
! 208:
! 209: #ifndef S_ISDIR
! 210: #define S_ISDIR(mode) ((mode) & _S_IFDIR)
! 211: #endif
! 212:
! 213: private int
! 214: get_type(const char *l, const char **t)
! 215: {
! 216: const struct type_tbl_s *p;
! 217:
! 218: for (p = type_tbl; p->len; p++) {
! 219: if (strncmp(l, p->name, p->len) == 0) {
! 220: if (t)
! 221: *t = l + p->len;
! 222: break;
! 223: }
! 224: }
! 225: return p->type;
! 226: }
! 227:
! 228: private void
! 229: init_file_tables(void)
! 230: {
! 231: static int done = 0;
! 232: const struct type_tbl_s *p;
! 233:
! 234: if (done)
! 235: return;
! 236: done++;
! 237:
! 238: for (p = type_tbl; p->len; p++) {
! 239: assert(p->type < FILE_NAMES_SIZE);
! 240: file_names[p->type] = p->name;
! 241: file_formats[p->type] = p->format;
! 242: }
! 243: }
! 244:
! 245: /*
! 246: * Handle one file or directory.
! 247: */
! 248: private int
! 249: apprentice_1(struct magic_set *ms, const char *fn, int action,
! 250: struct mlist *mlist)
! 251: {
! 252: struct magic *magic = NULL;
! 253: uint32_t nmagic = 0;
! 254: struct mlist *ml;
! 255: int rv = -1;
! 256: int mapped;
! 257:
! 258: if (magicsize != FILE_MAGICSIZE) {
! 259: file_error(ms, 0, "magic element size %lu != %lu",
! 260: (unsigned long)sizeof(*magic),
! 261: (unsigned long)FILE_MAGICSIZE);
! 262: return -1;
! 263: }
! 264:
! 265: if (action == FILE_COMPILE) {
! 266: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
! 267: if (rv != 0)
! 268: return -1;
! 269: rv = apprentice_compile(ms, &magic, &nmagic, fn);
! 270: efree(magic);
! 271: return rv;
! 272: }
! 273:
! 274: if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
! 275: if (fn) {
! 276: if (ms->flags & MAGIC_CHECK)
! 277: file_magwarn(ms, "using regular magic file `%s'", fn);
! 278: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
! 279: }
! 280:
! 281: if (rv != 0)
! 282: return -1;
! 283: }
! 284:
! 285: mapped = rv;
! 286:
! 287: if (magic == NULL) {
! 288: file_delmagic(magic, mapped, nmagic);
! 289: return -1;
! 290: }
! 291:
! 292: ml = emalloc(sizeof(*ml));
! 293:
! 294: ml->magic = magic;
! 295: ml->nmagic = nmagic;
! 296: ml->mapped = mapped;
! 297:
! 298: mlist->prev->next = ml;
! 299: ml->prev = mlist->prev;
! 300: ml->next = mlist;
! 301: mlist->prev = ml;
! 302:
! 303: return 0;
! 304: }
! 305:
! 306: protected void
! 307: file_delmagic(struct magic *p, int type, size_t entries)
! 308: {
! 309: if (p == NULL)
! 310: return;
! 311: switch (type) {
! 312: case 3:
! 313: /* Do nothing, it's part of the code segment */
! 314: break;
! 315:
! 316: case 1:
! 317: p--;
! 318: /*FALLTHROUGH*/
! 319:
! 320: case 0:
! 321: efree(p);
! 322: break;
! 323:
! 324: default:
! 325: abort();
! 326: }
! 327: }
! 328:
! 329: /* const char *fn: list of magic files and directories */
! 330: protected struct mlist *
! 331: file_apprentice(struct magic_set *ms, const char *fn, int action)
! 332: {
! 333: char *p, *mfn;
! 334: int file_err, errs = -1;
! 335: struct mlist *mlist;
! 336:
! 337: init_file_tables();
! 338:
! 339: if (fn == NULL)
! 340: fn = getenv("MAGIC");
! 341: if (fn == NULL) {
! 342: mlist = emalloc(sizeof(*mlist));
! 343: mlist->next = mlist->prev = mlist;
! 344: apprentice_1(ms, fn, action, mlist);
! 345: return mlist;
! 346: }
! 347:
! 348: mfn = estrdup(fn);
! 349: fn = mfn;
! 350:
! 351: mlist = emalloc(sizeof(*mlist));
! 352: mlist->next = mlist->prev = mlist;
! 353:
! 354: while (fn) {
! 355: p = strchr(fn, PATHSEP);
! 356: if (p)
! 357: *p++ = '\0';
! 358: if (*fn == '\0')
! 359: break;
! 360: file_err = apprentice_1(ms, fn, action, mlist);
! 361: errs = MAX(errs, file_err);
! 362: fn = p;
! 363: }
! 364: if (errs == -1) {
! 365: efree(mfn);
! 366: efree(mlist);
! 367: mlist = NULL;
! 368: file_error(ms, 0, "could not find any magic files!");
! 369: return NULL;
! 370: }
! 371: efree(mfn);
! 372: return mlist;
! 373: }
! 374:
! 375: /*
! 376: * Get weight of this magic entry, for sorting purposes.
! 377: */
! 378: private size_t
! 379: apprentice_magic_strength(const struct magic *m)
! 380: {
! 381: #define MULT 10
! 382: size_t val = 2 * MULT; /* baseline strength */
! 383:
! 384: switch (m->type) {
! 385: case FILE_DEFAULT: /* make sure this sorts last */
! 386: if (m->factor_op != FILE_FACTOR_OP_NONE)
! 387: abort();
! 388: return 0;
! 389:
! 390: case FILE_BYTE:
! 391: val += 1 * MULT;
! 392: break;
! 393:
! 394: case FILE_SHORT:
! 395: case FILE_LESHORT:
! 396: case FILE_BESHORT:
! 397: val += 2 * MULT;
! 398: break;
! 399:
! 400: case FILE_LONG:
! 401: case FILE_LELONG:
! 402: case FILE_BELONG:
! 403: case FILE_MELONG:
! 404: val += 4 * MULT;
! 405: break;
! 406:
! 407: case FILE_PSTRING:
! 408: case FILE_STRING:
! 409: val += m->vallen * MULT;
! 410: break;
! 411:
! 412: case FILE_BESTRING16:
! 413: case FILE_LESTRING16:
! 414: val += m->vallen * MULT / 2;
! 415: break;
! 416:
! 417: case FILE_SEARCH:
! 418: case FILE_REGEX:
! 419: val += m->vallen * MAX(MULT / m->vallen, 1);
! 420: break;
! 421:
! 422: case FILE_DATE:
! 423: case FILE_LEDATE:
! 424: case FILE_BEDATE:
! 425: case FILE_MEDATE:
! 426: case FILE_LDATE:
! 427: case FILE_LELDATE:
! 428: case FILE_BELDATE:
! 429: case FILE_MELDATE:
! 430: case FILE_FLOAT:
! 431: case FILE_BEFLOAT:
! 432: case FILE_LEFLOAT:
! 433: val += 4 * MULT;
! 434: break;
! 435:
! 436: case FILE_QUAD:
! 437: case FILE_BEQUAD:
! 438: case FILE_LEQUAD:
! 439: case FILE_QDATE:
! 440: case FILE_LEQDATE:
! 441: case FILE_BEQDATE:
! 442: case FILE_QLDATE:
! 443: case FILE_LEQLDATE:
! 444: case FILE_BEQLDATE:
! 445: case FILE_DOUBLE:
! 446: case FILE_BEDOUBLE:
! 447: case FILE_LEDOUBLE:
! 448: val += 8 * MULT;
! 449: break;
! 450:
! 451: default:
! 452: val = 0;
! 453: (void)fprintf(stderr, "Bad type %d\n", m->type);
! 454: abort();
! 455: }
! 456:
! 457: switch (m->reln) {
! 458: case 'x': /* matches anything penalize */
! 459: case '!': /* matches almost anything penalize */
! 460: val = 0;
! 461: break;
! 462:
! 463: case '=': /* Exact match, prefer */
! 464: val += MULT;
! 465: break;
! 466:
! 467: case '>':
! 468: case '<': /* comparison match reduce strength */
! 469: val -= 2 * MULT;
! 470: break;
! 471:
! 472: case '^':
! 473: case '&': /* masking bits, we could count them too */
! 474: val -= MULT;
! 475: break;
! 476:
! 477: default:
! 478: (void)fprintf(stderr, "Bad relation %c\n", m->reln);
! 479: abort();
! 480: }
! 481:
! 482: if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
! 483: val = 1;
! 484:
! 485: switch (m->factor_op) {
! 486: case FILE_FACTOR_OP_NONE:
! 487: break;
! 488: case FILE_FACTOR_OP_PLUS:
! 489: val += m->factor;
! 490: break;
! 491: case FILE_FACTOR_OP_MINUS:
! 492: val -= m->factor;
! 493: break;
! 494: case FILE_FACTOR_OP_TIMES:
! 495: val *= m->factor;
! 496: break;
! 497: case FILE_FACTOR_OP_DIV:
! 498: val /= m->factor;
! 499: break;
! 500: default:
! 501: abort();
! 502: }
! 503:
! 504:
! 505: /*
! 506: * Magic entries with no description get a bonus because they depend
! 507: * on subsequent magic entries to print something.
! 508: */
! 509: if (m->desc[0] == '\0')
! 510: val++;
! 511: return val;
! 512: }
! 513:
! 514: /*
! 515: * Sort callback for sorting entries by "strength" (basically length)
! 516: */
! 517: private int
! 518: apprentice_sort(const void *a, const void *b)
! 519: {
! 520: const struct magic_entry *ma = a;
! 521: const struct magic_entry *mb = b;
! 522: size_t sa = apprentice_magic_strength(ma->mp);
! 523: size_t sb = apprentice_magic_strength(mb->mp);
! 524: if (sa == sb)
! 525: return 0;
! 526: else if (sa > sb)
! 527: return -1;
! 528: else
! 529: return 1;
! 530: }
! 531:
! 532: private void
! 533: set_test_type(struct magic *mstart, struct magic *m)
! 534: {
! 535: switch (m->type) {
! 536: case FILE_BYTE:
! 537: case FILE_SHORT:
! 538: case FILE_LONG:
! 539: case FILE_DATE:
! 540: case FILE_BESHORT:
! 541: case FILE_BELONG:
! 542: case FILE_BEDATE:
! 543: case FILE_LESHORT:
! 544: case FILE_LELONG:
! 545: case FILE_LEDATE:
! 546: case FILE_LDATE:
! 547: case FILE_BELDATE:
! 548: case FILE_LELDATE:
! 549: case FILE_MEDATE:
! 550: case FILE_MELDATE:
! 551: case FILE_MELONG:
! 552: case FILE_QUAD:
! 553: case FILE_LEQUAD:
! 554: case FILE_BEQUAD:
! 555: case FILE_QDATE:
! 556: case FILE_LEQDATE:
! 557: case FILE_BEQDATE:
! 558: case FILE_QLDATE:
! 559: case FILE_LEQLDATE:
! 560: case FILE_BEQLDATE:
! 561: case FILE_FLOAT:
! 562: case FILE_BEFLOAT:
! 563: case FILE_LEFLOAT:
! 564: case FILE_DOUBLE:
! 565: case FILE_BEDOUBLE:
! 566: case FILE_LEDOUBLE:
! 567: case FILE_STRING:
! 568: case FILE_PSTRING:
! 569: case FILE_BESTRING16:
! 570: case FILE_LESTRING16:
! 571: /* binary test, set flag */
! 572: mstart->flag |= BINTEST;
! 573: break;
! 574: case FILE_REGEX:
! 575: case FILE_SEARCH:
! 576: /* binary test if pattern is not text */
! 577: if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
! 578: NULL) <= 0)
! 579: mstart->flag |= BINTEST;
! 580: break;
! 581: case FILE_DEFAULT:
! 582: /* can't deduce anything; we shouldn't see this at the
! 583: top level anyway */
! 584: break;
! 585: case FILE_INVALID:
! 586: default:
! 587: /* invalid search type, but no need to complain here */
! 588: break;
! 589: }
! 590: }
! 591:
! 592: /*
! 593: * Load and parse one file.
! 594: */
! 595: private void
! 596: load_1(struct magic_set *ms, int action, const char *fn, int *errs,
! 597: struct magic_entry **marray, uint32_t *marraycount)
! 598: {
! 599: char buffer[BUFSIZ + 1];
! 600: char *line;
! 601: size_t line_len;
! 602: size_t lineno = 0;
! 603:
! 604: php_stream *stream;
! 605:
! 606: TSRMLS_FETCH();
! 607:
! 608: #if PHP_API_VERSION < 20100412
! 609: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
! 610: #else
! 611: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
! 612: #endif
! 613:
! 614: if (stream == NULL) {
! 615: if (errno != ENOENT)
! 616: file_error(ms, errno, "cannot read magic file `%s'",
! 617: fn);
! 618: (*errs)++;
! 619: } else {
! 620:
! 621: /* read and parse this file */
! 622: #if (PHP_MAJOR_VERSION < 6)
! 623: for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &line_len)) != NULL; ms->line++) {
! 624: #else
! 625: for (ms->line = 1; (line = php_stream_get_line(stream, ZSTR(buffer), BUFSIZ, &line_len)) != NULL; ms->line++) {
! 626: #endif
! 627: if (line_len == 0) /* null line, garbage, etc */
! 628: continue;
! 629:
! 630: if (line[line_len - 1] == '\n') {
! 631: lineno++;
! 632: line[line_len - 1] = '\0'; /* delete newline */
! 633: }
! 634: if (line[0] == '\0') /* empty, do not parse */
! 635: continue;
! 636: if (line[0] == '#') /* comment, do not parse */
! 637: continue;
! 638:
! 639: if (line[0] == '!' && line[1] == ':') {
! 640: size_t i;
! 641:
! 642: for (i = 0; bang[i].name != NULL; i++) {
! 643: if (line_len - 2 > bang[i].len &&
! 644: memcmp(bang[i].name, line + 2,
! 645: bang[i].len) == 0)
! 646: break;
! 647: }
! 648: if (bang[i].name == NULL) {
! 649: file_error(ms, 0,
! 650: "Unknown !: entry `%s'", line);
! 651: (*errs)++;
! 652: continue;
! 653: }
! 654: if (*marraycount == 0) {
! 655: file_error(ms, 0,
! 656: "No current entry for :!%s type",
! 657: bang[i].name);
! 658: (*errs)++;
! 659: continue;
! 660: }
! 661: if ((*bang[i].fun)(ms,
! 662: &(*marray)[*marraycount - 1],
! 663: line + bang[i].len + 2) != 0) {
! 664: (*errs)++;
! 665: continue;
! 666: }
! 667: continue;
! 668: }
! 669: if (parse(ms, marray, marraycount, line, lineno, action) != 0)
! 670: (*errs)++;
! 671: }
! 672:
! 673: php_stream_close(stream);
! 674: }
! 675: }
! 676:
! 677: /*
! 678: * parse a file or directory of files
! 679: * const char *fn: name of magic file or directory
! 680: */
! 681: private int
! 682: apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
! 683: const char *fn, int action)
! 684: {
! 685: int errs = 0;
! 686: struct magic_entry *marray;
! 687: uint32_t marraycount, i, mentrycount = 0, starttest;
! 688: char subfn[MAXPATHLEN];
! 689: struct stat st;
! 690: DIR *dir;
! 691: struct dirent *d;
! 692:
! 693: ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
! 694:
! 695: maxmagic = MAXMAGIS;
! 696: marray = ecalloc(maxmagic, sizeof(*marray));
! 697: marraycount = 0;
! 698:
! 699: /* print silly verbose header for USG compat. */
! 700: if (action == FILE_CHECK)
! 701: (void)fprintf(stderr, "%s\n", usg_hdr);
! 702:
! 703: /* load directory or file */
! 704: /* FIXME: Read file names and sort them to prevent
! 705: non-determinism. See Debian bug #488562. */
! 706: if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
! 707: dir = opendir(fn);
! 708: if (dir) {
! 709: while ((d = readdir(dir)) != NULL) {
! 710: snprintf(subfn, sizeof(subfn), "%s/%s",
! 711: fn, d->d_name);
! 712: if (stat(subfn, &st) == 0 &&
! 713: S_ISREG(st.st_mode)) {
! 714: load_1(ms, action, subfn, &errs,
! 715: &marray, &marraycount);
! 716: }
! 717: }
! 718: closedir(dir);
! 719: } else
! 720: errs++;
! 721: } else
! 722: load_1(ms, action, fn, &errs, &marray, &marraycount);
! 723: if (errs)
! 724: goto out;
! 725:
! 726: /* Set types of tests */
! 727: for (i = 0; i < marraycount; ) {
! 728: if (marray[i].mp->cont_level != 0) {
! 729: i++;
! 730: continue;
! 731: }
! 732:
! 733: starttest = i;
! 734: do {
! 735: static const char text[] = "text";
! 736: static const char binary[] = "binary";
! 737: static const size_t len = sizeof(text);
! 738: set_test_type(marray[starttest].mp, marray[i].mp);
! 739: if ((ms->flags & MAGIC_DEBUG) == 0)
! 740: continue;
! 741: (void)fprintf(stderr, "%s%s%s: %s\n",
! 742: marray[i].mp->mimetype,
! 743: marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
! 744: marray[i].mp->desc[0] ? marray[i].mp->desc :
! 745: "(no description)",
! 746: marray[i].mp->flag & BINTEST ? binary : text);
! 747: if (marray[i].mp->flag & BINTEST) {
! 748: char *p = strstr(marray[i].mp->desc, text);
! 749: if (p && (p == marray[i].mp->desc ||
! 750: isspace((unsigned char)p[-1])) &&
! 751: (p + len - marray[i].mp->desc ==
! 752: MAXstring || (p[len] == '\0' ||
! 753: isspace((unsigned char)p[len]))))
! 754: (void)fprintf(stderr, "*** Possible "
! 755: "binary test for text type\n");
! 756: }
! 757: } while (++i < marraycount && marray[i].mp->cont_level != 0);
! 758: }
! 759:
! 760: qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
! 761:
! 762: /*
! 763: * Make sure that any level 0 "default" line is last (if one exists).
! 764: */
! 765: for (i = 0; i < marraycount; i++) {
! 766: if (marray[i].mp->cont_level == 0 &&
! 767: marray[i].mp->type == FILE_DEFAULT) {
! 768: while (++i < marraycount)
! 769: if (marray[i].mp->cont_level == 0)
! 770: break;
! 771: if (i != marraycount) {
! 772: ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
! 773: file_magwarn(ms,
! 774: "level 0 \"default\" did not sort last");
! 775: }
! 776: break;
! 777: }
! 778: }
! 779:
! 780: for (i = 0; i < marraycount; i++)
! 781: mentrycount += marray[i].cont_count;
! 782:
! 783: *magicp = emalloc(sizeof(**magicp) * mentrycount);
! 784:
! 785: mentrycount = 0;
! 786: for (i = 0; i < marraycount; i++) {
! 787: (void)memcpy(*magicp + mentrycount, marray[i].mp,
! 788: marray[i].cont_count * sizeof(**magicp));
! 789: mentrycount += marray[i].cont_count;
! 790: }
! 791: out:
! 792: for (i = 0; i < marraycount; i++)
! 793: efree(marray[i].mp);
! 794: efree(marray);
! 795: if (errs) {
! 796: *magicp = NULL;
! 797: *nmagicp = 0;
! 798: return errs;
! 799: } else {
! 800: *nmagicp = mentrycount;
! 801: return 0;
! 802: }
! 803:
! 804: }
! 805:
! 806: /*
! 807: * extend the sign bit if the comparison is to be signed
! 808: */
! 809: protected uint64_t
! 810: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
! 811: {
! 812: if (!(m->flag & UNSIGNED)) {
! 813: switch(m->type) {
! 814: /*
! 815: * Do not remove the casts below. They are
! 816: * vital. When later compared with the data,
! 817: * the sign extension must have happened.
! 818: */
! 819: case FILE_BYTE:
! 820: v = (char) v;
! 821: break;
! 822: case FILE_SHORT:
! 823: case FILE_BESHORT:
! 824: case FILE_LESHORT:
! 825: v = (short) v;
! 826: break;
! 827: case FILE_DATE:
! 828: case FILE_BEDATE:
! 829: case FILE_LEDATE:
! 830: case FILE_MEDATE:
! 831: case FILE_LDATE:
! 832: case FILE_BELDATE:
! 833: case FILE_LELDATE:
! 834: case FILE_MELDATE:
! 835: case FILE_LONG:
! 836: case FILE_BELONG:
! 837: case FILE_LELONG:
! 838: case FILE_MELONG:
! 839: case FILE_FLOAT:
! 840: case FILE_BEFLOAT:
! 841: case FILE_LEFLOAT:
! 842: v = (int32_t) v;
! 843: break;
! 844: case FILE_QUAD:
! 845: case FILE_BEQUAD:
! 846: case FILE_LEQUAD:
! 847: case FILE_QDATE:
! 848: case FILE_QLDATE:
! 849: case FILE_BEQDATE:
! 850: case FILE_BEQLDATE:
! 851: case FILE_LEQDATE:
! 852: case FILE_LEQLDATE:
! 853: case FILE_DOUBLE:
! 854: case FILE_BEDOUBLE:
! 855: case FILE_LEDOUBLE:
! 856: v = (int64_t) v;
! 857: break;
! 858: case FILE_STRING:
! 859: case FILE_PSTRING:
! 860: case FILE_BESTRING16:
! 861: case FILE_LESTRING16:
! 862: case FILE_REGEX:
! 863: case FILE_SEARCH:
! 864: case FILE_DEFAULT:
! 865: case FILE_INDIRECT:
! 866: break;
! 867: default:
! 868: if (ms->flags & MAGIC_CHECK)
! 869: file_magwarn(ms, "cannot happen: m->type=%d\n",
! 870: m->type);
! 871: return ~0U;
! 872: }
! 873: }
! 874: return v;
! 875: }
! 876:
! 877: private int
! 878: string_modifier_check(struct magic_set *ms, struct magic *m)
! 879: {
! 880: if ((ms->flags & MAGIC_CHECK) == 0)
! 881: return 0;
! 882:
! 883: switch (m->type) {
! 884: case FILE_BESTRING16:
! 885: case FILE_LESTRING16:
! 886: if (m->str_flags != 0) {
! 887: file_magwarn(ms,
! 888: "no modifiers allowed for 16-bit strings\n");
! 889: return -1;
! 890: }
! 891: break;
! 892: case FILE_STRING:
! 893: case FILE_PSTRING:
! 894: if ((m->str_flags & REGEX_OFFSET_START) != 0) {
! 895: file_magwarn(ms,
! 896: "'/%c' only allowed on regex and search\n",
! 897: CHAR_REGEX_OFFSET_START);
! 898: return -1;
! 899: }
! 900: break;
! 901: case FILE_SEARCH:
! 902: if (m->str_range == 0) {
! 903: file_magwarn(ms,
! 904: "missing range; defaulting to %d\n",
! 905: STRING_DEFAULT_RANGE);
! 906: m->str_range = STRING_DEFAULT_RANGE;
! 907: return -1;
! 908: }
! 909: break;
! 910: case FILE_REGEX:
! 911: if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
! 912: file_magwarn(ms, "'/%c' not allowed on regex\n",
! 913: CHAR_COMPACT_BLANK);
! 914: return -1;
! 915: }
! 916: if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
! 917: file_magwarn(ms, "'/%c' not allowed on regex\n",
! 918: CHAR_COMPACT_OPTIONAL_BLANK);
! 919: return -1;
! 920: }
! 921: break;
! 922: default:
! 923: file_magwarn(ms, "coding error: m->type=%d\n",
! 924: m->type);
! 925: return -1;
! 926: }
! 927: return 0;
! 928: }
! 929:
! 930: private int
! 931: get_op(char c)
! 932: {
! 933: switch (c) {
! 934: case '&':
! 935: return FILE_OPAND;
! 936: case '|':
! 937: return FILE_OPOR;
! 938: case '^':
! 939: return FILE_OPXOR;
! 940: case '+':
! 941: return FILE_OPADD;
! 942: case '-':
! 943: return FILE_OPMINUS;
! 944: case '*':
! 945: return FILE_OPMULTIPLY;
! 946: case '/':
! 947: return FILE_OPDIVIDE;
! 948: case '%':
! 949: return FILE_OPMODULO;
! 950: default:
! 951: return -1;
! 952: }
! 953: }
! 954:
! 955: #ifdef ENABLE_CONDITIONALS
! 956: private int
! 957: get_cond(const char *l, const char **t)
! 958: {
! 959: static const struct cond_tbl_s {
! 960: char name[8];
! 961: size_t len;
! 962: int cond;
! 963: } cond_tbl[] = {
! 964: { "if", 2, COND_IF },
! 965: { "elif", 4, COND_ELIF },
! 966: { "else", 4, COND_ELSE },
! 967: { "", 0, COND_NONE },
! 968: };
! 969: const struct cond_tbl_s *p;
! 970:
! 971: for (p = cond_tbl; p->len; p++) {
! 972: if (strncmp(l, p->name, p->len) == 0 &&
! 973: isspace((unsigned char)l[p->len])) {
! 974: if (t)
! 975: *t = l + p->len;
! 976: break;
! 977: }
! 978: }
! 979: return p->cond;
! 980: }
! 981:
! 982: private int
! 983: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
! 984: {
! 985: int last_cond;
! 986: last_cond = ms->c.li[cont_level].last_cond;
! 987:
! 988: switch (cond) {
! 989: case COND_IF:
! 990: if (last_cond != COND_NONE && last_cond != COND_ELIF) {
! 991: if (ms->flags & MAGIC_CHECK)
! 992: file_magwarn(ms, "syntax error: `if'");
! 993: return -1;
! 994: }
! 995: last_cond = COND_IF;
! 996: break;
! 997:
! 998: case COND_ELIF:
! 999: if (last_cond != COND_IF && last_cond != COND_ELIF) {
! 1000: if (ms->flags & MAGIC_CHECK)
! 1001: file_magwarn(ms, "syntax error: `elif'");
! 1002: return -1;
! 1003: }
! 1004: last_cond = COND_ELIF;
! 1005: break;
! 1006:
! 1007: case COND_ELSE:
! 1008: if (last_cond != COND_IF && last_cond != COND_ELIF) {
! 1009: if (ms->flags & MAGIC_CHECK)
! 1010: file_magwarn(ms, "syntax error: `else'");
! 1011: return -1;
! 1012: }
! 1013: last_cond = COND_NONE;
! 1014: break;
! 1015:
! 1016: case COND_NONE:
! 1017: last_cond = COND_NONE;
! 1018: break;
! 1019: }
! 1020:
! 1021: ms->c.li[cont_level].last_cond = last_cond;
! 1022: return 0;
! 1023: }
! 1024: #endif /* ENABLE_CONDITIONALS */
! 1025:
! 1026: /*
! 1027: * parse one line from magic file, put into magic[index++] if valid
! 1028: */
! 1029: private int
! 1030: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
! 1031: const char *line, size_t lineno, int action)
! 1032: {
! 1033: #ifdef ENABLE_CONDITIONALS
! 1034: static uint32_t last_cont_level = 0;
! 1035: #endif
! 1036: size_t i;
! 1037: struct magic_entry *me;
! 1038: struct magic *m;
! 1039: const char *l = line;
! 1040: char *t;
! 1041: int op;
! 1042: uint32_t cont_level;
! 1043:
! 1044: cont_level = 0;
! 1045:
! 1046: while (*l == '>') {
! 1047: ++l; /* step over */
! 1048: cont_level++;
! 1049: }
! 1050: #ifdef ENABLE_CONDITIONALS
! 1051: if (cont_level == 0 || cont_level > last_cont_level)
! 1052: if (file_check_mem(ms, cont_level) == -1)
! 1053: return -1;
! 1054: last_cont_level = cont_level;
! 1055: #endif
! 1056:
! 1057: #define ALLOC_CHUNK (size_t)10
! 1058: #define ALLOC_INCR (size_t)200
! 1059:
! 1060: if (cont_level != 0) {
! 1061: if (*nmentryp == 0) {
! 1062: file_error(ms, 0, "No current entry for continuation");
! 1063: return -1;
! 1064: }
! 1065: me = &(*mentryp)[*nmentryp - 1];
! 1066: if (me->cont_count == me->max_count) {
! 1067: struct magic *nm;
! 1068: size_t cnt = me->max_count + ALLOC_CHUNK;
! 1069: nm = erealloc(me->mp, sizeof(*nm) * cnt);
! 1070: me->mp = m = nm;
! 1071: me->max_count = cnt;
! 1072: }
! 1073: m = &me->mp[me->cont_count++];
! 1074: (void)memset(m, 0, sizeof(*m));
! 1075: m->cont_level = cont_level;
! 1076: } else {
! 1077: if (*nmentryp == maxmagic) {
! 1078: struct magic_entry *mp;
! 1079:
! 1080: maxmagic += ALLOC_INCR;
! 1081: mp = erealloc(*mentryp, sizeof(*mp) * maxmagic);
! 1082: (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * ALLOC_INCR);
! 1083: *mentryp = mp;
! 1084: }
! 1085: me = &(*mentryp)[*nmentryp];
! 1086: if (me->mp == NULL) {
! 1087: m = safe_emalloc(sizeof(*m), ALLOC_CHUNK, 0);
! 1088: me->mp = m;
! 1089: me->max_count = ALLOC_CHUNK;
! 1090: } else
! 1091: m = me->mp;
! 1092: (void)memset(m, 0, sizeof(*m));
! 1093: m->factor_op = FILE_FACTOR_OP_NONE;
! 1094: m->cont_level = 0;
! 1095: me->cont_count = 1;
! 1096: }
! 1097: m->lineno = lineno;
! 1098:
! 1099: if (*l == '&') { /* m->cont_level == 0 checked below. */
! 1100: ++l; /* step over */
! 1101: m->flag |= OFFADD;
! 1102: }
! 1103: if (*l == '(') {
! 1104: ++l; /* step over */
! 1105: m->flag |= INDIR;
! 1106: if (m->flag & OFFADD)
! 1107: m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
! 1108:
! 1109: if (*l == '&') { /* m->cont_level == 0 checked below */
! 1110: ++l; /* step over */
! 1111: m->flag |= OFFADD;
! 1112: }
! 1113: }
! 1114: /* Indirect offsets are not valid at level 0. */
! 1115: if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
! 1116: if (ms->flags & MAGIC_CHECK)
! 1117: file_magwarn(ms, "relative offset at level 0");
! 1118:
! 1119: /* get offset, then skip over it */
! 1120: m->offset = (uint32_t)strtoul(l, &t, 0);
! 1121: if (l == t)
! 1122: if (ms->flags & MAGIC_CHECK)
! 1123: file_magwarn(ms, "offset `%s' invalid", l);
! 1124: l = t;
! 1125:
! 1126: if (m->flag & INDIR) {
! 1127: m->in_type = FILE_LONG;
! 1128: m->in_offset = 0;
! 1129: /*
! 1130: * read [.lbs][+-]nnnnn)
! 1131: */
! 1132: if (*l == '.') {
! 1133: l++;
! 1134: switch (*l) {
! 1135: case 'l':
! 1136: m->in_type = FILE_LELONG;
! 1137: break;
! 1138: case 'L':
! 1139: m->in_type = FILE_BELONG;
! 1140: break;
! 1141: case 'm':
! 1142: m->in_type = FILE_MELONG;
! 1143: break;
! 1144: case 'h':
! 1145: case 's':
! 1146: m->in_type = FILE_LESHORT;
! 1147: break;
! 1148: case 'H':
! 1149: case 'S':
! 1150: m->in_type = FILE_BESHORT;
! 1151: break;
! 1152: case 'c':
! 1153: case 'b':
! 1154: case 'C':
! 1155: case 'B':
! 1156: m->in_type = FILE_BYTE;
! 1157: break;
! 1158: case 'e':
! 1159: case 'f':
! 1160: case 'g':
! 1161: m->in_type = FILE_LEDOUBLE;
! 1162: break;
! 1163: case 'E':
! 1164: case 'F':
! 1165: case 'G':
! 1166: m->in_type = FILE_BEDOUBLE;
! 1167: break;
! 1168: case 'i':
! 1169: m->in_type = FILE_LEID3;
! 1170: break;
! 1171: case 'I':
! 1172: m->in_type = FILE_BEID3;
! 1173: break;
! 1174: default:
! 1175: if (ms->flags & MAGIC_CHECK)
! 1176: file_magwarn(ms,
! 1177: "indirect offset type `%c' invalid",
! 1178: *l);
! 1179: break;
! 1180: }
! 1181: l++;
! 1182: }
! 1183:
! 1184: m->in_op = 0;
! 1185: if (*l == '~') {
! 1186: m->in_op |= FILE_OPINVERSE;
! 1187: l++;
! 1188: }
! 1189: if ((op = get_op(*l)) != -1) {
! 1190: m->in_op |= op;
! 1191: l++;
! 1192: }
! 1193: if (*l == '(') {
! 1194: m->in_op |= FILE_OPINDIRECT;
! 1195: l++;
! 1196: }
! 1197: if (isdigit((unsigned char)*l) || *l == '-') {
! 1198: m->in_offset = (int32_t)strtol(l, &t, 0);
! 1199: if (l == t)
! 1200: if (ms->flags & MAGIC_CHECK)
! 1201: file_magwarn(ms,
! 1202: "in_offset `%s' invalid", l);
! 1203: l = t;
! 1204: }
! 1205: if (*l++ != ')' ||
! 1206: ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
! 1207: if (ms->flags & MAGIC_CHECK)
! 1208: file_magwarn(ms,
! 1209: "missing ')' in indirect offset");
! 1210: }
! 1211: EATAB;
! 1212:
! 1213: #ifdef ENABLE_CONDITIONALS
! 1214: m->cond = get_cond(l, &l);
! 1215: if (check_cond(ms, m->cond, cont_level) == -1)
! 1216: return -1;
! 1217:
! 1218: EATAB;
! 1219: #endif
! 1220:
! 1221: if (*l == 'u') {
! 1222: ++l;
! 1223: m->flag |= UNSIGNED;
! 1224: }
! 1225:
! 1226: m->type = get_type(l, &l);
! 1227: if (m->type == FILE_INVALID) {
! 1228: if (ms->flags & MAGIC_CHECK)
! 1229: file_magwarn(ms, "type `%s' invalid", l);
! 1230: return -1;
! 1231: }
! 1232:
! 1233: /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
! 1234: /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
! 1235:
! 1236: m->mask_op = 0;
! 1237: if (*l == '~') {
! 1238: if (!IS_LIBMAGIC_STRING(m->type))
! 1239: m->mask_op |= FILE_OPINVERSE;
! 1240: else if (ms->flags & MAGIC_CHECK)
! 1241: file_magwarn(ms, "'~' invalid for string types");
! 1242: ++l;
! 1243: }
! 1244: m->str_range = 0;
! 1245: m->str_flags = 0;
! 1246: m->num_mask = 0;
! 1247: if ((op = get_op(*l)) != -1) {
! 1248: if (!IS_LIBMAGIC_STRING(m->type)) {
! 1249: uint64_t val;
! 1250: ++l;
! 1251: m->mask_op |= op;
! 1252: val = (uint64_t)strtoull(l, &t, 0);
! 1253: l = t;
! 1254: m->num_mask = file_signextend(ms, m, val);
! 1255: eatsize(&l);
! 1256: }
! 1257: else if (op == FILE_OPDIVIDE) {
! 1258: int have_range = 0;
! 1259: while (!isspace((unsigned char)*++l)) {
! 1260: switch (*l) {
! 1261: case '0': case '1': case '2':
! 1262: case '3': case '4': case '5':
! 1263: case '6': case '7': case '8':
! 1264: case '9':
! 1265: if (have_range &&
! 1266: (ms->flags & MAGIC_CHECK))
! 1267: file_magwarn(ms,
! 1268: "multiple ranges");
! 1269: have_range = 1;
! 1270: m->str_range = strtoul(l, &t, 0);
! 1271: if (m->str_range == 0)
! 1272: file_magwarn(ms,
! 1273: "zero range");
! 1274: l = t - 1;
! 1275: break;
! 1276: case CHAR_COMPACT_BLANK:
! 1277: m->str_flags |= STRING_COMPACT_BLANK;
! 1278: break;
! 1279: case CHAR_COMPACT_OPTIONAL_BLANK:
! 1280: m->str_flags |=
! 1281: STRING_COMPACT_OPTIONAL_BLANK;
! 1282: break;
! 1283: case CHAR_IGNORE_LOWERCASE:
! 1284: m->str_flags |= STRING_IGNORE_LOWERCASE;
! 1285: break;
! 1286: case CHAR_IGNORE_UPPERCASE:
! 1287: m->str_flags |= STRING_IGNORE_UPPERCASE;
! 1288: break;
! 1289: case CHAR_REGEX_OFFSET_START:
! 1290: m->str_flags |= REGEX_OFFSET_START;
! 1291: break;
! 1292: default:
! 1293: if (ms->flags & MAGIC_CHECK)
! 1294: file_magwarn(ms,
! 1295: "string extension `%c' invalid",
! 1296: *l);
! 1297: return -1;
! 1298: }
! 1299: /* allow multiple '/' for readability */
! 1300: if (l[1] == '/' &&
! 1301: !isspace((unsigned char)l[2]))
! 1302: l++;
! 1303: }
! 1304: if (string_modifier_check(ms, m) == -1)
! 1305: return -1;
! 1306: }
! 1307: else {
! 1308: if (ms->flags & MAGIC_CHECK)
! 1309: file_magwarn(ms, "invalid string op: %c", *t);
! 1310: return -1;
! 1311: }
! 1312: }
! 1313: /*
! 1314: * We used to set mask to all 1's here, instead let's just not do
! 1315: * anything if mask = 0 (unless you have a better idea)
! 1316: */
! 1317: EATAB;
! 1318:
! 1319: switch (*l) {
! 1320: case '>':
! 1321: case '<':
! 1322: m->reln = *l;
! 1323: ++l;
! 1324: if (*l == '=') {
! 1325: if (ms->flags & MAGIC_CHECK) {
! 1326: file_magwarn(ms, "%c= not supported",
! 1327: m->reln);
! 1328: return -1;
! 1329: }
! 1330: ++l;
! 1331: }
! 1332: break;
! 1333: /* Old-style anding: "0 byte &0x80 dynamically linked" */
! 1334: case '&':
! 1335: case '^':
! 1336: case '=':
! 1337: m->reln = *l;
! 1338: ++l;
! 1339: if (*l == '=') {
! 1340: /* HP compat: ignore &= etc. */
! 1341: ++l;
! 1342: }
! 1343: break;
! 1344: case '!':
! 1345: m->reln = *l;
! 1346: ++l;
! 1347: break;
! 1348: default:
! 1349: m->reln = '='; /* the default relation */
! 1350: if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
! 1351: isspace((unsigned char)l[1])) || !l[1])) {
! 1352: m->reln = *l;
! 1353: ++l;
! 1354: }
! 1355: break;
! 1356: }
! 1357: /*
! 1358: * Grab the value part, except for an 'x' reln.
! 1359: */
! 1360: if (m->reln != 'x' && getvalue(ms, m, &l, action))
! 1361: return -1;
! 1362:
! 1363: /*
! 1364: * TODO finish this macro and start using it!
! 1365: * #define offsetcheck {if (offset > HOWMANY-1)
! 1366: * magwarn("offset too big"); }
! 1367: */
! 1368:
! 1369: /*
! 1370: * Now get last part - the description
! 1371: */
! 1372: EATAB;
! 1373: if (l[0] == '\b') {
! 1374: ++l;
! 1375: m->flag |= NOSPACE;
! 1376: } else if ((l[0] == '\\') && (l[1] == 'b')) {
! 1377: ++l;
! 1378: ++l;
! 1379: m->flag |= NOSPACE;
! 1380: }
! 1381: for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
! 1382: continue;
! 1383: if (i == sizeof(m->desc)) {
! 1384: m->desc[sizeof(m->desc) - 1] = '\0';
! 1385: if (ms->flags & MAGIC_CHECK)
! 1386: file_magwarn(ms, "description `%s' truncated", m->desc);
! 1387: }
! 1388:
! 1389: /*
! 1390: * We only do this check while compiling, or if any of the magic
! 1391: * files were not compiled.
! 1392: */
! 1393: if (ms->flags & MAGIC_CHECK) {
! 1394: if (check_format(ms, m) == -1)
! 1395: return -1;
! 1396: }
! 1397: m->mimetype[0] = '\0'; /* initialise MIME type to none */
! 1398: if (m->cont_level == 0)
! 1399: ++(*nmentryp); /* make room for next */
! 1400: return 0;
! 1401: }
! 1402:
! 1403: /*
! 1404: * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
! 1405: * if valid
! 1406: */
! 1407: private int
! 1408: parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
! 1409: {
! 1410: const char *l = line;
! 1411: char *el;
! 1412: unsigned long factor;
! 1413: struct magic *m = &me->mp[0];
! 1414:
! 1415: if (m->factor_op != FILE_FACTOR_OP_NONE) {
! 1416: file_magwarn(ms,
! 1417: "Current entry already has a strength type: %c %d",
! 1418: m->factor_op, m->factor);
! 1419: return -1;
! 1420: }
! 1421: EATAB;
! 1422: switch (*l) {
! 1423: case FILE_FACTOR_OP_NONE:
! 1424: case FILE_FACTOR_OP_PLUS:
! 1425: case FILE_FACTOR_OP_MINUS:
! 1426: case FILE_FACTOR_OP_TIMES:
! 1427: case FILE_FACTOR_OP_DIV:
! 1428: m->factor_op = *l++;
! 1429: break;
! 1430: default:
! 1431: file_magwarn(ms, "Unknown factor op `%c'", *l);
! 1432: return -1;
! 1433: }
! 1434: EATAB;
! 1435: factor = strtoul(l, &el, 0);
! 1436: if (factor > 255) {
! 1437: file_magwarn(ms, "Too large factor `%lu'", factor);
! 1438: goto out;
! 1439: }
! 1440: if (*el && !isspace((unsigned char)*el)) {
! 1441: file_magwarn(ms, "Bad factor `%s'", l);
! 1442: goto out;
! 1443: }
! 1444: m->factor = (uint8_t)factor;
! 1445: if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
! 1446: file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
! 1447: m->factor_op, m->factor);
! 1448: goto out;
! 1449: }
! 1450: return 0;
! 1451: out:
! 1452: m->factor_op = FILE_FACTOR_OP_NONE;
! 1453: m->factor = 0;
! 1454: return -1;
! 1455: }
! 1456:
! 1457: /*
! 1458: * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
! 1459: */
! 1460: private int
! 1461: parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
! 1462: {
! 1463: size_t i;
! 1464: const char *l = line;
! 1465: struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
! 1466:
! 1467: if (m->apple[0] != '\0') {
! 1468: file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
! 1469: " new type `%s'", m->mimetype, l);
! 1470: return -1;
! 1471: }
! 1472:
! 1473: EATAB;
! 1474: for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
! 1475: || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
! 1476: continue;
! 1477: if (i == sizeof(m->apple) && *l) {
! 1478: if (ms->flags & MAGIC_CHECK)
! 1479: file_magwarn(ms, "APPLE type `%s' truncated %zu",
! 1480: line, i);
! 1481: }
! 1482:
! 1483: if (i > 0)
! 1484: return 0;
! 1485: else
! 1486: return -1;
! 1487: }
! 1488:
! 1489: /*
! 1490: * parse a MIME annotation line from magic file, put into magic[index - 1]
! 1491: * if valid
! 1492: */
! 1493: private int
! 1494: parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
! 1495: {
! 1496: size_t i;
! 1497: const char *l = line;
! 1498: struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
! 1499:
! 1500: if (m->mimetype[0] != '\0') {
! 1501: file_magwarn(ms, "Current entry already has a MIME type `%s',"
! 1502: " new type `%s'", m->mimetype, l);
! 1503: return -1;
! 1504: }
! 1505:
! 1506: EATAB;
! 1507: for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
! 1508: || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
! 1509: continue;
! 1510: if (i == sizeof(m->mimetype)) {
! 1511: m->desc[sizeof(m->mimetype) - 1] = '\0';
! 1512: if (ms->flags & MAGIC_CHECK)
! 1513: file_magwarn(ms, "MIME type `%s' truncated %zu",
! 1514: m->mimetype, i);
! 1515: } else
! 1516: m->mimetype[i] = '\0';
! 1517:
! 1518: if (i > 0)
! 1519: return 0;
! 1520: else
! 1521: return -1;
! 1522: }
! 1523:
! 1524: private int
! 1525: check_format_type(const char *ptr, int type)
! 1526: {
! 1527: int quad = 0;
! 1528: if (*ptr == '\0') {
! 1529: /* Missing format string; bad */
! 1530: return -1;
! 1531: }
! 1532:
! 1533: switch (type) {
! 1534: case FILE_FMT_QUAD:
! 1535: quad = 1;
! 1536: /*FALLTHROUGH*/
! 1537: case FILE_FMT_NUM:
! 1538: if (*ptr == '-')
! 1539: ptr++;
! 1540: if (*ptr == '.')
! 1541: ptr++;
! 1542: while (isdigit((unsigned char)*ptr)) ptr++;
! 1543: if (*ptr == '.')
! 1544: ptr++;
! 1545: while (isdigit((unsigned char)*ptr)) ptr++;
! 1546: if (quad) {
! 1547: if (*ptr++ != 'l')
! 1548: return -1;
! 1549: if (*ptr++ != 'l')
! 1550: return -1;
! 1551: }
! 1552:
! 1553: switch (*ptr++) {
! 1554: case 'l':
! 1555: switch (*ptr++) {
! 1556: case 'i':
! 1557: case 'd':
! 1558: case 'u':
! 1559: case 'x':
! 1560: case 'X':
! 1561: return 0;
! 1562: default:
! 1563: return -1;
! 1564: }
! 1565:
! 1566: case 'h':
! 1567: switch (*ptr++) {
! 1568: case 'h':
! 1569: switch (*ptr++) {
! 1570: case 'i':
! 1571: case 'd':
! 1572: case 'u':
! 1573: case 'x':
! 1574: case 'X':
! 1575: return 0;
! 1576: default:
! 1577: return -1;
! 1578: }
! 1579: case 'd':
! 1580: return 0;
! 1581: default:
! 1582: return -1;
! 1583: }
! 1584:
! 1585: case 'i':
! 1586: case 'c':
! 1587: case 'd':
! 1588: case 'u':
! 1589: case 'x':
! 1590: case 'X':
! 1591: return 0;
! 1592:
! 1593: default:
! 1594: return -1;
! 1595: }
! 1596:
! 1597: case FILE_FMT_FLOAT:
! 1598: case FILE_FMT_DOUBLE:
! 1599: if (*ptr == '-')
! 1600: ptr++;
! 1601: if (*ptr == '.')
! 1602: ptr++;
! 1603: while (isdigit((unsigned char)*ptr)) ptr++;
! 1604: if (*ptr == '.')
! 1605: ptr++;
! 1606: while (isdigit((unsigned char)*ptr)) ptr++;
! 1607:
! 1608: switch (*ptr++) {
! 1609: case 'e':
! 1610: case 'E':
! 1611: case 'f':
! 1612: case 'F':
! 1613: case 'g':
! 1614: case 'G':
! 1615: return 0;
! 1616:
! 1617: default:
! 1618: return -1;
! 1619: }
! 1620:
! 1621:
! 1622: case FILE_FMT_STR:
! 1623: if (*ptr == '-')
! 1624: ptr++;
! 1625: while (isdigit((unsigned char )*ptr))
! 1626: ptr++;
! 1627: if (*ptr == '.') {
! 1628: ptr++;
! 1629: while (isdigit((unsigned char )*ptr))
! 1630: ptr++;
! 1631: }
! 1632:
! 1633: switch (*ptr++) {
! 1634: case 's':
! 1635: return 0;
! 1636: default:
! 1637: return -1;
! 1638: }
! 1639:
! 1640: default:
! 1641: /* internal error */
! 1642: abort();
! 1643: }
! 1644: /*NOTREACHED*/
! 1645: return -1;
! 1646: }
! 1647:
! 1648: /*
! 1649: * Check that the optional printf format in description matches
! 1650: * the type of the magic.
! 1651: */
! 1652: private int
! 1653: check_format(struct magic_set *ms, struct magic *m)
! 1654: {
! 1655: char *ptr;
! 1656:
! 1657: for (ptr = m->desc; *ptr; ptr++)
! 1658: if (*ptr == '%')
! 1659: break;
! 1660: if (*ptr == '\0') {
! 1661: /* No format string; ok */
! 1662: return 1;
! 1663: }
! 1664:
! 1665: assert(file_nformats == file_nnames);
! 1666:
! 1667: if (m->type >= file_nformats) {
! 1668: file_magwarn(ms, "Internal error inconsistency between "
! 1669: "m->type and format strings");
! 1670: return -1;
! 1671: }
! 1672: if (file_formats[m->type] == FILE_FMT_NONE) {
! 1673: file_magwarn(ms, "No format string for `%s' with description "
! 1674: "`%s'", m->desc, file_names[m->type]);
! 1675: return -1;
! 1676: }
! 1677:
! 1678: ptr++;
! 1679: if (check_format_type(ptr, file_formats[m->type]) == -1) {
! 1680: /*
! 1681: * TODO: this error message is unhelpful if the format
! 1682: * string is not one character long
! 1683: */
! 1684: file_magwarn(ms, "Printf format `%c' is not valid for type "
! 1685: "`%s' in description `%s'", *ptr ? *ptr : '?',
! 1686: file_names[m->type], m->desc);
! 1687: return -1;
! 1688: }
! 1689:
! 1690: for (; *ptr; ptr++) {
! 1691: if (*ptr == '%') {
! 1692: file_magwarn(ms,
! 1693: "Too many format strings (should have at most one) "
! 1694: "for `%s' with description `%s'",
! 1695: file_names[m->type], m->desc);
! 1696: return -1;
! 1697: }
! 1698: }
! 1699: return 0;
! 1700: }
! 1701:
! 1702: /*
! 1703: * Read a numeric value from a pointer, into the value union of a magic
! 1704: * pointer, according to the magic type. Update the string pointer to point
! 1705: * just after the number read. Return 0 for success, non-zero for failure.
! 1706: */
! 1707: private int
! 1708: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
! 1709: {
! 1710: switch (m->type) {
! 1711: case FILE_BESTRING16:
! 1712: case FILE_LESTRING16:
! 1713: case FILE_STRING:
! 1714: case FILE_PSTRING:
! 1715: case FILE_REGEX:
! 1716: case FILE_SEARCH:
! 1717: *p = getstr(ms, m, *p, action == FILE_COMPILE);
! 1718: if (*p == NULL) {
! 1719: if (ms->flags & MAGIC_CHECK)
! 1720: file_magwarn(ms, "cannot get string from `%s'",
! 1721: m->value.s);
! 1722: return -1;
! 1723: }
! 1724: return 0;
! 1725: case FILE_FLOAT:
! 1726: case FILE_BEFLOAT:
! 1727: case FILE_LEFLOAT:
! 1728: if (m->reln != 'x') {
! 1729: char *ep;
! 1730: #ifdef HAVE_STRTOF
! 1731: m->value.f = strtof(*p, &ep);
! 1732: #else
! 1733: m->value.f = (float)strtod(*p, &ep);
! 1734: #endif
! 1735: *p = ep;
! 1736: }
! 1737: return 0;
! 1738: case FILE_DOUBLE:
! 1739: case FILE_BEDOUBLE:
! 1740: case FILE_LEDOUBLE:
! 1741: if (m->reln != 'x') {
! 1742: char *ep;
! 1743: m->value.d = strtod(*p, &ep);
! 1744: *p = ep;
! 1745: }
! 1746: return 0;
! 1747: default:
! 1748: if (m->reln != 'x') {
! 1749: char *ep;
! 1750: m->value.q = file_signextend(ms, m,
! 1751: (uint64_t)strtoull(*p, &ep, 0));
! 1752: *p = ep;
! 1753: eatsize(p);
! 1754: }
! 1755: return 0;
! 1756: }
! 1757: }
! 1758:
! 1759: /*
! 1760: * Convert a string containing C character escapes. Stop at an unescaped
! 1761: * space or tab.
! 1762: * Copy the converted version to "m->value.s", and the length in m->vallen.
! 1763: * Return updated scan pointer as function result. Warn if set.
! 1764: */
! 1765: private const char *
! 1766: getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
! 1767: {
! 1768: const char *origs = s;
! 1769: char *p = m->value.s;
! 1770: size_t plen = sizeof(m->value.s);
! 1771: char *origp = p;
! 1772: char *pmax = p + plen - 1;
! 1773: int c;
! 1774: int val;
! 1775:
! 1776: while ((c = *s++) != '\0') {
! 1777: if (isspace((unsigned char) c))
! 1778: break;
! 1779: if (p >= pmax) {
! 1780: file_error(ms, 0, "string too long: `%s'", origs);
! 1781: return NULL;
! 1782: }
! 1783: if (c == '\\') {
! 1784: switch(c = *s++) {
! 1785:
! 1786: case '\0':
! 1787: if (warn)
! 1788: file_magwarn(ms, "incomplete escape");
! 1789: goto out;
! 1790:
! 1791: case '\t':
! 1792: if (warn) {
! 1793: file_magwarn(ms,
! 1794: "escaped tab found, use \\t instead");
! 1795: warn = 0; /* already did */
! 1796: }
! 1797: /*FALLTHROUGH*/
! 1798: default:
! 1799: if (warn) {
! 1800: if (isprint((unsigned char)c)) {
! 1801: /* Allow escaping of
! 1802: * ``relations'' */
! 1803: if (strchr("<>&^=!", c)
! 1804: == NULL) {
! 1805: file_magwarn(ms, "no "
! 1806: "need to escape "
! 1807: "`%c'", c);
! 1808: }
! 1809: } else {
! 1810: file_magwarn(ms,
! 1811: "unknown escape sequence: "
! 1812: "\\%03o", c);
! 1813: }
! 1814: }
! 1815: /*FALLTHROUGH*/
! 1816: /* space, perhaps force people to use \040? */
! 1817: case ' ':
! 1818: #if 0
! 1819: /*
! 1820: * Other things people escape, but shouldn't need to,
! 1821: * so we disallow them
! 1822: */
! 1823: case '\'':
! 1824: case '"':
! 1825: case '?':
! 1826: #endif
! 1827: /* Relations */
! 1828: case '>':
! 1829: case '<':
! 1830: case '&':
! 1831: case '^':
! 1832: case '=':
! 1833: case '!':
! 1834: /* and baskslash itself */
! 1835: case '\\':
! 1836: *p++ = (char) c;
! 1837: break;
! 1838:
! 1839: case 'a':
! 1840: *p++ = '\a';
! 1841: break;
! 1842:
! 1843: case 'b':
! 1844: *p++ = '\b';
! 1845: break;
! 1846:
! 1847: case 'f':
! 1848: *p++ = '\f';
! 1849: break;
! 1850:
! 1851: case 'n':
! 1852: *p++ = '\n';
! 1853: break;
! 1854:
! 1855: case 'r':
! 1856: *p++ = '\r';
! 1857: break;
! 1858:
! 1859: case 't':
! 1860: *p++ = '\t';
! 1861: break;
! 1862:
! 1863: case 'v':
! 1864: *p++ = '\v';
! 1865: break;
! 1866:
! 1867: /* \ and up to 3 octal digits */
! 1868: case '0':
! 1869: case '1':
! 1870: case '2':
! 1871: case '3':
! 1872: case '4':
! 1873: case '5':
! 1874: case '6':
! 1875: case '7':
! 1876: val = c - '0';
! 1877: c = *s++; /* try for 2 */
! 1878: if (c >= '0' && c <= '7') {
! 1879: val = (val << 3) | (c - '0');
! 1880: c = *s++; /* try for 3 */
! 1881: if (c >= '0' && c <= '7')
! 1882: val = (val << 3) | (c-'0');
! 1883: else
! 1884: --s;
! 1885: }
! 1886: else
! 1887: --s;
! 1888: *p++ = (char)val;
! 1889: break;
! 1890:
! 1891: /* \x and up to 2 hex digits */
! 1892: case 'x':
! 1893: val = 'x'; /* Default if no digits */
! 1894: c = hextoint(*s++); /* Get next char */
! 1895: if (c >= 0) {
! 1896: val = c;
! 1897: c = hextoint(*s++);
! 1898: if (c >= 0)
! 1899: val = (val << 4) + c;
! 1900: else
! 1901: --s;
! 1902: } else
! 1903: --s;
! 1904: *p++ = (char)val;
! 1905: break;
! 1906: }
! 1907: } else
! 1908: *p++ = (char)c;
! 1909: }
! 1910: out:
! 1911: *p = '\0';
! 1912: m->vallen = p - origp;
! 1913: if (m->type == FILE_PSTRING)
! 1914: m->vallen++;
! 1915: return s;
! 1916: }
! 1917:
! 1918:
! 1919: /* Single hex char to int; -1 if not a hex char. */
! 1920: private int
! 1921: hextoint(int c)
! 1922: {
! 1923: if (!isascii((unsigned char) c))
! 1924: return -1;
! 1925: if (isdigit((unsigned char) c))
! 1926: return c - '0';
! 1927: if ((c >= 'a') && (c <= 'f'))
! 1928: return c + 10 - 'a';
! 1929: if (( c>= 'A') && (c <= 'F'))
! 1930: return c + 10 - 'A';
! 1931: return -1;
! 1932: }
! 1933:
! 1934:
! 1935: /*
! 1936: * Print a string containing C character escapes.
! 1937: */
! 1938: protected void
! 1939: file_showstr(FILE *fp, const char *s, size_t len)
! 1940: {
! 1941: char c;
! 1942:
! 1943: for (;;) {
! 1944: c = *s++;
! 1945: if (len == ~0U) {
! 1946: if (c == '\0')
! 1947: break;
! 1948: }
! 1949: else {
! 1950: if (len-- == 0)
! 1951: break;
! 1952: }
! 1953: if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
! 1954: (void) fputc(c, fp);
! 1955: else {
! 1956: (void) fputc('\\', fp);
! 1957: switch (c) {
! 1958: case '\a':
! 1959: (void) fputc('a', fp);
! 1960: break;
! 1961:
! 1962: case '\b':
! 1963: (void) fputc('b', fp);
! 1964: break;
! 1965:
! 1966: case '\f':
! 1967: (void) fputc('f', fp);
! 1968: break;
! 1969:
! 1970: case '\n':
! 1971: (void) fputc('n', fp);
! 1972: break;
! 1973:
! 1974: case '\r':
! 1975: (void) fputc('r', fp);
! 1976: break;
! 1977:
! 1978: case '\t':
! 1979: (void) fputc('t', fp);
! 1980: break;
! 1981:
! 1982: case '\v':
! 1983: (void) fputc('v', fp);
! 1984: break;
! 1985:
! 1986: default:
! 1987: (void) fprintf(fp, "%.3o", c & 0377);
! 1988: break;
! 1989: }
! 1990: }
! 1991: }
! 1992: }
! 1993:
! 1994: /*
! 1995: * eatsize(): Eat the size spec from a number [eg. 10UL]
! 1996: */
! 1997: private void
! 1998: eatsize(const char **p)
! 1999: {
! 2000: const char *l = *p;
! 2001:
! 2002: if (LOWCASE(*l) == 'u')
! 2003: l++;
! 2004:
! 2005: switch (LOWCASE(*l)) {
! 2006: case 'l': /* long */
! 2007: case 's': /* short */
! 2008: case 'h': /* short */
! 2009: case 'b': /* char/byte */
! 2010: case 'c': /* char/byte */
! 2011: l++;
! 2012: /*FALLTHROUGH*/
! 2013: default:
! 2014: break;
! 2015: }
! 2016:
! 2017: *p = l;
! 2018: }
! 2019:
! 2020: /*
! 2021: * handle a compiled file.
! 2022: * return -1 = error
! 2023: * return 1 = memory structure you can free
! 2024: * return 3 = bundled library from PHP
! 2025: */
! 2026: private int
! 2027: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
! 2028: const char *fn)
! 2029: {
! 2030: uint32_t *ptr;
! 2031: uint32_t version;
! 2032: int needsbyteswap;
! 2033: char *dbname = NULL;
! 2034: void *mm = NULL;
! 2035: int ret = 0;
! 2036: php_stream *stream = NULL;
! 2037: php_stream_statbuf st;
! 2038:
! 2039:
! 2040: TSRMLS_FETCH();
! 2041:
! 2042: if (fn == NULL) {
! 2043: mm = (void *)&php_magic_database;
! 2044: ret = 3;
! 2045: goto internal_loaded;
! 2046: }
! 2047:
! 2048: dbname = mkdbname(ms, fn, 0);
! 2049: if (dbname == NULL)
! 2050: goto error2;
! 2051:
! 2052: #if PHP_API_VERSION < 20100412
! 2053: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
! 2054: #else
! 2055: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
! 2056: #endif
! 2057:
! 2058: if (!stream) {
! 2059: goto error2;
! 2060: }
! 2061:
! 2062: if (php_stream_stat(stream, &st) < 0) {
! 2063: file_error(ms, errno, "cannot stat `%s'", dbname);
! 2064: goto error1;
! 2065: }
! 2066:
! 2067: if (st.sb.st_size < 8) {
! 2068: file_error(ms, 0, "file `%s' is too small", dbname);
! 2069: goto error1;
! 2070: }
! 2071:
! 2072: mm = emalloc((size_t)st.sb.st_size);
! 2073: ret = 1;
! 2074: if (php_stream_read(stream, mm, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) {
! 2075: file_badread(ms);
! 2076: goto error1;
! 2077: }
! 2078:
! 2079: php_stream_close(stream);
! 2080: stream = NULL;
! 2081:
! 2082: internal_loaded:
! 2083: *magicp = mm;
! 2084: ptr = (uint32_t *)(void *)*magicp;
! 2085: if (*ptr != MAGICNO) {
! 2086: if (swap4(*ptr) != MAGICNO) {
! 2087: file_error(ms, 0, "bad magic in `%s'", dbname);
! 2088: goto error1;
! 2089: }
! 2090: needsbyteswap = 1;
! 2091: } else {
! 2092: needsbyteswap = 0;
! 2093: }
! 2094:
! 2095: if (needsbyteswap)
! 2096: version = swap4(ptr[1]);
! 2097: else
! 2098: version = ptr[1];
! 2099:
! 2100: if (version != VERSIONNO) {
! 2101: file_error(ms, 0, "File %d.%d supports only version %d magic "
! 2102: "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
! 2103: VERSIONNO, dbname, version);
! 2104: goto error1;
! 2105: }
! 2106:
! 2107: /* php_magic_database is a const, performing writes will segfault. This is for big-endian
! 2108: machines only, PPC and Sparc specifically. Consider static variable or MINIT in
! 2109: future. */
! 2110: if (needsbyteswap && fn == NULL) {
! 2111: mm = emalloc(sizeof(php_magic_database));
! 2112: mm = memcpy(mm, php_magic_database, sizeof(php_magic_database));
! 2113: *magicp = mm;
! 2114: ret = 1;
! 2115: }
! 2116:
! 2117: if (fn == NULL) {
! 2118: *nmagicp = (sizeof(php_magic_database) / sizeof(struct magic));
! 2119: } else {
! 2120: *nmagicp = (uint32_t)(st.sb.st_size / sizeof(struct magic));
! 2121: }
! 2122: if (*nmagicp > 0) {
! 2123: (*nmagicp)--;
! 2124: }
! 2125: (*magicp)++;
! 2126: if (needsbyteswap) {
! 2127: byteswap(*magicp, *nmagicp);
! 2128: }
! 2129:
! 2130: if (dbname) {
! 2131: efree(dbname);
! 2132: }
! 2133: return ret;
! 2134:
! 2135: error1:
! 2136: if (stream) {
! 2137: php_stream_close(stream);
! 2138: }
! 2139:
! 2140: if (mm && ret == 1) {
! 2141: efree(mm);
! 2142: } else {
! 2143: *magicp = NULL;
! 2144: *nmagicp = 0;
! 2145: }
! 2146: error2:
! 2147: if (dbname) {
! 2148: efree(dbname);
! 2149: }
! 2150: return -1;
! 2151: }
! 2152:
! 2153: private const uint32_t ar[] = {
! 2154: MAGICNO, VERSIONNO
! 2155: };
! 2156: /*
! 2157: * handle an mmaped file.
! 2158: */
! 2159: private int
! 2160: apprentice_compile(struct magic_set *ms, struct magic **magicp,
! 2161: uint32_t *nmagicp, const char *fn)
! 2162: {
! 2163: char *dbname;
! 2164: int rv = -1;
! 2165: php_stream *stream;
! 2166:
! 2167: TSRMLS_FETCH();
! 2168:
! 2169: dbname = mkdbname(ms, fn, 0);
! 2170:
! 2171: if (dbname == NULL) {
! 2172: goto out;
! 2173: }
! 2174:
! 2175: /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */
! 2176: #if PHP_API_VERSION < 20100412
! 2177: stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
! 2178: #else
! 2179: stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL);
! 2180: #endif
! 2181:
! 2182: if (!stream) {
! 2183: file_error(ms, errno, "cannot open `%s'", dbname);
! 2184: goto out;
! 2185: }
! 2186:
! 2187: if (php_stream_write(stream, (char *)ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
! 2188: file_error(ms, errno, "error writing `%s'", dbname);
! 2189: goto out;
! 2190: }
! 2191:
! 2192: if (php_stream_seek(stream,(off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
! 2193: file_error(ms, errno, "error seeking `%s'", dbname);
! 2194: goto out;
! 2195: }
! 2196:
! 2197: if (php_stream_write(stream, (char *)*magicp, (sizeof(struct magic) * *nmagicp) != (ssize_t)(sizeof(struct magic) * *nmagicp))) {
! 2198: file_error(ms, errno, "error writing `%s'", dbname);
! 2199: goto out;
! 2200: }
! 2201:
! 2202: php_stream_close(stream);
! 2203:
! 2204: rv = 0;
! 2205: out:
! 2206: efree(dbname);
! 2207: return rv;
! 2208: }
! 2209:
! 2210: private const char ext[] = ".mgc";
! 2211: /*
! 2212: * make a dbname
! 2213: */
! 2214: private char *
! 2215: mkdbname(struct magic_set *ms, const char *fn, int strip)
! 2216: {
! 2217: const char *p, *q;
! 2218: char *buf;
! 2219: TSRMLS_FETCH();
! 2220:
! 2221: if (strip) {
! 2222: if ((p = strrchr(fn, '/')) != NULL)
! 2223: fn = ++p;
! 2224: }
! 2225:
! 2226: for (q = fn; *q; q++)
! 2227: continue;
! 2228: /* Look for .mgc */
! 2229: for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
! 2230: if (*p != *q)
! 2231: break;
! 2232:
! 2233: /* Did not find .mgc, restore q */
! 2234: if (p >= ext)
! 2235: while (*q)
! 2236: q++;
! 2237:
! 2238: q++;
! 2239: /* Compatibility with old code that looked in .mime */
! 2240: if (ms->flags & MAGIC_MIME) {
! 2241: spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", (int)(q - fn), fn, ext);
! 2242: if (VCWD_ACCESS(buf, R_OK) != -1) {
! 2243: ms->flags &= MAGIC_MIME_TYPE;
! 2244: return buf;
! 2245: }
! 2246: efree(buf);
! 2247: }
! 2248: spprintf(&buf, MAXPATHLEN, "%.*s%s", (int)(q - fn), fn, ext);
! 2249:
! 2250: /* Compatibility with old code that looked in .mime */
! 2251: if (strstr(p, ".mime") != NULL)
! 2252: ms->flags &= MAGIC_MIME_TYPE;
! 2253: return buf;
! 2254: }
! 2255:
! 2256: /*
! 2257: * Byteswap an mmap'ed file if needed
! 2258: */
! 2259: private void
! 2260: byteswap(struct magic *magic, uint32_t nmagic)
! 2261: {
! 2262: uint32_t i;
! 2263: for (i = 0; i < nmagic; i++)
! 2264: bs1(&magic[i]);
! 2265: }
! 2266:
! 2267: /*
! 2268: * swap a short
! 2269: */
! 2270: private uint16_t
! 2271: swap2(uint16_t sv)
! 2272: {
! 2273: uint16_t rv;
! 2274: uint8_t *s = (uint8_t *)(void *)&sv;
! 2275: uint8_t *d = (uint8_t *)(void *)&rv;
! 2276: d[0] = s[1];
! 2277: d[1] = s[0];
! 2278: return rv;
! 2279: }
! 2280:
! 2281: /*
! 2282: * swap an int
! 2283: */
! 2284: private uint32_t
! 2285: swap4(uint32_t sv)
! 2286: {
! 2287: uint32_t rv;
! 2288: uint8_t *s = (uint8_t *)(void *)&sv;
! 2289: uint8_t *d = (uint8_t *)(void *)&rv;
! 2290: d[0] = s[3];
! 2291: d[1] = s[2];
! 2292: d[2] = s[1];
! 2293: d[3] = s[0];
! 2294: return rv;
! 2295: }
! 2296:
! 2297: /*
! 2298: * swap a quad
! 2299: */
! 2300: private uint64_t
! 2301: swap8(uint64_t sv)
! 2302: {
! 2303: uint64_t rv;
! 2304: uint8_t *s = (uint8_t *)(void *)&sv;
! 2305: uint8_t *d = (uint8_t *)(void *)&rv;
! 2306: #if 0
! 2307: d[0] = s[3];
! 2308: d[1] = s[2];
! 2309: d[2] = s[1];
! 2310: d[3] = s[0];
! 2311: d[4] = s[7];
! 2312: d[5] = s[6];
! 2313: d[6] = s[5];
! 2314: d[7] = s[4];
! 2315: #else
! 2316: d[0] = s[7];
! 2317: d[1] = s[6];
! 2318: d[2] = s[5];
! 2319: d[3] = s[4];
! 2320: d[4] = s[3];
! 2321: d[5] = s[2];
! 2322: d[6] = s[1];
! 2323: d[7] = s[0];
! 2324: #endif
! 2325: return rv;
! 2326: }
! 2327:
! 2328: /*
! 2329: * byteswap a single magic entry
! 2330: */
! 2331: private void
! 2332: bs1(struct magic *m)
! 2333: {
! 2334: m->cont_level = swap2(m->cont_level);
! 2335: m->offset = swap4((uint32_t)m->offset);
! 2336: m->in_offset = swap4((uint32_t)m->in_offset);
! 2337: m->lineno = swap4((uint32_t)m->lineno);
! 2338: if (IS_LIBMAGIC_STRING(m->type)) {
! 2339: m->str_range = swap4(m->str_range);
! 2340: m->str_flags = swap4(m->str_flags);
! 2341: }
! 2342: else {
! 2343: m->value.q = swap8(m->value.q);
! 2344: m->num_mask = swap8(m->num_mask);
! 2345: }
! 2346: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>