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