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