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