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