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 "file.h" 33 34 #ifndef lint 35 FILE_RCSID("@(#)$File: apprentice.c,v 1.211 2014/06/03 19:01:34 christos Exp $") 36 #endif /* lint */ 37 38 #include "magic.h" 39 #include <stdlib.h> 40 #ifdef HAVE_UNISTD_H 41 #include <unistd.h> 42 #endif 43 #ifdef HAVE_STDDEF_H 44 #include <stddef.h> 45 #endif 46 #include <string.h> 47 #include <assert.h> 48 #include <ctype.h> 49 #include <fcntl.h> 50 #ifdef QUICK 51 #include <sys/mman.h> 52 #endif 53 #include <dirent.h> 54 #if defined(HAVE_LIMITS_H) 55 #include <limits.h> 56 #endif 57 58 #ifndef SSIZE_MAX 59 #define MAXMAGIC_SIZE ((ssize_t)0x7fffffff) 60 #else 61 #define MAXMAGIC_SIZE SSIZE_MAX 62 #endif 63 64 #define EATAB {while (isascii((unsigned char) *l) && \ 65 isspace((unsigned char) *l)) ++l;} 66 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \ 67 tolower((unsigned char) (l)) : (l)) 68 /* 69 * Work around a bug in headers on Digital Unix. 70 * At least confirmed for: OSF1 V4.0 878 71 */ 72 #if defined(__osf__) && defined(__DECC) 73 #ifdef MAP_FAILED 74 #undef MAP_FAILED 75 #endif 76 #endif 77 78 #ifndef MAP_FAILED 79 #define MAP_FAILED (void *) -1 80 #endif 81 82 #ifndef MAP_FILE 83 #define MAP_FILE 0 84 #endif 85 86 #define ALLOC_CHUNK (size_t)10 87 #define ALLOC_INCR (size_t)200 88 89 struct magic_entry { 90 struct magic *mp; 91 uint32_t cont_count; 92 uint32_t max_count; 93 }; 94 95 struct magic_entry_set { 96 struct magic_entry *me; 97 uint32_t count; 98 uint32_t max; 99 }; 100 101 struct magic_map { 102 void *p; 103 size_t len; 104 struct magic *magic[MAGIC_SETS]; 105 uint32_t nmagic[MAGIC_SETS]; 106 }; 107 108 int file_formats[FILE_NAMES_SIZE]; 109 const size_t file_nformats = FILE_NAMES_SIZE; 110 const char *file_names[FILE_NAMES_SIZE]; 111 const size_t file_nnames = FILE_NAMES_SIZE; 112 113 private int getvalue(struct magic_set *ms, struct magic *, const char **, int); 114 private int hextoint(int); 115 private const char *getstr(struct magic_set *, struct magic *, const char *, 116 int); 117 private int parse(struct magic_set *, struct magic_entry *, const char *, 118 size_t, int); 119 private void eatsize(const char **); 120 private int apprentice_1(struct magic_set *, const char *, int); 121 private size_t apprentice_magic_strength(const struct magic *); 122 private int apprentice_sort(const void *, const void *); 123 private void apprentice_list(struct mlist *, int ); 124 private struct magic_map *apprentice_load(struct magic_set *, 125 const char *, int); 126 private struct mlist *mlist_alloc(void); 127 private void mlist_free(struct mlist *); 128 private void byteswap(struct magic *, uint32_t); 129 private void bs1(struct magic *); 130 private uint16_t swap2(uint16_t); 131 private uint32_t swap4(uint32_t); 132 private uint64_t swap8(uint64_t); 133 private char *mkdbname(struct magic_set *, const char *, int); 134 private struct magic_map *apprentice_map(struct magic_set *, const char *); 135 private void apprentice_unmap(struct magic_map *); 136 private int apprentice_compile(struct magic_set *, struct magic_map *, 137 const char *); 138 private int check_format_type(const char *, int); 139 private int check_format(struct magic_set *, struct magic *); 140 private int get_op(char); 141 private int parse_mime(struct magic_set *, struct magic_entry *, const char *); 142 private int parse_strength(struct magic_set *, struct magic_entry *, const char *); 143 private int parse_apple(struct magic_set *, struct magic_entry *, const char *); 144 145 146 private size_t magicsize = sizeof(struct magic); 147 148 private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; 149 150 private struct { 151 const char *name; 152 size_t len; 153 int (*fun)(struct magic_set *, struct magic_entry *, const char *); 154 } bang[] = { 155 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name } 156 DECLARE_FIELD(mime), 157 DECLARE_FIELD(apple), 158 DECLARE_FIELD(strength), 159 #undef DECLARE_FIELD 160 { NULL, 0, NULL } 161 }; 162 163 #ifdef COMPILE_ONLY 164 165 int main(int, char *[]); 166 167 int 168 main(int argc, char *argv[]) 169 { 170 int ret; 171 struct magic_set *ms; 172 char *progname; 173 174 if ((progname = strrchr(argv[0], '/')) != NULL) 175 progname++; 176 else 177 progname = argv[0]; 178 179 if (argc != 2) { 180 (void)fprintf(stderr, "Usage: %s file\n", progname); 181 return 1; 182 } 183 184 if ((ms = magic_open(MAGIC_CHECK)) == NULL) { 185 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 186 return 1; 187 } 188 ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; 189 if (ret == 1) 190 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); 191 magic_close(ms); 192 return ret; 193 } 194 #endif /* COMPILE_ONLY */ 195 196 struct type_tbl_s { 197 const char name[16]; 198 const size_t len; 199 const int type; 200 const int format; 201 }; 202 203 /* 204 * XXX - the actual Single UNIX Specification says that "long" means "long", 205 * as in the C data type, but we treat it as meaning "4-byte integer". 206 * Given that the OS X version of file 5.04 did the same, I guess that passes 207 * the actual test; having "long" be dependent on how big a "long" is on 208 * the machine running "file" is silly. 209 */ 210 static const struct type_tbl_s type_tbl[] = { 211 # define XX(s) s, (sizeof(s) - 1) 212 # define XX_NULL "", 0 213 { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, 214 { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, 215 { XX("short"), FILE_SHORT, FILE_FMT_NUM }, 216 { XX("default"), FILE_DEFAULT, FILE_FMT_NONE }, 217 { XX("long"), FILE_LONG, FILE_FMT_NUM }, 218 { XX("string"), FILE_STRING, FILE_FMT_STR }, 219 { XX("date"), FILE_DATE, FILE_FMT_STR }, 220 { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM }, 221 { XX("belong"), FILE_BELONG, FILE_FMT_NUM }, 222 { XX("bedate"), FILE_BEDATE, FILE_FMT_STR }, 223 { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM }, 224 { XX("lelong"), FILE_LELONG, FILE_FMT_NUM }, 225 { XX("ledate"), FILE_LEDATE, FILE_FMT_STR }, 226 { XX("pstring"), FILE_PSTRING, FILE_FMT_STR }, 227 { XX("ldate"), FILE_LDATE, FILE_FMT_STR }, 228 { XX("beldate"), FILE_BELDATE, FILE_FMT_STR }, 229 { XX("leldate"), FILE_LELDATE, FILE_FMT_STR }, 230 { XX("regex"), FILE_REGEX, FILE_FMT_STR }, 231 { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR }, 232 { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR }, 233 { XX("search"), FILE_SEARCH, FILE_FMT_STR }, 234 { XX("medate"), FILE_MEDATE, FILE_FMT_STR }, 235 { XX("meldate"), FILE_MELDATE, FILE_FMT_STR }, 236 { XX("melong"), FILE_MELONG, FILE_FMT_NUM }, 237 { XX("quad"), FILE_QUAD, FILE_FMT_QUAD }, 238 { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD }, 239 { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD }, 240 { XX("qdate"), FILE_QDATE, FILE_FMT_STR }, 241 { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR }, 242 { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR }, 243 { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, 244 { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, 245 { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, 246 { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT }, 247 { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT }, 248 { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT }, 249 { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE }, 250 { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE }, 251 { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, 252 { XX("leid3"), FILE_LEID3, FILE_FMT_NUM }, 253 { XX("beid3"), FILE_BEID3, FILE_FMT_NUM }, 254 { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM }, 255 { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, 256 { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, 257 { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, 258 { XX("name"), FILE_NAME, FILE_FMT_NONE }, 259 { XX("use"), FILE_USE, FILE_FMT_NONE }, 260 { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, 261 { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 262 }; 263 264 /* 265 * These are not types, and cannot be preceded by "u" to make them 266 * unsigned. 267 */ 268 static const struct type_tbl_s special_tbl[] = { 269 { XX("name"), FILE_NAME, FILE_FMT_STR }, 270 { XX("use"), FILE_USE, FILE_FMT_STR }, 271 { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 272 }; 273 # undef XX 274 # undef XX_NULL 275 276 private int 277 get_type(const struct type_tbl_s *tbl, const char *l, const char **t) 278 { 279 const struct type_tbl_s *p; 280 281 for (p = tbl; p->len; p++) { 282 if (strncmp(l, p->name, p->len) == 0) { 283 if (t) 284 *t = l + p->len; 285 break; 286 } 287 } 288 return p->type; 289 } 290 291 private int 292 get_standard_integer_type(const char *l, const char **t) 293 { 294 int type; 295 296 if (isalpha((unsigned char)l[1])) { 297 switch (l[1]) { 298 case 'C': 299 /* "dC" and "uC" */ 300 type = FILE_BYTE; 301 break; 302 case 'S': 303 /* "dS" and "uS" */ 304 type = FILE_SHORT; 305 break; 306 case 'I': 307 case 'L': 308 /* 309 * "dI", "dL", "uI", and "uL". 310 * 311 * XXX - the actual Single UNIX Specification says 312 * that "L" means "long", as in the C data type, 313 * but we treat it as meaning "4-byte integer". 314 * Given that the OS X version of file 5.04 did 315 * the same, I guess that passes the actual SUS 316 * validation suite; having "dL" be dependent on 317 * how big a "long" is on the machine running 318 * "file" is silly. 319 */ 320 type = FILE_LONG; 321 break; 322 case 'Q': 323 /* "dQ" and "uQ" */ 324 type = FILE_QUAD; 325 break; 326 default: 327 /* "d{anything else}", "u{anything else}" */ 328 return FILE_INVALID; 329 } 330 l += 2; 331 } else if (isdigit((unsigned char)l[1])) { 332 /* 333 * "d{num}" and "u{num}"; we only support {num} values 334 * of 1, 2, 4, and 8 - the Single UNIX Specification 335 * doesn't say anything about whether arbitrary 336 * values should be supported, but both the Solaris 10 337 * and OS X Mountain Lion versions of file passed the 338 * Single UNIX Specification validation suite, and 339 * neither of them support values bigger than 8 or 340 * non-power-of-2 values. 341 */ 342 if (isdigit((unsigned char)l[2])) { 343 /* Multi-digit, so > 9 */ 344 return FILE_INVALID; 345 } 346 switch (l[1]) { 347 case '1': 348 type = FILE_BYTE; 349 break; 350 case '2': 351 type = FILE_SHORT; 352 break; 353 case '4': 354 type = FILE_LONG; 355 break; 356 case '8': 357 type = FILE_QUAD; 358 break; 359 default: 360 /* XXX - what about 3, 5, 6, or 7? */ 361 return FILE_INVALID; 362 } 363 l += 2; 364 } else { 365 /* 366 * "d" or "u" by itself. 367 */ 368 type = FILE_LONG; 369 ++l; 370 } 371 if (t) 372 *t = l; 373 return type; 374 } 375 376 private void 377 init_file_tables(void) 378 { 379 static int done = 0; 380 const struct type_tbl_s *p; 381 382 if (done) 383 return; 384 done++; 385 386 for (p = type_tbl; p->len; p++) { 387 assert(p->type < FILE_NAMES_SIZE); 388 file_names[p->type] = p->name; 389 file_formats[p->type] = p->format; 390 } 391 assert(p - type_tbl == FILE_NAMES_SIZE); 392 } 393 394 private int 395 add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) 396 { 397 struct mlist *ml; 398 399 if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 400 return -1; 401 402 ml->map = idx == 0 ? map : NULL; 403 ml->magic = map->magic[idx]; 404 ml->nmagic = map->nmagic[idx]; 405 406 mlp->prev->next = ml; 407 ml->prev = mlp->prev; 408 ml->next = mlp; 409 mlp->prev = ml; 410 return 0; 411 } 412 413 /* 414 * Handle one file or directory. 415 */ 416 private int 417 apprentice_1(struct magic_set *ms, const char *fn, int action) 418 { 419 #ifndef COMPILE_ONLY 420 struct mlist *ml; 421 #endif /* COMPILE_ONLY */ 422 struct magic_map *map; 423 #ifndef COMPILE_ONLY 424 size_t i; 425 #endif /* COMPILE_ONLY */ 426 427 if (magicsize != FILE_MAGICSIZE) { 428 file_error(ms, 0, "magic element size %lu != %lu", 429 (unsigned long)sizeof(*map->magic[0]), 430 (unsigned long)FILE_MAGICSIZE); 431 return -1; 432 } 433 434 if (action == FILE_COMPILE) { 435 map = apprentice_load(ms, fn, action); 436 if (map == NULL) 437 return -1; 438 return apprentice_compile(ms, map, fn); 439 } 440 441 #ifndef COMPILE_ONLY 442 map = apprentice_map(ms, fn); 443 if (map == NULL) { 444 if (ms->flags & MAGIC_CHECK) 445 file_magwarn(ms, "using regular magic file `%s'", fn); 446 map = apprentice_load(ms, fn, action); 447 if (map == NULL) 448 return -1; 449 } 450 451 for (i = 0; i < MAGIC_SETS; i++) { 452 if (add_mlist(ms->mlist[i], map, i) == -1) { 453 file_oomem(ms, sizeof(*ml)); 454 apprentice_unmap(map); 455 return -1; 456 } 457 } 458 459 if (action == FILE_LIST) { 460 for (i = 0; i < MAGIC_SETS; i++) { 461 printf("Set %zu:\nBinary patterns:\n", i); 462 apprentice_list(ms->mlist[i], BINTEST); 463 printf("Text patterns:\n"); 464 apprentice_list(ms->mlist[i], TEXTTEST); 465 } 466 } 467 #endif /* COMPILE_ONLY */ 468 469 return 0; 470 } 471 472 protected void 473 file_ms_free(struct magic_set *ms) 474 { 475 size_t i; 476 if (ms == NULL) 477 return; 478 for (i = 0; i < MAGIC_SETS; i++) 479 mlist_free(ms->mlist[i]); 480 free(ms->o.pbuf); 481 free(ms->o.buf); 482 free(ms->c.li); 483 free(ms); 484 } 485 486 protected struct magic_set * 487 file_ms_alloc(int flags) 488 { 489 struct magic_set *ms; 490 size_t i, len; 491 492 if ((ms = CAST(struct magic_set *, calloc((size_t)1, 493 sizeof(struct magic_set)))) == NULL) 494 return NULL; 495 496 if (magic_setflags(ms, flags) == -1) { 497 errno = EINVAL; 498 goto free; 499 } 500 501 ms->o.buf = ms->o.pbuf = NULL; 502 len = (ms->c.len = 10) * sizeof(*ms->c.li); 503 504 if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 505 goto free; 506 507 ms->event_flags = 0; 508 ms->error = -1; 509 for (i = 0; i < MAGIC_SETS; i++) 510 ms->mlist[i] = NULL; 511 ms->file = "unknown"; 512 ms->line = 0; 513 return ms; 514 free: 515 free(ms); 516 return NULL; 517 } 518 519 private void 520 apprentice_unmap(struct magic_map *map) 521 { 522 if (map == NULL) 523 return; 524 if (map->p != NULL) { 525 #ifdef QUICK 526 if (map->len) 527 (void)munmap(map->p, map->len); 528 else 529 #endif 530 free(map->p); 531 } else { 532 uint32_t j; 533 for (j = 0; j < MAGIC_SETS; j++) 534 free(map->magic[j]); 535 } 536 free(map); 537 } 538 539 private struct mlist * 540 mlist_alloc(void) 541 { 542 struct mlist *mlist; 543 if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 544 return NULL; 545 } 546 mlist->next = mlist->prev = mlist; 547 return mlist; 548 } 549 550 private void 551 mlist_free(struct mlist *mlist) 552 { 553 struct mlist *ml; 554 555 if (mlist == NULL) 556 return; 557 558 for (ml = mlist->next; ml != mlist;) { 559 struct mlist *next = ml->next; 560 if (ml->map) 561 apprentice_unmap(ml->map); 562 free(ml); 563 ml = next; 564 } 565 free(ml); 566 } 567 568 /* const char *fn: list of magic files and directories */ 569 protected int 570 file_apprentice(struct magic_set *ms, const char *fn, int action) 571 { 572 char *p, *mfn; 573 int file_err, errs = -1; 574 size_t i; 575 576 if (ms->mlist[0] != NULL) 577 file_reset(ms); 578 579 if ((fn = magic_getpath(fn, action)) == NULL) 580 return -1; 581 582 init_file_tables(); 583 584 if ((mfn = strdup(fn)) == NULL) { 585 file_oomem(ms, strlen(fn)); 586 return -1; 587 } 588 589 for (i = 0; i < MAGIC_SETS; i++) { 590 mlist_free(ms->mlist[i]); 591 if ((ms->mlist[i] = mlist_alloc()) == NULL) { 592 file_oomem(ms, sizeof(*ms->mlist[i])); 593 if (i != 0) { 594 --i; 595 do 596 mlist_free(ms->mlist[i]); 597 while (i != 0); 598 } 599 free(mfn); 600 return -1; 601 } 602 } 603 fn = mfn; 604 605 while (fn) { 606 p = strchr(fn, PATHSEP); 607 if (p) 608 *p++ = '\0'; 609 if (*fn == '\0') 610 break; 611 file_err = apprentice_1(ms, fn, action); 612 errs = MAX(errs, file_err); 613 fn = p; 614 } 615 616 free(mfn); 617 618 if (errs == -1) { 619 for (i = 0; i < MAGIC_SETS; i++) { 620 mlist_free(ms->mlist[i]); 621 ms->mlist[i] = NULL; 622 } 623 file_error(ms, 0, "could not find any valid magic files!"); 624 return -1; 625 } 626 627 #if 0 628 /* 629 * Always leave the database loaded 630 */ 631 if (action == FILE_LOAD) 632 return 0; 633 634 for (i = 0; i < MAGIC_SETS; i++) { 635 mlist_free(ms->mlist[i]); 636 ms->mlist[i] = NULL; 637 } 638 #endif 639 640 switch (action) { 641 case FILE_LOAD: 642 case FILE_COMPILE: 643 case FILE_CHECK: 644 case FILE_LIST: 645 return 0; 646 default: 647 file_error(ms, 0, "Invalid action %d", action); 648 return -1; 649 } 650 } 651 652 /* 653 * Compute the real length of a magic expression, for the purposes 654 * of determining how "strong" a magic expression is (approximating 655 * how specific its matches are): 656 * - magic characters count 0 unless escaped. 657 * - [] expressions count 1 658 * - {} expressions count 0 659 * - regular characters or escaped magic characters count 1 660 * - 0 length expressions count as one 661 */ 662 private size_t 663 nonmagic(const char *str) 664 { 665 const char *p; 666 size_t rv = 0; 667 668 for (p = str; *p; p++) 669 switch (*p) { 670 case '\\': /* Escaped anything counts 1 */ 671 if (!*++p) 672 p--; 673 rv++; 674 continue; 675 case '?': /* Magic characters count 0 */ 676 case '*': 677 case '.': 678 case '+': 679 case '^': 680 case '$': 681 continue; 682 case '[': /* Bracketed expressions count 1 the ']' */ 683 while (*p && *p != ']') 684 p++; 685 p--; 686 continue; 687 case '{': /* Braced expressions count 0 */ 688 while (*p && *p != '}') 689 p++; 690 if (!*p) 691 p--; 692 continue; 693 default: /* Anything else counts 1 */ 694 rv++; 695 continue; 696 } 697 698 return rv == 0 ? 1 : rv; /* Return at least 1 */ 699 } 700 701 /* 702 * Get weight of this magic entry, for sorting purposes. 703 */ 704 private size_t 705 apprentice_magic_strength(const struct magic *m) 706 { 707 #define MULT 10 708 size_t v, val = 2 * MULT; /* baseline strength */ 709 710 switch (m->type) { 711 case FILE_DEFAULT: /* make sure this sorts last */ 712 if (m->factor_op != FILE_FACTOR_OP_NONE) 713 abort(); 714 return 0; 715 716 case FILE_BYTE: 717 val += 1 * MULT; 718 break; 719 720 case FILE_SHORT: 721 case FILE_LESHORT: 722 case FILE_BESHORT: 723 val += 2 * MULT; 724 break; 725 726 case FILE_LONG: 727 case FILE_LELONG: 728 case FILE_BELONG: 729 case FILE_MELONG: 730 val += 4 * MULT; 731 break; 732 733 case FILE_PSTRING: 734 case FILE_STRING: 735 val += m->vallen * MULT; 736 break; 737 738 case FILE_BESTRING16: 739 case FILE_LESTRING16: 740 val += m->vallen * MULT / 2; 741 break; 742 743 case FILE_SEARCH: 744 val += m->vallen * MAX(MULT / m->vallen, 1); 745 break; 746 747 case FILE_REGEX: 748 v = nonmagic(m->value.s); 749 val += v * MAX(MULT / v, 1); 750 break; 751 752 case FILE_DATE: 753 case FILE_LEDATE: 754 case FILE_BEDATE: 755 case FILE_MEDATE: 756 case FILE_LDATE: 757 case FILE_LELDATE: 758 case FILE_BELDATE: 759 case FILE_MELDATE: 760 case FILE_FLOAT: 761 case FILE_BEFLOAT: 762 case FILE_LEFLOAT: 763 val += 4 * MULT; 764 break; 765 766 case FILE_QUAD: 767 case FILE_BEQUAD: 768 case FILE_LEQUAD: 769 case FILE_QDATE: 770 case FILE_LEQDATE: 771 case FILE_BEQDATE: 772 case FILE_QLDATE: 773 case FILE_LEQLDATE: 774 case FILE_BEQLDATE: 775 case FILE_QWDATE: 776 case FILE_LEQWDATE: 777 case FILE_BEQWDATE: 778 case FILE_DOUBLE: 779 case FILE_BEDOUBLE: 780 case FILE_LEDOUBLE: 781 val += 8 * MULT; 782 break; 783 784 case FILE_INDIRECT: 785 case FILE_NAME: 786 case FILE_USE: 787 break; 788 789 default: 790 (void)fprintf(stderr, "Bad type %d\n", m->type); 791 abort(); 792 } 793 794 switch (m->reln) { 795 case 'x': /* matches anything penalize */ 796 case '!': /* matches almost anything penalize */ 797 val = 0; 798 break; 799 800 case '=': /* Exact match, prefer */ 801 val += MULT; 802 break; 803 804 case '>': 805 case '<': /* comparison match reduce strength */ 806 val -= 2 * MULT; 807 break; 808 809 case '^': 810 case '&': /* masking bits, we could count them too */ 811 val -= MULT; 812 break; 813 814 default: 815 (void)fprintf(stderr, "Bad relation %c\n", m->reln); 816 abort(); 817 } 818 819 if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */ 820 val = 1; 821 822 switch (m->factor_op) { 823 case FILE_FACTOR_OP_NONE: 824 break; 825 case FILE_FACTOR_OP_PLUS: 826 val += m->factor; 827 break; 828 case FILE_FACTOR_OP_MINUS: 829 val -= m->factor; 830 break; 831 case FILE_FACTOR_OP_TIMES: 832 val *= m->factor; 833 break; 834 case FILE_FACTOR_OP_DIV: 835 val /= m->factor; 836 break; 837 default: 838 abort(); 839 } 840 841 /* 842 * Magic entries with no description get a bonus because they depend 843 * on subsequent magic entries to print something. 844 */ 845 if (m->desc[0] == '\0') 846 val++; 847 return val; 848 } 849 850 /* 851 * Sort callback for sorting entries by "strength" (basically length) 852 */ 853 private int 854 apprentice_sort(const void *a, const void *b) 855 { 856 const struct magic_entry *ma = CAST(const struct magic_entry *, a); 857 const struct magic_entry *mb = CAST(const struct magic_entry *, b); 858 size_t sa = apprentice_magic_strength(ma->mp); 859 size_t sb = apprentice_magic_strength(mb->mp); 860 if (sa == sb) 861 return 0; 862 else if (sa > sb) 863 return -1; 864 else 865 return 1; 866 } 867 868 /* 869 * Shows sorted patterns list in the order which is used for the matching 870 */ 871 private void 872 apprentice_list(struct mlist *mlist, int mode) 873 { 874 uint32_t magindex = 0; 875 struct mlist *ml; 876 for (ml = mlist->next; ml != mlist; ml = ml->next) { 877 for (magindex = 0; magindex < ml->nmagic; magindex++) { 878 struct magic *m = &ml->magic[magindex]; 879 if ((m->flag & mode) != mode) { 880 /* Skip sub-tests */ 881 while (magindex + 1 < ml->nmagic && 882 ml->magic[magindex + 1].cont_level != 0) 883 ++magindex; 884 continue; /* Skip to next top-level test*/ 885 } 886 887 /* 888 * Try to iterate over the tree until we find item with 889 * description/mimetype. 890 */ 891 while (magindex + 1 < ml->nmagic && 892 ml->magic[magindex + 1].cont_level != 0 && 893 *ml->magic[magindex].desc == '\0' && 894 *ml->magic[magindex].mimetype == '\0') 895 magindex++; 896 897 printf("Strength = %3" SIZE_T_FORMAT "u : %s [%s]\n", 898 apprentice_magic_strength(m), 899 ml->magic[magindex].desc, 900 ml->magic[magindex].mimetype); 901 } 902 } 903 } 904 905 private void 906 set_test_type(struct magic *mstart, struct magic *m) 907 { 908 switch (m->type) { 909 case FILE_BYTE: 910 case FILE_SHORT: 911 case FILE_LONG: 912 case FILE_DATE: 913 case FILE_BESHORT: 914 case FILE_BELONG: 915 case FILE_BEDATE: 916 case FILE_LESHORT: 917 case FILE_LELONG: 918 case FILE_LEDATE: 919 case FILE_LDATE: 920 case FILE_BELDATE: 921 case FILE_LELDATE: 922 case FILE_MEDATE: 923 case FILE_MELDATE: 924 case FILE_MELONG: 925 case FILE_QUAD: 926 case FILE_LEQUAD: 927 case FILE_BEQUAD: 928 case FILE_QDATE: 929 case FILE_LEQDATE: 930 case FILE_BEQDATE: 931 case FILE_QLDATE: 932 case FILE_LEQLDATE: 933 case FILE_BEQLDATE: 934 case FILE_QWDATE: 935 case FILE_LEQWDATE: 936 case FILE_BEQWDATE: 937 case FILE_FLOAT: 938 case FILE_BEFLOAT: 939 case FILE_LEFLOAT: 940 case FILE_DOUBLE: 941 case FILE_BEDOUBLE: 942 case FILE_LEDOUBLE: 943 mstart->flag |= BINTEST; 944 break; 945 case FILE_STRING: 946 case FILE_PSTRING: 947 case FILE_BESTRING16: 948 case FILE_LESTRING16: 949 /* Allow text overrides */ 950 if (mstart->str_flags & STRING_TEXTTEST) 951 mstart->flag |= TEXTTEST; 952 else 953 mstart->flag |= BINTEST; 954 break; 955 case FILE_REGEX: 956 case FILE_SEARCH: 957 /* Check for override */ 958 if (mstart->str_flags & STRING_BINTEST) 959 mstart->flag |= BINTEST; 960 if (mstart->str_flags & STRING_TEXTTEST) 961 mstart->flag |= TEXTTEST; 962 963 if (mstart->flag & (TEXTTEST|BINTEST)) 964 break; 965 966 /* binary test if pattern is not text */ 967 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL, 968 NULL) <= 0) 969 mstart->flag |= BINTEST; 970 else 971 mstart->flag |= TEXTTEST; 972 break; 973 case FILE_DEFAULT: 974 /* can't deduce anything; we shouldn't see this at the 975 top level anyway */ 976 break; 977 case FILE_INVALID: 978 default: 979 /* invalid search type, but no need to complain here */ 980 break; 981 } 982 } 983 984 private int 985 addentry(struct magic_set *ms, struct magic_entry *me, 986 struct magic_entry_set *mset) 987 { 988 size_t i = me->mp->type == FILE_NAME ? 1 : 0; 989 if (mset[i].count == mset[i].max) { 990 struct magic_entry *mp; 991 992 mset[i].max += ALLOC_INCR; 993 if ((mp = CAST(struct magic_entry *, 994 realloc(mset[i].me, sizeof(*mp) * mset[i].max))) == 995 NULL) { 996 file_oomem(ms, sizeof(*mp) * mset[i].max); 997 return -1; 998 } 999 (void)memset(&mp[mset[i].count], 0, sizeof(*mp) * 1000 ALLOC_INCR); 1001 mset[i].me = mp; 1002 } 1003 mset[i].me[mset[i].count++] = *me; 1004 memset(me, 0, sizeof(*me)); 1005 return 0; 1006 } 1007 1008 /* 1009 * Load and parse one file. 1010 */ 1011 private void 1012 load_1(struct magic_set *ms, int action, const char *fn, int *errs, 1013 struct magic_entry_set *mset) 1014 { 1015 size_t lineno = 0, llen = 0; 1016 char *line = NULL; 1017 ssize_t len; 1018 struct magic_entry me; 1019 1020 FILE *f = fopen(ms->file = fn, "r"); 1021 if (f == NULL) { 1022 if (errno != ENOENT) 1023 file_error(ms, errno, "cannot read magic file `%s'", 1024 fn); 1025 (*errs)++; 1026 return; 1027 } 1028 1029 memset(&me, 0, sizeof(me)); 1030 /* read and parse this file */ 1031 for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 1032 ms->line++) { 1033 if (len == 0) /* null line, garbage, etc */ 1034 continue; 1035 if (line[len - 1] == '\n') { 1036 lineno++; 1037 line[len - 1] = '\0'; /* delete newline */ 1038 } 1039 switch (line[0]) { 1040 case '\0': /* empty, do not parse */ 1041 case '#': /* comment, do not parse */ 1042 continue; 1043 case '!': 1044 if (line[1] == ':') { 1045 size_t i; 1046 1047 for (i = 0; bang[i].name != NULL; i++) { 1048 if ((size_t)(len - 2) > bang[i].len && 1049 memcmp(bang[i].name, line + 2, 1050 bang[i].len) == 0) 1051 break; 1052 } 1053 if (bang[i].name == NULL) { 1054 file_error(ms, 0, 1055 "Unknown !: entry `%s'", line); 1056 (*errs)++; 1057 continue; 1058 } 1059 if (me.mp == NULL) { 1060 file_error(ms, 0, 1061 "No current entry for :!%s type", 1062 bang[i].name); 1063 (*errs)++; 1064 continue; 1065 } 1066 if ((*bang[i].fun)(ms, &me, 1067 line + bang[i].len + 2) != 0) { 1068 (*errs)++; 1069 continue; 1070 } 1071 continue; 1072 } 1073 /*FALLTHROUGH*/ 1074 default: 1075 again: 1076 switch (parse(ms, &me, line, lineno, action)) { 1077 case 0: 1078 continue; 1079 case 1: 1080 (void)addentry(ms, &me, mset); 1081 goto again; 1082 default: 1083 (*errs)++; 1084 break; 1085 } 1086 } 1087 } 1088 if (me.mp) 1089 (void)addentry(ms, &me, mset); 1090 free(line); 1091 (void)fclose(f); 1092 } 1093 1094 /* 1095 * parse a file or directory of files 1096 * const char *fn: name of magic file or directory 1097 */ 1098 private int 1099 cmpstrp(const void *p1, const void *p2) 1100 { 1101 return strcmp(*(char *const *)p1, *(char *const *)p2); 1102 } 1103 1104 1105 private uint32_t 1106 set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1107 uint32_t starttest) 1108 { 1109 static const char text[] = "text"; 1110 static const char binary[] = "binary"; 1111 static const size_t len = sizeof(text); 1112 1113 uint32_t i = starttest; 1114 1115 do { 1116 set_test_type(me[starttest].mp, me[i].mp); 1117 if ((ms->flags & MAGIC_DEBUG) == 0) 1118 continue; 1119 (void)fprintf(stderr, "%s%s%s: %s\n", 1120 me[i].mp->mimetype, 1121 me[i].mp->mimetype[0] == '\0' ? "" : "; ", 1122 me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", 1123 me[i].mp->flag & BINTEST ? binary : text); 1124 if (me[i].mp->flag & BINTEST) { 1125 char *p = strstr(me[i].mp->desc, text); 1126 if (p && (p == me[i].mp->desc || 1127 isspace((unsigned char)p[-1])) && 1128 (p + len - me[i].mp->desc == MAXstring 1129 || (p[len] == '\0' || 1130 isspace((unsigned char)p[len])))) 1131 (void)fprintf(stderr, "*** Possible " 1132 "binary test for text type\n"); 1133 } 1134 } while (++i < nme && me[i].mp->cont_level != 0); 1135 return i; 1136 } 1137 1138 private void 1139 set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) 1140 { 1141 uint32_t i; 1142 for (i = 0; i < nme; i++) { 1143 if (me[i].mp->cont_level == 0 && 1144 me[i].mp->type == FILE_DEFAULT) { 1145 while (++i < nme) 1146 if (me[i].mp->cont_level == 0) 1147 break; 1148 if (i != nme) { 1149 /* XXX - Ugh! */ 1150 ms->line = me[i].mp->lineno; 1151 file_magwarn(ms, 1152 "level 0 \"default\" did not sort last"); 1153 } 1154 return; 1155 } 1156 } 1157 } 1158 1159 private int 1160 coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1161 struct magic **ma, uint32_t *nma) 1162 { 1163 uint32_t i, mentrycount = 0; 1164 size_t slen; 1165 1166 for (i = 0; i < nme; i++) 1167 mentrycount += me[i].cont_count; 1168 1169 slen = sizeof(**ma) * mentrycount; 1170 if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 1171 file_oomem(ms, slen); 1172 return -1; 1173 } 1174 1175 mentrycount = 0; 1176 for (i = 0; i < nme; i++) { 1177 (void)memcpy(*ma + mentrycount, me[i].mp, 1178 me[i].cont_count * sizeof(**ma)); 1179 mentrycount += me[i].cont_count; 1180 } 1181 *nma = mentrycount; 1182 return 0; 1183 } 1184 1185 private void 1186 magic_entry_free(struct magic_entry *me, uint32_t nme) 1187 { 1188 uint32_t i; 1189 if (me == NULL) 1190 return; 1191 for (i = 0; i < nme; i++) 1192 free(me[i].mp); 1193 free(me); 1194 } 1195 1196 private struct magic_map * 1197 apprentice_load(struct magic_set *ms, const char *fn, int action) 1198 { 1199 int errs = 0; 1200 uint32_t i, j; 1201 size_t files = 0, maxfiles = 0; 1202 char **filearr = NULL, *mfn; 1203 struct stat st; 1204 struct magic_map *map; 1205 struct magic_entry_set mset[MAGIC_SETS]; 1206 DIR *dir; 1207 struct dirent *d; 1208 1209 memset(mset, 0, sizeof(mset)); 1210 ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 1211 1212 1213 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 1214 { 1215 file_oomem(ms, sizeof(*map)); 1216 return NULL; 1217 } 1218 1219 /* print silly verbose header for USG compat. */ 1220 if (action == FILE_CHECK) 1221 (void)fprintf(stderr, "%s\n", usg_hdr); 1222 1223 /* load directory or file */ 1224 if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 1225 dir = opendir(fn); 1226 if (!dir) { 1227 errs++; 1228 goto out; 1229 } 1230 while ((d = readdir(dir)) != NULL) { 1231 if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 1232 file_oomem(ms, 1233 strlen(fn) + strlen(d->d_name) + 2); 1234 errs++; 1235 closedir(dir); 1236 goto out; 1237 } 1238 if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 1239 free(mfn); 1240 continue; 1241 } 1242 if (files >= maxfiles) { 1243 size_t mlen; 1244 maxfiles = (maxfiles + 1) * 2; 1245 mlen = maxfiles * sizeof(*filearr); 1246 if ((filearr = CAST(char **, 1247 realloc(filearr, mlen))) == NULL) { 1248 file_oomem(ms, mlen); 1249 free(mfn); 1250 closedir(dir); 1251 errs++; 1252 goto out; 1253 } 1254 } 1255 filearr[files++] = mfn; 1256 } 1257 closedir(dir); 1258 qsort(filearr, files, sizeof(*filearr), cmpstrp); 1259 for (i = 0; i < files; i++) { 1260 load_1(ms, action, filearr[i], &errs, mset); 1261 free(filearr[i]); 1262 } 1263 free(filearr); 1264 } else 1265 load_1(ms, action, fn, &errs, mset); 1266 if (errs) 1267 goto out; 1268 1269 for (j = 0; j < MAGIC_SETS; j++) { 1270 /* Set types of tests */ 1271 for (i = 0; i < mset[j].count; ) { 1272 if (mset[j].me[i].mp->cont_level != 0) { 1273 i++; 1274 continue; 1275 } 1276 i = set_text_binary(ms, mset[j].me, mset[j].count, i); 1277 } 1278 qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me), 1279 apprentice_sort); 1280 1281 /* 1282 * Make sure that any level 0 "default" line is last 1283 * (if one exists). 1284 */ 1285 set_last_default(ms, mset[j].me, mset[j].count); 1286 1287 /* coalesce per file arrays into a single one */ 1288 if (coalesce_entries(ms, mset[j].me, mset[j].count, 1289 &map->magic[j], &map->nmagic[j]) == -1) { 1290 errs++; 1291 goto out; 1292 } 1293 } 1294 1295 out: 1296 for (j = 0; j < MAGIC_SETS; j++) 1297 magic_entry_free(mset[j].me, mset[j].count); 1298 1299 if (errs) { 1300 apprentice_unmap(map); 1301 return NULL; 1302 } 1303 return map; 1304 } 1305 1306 /* 1307 * extend the sign bit if the comparison is to be signed 1308 */ 1309 protected uint64_t 1310 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) 1311 { 1312 if (!(m->flag & UNSIGNED)) { 1313 switch(m->type) { 1314 /* 1315 * Do not remove the casts below. They are 1316 * vital. When later compared with the data, 1317 * the sign extension must have happened. 1318 */ 1319 case FILE_BYTE: 1320 v = (char) v; 1321 break; 1322 case FILE_SHORT: 1323 case FILE_BESHORT: 1324 case FILE_LESHORT: 1325 v = (short) v; 1326 break; 1327 case FILE_DATE: 1328 case FILE_BEDATE: 1329 case FILE_LEDATE: 1330 case FILE_MEDATE: 1331 case FILE_LDATE: 1332 case FILE_BELDATE: 1333 case FILE_LELDATE: 1334 case FILE_MELDATE: 1335 case FILE_LONG: 1336 case FILE_BELONG: 1337 case FILE_LELONG: 1338 case FILE_MELONG: 1339 case FILE_FLOAT: 1340 case FILE_BEFLOAT: 1341 case FILE_LEFLOAT: 1342 v = (int32_t) v; 1343 break; 1344 case FILE_QUAD: 1345 case FILE_BEQUAD: 1346 case FILE_LEQUAD: 1347 case FILE_QDATE: 1348 case FILE_QLDATE: 1349 case FILE_QWDATE: 1350 case FILE_BEQDATE: 1351 case FILE_BEQLDATE: 1352 case FILE_BEQWDATE: 1353 case FILE_LEQDATE: 1354 case FILE_LEQLDATE: 1355 case FILE_LEQWDATE: 1356 case FILE_DOUBLE: 1357 case FILE_BEDOUBLE: 1358 case FILE_LEDOUBLE: 1359 v = (int64_t) v; 1360 break; 1361 case FILE_STRING: 1362 case FILE_PSTRING: 1363 case FILE_BESTRING16: 1364 case FILE_LESTRING16: 1365 case FILE_REGEX: 1366 case FILE_SEARCH: 1367 case FILE_DEFAULT: 1368 case FILE_INDIRECT: 1369 case FILE_NAME: 1370 case FILE_USE: 1371 case FILE_CLEAR: 1372 break; 1373 default: 1374 if (ms->flags & MAGIC_CHECK) 1375 file_magwarn(ms, "cannot happen: m->type=%d\n", 1376 m->type); 1377 return ~0U; 1378 } 1379 } 1380 return v; 1381 } 1382 1383 private int 1384 string_modifier_check(struct magic_set *ms, struct magic *m) 1385 { 1386 if ((ms->flags & MAGIC_CHECK) == 0) 1387 return 0; 1388 1389 if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) && 1390 (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) { 1391 file_magwarn(ms, 1392 "'/BHhLl' modifiers are only allowed for pascal strings\n"); 1393 return -1; 1394 } 1395 switch (m->type) { 1396 case FILE_BESTRING16: 1397 case FILE_LESTRING16: 1398 if (m->str_flags != 0) { 1399 file_magwarn(ms, 1400 "no modifiers allowed for 16-bit strings\n"); 1401 return -1; 1402 } 1403 break; 1404 case FILE_STRING: 1405 case FILE_PSTRING: 1406 if ((m->str_flags & REGEX_OFFSET_START) != 0) { 1407 file_magwarn(ms, 1408 "'/%c' only allowed on regex and search\n", 1409 CHAR_REGEX_OFFSET_START); 1410 return -1; 1411 } 1412 break; 1413 case FILE_SEARCH: 1414 if (m->str_range == 0) { 1415 file_magwarn(ms, 1416 "missing range; defaulting to %d\n", 1417 STRING_DEFAULT_RANGE); 1418 m->str_range = STRING_DEFAULT_RANGE; 1419 return -1; 1420 } 1421 break; 1422 case FILE_REGEX: 1423 if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) { 1424 file_magwarn(ms, "'/%c' not allowed on regex\n", 1425 CHAR_COMPACT_WHITESPACE); 1426 return -1; 1427 } 1428 if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) { 1429 file_magwarn(ms, "'/%c' not allowed on regex\n", 1430 CHAR_COMPACT_OPTIONAL_WHITESPACE); 1431 return -1; 1432 } 1433 break; 1434 default: 1435 file_magwarn(ms, "coding error: m->type=%d\n", 1436 m->type); 1437 return -1; 1438 } 1439 return 0; 1440 } 1441 1442 private int 1443 get_op(char c) 1444 { 1445 switch (c) { 1446 case '&': 1447 return FILE_OPAND; 1448 case '|': 1449 return FILE_OPOR; 1450 case '^': 1451 return FILE_OPXOR; 1452 case '+': 1453 return FILE_OPADD; 1454 case '-': 1455 return FILE_OPMINUS; 1456 case '*': 1457 return FILE_OPMULTIPLY; 1458 case '/': 1459 return FILE_OPDIVIDE; 1460 case '%': 1461 return FILE_OPMODULO; 1462 default: 1463 return -1; 1464 } 1465 } 1466 1467 #ifdef ENABLE_CONDITIONALS 1468 private int 1469 get_cond(const char *l, const char **t) 1470 { 1471 static const struct cond_tbl_s { 1472 char name[8]; 1473 size_t len; 1474 int cond; 1475 } cond_tbl[] = { 1476 { "if", 2, COND_IF }, 1477 { "elif", 4, COND_ELIF }, 1478 { "else", 4, COND_ELSE }, 1479 { "", 0, COND_NONE }, 1480 }; 1481 const struct cond_tbl_s *p; 1482 1483 for (p = cond_tbl; p->len; p++) { 1484 if (strncmp(l, p->name, p->len) == 0 && 1485 isspace((unsigned char)l[p->len])) { 1486 if (t) 1487 *t = l + p->len; 1488 break; 1489 } 1490 } 1491 return p->cond; 1492 } 1493 1494 private int 1495 check_cond(struct magic_set *ms, int cond, uint32_t cont_level) 1496 { 1497 int last_cond; 1498 last_cond = ms->c.li[cont_level].last_cond; 1499 1500 switch (cond) { 1501 case COND_IF: 1502 if (last_cond != COND_NONE && last_cond != COND_ELIF) { 1503 if (ms->flags & MAGIC_CHECK) 1504 file_magwarn(ms, "syntax error: `if'"); 1505 return -1; 1506 } 1507 last_cond = COND_IF; 1508 break; 1509 1510 case COND_ELIF: 1511 if (last_cond != COND_IF && last_cond != COND_ELIF) { 1512 if (ms->flags & MAGIC_CHECK) 1513 file_magwarn(ms, "syntax error: `elif'"); 1514 return -1; 1515 } 1516 last_cond = COND_ELIF; 1517 break; 1518 1519 case COND_ELSE: 1520 if (last_cond != COND_IF && last_cond != COND_ELIF) { 1521 if (ms->flags & MAGIC_CHECK) 1522 file_magwarn(ms, "syntax error: `else'"); 1523 return -1; 1524 } 1525 last_cond = COND_NONE; 1526 break; 1527 1528 case COND_NONE: 1529 last_cond = COND_NONE; 1530 break; 1531 } 1532 1533 ms->c.li[cont_level].last_cond = last_cond; 1534 return 0; 1535 } 1536 #endif /* ENABLE_CONDITIONALS */ 1537 1538 /* 1539 * parse one line from magic file, put into magic[index++] if valid 1540 */ 1541 private int 1542 parse(struct magic_set *ms, struct magic_entry *me, const char *line, 1543 size_t lineno, int action) 1544 { 1545 #ifdef ENABLE_CONDITIONALS 1546 static uint32_t last_cont_level = 0; 1547 #endif 1548 size_t i; 1549 struct magic *m; 1550 const char *l = line; 1551 char *t; 1552 int op; 1553 uint32_t cont_level; 1554 int32_t diff; 1555 1556 cont_level = 0; 1557 1558 /* 1559 * Parse the offset. 1560 */ 1561 while (*l == '>') { 1562 ++l; /* step over */ 1563 cont_level++; 1564 } 1565 #ifdef ENABLE_CONDITIONALS 1566 if (cont_level == 0 || cont_level > last_cont_level) 1567 if (file_check_mem(ms, cont_level) == -1) 1568 return -1; 1569 last_cont_level = cont_level; 1570 #endif 1571 if (cont_level != 0) { 1572 if (me->mp == NULL) { 1573 file_magerror(ms, "No current entry for continuation"); 1574 return -1; 1575 } 1576 if (me->cont_count == 0) { 1577 file_magerror(ms, "Continuations present with 0 count"); 1578 return -1; 1579 } 1580 m = &me->mp[me->cont_count - 1]; 1581 diff = (int32_t)cont_level - (int32_t)m->cont_level; 1582 if (diff > 1) 1583 file_magwarn(ms, "New continuation level %u is more " 1584 "than one larger than current level %u", cont_level, 1585 m->cont_level); 1586 if (me->cont_count == me->max_count) { 1587 struct magic *nm; 1588 size_t cnt = me->max_count + ALLOC_CHUNK; 1589 if ((nm = CAST(struct magic *, realloc(me->mp, 1590 sizeof(*nm) * cnt))) == NULL) { 1591 file_oomem(ms, sizeof(*nm) * cnt); 1592 return -1; 1593 } 1594 me->mp = m = nm; 1595 me->max_count = CAST(uint32_t, cnt); 1596 } 1597 m = &me->mp[me->cont_count++]; 1598 (void)memset(m, 0, sizeof(*m)); 1599 m->cont_level = cont_level; 1600 } else { 1601 static const size_t len = sizeof(*m) * ALLOC_CHUNK; 1602 if (me->mp != NULL) 1603 return 1; 1604 if ((m = CAST(struct magic *, malloc(len))) == NULL) { 1605 file_oomem(ms, len); 1606 return -1; 1607 } 1608 me->mp = m; 1609 me->max_count = ALLOC_CHUNK; 1610 (void)memset(m, 0, sizeof(*m)); 1611 m->factor_op = FILE_FACTOR_OP_NONE; 1612 m->cont_level = 0; 1613 me->cont_count = 1; 1614 } 1615 m->lineno = CAST(uint32_t, lineno); 1616 1617 if (*l == '&') { /* m->cont_level == 0 checked below. */ 1618 ++l; /* step over */ 1619 m->flag |= OFFADD; 1620 } 1621 if (*l == '(') { 1622 ++l; /* step over */ 1623 m->flag |= INDIR; 1624 if (m->flag & OFFADD) 1625 m->flag = (m->flag & ~OFFADD) | INDIROFFADD; 1626 1627 if (*l == '&') { /* m->cont_level == 0 checked below */ 1628 ++l; /* step over */ 1629 m->flag |= OFFADD; 1630 } 1631 } 1632 /* Indirect offsets are not valid at level 0. */ 1633 if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) 1634 if (ms->flags & MAGIC_CHECK) 1635 file_magwarn(ms, "relative offset at level 0"); 1636 1637 /* get offset, then skip over it */ 1638 m->offset = (uint32_t)strtoul(l, &t, 0); 1639 if (l == t) 1640 if (ms->flags & MAGIC_CHECK) 1641 file_magwarn(ms, "offset `%s' invalid", l); 1642 l = t; 1643 1644 if (m->flag & INDIR) { 1645 m->in_type = FILE_LONG; 1646 m->in_offset = 0; 1647 /* 1648 * read [.lbs][+-]nnnnn) 1649 */ 1650 if (*l == '.') { 1651 l++; 1652 switch (*l) { 1653 case 'l': 1654 m->in_type = FILE_LELONG; 1655 break; 1656 case 'L': 1657 m->in_type = FILE_BELONG; 1658 break; 1659 case 'm': 1660 m->in_type = FILE_MELONG; 1661 break; 1662 case 'h': 1663 case 's': 1664 m->in_type = FILE_LESHORT; 1665 break; 1666 case 'H': 1667 case 'S': 1668 m->in_type = FILE_BESHORT; 1669 break; 1670 case 'c': 1671 case 'b': 1672 case 'C': 1673 case 'B': 1674 m->in_type = FILE_BYTE; 1675 break; 1676 case 'e': 1677 case 'f': 1678 case 'g': 1679 m->in_type = FILE_LEDOUBLE; 1680 break; 1681 case 'E': 1682 case 'F': 1683 case 'G': 1684 m->in_type = FILE_BEDOUBLE; 1685 break; 1686 case 'i': 1687 m->in_type = FILE_LEID3; 1688 break; 1689 case 'I': 1690 m->in_type = FILE_BEID3; 1691 break; 1692 default: 1693 if (ms->flags & MAGIC_CHECK) 1694 file_magwarn(ms, 1695 "indirect offset type `%c' invalid", 1696 *l); 1697 break; 1698 } 1699 l++; 1700 } 1701 1702 m->in_op = 0; 1703 if (*l == '~') { 1704 m->in_op |= FILE_OPINVERSE; 1705 l++; 1706 } 1707 if ((op = get_op(*l)) != -1) { 1708 m->in_op |= op; 1709 l++; 1710 } 1711 if (*l == '(') { 1712 m->in_op |= FILE_OPINDIRECT; 1713 l++; 1714 } 1715 if (isdigit((unsigned char)*l) || *l == '-') { 1716 m->in_offset = (int32_t)strtol(l, &t, 0); 1717 if (l == t) 1718 if (ms->flags & MAGIC_CHECK) 1719 file_magwarn(ms, 1720 "in_offset `%s' invalid", l); 1721 l = t; 1722 } 1723 if (*l++ != ')' || 1724 ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) 1725 if (ms->flags & MAGIC_CHECK) 1726 file_magwarn(ms, 1727 "missing ')' in indirect offset"); 1728 } 1729 EATAB; 1730 1731 #ifdef ENABLE_CONDITIONALS 1732 m->cond = get_cond(l, &l); 1733 if (check_cond(ms, m->cond, cont_level) == -1) 1734 return -1; 1735 1736 EATAB; 1737 #endif 1738 1739 /* 1740 * Parse the type. 1741 */ 1742 if (*l == 'u') { 1743 /* 1744 * Try it as a keyword type prefixed by "u"; match what 1745 * follows the "u". If that fails, try it as an SUS 1746 * integer type. 1747 */ 1748 m->type = get_type(type_tbl, l + 1, &l); 1749 if (m->type == FILE_INVALID) { 1750 /* 1751 * Not a keyword type; parse it as an SUS type, 1752 * 'u' possibly followed by a number or C/S/L. 1753 */ 1754 m->type = get_standard_integer_type(l, &l); 1755 } 1756 /* It's unsigned. */ 1757 if (m->type != FILE_INVALID) 1758 m->flag |= UNSIGNED; 1759 } else { 1760 /* 1761 * Try it as a keyword type. If that fails, try it as 1762 * an SUS integer type if it begins with "d" or as an 1763 * SUS string type if it begins with "s". In any case, 1764 * it's not unsigned. 1765 */ 1766 m->type = get_type(type_tbl, l, &l); 1767 if (m->type == FILE_INVALID) { 1768 /* 1769 * Not a keyword type; parse it as an SUS type, 1770 * either 'd' possibly followed by a number or 1771 * C/S/L, or just 's'. 1772 */ 1773 if (*l == 'd') 1774 m->type = get_standard_integer_type(l, &l); 1775 else if (*l == 's' && !isalpha((unsigned char)l[1])) { 1776 m->type = FILE_STRING; 1777 ++l; 1778 } 1779 } 1780 } 1781 1782 if (m->type == FILE_INVALID) { 1783 /* Not found - try it as a special keyword. */ 1784 m->type = get_type(special_tbl, l, &l); 1785 } 1786 1787 if (m->type == FILE_INVALID) { 1788 if (ms->flags & MAGIC_CHECK) 1789 file_magwarn(ms, "type `%s' invalid", l); 1790 return -1; 1791 } 1792 1793 /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ 1794 /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ 1795 1796 m->mask_op = 0; 1797 if (*l == '~') { 1798 if (!IS_STRING(m->type)) 1799 m->mask_op |= FILE_OPINVERSE; 1800 else if (ms->flags & MAGIC_CHECK) 1801 file_magwarn(ms, "'~' invalid for string types"); 1802 ++l; 1803 } 1804 m->str_range = 0; 1805 m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 1806 if ((op = get_op(*l)) != -1) { 1807 if (!IS_STRING(m->type)) { 1808 uint64_t val; 1809 ++l; 1810 m->mask_op |= op; 1811 val = (uint64_t)strtoull(l, &t, 0); 1812 l = t; 1813 m->num_mask = file_signextend(ms, m, val); 1814 eatsize(&l); 1815 } 1816 else if (op == FILE_OPDIVIDE) { 1817 int have_range = 0; 1818 while (!isspace((unsigned char)*++l)) { 1819 switch (*l) { 1820 case '0': case '1': case '2': 1821 case '3': case '4': case '5': 1822 case '6': case '7': case '8': 1823 case '9': 1824 if (have_range && 1825 (ms->flags & MAGIC_CHECK)) 1826 file_magwarn(ms, 1827 "multiple ranges"); 1828 have_range = 1; 1829 m->str_range = CAST(uint32_t, 1830 strtoul(l, &t, 0)); 1831 if (m->str_range == 0) 1832 file_magwarn(ms, 1833 "zero range"); 1834 l = t - 1; 1835 break; 1836 case CHAR_COMPACT_WHITESPACE: 1837 m->str_flags |= 1838 STRING_COMPACT_WHITESPACE; 1839 break; 1840 case CHAR_COMPACT_OPTIONAL_WHITESPACE: 1841 m->str_flags |= 1842 STRING_COMPACT_OPTIONAL_WHITESPACE; 1843 break; 1844 case CHAR_IGNORE_LOWERCASE: 1845 m->str_flags |= STRING_IGNORE_LOWERCASE; 1846 break; 1847 case CHAR_IGNORE_UPPERCASE: 1848 m->str_flags |= STRING_IGNORE_UPPERCASE; 1849 break; 1850 case CHAR_REGEX_OFFSET_START: 1851 m->str_flags |= REGEX_OFFSET_START; 1852 break; 1853 case CHAR_BINTEST: 1854 m->str_flags |= STRING_BINTEST; 1855 break; 1856 case CHAR_TEXTTEST: 1857 m->str_flags |= STRING_TEXTTEST; 1858 break; 1859 case CHAR_TRIM: 1860 m->str_flags |= STRING_TRIM; 1861 break; 1862 case CHAR_PSTRING_1_LE: 1863 if (m->type != FILE_PSTRING) 1864 goto bad; 1865 m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_1_LE; 1866 break; 1867 case CHAR_PSTRING_2_BE: 1868 if (m->type != FILE_PSTRING) 1869 goto bad; 1870 m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_BE; 1871 break; 1872 case CHAR_PSTRING_2_LE: 1873 if (m->type != FILE_PSTRING) 1874 goto bad; 1875 m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_LE; 1876 break; 1877 case CHAR_PSTRING_4_BE: 1878 if (m->type != FILE_PSTRING) 1879 goto bad; 1880 m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_BE; 1881 break; 1882 case CHAR_PSTRING_4_LE: 1883 switch (m->type) { 1884 case FILE_PSTRING: 1885 case FILE_REGEX: 1886 break; 1887 default: 1888 goto bad; 1889 } 1890 m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_LE; 1891 break; 1892 case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: 1893 if (m->type != FILE_PSTRING) 1894 goto bad; 1895 m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; 1896 break; 1897 default: 1898 bad: 1899 if (ms->flags & MAGIC_CHECK) 1900 file_magwarn(ms, 1901 "string extension `%c' " 1902 "invalid", *l); 1903 return -1; 1904 } 1905 /* allow multiple '/' for readability */ 1906 if (l[1] == '/' && 1907 !isspace((unsigned char)l[2])) 1908 l++; 1909 } 1910 if (string_modifier_check(ms, m) == -1) 1911 return -1; 1912 } 1913 else { 1914 if (ms->flags & MAGIC_CHECK) 1915 file_magwarn(ms, "invalid string op: %c", *t); 1916 return -1; 1917 } 1918 } 1919 /* 1920 * We used to set mask to all 1's here, instead let's just not do 1921 * anything if mask = 0 (unless you have a better idea) 1922 */ 1923 EATAB; 1924 1925 switch (*l) { 1926 case '>': 1927 case '<': 1928 m->reln = *l; 1929 ++l; 1930 if (*l == '=') { 1931 if (ms->flags & MAGIC_CHECK) { 1932 file_magwarn(ms, "%c= not supported", 1933 m->reln); 1934 return -1; 1935 } 1936 ++l; 1937 } 1938 break; 1939 /* Old-style anding: "0 byte &0x80 dynamically linked" */ 1940 case '&': 1941 case '^': 1942 case '=': 1943 m->reln = *l; 1944 ++l; 1945 if (*l == '=') { 1946 /* HP compat: ignore &= etc. */ 1947 ++l; 1948 } 1949 break; 1950 case '!': 1951 m->reln = *l; 1952 ++l; 1953 break; 1954 default: 1955 m->reln = '='; /* the default relation */ 1956 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 1957 isspace((unsigned char)l[1])) || !l[1])) { 1958 m->reln = *l; 1959 ++l; 1960 } 1961 break; 1962 } 1963 /* 1964 * Grab the value part, except for an 'x' reln. 1965 */ 1966 if (m->reln != 'x' && getvalue(ms, m, &l, action)) 1967 return -1; 1968 1969 /* 1970 * TODO finish this macro and start using it! 1971 * #define offsetcheck {if (offset > HOWMANY-1) 1972 * magwarn("offset too big"); } 1973 */ 1974 1975 /* 1976 * Now get last part - the description 1977 */ 1978 EATAB; 1979 if (l[0] == '\b') { 1980 ++l; 1981 m->flag |= NOSPACE; 1982 } else if ((l[0] == '\\') && (l[1] == 'b')) { 1983 ++l; 1984 ++l; 1985 m->flag |= NOSPACE; 1986 } 1987 for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); ) 1988 continue; 1989 if (i == sizeof(m->desc)) { 1990 m->desc[sizeof(m->desc) - 1] = '\0'; 1991 if (ms->flags & MAGIC_CHECK) 1992 file_magwarn(ms, "description `%s' truncated", m->desc); 1993 } 1994 1995 /* 1996 * We only do this check while compiling, or if any of the magic 1997 * files were not compiled. 1998 */ 1999 if (ms->flags & MAGIC_CHECK) { 2000 if (check_format(ms, m) == -1) 2001 return -1; 2002 } 2003 #ifndef COMPILE_ONLY 2004 if (action == FILE_CHECK) { 2005 file_mdump(m); 2006 } 2007 #endif 2008 m->mimetype[0] = '\0'; /* initialise MIME type to none */ 2009 return 0; 2010 } 2011 2012 /* 2013 * parse a STRENGTH annotation line from magic file, put into magic[index - 1] 2014 * if valid 2015 */ 2016 private int 2017 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line) 2018 { 2019 const char *l = line; 2020 char *el; 2021 unsigned long factor; 2022 struct magic *m = &me->mp[0]; 2023 2024 if (m->factor_op != FILE_FACTOR_OP_NONE) { 2025 file_magwarn(ms, 2026 "Current entry already has a strength type: %c %d", 2027 m->factor_op, m->factor); 2028 return -1; 2029 } 2030 if (m->type == FILE_NAME) { 2031 file_magwarn(ms, "%s: Strength setting is not supported in " 2032 "\"name\" magic entries", m->value.s); 2033 return -1; 2034 } 2035 EATAB; 2036 switch (*l) { 2037 case FILE_FACTOR_OP_NONE: 2038 case FILE_FACTOR_OP_PLUS: 2039 case FILE_FACTOR_OP_MINUS: 2040 case FILE_FACTOR_OP_TIMES: 2041 case FILE_FACTOR_OP_DIV: 2042 m->factor_op = *l++; 2043 break; 2044 default: 2045 file_magwarn(ms, "Unknown factor op `%c'", *l); 2046 return -1; 2047 } 2048 EATAB; 2049 factor = strtoul(l, &el, 0); 2050 if (factor > 255) { 2051 file_magwarn(ms, "Too large factor `%lu'", factor); 2052 goto out; 2053 } 2054 if (*el && !isspace((unsigned char)*el)) { 2055 file_magwarn(ms, "Bad factor `%s'", l); 2056 goto out; 2057 } 2058 m->factor = (uint8_t)factor; 2059 if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) { 2060 file_magwarn(ms, "Cannot have factor op `%c' and factor %u", 2061 m->factor_op, m->factor); 2062 goto out; 2063 } 2064 return 0; 2065 out: 2066 m->factor_op = FILE_FACTOR_OP_NONE; 2067 m->factor = 0; 2068 return -1; 2069 } 2070 2071 private int 2072 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 2073 off_t off, size_t len, const char *name, int nt) 2074 { 2075 size_t i; 2076 const char *l = line; 2077 struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; 2078 char *buf = (char *)m + off; 2079 2080 if (buf[0] != '\0') { 2081 len = nt ? strlen(buf) : len; 2082 file_magwarn(ms, "Current entry already has a %s type " 2083 "`%.*s', new type `%s'", name, (int)len, buf, l); 2084 return -1; 2085 } 2086 2087 if (*m->desc == '\0') { 2088 file_magwarn(ms, "Current entry does not yet have a " 2089 "description for adding a %s type", name); 2090 return -1; 2091 } 2092 2093 EATAB; 2094 for (i = 0; *l && ((isascii((unsigned char)*l) && 2095 isalnum((unsigned char)*l)) || strchr("-+/.", *l)) && 2096 i < len; buf[i++] = *l++) 2097 continue; 2098 2099 if (i == len && *l) { 2100 if (nt) 2101 buf[len - 1] = '\0'; 2102 if (ms->flags & MAGIC_CHECK) 2103 file_magwarn(ms, "%s type `%s' truncated %" 2104 SIZE_T_FORMAT "u", name, line, i); 2105 } else { 2106 if (nt) 2107 buf[i] = '\0'; 2108 } 2109 2110 if (i > 0) 2111 return 0; 2112 else 2113 return -1; 2114 } 2115 2116 /* 2117 * Parse an Apple CREATOR/TYPE annotation from magic file and put it into 2118 * magic[index - 1] 2119 */ 2120 private int 2121 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) 2122 { 2123 struct magic *m = &me->mp[0]; 2124 2125 return parse_extra(ms, me, line, offsetof(struct magic, apple), 2126 sizeof(m->apple), "APPLE", 0); 2127 } 2128 2129 /* 2130 * parse a MIME annotation line from magic file, put into magic[index - 1] 2131 * if valid 2132 */ 2133 private int 2134 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) 2135 { 2136 struct magic *m = &me->mp[0]; 2137 2138 return parse_extra(ms, me, line, offsetof(struct magic, mimetype), 2139 sizeof(m->mimetype), "MIME", 1); 2140 } 2141 2142 private int 2143 check_format_type(const char *ptr, int type) 2144 { 2145 int quad = 0, h; 2146 if (*ptr == '\0') { 2147 /* Missing format string; bad */ 2148 return -1; 2149 } 2150 2151 switch (file_formats[type]) { 2152 case FILE_FMT_QUAD: 2153 quad = 1; 2154 /*FALLTHROUGH*/ 2155 case FILE_FMT_NUM: 2156 if (quad == 0) { 2157 switch (type) { 2158 case FILE_BYTE: 2159 h = 2; 2160 break; 2161 case FILE_SHORT: 2162 case FILE_BESHORT: 2163 case FILE_LESHORT: 2164 h = 1; 2165 break; 2166 case FILE_LONG: 2167 case FILE_BELONG: 2168 case FILE_LELONG: 2169 case FILE_MELONG: 2170 case FILE_LEID3: 2171 case FILE_BEID3: 2172 case FILE_INDIRECT: 2173 h = 0; 2174 break; 2175 default: 2176 abort(); 2177 } 2178 } else 2179 h = 0; 2180 if (*ptr == '-') 2181 ptr++; 2182 if (*ptr == '.') 2183 ptr++; 2184 while (isdigit((unsigned char)*ptr)) ptr++; 2185 if (*ptr == '.') 2186 ptr++; 2187 while (isdigit((unsigned char)*ptr)) ptr++; 2188 if (quad) { 2189 if (*ptr++ != 'l') 2190 return -1; 2191 if (*ptr++ != 'l') 2192 return -1; 2193 } 2194 2195 switch (*ptr++) { 2196 #ifdef STRICT_FORMAT /* "long" formats are int formats for us */ 2197 /* so don't accept the 'l' modifier */ 2198 case 'l': 2199 switch (*ptr++) { 2200 case 'i': 2201 case 'd': 2202 case 'u': 2203 case 'o': 2204 case 'x': 2205 case 'X': 2206 return h != 0 ? -1 : 0; 2207 default: 2208 return -1; 2209 } 2210 2211 /* 2212 * Don't accept h and hh modifiers. They make writing 2213 * magic entries more complicated, for very little benefit 2214 */ 2215 case 'h': 2216 if (h-- <= 0) 2217 return -1; 2218 switch (*ptr++) { 2219 case 'h': 2220 if (h-- <= 0) 2221 return -1; 2222 switch (*ptr++) { 2223 case 'i': 2224 case 'd': 2225 case 'u': 2226 case 'o': 2227 case 'x': 2228 case 'X': 2229 return 0; 2230 default: 2231 return -1; 2232 } 2233 case 'i': 2234 case 'd': 2235 case 'u': 2236 case 'o': 2237 case 'x': 2238 case 'X': 2239 return h != 0 ? -1 : 0; 2240 default: 2241 return -1; 2242 } 2243 #endif 2244 case 'c': 2245 return h != 2 ? -1 : 0; 2246 case 'i': 2247 case 'd': 2248 case 'u': 2249 case 'o': 2250 case 'x': 2251 case 'X': 2252 #ifdef STRICT_FORMAT 2253 return h != 0 ? -1 : 0; 2254 #else 2255 return 0; 2256 #endif 2257 default: 2258 return -1; 2259 } 2260 2261 case FILE_FMT_FLOAT: 2262 case FILE_FMT_DOUBLE: 2263 if (*ptr == '-') 2264 ptr++; 2265 if (*ptr == '.') 2266 ptr++; 2267 while (isdigit((unsigned char)*ptr)) ptr++; 2268 if (*ptr == '.') 2269 ptr++; 2270 while (isdigit((unsigned char)*ptr)) ptr++; 2271 2272 switch (*ptr++) { 2273 case 'e': 2274 case 'E': 2275 case 'f': 2276 case 'F': 2277 case 'g': 2278 case 'G': 2279 return 0; 2280 2281 default: 2282 return -1; 2283 } 2284 2285 2286 case FILE_FMT_STR: 2287 if (*ptr == '-') 2288 ptr++; 2289 while (isdigit((unsigned char )*ptr)) 2290 ptr++; 2291 if (*ptr == '.') { 2292 ptr++; 2293 while (isdigit((unsigned char )*ptr)) 2294 ptr++; 2295 } 2296 2297 switch (*ptr++) { 2298 case 's': 2299 return 0; 2300 default: 2301 return -1; 2302 } 2303 2304 default: 2305 /* internal error */ 2306 abort(); 2307 } 2308 /*NOTREACHED*/ 2309 return -1; 2310 } 2311 2312 /* 2313 * Check that the optional printf format in description matches 2314 * the type of the magic. 2315 */ 2316 private int 2317 check_format(struct magic_set *ms, struct magic *m) 2318 { 2319 char *ptr; 2320 2321 for (ptr = m->desc; *ptr; ptr++) 2322 if (*ptr == '%') 2323 break; 2324 if (*ptr == '\0') { 2325 /* No format string; ok */ 2326 return 1; 2327 } 2328 2329 assert(file_nformats == file_nnames); 2330 2331 if (m->type >= file_nformats) { 2332 file_magwarn(ms, "Internal error inconsistency between " 2333 "m->type and format strings"); 2334 return -1; 2335 } 2336 if (file_formats[m->type] == FILE_FMT_NONE) { 2337 file_magwarn(ms, "No format string for `%s' with description " 2338 "`%s'", m->desc, file_names[m->type]); 2339 return -1; 2340 } 2341 2342 ptr++; 2343 if (check_format_type(ptr, m->type) == -1) { 2344 /* 2345 * TODO: this error message is unhelpful if the format 2346 * string is not one character long 2347 */ 2348 file_magwarn(ms, "Printf format `%c' is not valid for type " 2349 "`%s' in description `%s'", *ptr ? *ptr : '?', 2350 file_names[m->type], m->desc); 2351 return -1; 2352 } 2353 2354 for (; *ptr; ptr++) { 2355 if (*ptr == '%') { 2356 file_magwarn(ms, 2357 "Too many format strings (should have at most one) " 2358 "for `%s' with description `%s'", 2359 file_names[m->type], m->desc); 2360 return -1; 2361 } 2362 } 2363 return 0; 2364 } 2365 2366 /* 2367 * Read a numeric value from a pointer, into the value union of a magic 2368 * pointer, according to the magic type. Update the string pointer to point 2369 * just after the number read. Return 0 for success, non-zero for failure. 2370 */ 2371 private int 2372 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) 2373 { 2374 switch (m->type) { 2375 case FILE_BESTRING16: 2376 case FILE_LESTRING16: 2377 case FILE_STRING: 2378 case FILE_PSTRING: 2379 case FILE_REGEX: 2380 case FILE_SEARCH: 2381 case FILE_NAME: 2382 case FILE_USE: 2383 *p = getstr(ms, m, *p, action == FILE_COMPILE); 2384 if (*p == NULL) { 2385 if (ms->flags & MAGIC_CHECK) 2386 file_magwarn(ms, "cannot get string from `%s'", 2387 m->value.s); 2388 return -1; 2389 } 2390 if (m->type == FILE_REGEX) { 2391 file_regex_t rx; 2392 int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED); 2393 if (rc) { 2394 if (ms->flags & MAGIC_CHECK) 2395 file_regerror(&rx, rc, ms); 2396 } 2397 file_regfree(&rx); 2398 return rc ? -1 : 0; 2399 } 2400 return 0; 2401 case FILE_FLOAT: 2402 case FILE_BEFLOAT: 2403 case FILE_LEFLOAT: 2404 if (m->reln != 'x') { 2405 char *ep; 2406 #ifdef HAVE_STRTOF 2407 m->value.f = strtof(*p, &ep); 2408 #else 2409 m->value.f = (float)strtod(*p, &ep); 2410 #endif 2411 *p = ep; 2412 } 2413 return 0; 2414 case FILE_DOUBLE: 2415 case FILE_BEDOUBLE: 2416 case FILE_LEDOUBLE: 2417 if (m->reln != 'x') { 2418 char *ep; 2419 m->value.d = strtod(*p, &ep); 2420 *p = ep; 2421 } 2422 return 0; 2423 default: 2424 if (m->reln != 'x') { 2425 char *ep; 2426 m->value.q = file_signextend(ms, m, 2427 (uint64_t)strtoull(*p, &ep, 0)); 2428 *p = ep; 2429 eatsize(p); 2430 } 2431 return 0; 2432 } 2433 } 2434 2435 /* 2436 * Convert a string containing C character escapes. Stop at an unescaped 2437 * space or tab. 2438 * Copy the converted version to "m->value.s", and the length in m->vallen. 2439 * Return updated scan pointer as function result. Warn if set. 2440 */ 2441 private const char * 2442 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn) 2443 { 2444 const char *origs = s; 2445 char *p = m->value.s; 2446 size_t plen = sizeof(m->value.s); 2447 char *origp = p; 2448 char *pmax = p + plen - 1; 2449 int c; 2450 int val; 2451 2452 while ((c = *s++) != '\0') { 2453 if (isspace((unsigned char) c)) 2454 break; 2455 if (p >= pmax) { 2456 file_error(ms, 0, "string too long: `%s'", origs); 2457 return NULL; 2458 } 2459 if (c == '\\') { 2460 switch(c = *s++) { 2461 2462 case '\0': 2463 if (warn) 2464 file_magwarn(ms, "incomplete escape"); 2465 goto out; 2466 2467 case '\t': 2468 if (warn) { 2469 file_magwarn(ms, 2470 "escaped tab found, use \\t instead"); 2471 warn = 0; /* already did */ 2472 } 2473 /*FALLTHROUGH*/ 2474 default: 2475 if (warn) { 2476 if (isprint((unsigned char)c)) { 2477 /* Allow escaping of 2478 * ``relations'' */ 2479 if (strchr("<>&^=!", c) == NULL 2480 && (m->type != FILE_REGEX || 2481 strchr("[]().*?^$|{}", c) 2482 == NULL)) { 2483 file_magwarn(ms, "no " 2484 "need to escape " 2485 "`%c'", c); 2486 } 2487 } else { 2488 file_magwarn(ms, 2489 "unknown escape sequence: " 2490 "\\%03o", c); 2491 } 2492 } 2493 /*FALLTHROUGH*/ 2494 /* space, perhaps force people to use \040? */ 2495 case ' ': 2496 #if 0 2497 /* 2498 * Other things people escape, but shouldn't need to, 2499 * so we disallow them 2500 */ 2501 case '\'': 2502 case '"': 2503 case '?': 2504 #endif 2505 /* Relations */ 2506 case '>': 2507 case '<': 2508 case '&': 2509 case '^': 2510 case '=': 2511 case '!': 2512 /* and baskslash itself */ 2513 case '\\': 2514 *p++ = (char) c; 2515 break; 2516 2517 case 'a': 2518 *p++ = '\a'; 2519 break; 2520 2521 case 'b': 2522 *p++ = '\b'; 2523 break; 2524 2525 case 'f': 2526 *p++ = '\f'; 2527 break; 2528 2529 case 'n': 2530 *p++ = '\n'; 2531 break; 2532 2533 case 'r': 2534 *p++ = '\r'; 2535 break; 2536 2537 case 't': 2538 *p++ = '\t'; 2539 break; 2540 2541 case 'v': 2542 *p++ = '\v'; 2543 break; 2544 2545 /* \ and up to 3 octal digits */ 2546 case '0': 2547 case '1': 2548 case '2': 2549 case '3': 2550 case '4': 2551 case '5': 2552 case '6': 2553 case '7': 2554 val = c - '0'; 2555 c = *s++; /* try for 2 */ 2556 if (c >= '0' && c <= '7') { 2557 val = (val << 3) | (c - '0'); 2558 c = *s++; /* try for 3 */ 2559 if (c >= '0' && c <= '7') 2560 val = (val << 3) | (c-'0'); 2561 else 2562 --s; 2563 } 2564 else 2565 --s; 2566 *p++ = (char)val; 2567 break; 2568 2569 /* \x and up to 2 hex digits */ 2570 case 'x': 2571 val = 'x'; /* Default if no digits */ 2572 c = hextoint(*s++); /* Get next char */ 2573 if (c >= 0) { 2574 val = c; 2575 c = hextoint(*s++); 2576 if (c >= 0) 2577 val = (val << 4) + c; 2578 else 2579 --s; 2580 } else 2581 --s; 2582 *p++ = (char)val; 2583 break; 2584 } 2585 } else 2586 *p++ = (char)c; 2587 } 2588 out: 2589 *p = '\0'; 2590 m->vallen = CAST(unsigned char, (p - origp)); 2591 if (m->type == FILE_PSTRING) 2592 m->vallen += (unsigned char)file_pstring_length_size(m); 2593 return s; 2594 } 2595 2596 2597 /* Single hex char to int; -1 if not a hex char. */ 2598 private int 2599 hextoint(int c) 2600 { 2601 if (!isascii((unsigned char) c)) 2602 return -1; 2603 if (isdigit((unsigned char) c)) 2604 return c - '0'; 2605 if ((c >= 'a') && (c <= 'f')) 2606 return c + 10 - 'a'; 2607 if (( c>= 'A') && (c <= 'F')) 2608 return c + 10 - 'A'; 2609 return -1; 2610 } 2611 2612 2613 /* 2614 * Print a string containing C character escapes. 2615 */ 2616 protected void 2617 file_showstr(FILE *fp, const char *s, size_t len) 2618 { 2619 char c; 2620 2621 for (;;) { 2622 if (len == ~0U) { 2623 c = *s++; 2624 if (c == '\0') 2625 break; 2626 } 2627 else { 2628 if (len-- == 0) 2629 break; 2630 c = *s++; 2631 } 2632 if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */ 2633 (void) fputc(c, fp); 2634 else { 2635 (void) fputc('\\', fp); 2636 switch (c) { 2637 case '\a': 2638 (void) fputc('a', fp); 2639 break; 2640 2641 case '\b': 2642 (void) fputc('b', fp); 2643 break; 2644 2645 case '\f': 2646 (void) fputc('f', fp); 2647 break; 2648 2649 case '\n': 2650 (void) fputc('n', fp); 2651 break; 2652 2653 case '\r': 2654 (void) fputc('r', fp); 2655 break; 2656 2657 case '\t': 2658 (void) fputc('t', fp); 2659 break; 2660 2661 case '\v': 2662 (void) fputc('v', fp); 2663 break; 2664 2665 default: 2666 (void) fprintf(fp, "%.3o", c & 0377); 2667 break; 2668 } 2669 } 2670 } 2671 } 2672 2673 /* 2674 * eatsize(): Eat the size spec from a number [eg. 10UL] 2675 */ 2676 private void 2677 eatsize(const char **p) 2678 { 2679 const char *l = *p; 2680 2681 if (LOWCASE(*l) == 'u') 2682 l++; 2683 2684 switch (LOWCASE(*l)) { 2685 case 'l': /* long */ 2686 case 's': /* short */ 2687 case 'h': /* short */ 2688 case 'b': /* char/byte */ 2689 case 'c': /* char/byte */ 2690 l++; 2691 /*FALLTHROUGH*/ 2692 default: 2693 break; 2694 } 2695 2696 *p = l; 2697 } 2698 2699 /* 2700 * handle a compiled file. 2701 */ 2702 2703 private struct magic_map * 2704 apprentice_map(struct magic_set *ms, const char *fn) 2705 { 2706 int fd; 2707 struct stat st; 2708 uint32_t *ptr; 2709 uint32_t version, entries, nentries; 2710 int needsbyteswap; 2711 char *dbname = NULL; 2712 struct magic_map *map; 2713 size_t i; 2714 2715 fd = -1; 2716 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2717 file_oomem(ms, sizeof(*map)); 2718 goto error; 2719 } 2720 2721 dbname = mkdbname(ms, fn, 0); 2722 if (dbname == NULL) 2723 goto error; 2724 2725 if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 2726 goto error; 2727 2728 if (fstat(fd, &st) == -1) { 2729 file_error(ms, errno, "cannot stat `%s'", dbname); 2730 goto error; 2731 } 2732 if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) { 2733 file_error(ms, 0, "file `%s' is too %s", dbname, 2734 st.st_size < 8 ? "small" : "large"); 2735 goto error; 2736 } 2737 2738 map->len = (size_t)st.st_size; 2739 #ifdef QUICK 2740 if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, 2741 MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { 2742 file_error(ms, errno, "cannot map `%s'", dbname); 2743 goto error; 2744 } 2745 #else 2746 if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 2747 file_oomem(ms, map->len); 2748 goto error; 2749 } 2750 if (read(fd, map->p, map->len) != (ssize_t)map->len) { 2751 file_badread(ms); 2752 goto error; 2753 } 2754 map->len = 0; 2755 #define RET 1 2756 #endif 2757 (void)close(fd); 2758 fd = -1; 2759 ptr = CAST(uint32_t *, map->p); 2760 if (*ptr != MAGICNO) { 2761 if (swap4(*ptr) != MAGICNO) { 2762 file_error(ms, 0, "bad magic in `%s'", dbname); 2763 goto error; 2764 } 2765 needsbyteswap = 1; 2766 } else 2767 needsbyteswap = 0; 2768 if (needsbyteswap) 2769 version = swap4(ptr[1]); 2770 else 2771 version = ptr[1]; 2772 if (version != VERSIONNO) { 2773 file_error(ms, 0, "File %s supports only version %d magic " 2774 "files. `%s' is version %d", VERSION, 2775 VERSIONNO, dbname, version); 2776 goto error; 2777 } 2778 entries = (uint32_t)(st.st_size / sizeof(struct magic)); 2779 if ((off_t)(entries * sizeof(struct magic)) != st.st_size) { 2780 file_error(ms, 0, "Size of `%s' %" INT64_T_FORMAT "u is not " 2781 "a multiple of %" SIZE_T_FORMAT "u", 2782 dbname, (unsigned long long)st.st_size, 2783 sizeof(struct magic)); 2784 goto error; 2785 } 2786 map->magic[0] = CAST(struct magic *, map->p) + 1; 2787 nentries = 0; 2788 for (i = 0; i < MAGIC_SETS; i++) { 2789 if (needsbyteswap) 2790 map->nmagic[i] = swap4(ptr[i + 2]); 2791 else 2792 map->nmagic[i] = ptr[i + 2]; 2793 if (i != MAGIC_SETS - 1) 2794 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 2795 nentries += map->nmagic[i]; 2796 } 2797 if (entries != nentries + 1) { 2798 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 2799 dbname, entries, nentries + 1); 2800 goto error; 2801 } 2802 if (needsbyteswap) 2803 for (i = 0; i < MAGIC_SETS; i++) 2804 byteswap(map->magic[i], map->nmagic[i]); 2805 free(dbname); 2806 return map; 2807 2808 error: 2809 if (fd != -1) 2810 (void)close(fd); 2811 apprentice_unmap(map); 2812 free(dbname); 2813 return NULL; 2814 } 2815 2816 /* 2817 * handle an mmaped file. 2818 */ 2819 private int 2820 apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) 2821 { 2822 static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 2823 static const size_t m = sizeof(**map->magic); 2824 int fd = -1; 2825 size_t len; 2826 char *dbname; 2827 int rv = -1; 2828 uint32_t i; 2829 union { 2830 struct magic m; 2831 uint32_t h[2 + MAGIC_SETS]; 2832 } hdr; 2833 2834 dbname = mkdbname(ms, fn, 1); 2835 2836 if (dbname == NULL) 2837 goto out; 2838 2839 if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 2840 { 2841 file_error(ms, errno, "cannot open `%s'", dbname); 2842 goto out; 2843 } 2844 memset(&hdr, 0, sizeof(hdr)); 2845 hdr.h[0] = MAGICNO; 2846 hdr.h[1] = VERSIONNO; 2847 memcpy(hdr.h + 2, map->nmagic, nm); 2848 2849 if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 2850 file_error(ms, errno, "error writing `%s'", dbname); 2851 goto out; 2852 } 2853 2854 for (i = 0; i < MAGIC_SETS; i++) { 2855 len = m * map->nmagic[i]; 2856 if (write(fd, map->magic[i], len) != (ssize_t)len) { 2857 file_error(ms, errno, "error writing `%s'", dbname); 2858 goto out; 2859 } 2860 } 2861 2862 if (fd != -1) 2863 (void)close(fd); 2864 rv = 0; 2865 out: 2866 free(dbname); 2867 return rv; 2868 } 2869 2870 private const char ext[] = ".mgc"; 2871 /* 2872 * make a dbname 2873 */ 2874 private char * 2875 mkdbname(struct magic_set *ms, const char *fn, int strip) 2876 { 2877 const char *p, *q; 2878 char *buf; 2879 2880 if (strip) { 2881 if ((p = strrchr(fn, '/')) != NULL) 2882 fn = ++p; 2883 } 2884 2885 for (q = fn; *q; q++) 2886 continue; 2887 /* Look for .mgc */ 2888 for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--) 2889 if (*p != *q) 2890 break; 2891 2892 /* Did not find .mgc, restore q */ 2893 if (p >= ext) 2894 while (*q) 2895 q++; 2896 2897 q++; 2898 /* Compatibility with old code that looked in .mime */ 2899 if (ms->flags & MAGIC_MIME) { 2900 if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0) 2901 return NULL; 2902 if (access(buf, R_OK) != -1) { 2903 ms->flags &= MAGIC_MIME_TYPE; 2904 return buf; 2905 } 2906 free(buf); 2907 } 2908 if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0) 2909 return NULL; 2910 2911 /* Compatibility with old code that looked in .mime */ 2912 if (strstr(p, ".mime") != NULL) 2913 ms->flags &= MAGIC_MIME_TYPE; 2914 return buf; 2915 } 2916 2917 /* 2918 * Byteswap an mmap'ed file if needed 2919 */ 2920 private void 2921 byteswap(struct magic *magic, uint32_t nmagic) 2922 { 2923 uint32_t i; 2924 for (i = 0; i < nmagic; i++) 2925 bs1(&magic[i]); 2926 } 2927 2928 /* 2929 * swap a short 2930 */ 2931 private uint16_t 2932 swap2(uint16_t sv) 2933 { 2934 uint16_t rv; 2935 uint8_t *s = (uint8_t *)(void *)&sv; 2936 uint8_t *d = (uint8_t *)(void *)&rv; 2937 d[0] = s[1]; 2938 d[1] = s[0]; 2939 return rv; 2940 } 2941 2942 /* 2943 * swap an int 2944 */ 2945 private uint32_t 2946 swap4(uint32_t sv) 2947 { 2948 uint32_t rv; 2949 uint8_t *s = (uint8_t *)(void *)&sv; 2950 uint8_t *d = (uint8_t *)(void *)&rv; 2951 d[0] = s[3]; 2952 d[1] = s[2]; 2953 d[2] = s[1]; 2954 d[3] = s[0]; 2955 return rv; 2956 } 2957 2958 /* 2959 * swap a quad 2960 */ 2961 private uint64_t 2962 swap8(uint64_t sv) 2963 { 2964 uint64_t rv; 2965 uint8_t *s = (uint8_t *)(void *)&sv; 2966 uint8_t *d = (uint8_t *)(void *)&rv; 2967 #if 0 2968 d[0] = s[3]; 2969 d[1] = s[2]; 2970 d[2] = s[1]; 2971 d[3] = s[0]; 2972 d[4] = s[7]; 2973 d[5] = s[6]; 2974 d[6] = s[5]; 2975 d[7] = s[4]; 2976 #else 2977 d[0] = s[7]; 2978 d[1] = s[6]; 2979 d[2] = s[5]; 2980 d[3] = s[4]; 2981 d[4] = s[3]; 2982 d[5] = s[2]; 2983 d[6] = s[1]; 2984 d[7] = s[0]; 2985 #endif 2986 return rv; 2987 } 2988 2989 /* 2990 * byteswap a single magic entry 2991 */ 2992 private void 2993 bs1(struct magic *m) 2994 { 2995 m->cont_level = swap2(m->cont_level); 2996 m->offset = swap4((uint32_t)m->offset); 2997 m->in_offset = swap4((uint32_t)m->in_offset); 2998 m->lineno = swap4((uint32_t)m->lineno); 2999 if (IS_STRING(m->type)) { 3000 m->str_range = swap4(m->str_range); 3001 m->str_flags = swap4(m->str_flags); 3002 } 3003 else { 3004 m->value.q = swap8(m->value.q); 3005 m->num_mask = swap8(m->num_mask); 3006 } 3007 } 3008 3009 protected size_t 3010 file_pstring_length_size(const struct magic *m) 3011 { 3012 switch (m->str_flags & PSTRING_LEN) { 3013 case PSTRING_1_LE: 3014 return 1; 3015 case PSTRING_2_LE: 3016 case PSTRING_2_BE: 3017 return 2; 3018 case PSTRING_4_LE: 3019 case PSTRING_4_BE: 3020 return 4; 3021 default: 3022 abort(); /* Impossible */ 3023 return 1; 3024 } 3025 } 3026 protected size_t 3027 file_pstring_get_length(const struct magic *m, const char *s) 3028 { 3029 size_t len = 0; 3030 3031 switch (m->str_flags & PSTRING_LEN) { 3032 case PSTRING_1_LE: 3033 len = *s; 3034 break; 3035 case PSTRING_2_LE: 3036 len = (s[1] << 8) | s[0]; 3037 break; 3038 case PSTRING_2_BE: 3039 len = (s[0] << 8) | s[1]; 3040 break; 3041 case PSTRING_4_LE: 3042 len = (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0]; 3043 break; 3044 case PSTRING_4_BE: 3045 len = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; 3046 break; 3047 default: 3048 abort(); /* Impossible */ 3049 } 3050 3051 if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) 3052 len -= file_pstring_length_size(m); 3053 3054 return len; 3055 } 3056 3057 protected int 3058 file_magicfind(struct magic_set *ms, const char *name, struct mlist *v) 3059 { 3060 uint32_t i, j; 3061 struct mlist *mlist, *ml; 3062 3063 mlist = ms->mlist[1]; 3064 3065 for (ml = mlist->next; ml != mlist; ml = ml->next) { 3066 struct magic *ma = ml->magic; 3067 uint32_t nma = ml->nmagic; 3068 for (i = 0; i < nma; i++) { 3069 if (ma[i].type != FILE_NAME) 3070 continue; 3071 if (strcmp(ma[i].value.s, name) == 0) { 3072 v->magic = &ma[i]; 3073 for (j = i + 1; j < nma; j++) 3074 if (ma[j].cont_level == 0) 3075 break; 3076 v->nmagic = j - i; 3077 return 0; 3078 } 3079 } 3080 } 3081 return -1; 3082 } 3083