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