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