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