1 /* 2 * Copyright (c) Ian F. Darwin 1986-1995. 3 * Software written by Ian F. Darwin and others; 4 * maintained 1995-present by Christos Zoulas and others. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice immediately at the beginning of the file, without modification, 11 * this list of conditions, and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 * softmagic - interpret variable magic from MAGIC 30 */ 31 32 #include "file.h" 33 34 #ifndef lint 35 FILE_RCSID("@(#)$File: softmagic.c,v 1.262 2018/06/22 20:39:50 christos Exp $") 36 #endif /* lint */ 37 38 #include "magic.h" 39 #include <assert.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <stdlib.h> 43 #include <time.h> 44 #include "der.h" 45 46 private int match(struct magic_set *, struct magic *, uint32_t, 47 const struct buffer *, size_t, int, int, int, uint16_t *, 48 uint16_t *, int *, int *, int *); 49 private int mget(struct magic_set *, struct magic *, const struct buffer *, 50 const unsigned char *, size_t, 51 size_t, unsigned int, int, int, int, uint16_t *, 52 uint16_t *, int *, int *, int *); 53 private int msetoffset(struct magic_set *, struct magic *, struct buffer *, 54 const struct buffer *, size_t, unsigned int); 55 private int magiccheck(struct magic_set *, struct magic *); 56 private int32_t mprint(struct magic_set *, struct magic *); 57 private int moffset(struct magic_set *, struct magic *, const struct buffer *, 58 int32_t *); 59 private void mdebug(uint32_t, const char *, size_t); 60 private int mcopy(struct magic_set *, union VALUETYPE *, int, int, 61 const unsigned char *, uint32_t, size_t, struct magic *); 62 private int mconvert(struct magic_set *, struct magic *, int); 63 private int print_sep(struct magic_set *, int); 64 private int handle_annotation(struct magic_set *, struct magic *, int); 65 private int cvt_8(union VALUETYPE *, const struct magic *); 66 private int cvt_16(union VALUETYPE *, const struct magic *); 67 private int cvt_32(union VALUETYPE *, const struct magic *); 68 private int cvt_64(union VALUETYPE *, const struct magic *); 69 70 #define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o))) 71 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \ 72 ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \ 73 ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \ 74 ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7])) 75 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \ 76 ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \ 77 ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \ 78 ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0])) 79 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \ 80 ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0])) 81 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \ 82 ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3])) 83 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \ 84 ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2])) 85 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1])) 86 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0])) 87 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p)) 88 89 /* 90 * softmagic - lookup one file in parsed, in-memory copy of database 91 * Passed the name and FILE * of one file to be typed. 92 */ 93 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ 94 protected int 95 file_softmagic(struct magic_set *ms, const struct buffer *b, 96 uint16_t *indir_count, uint16_t *name_count, int mode, int text) 97 { 98 struct mlist *ml; 99 int rv, printed_something = 0, need_separator = 0; 100 uint16_t nc, ic; 101 102 if (name_count == NULL) { 103 nc = 0; 104 name_count = &nc; 105 } 106 if (indir_count == NULL) { 107 ic = 0; 108 indir_count = ⁣ 109 } 110 111 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) 112 if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode, 113 text, 0, indir_count, name_count, 114 &printed_something, &need_separator, NULL)) != 0) 115 return rv; 116 117 return 0; 118 } 119 120 #define FILE_FMTDEBUG 121 #ifdef FILE_FMTDEBUG 122 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 123 124 private const char * __attribute__((__format_arg__(3))) 125 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def, 126 const char *file, size_t line) 127 { 128 const char *ptr = fmtcheck(desc, def); 129 if (ptr == def) 130 file_magerror(ms, 131 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" 132 " with `%s'", file, line, desc, def); 133 return ptr; 134 } 135 #else 136 #define F(a, b, c) fmtcheck((b), (c)) 137 #endif 138 139 /* 140 * Go through the whole list, stopping if you find a match. Process all 141 * the continuations of that match before returning. 142 * 143 * We support multi-level continuations: 144 * 145 * At any time when processing a successful top-level match, there is a 146 * current continuation level; it represents the level of the last 147 * successfully matched continuation. 148 * 149 * Continuations above that level are skipped as, if we see one, it 150 * means that the continuation that controls them - i.e, the 151 * lower-level continuation preceding them - failed to match. 152 * 153 * Continuations below that level are processed as, if we see one, 154 * it means we've finished processing or skipping higher-level 155 * continuations under the control of a successful or unsuccessful 156 * lower-level continuation, and are now seeing the next lower-level 157 * continuation and should process it. The current continuation 158 * level reverts to the level of the one we're seeing. 159 * 160 * Continuations at the current level are processed as, if we see 161 * one, there's no lower-level continuation that may have failed. 162 * 163 * If a continuation matches, we bump the current continuation level 164 * so that higher-level continuations are processed. 165 */ 166 private int 167 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, 168 const struct buffer *b, size_t offset, int mode, int text, 169 int flip, uint16_t *indir_count, uint16_t *name_count, 170 int *printed_something, int *need_separator, int *returnval) 171 { 172 uint32_t magindex = 0; 173 unsigned int cont_level = 0; 174 int returnvalv = 0, e; /* if a match is found it is set to 1*/ 175 int firstline = 1; /* a flag to print X\n X\n- X */ 176 struct buffer bb; 177 int print = (ms->flags & MAGIC_NODESC) == 0; 178 179 if (returnval == NULL) 180 returnval = &returnvalv; 181 182 if (file_check_mem(ms, cont_level) == -1) 183 return -1; 184 185 for (magindex = 0; magindex < nmagic; magindex++) { 186 int flush = 0; 187 struct magic *m = &magic[magindex]; 188 189 if (m->type != FILE_NAME) 190 if ((IS_STRING(m->type) && 191 #define FLT (STRING_BINTEST | STRING_TEXTTEST) 192 ((text && (m->str_flags & FLT) == STRING_BINTEST) || 193 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 194 (m->flag & mode) != mode) { 195 flush: 196 /* Skip sub-tests */ 197 while (magindex < nmagic - 1 && 198 magic[magindex + 1].cont_level != 0) 199 magindex++; 200 cont_level = 0; 201 continue; /* Skip to next top-level test*/ 202 } 203 204 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) 205 goto flush; 206 ms->line = m->lineno; 207 208 /* if main entry matches, print it... */ 209 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, cont_level, 210 mode, text, flip, indir_count, name_count, 211 printed_something, need_separator, returnval)) { 212 case -1: 213 return -1; 214 case 0: 215 flush = m->reln != '!'; 216 break; 217 default: 218 if (m->type == FILE_INDIRECT) 219 *returnval = 1; 220 221 switch (magiccheck(ms, m)) { 222 case -1: 223 return -1; 224 case 0: 225 flush++; 226 break; 227 default: 228 flush = 0; 229 break; 230 } 231 break; 232 } 233 if (flush) { 234 /* 235 * main entry didn't match, 236 * flush its continuations 237 */ 238 goto flush; 239 } 240 241 if ((e = handle_annotation(ms, m, firstline)) != 0) { 242 *need_separator = 1; 243 *printed_something = 1; 244 *returnval = 1; 245 return e; 246 } 247 248 /* 249 * If we are going to print something, we'll need to print 250 * a blank before we print something else. 251 */ 252 if (*m->desc) { 253 *need_separator = 1; 254 *printed_something = 1; 255 if (print_sep(ms, firstline) == -1) 256 return -1; 257 } 258 259 if (print && mprint(ms, m) == -1) 260 return -1; 261 262 switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { 263 case -1: 264 case 0: 265 goto flush; 266 default: 267 break; 268 } 269 270 /* and any continuations that match */ 271 if (file_check_mem(ms, ++cont_level) == -1) 272 return -1; 273 274 while (magindex + 1 < nmagic && 275 magic[magindex + 1].cont_level != 0) { 276 m = &magic[++magindex]; 277 ms->line = m->lineno; /* for messages */ 278 279 if (cont_level < m->cont_level) 280 continue; 281 if (cont_level > m->cont_level) { 282 /* 283 * We're at the end of the level 284 * "cont_level" continuations. 285 */ 286 cont_level = m->cont_level; 287 } 288 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) 289 goto flush; 290 if (m->flag & OFFADD) { 291 ms->offset += 292 ms->c.li[cont_level - 1].off; 293 } 294 295 #ifdef ENABLE_CONDITIONALS 296 if (m->cond == COND_ELSE || 297 m->cond == COND_ELIF) { 298 if (ms->c.li[cont_level].last_match == 1) 299 continue; 300 } 301 #endif 302 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, 303 cont_level, mode, text, flip, indir_count, 304 name_count, printed_something, need_separator, 305 returnval)) { 306 case -1: 307 return -1; 308 case 0: 309 if (m->reln != '!') 310 continue; 311 flush = 1; 312 break; 313 default: 314 if (m->type == FILE_INDIRECT) 315 *returnval = 1; 316 flush = 0; 317 break; 318 } 319 320 switch (flush ? 1 : magiccheck(ms, m)) { 321 case -1: 322 return -1; 323 case 0: 324 #ifdef ENABLE_CONDITIONALS 325 ms->c.li[cont_level].last_match = 0; 326 #endif 327 break; 328 default: 329 #ifdef ENABLE_CONDITIONALS 330 ms->c.li[cont_level].last_match = 1; 331 #endif 332 if (m->type == FILE_CLEAR) 333 ms->c.li[cont_level].got_match = 0; 334 else if (ms->c.li[cont_level].got_match) { 335 if (m->type == FILE_DEFAULT) 336 break; 337 } else 338 ms->c.li[cont_level].got_match = 1; 339 340 if ((e = handle_annotation(ms, m, firstline)) 341 != 0) { 342 *need_separator = 1; 343 *printed_something = 1; 344 *returnval = 1; 345 return e; 346 } 347 /* 348 * If we are going to print something, 349 * make sure that we have a separator first. 350 */ 351 if (*m->desc) { 352 if (!*printed_something) { 353 *printed_something = 1; 354 if (print_sep(ms, firstline) 355 == -1) 356 return -1; 357 } 358 } 359 /* 360 * This continuation matched. Print 361 * its message, with a blank before it 362 * if the previous item printed and 363 * this item isn't empty. 364 */ 365 /* space if previous printed */ 366 if (*need_separator 367 && ((m->flag & NOSPACE) == 0) 368 && *m->desc) { 369 if (print && 370 file_printf(ms, " ") == -1) 371 return -1; 372 *need_separator = 0; 373 } 374 if (print && mprint(ms, m) == -1) 375 return -1; 376 377 switch (moffset(ms, m, &bb, 378 &ms->c.li[cont_level].off)) { 379 case -1: 380 case 0: 381 flush = 1; 382 cont_level--; 383 break; 384 default: 385 break; 386 } 387 388 if (*m->desc) 389 *need_separator = 1; 390 391 /* 392 * If we see any continuations 393 * at a higher level, 394 * process them. 395 */ 396 if (file_check_mem(ms, ++cont_level) == -1) 397 return -1; 398 break; 399 } 400 } 401 if (*printed_something) { 402 firstline = 0; 403 if (print) 404 *returnval = 1; 405 } 406 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) { 407 return *returnval; /* don't keep searching */ 408 } 409 cont_level = 0; 410 } 411 return *returnval; /* This is hit if -k is set or there is no match */ 412 } 413 414 private int 415 check_fmt(struct magic_set *ms, const char *fmt) 416 { 417 file_regex_t rx; 418 int rc, rv = -1; 419 420 if (strchr(fmt, '%') == NULL) 421 return 0; 422 423 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); 424 if (rc) { 425 file_regerror(&rx, rc, ms); 426 } else { 427 rc = file_regexec(&rx, fmt, 0, 0, 0); 428 rv = !rc; 429 } 430 file_regfree(&rx); 431 return rv; 432 } 433 434 #if !defined(HAVE_STRNDUP) || defined(__aiws__) 435 # ifdef __aiws__ 436 # define strndup aix_strndup /* aix is broken */ 437 # endif 438 char *strndup(const char *, size_t); 439 440 char * 441 strndup(const char *str, size_t n) 442 { 443 size_t len; 444 char *copy; 445 446 for (len = 0; len < n && str[len]; len++) 447 continue; 448 if ((copy = malloc(len + 1)) == NULL) 449 return NULL; 450 (void)memcpy(copy, str, len); 451 copy[len] = '\0'; 452 return copy; 453 } 454 #endif /* HAVE_STRNDUP */ 455 456 static int 457 varexpand(struct magic_set *ms, char *buf, size_t len, const char *str) 458 { 459 const char *ptr, *sptr, *e, *t, *ee, *et; 460 size_t l; 461 462 for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) { 463 l = (size_t)(ptr - sptr); 464 if (l >= len) 465 return -1; 466 memcpy(buf, sptr, l); 467 buf += l; 468 len -= l; 469 ptr += 2; 470 if (!*ptr || ptr[1] != '?') 471 return -1; 472 for (et = t = ptr + 2; *et && *et != ':'; et++) 473 continue; 474 if (*et != ':') 475 return -1; 476 for (ee = e = et + 1; *ee && *ee != '}'; ee++) 477 continue; 478 if (*ee != '}') 479 return -1; 480 switch (*ptr) { 481 case 'x': 482 if (ms->mode & 0111) { 483 ptr = t; 484 l = et - t; 485 } else { 486 ptr = e; 487 l = ee - e; 488 } 489 break; 490 default: 491 return -1; 492 } 493 if (l >= len) 494 return -1; 495 memcpy(buf, ptr, l); 496 buf += l; 497 len -= l; 498 sptr = ee + 1; 499 } 500 501 l = strlen(sptr); 502 if (l >= len) 503 return -1; 504 505 memcpy(buf, sptr, l); 506 buf[l] = '\0'; 507 return 0; 508 } 509 510 511 private int32_t 512 mprint(struct magic_set *ms, struct magic *m) 513 { 514 uint64_t v; 515 float vf; 516 double vd; 517 int64_t t = 0; 518 char buf[128], tbuf[26], sbuf[512], ebuf[512]; 519 const char *desc; 520 union VALUETYPE *p = &ms->ms_value; 521 522 if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1) 523 desc = m->desc; 524 else 525 desc = ebuf; 526 527 switch (m->type) { 528 case FILE_BYTE: 529 v = file_signextend(ms, m, (uint64_t)p->b); 530 switch (check_fmt(ms, desc)) { 531 case -1: 532 return -1; 533 case 1: 534 (void)snprintf(buf, sizeof(buf), "%d", 535 (unsigned char)v); 536 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 537 return -1; 538 break; 539 default: 540 if (file_printf(ms, F(ms, desc, "%d"), 541 (unsigned char) v) == -1) 542 return -1; 543 break; 544 } 545 t = ms->offset + sizeof(char); 546 break; 547 548 case FILE_SHORT: 549 case FILE_BESHORT: 550 case FILE_LESHORT: 551 v = file_signextend(ms, m, (uint64_t)p->h); 552 switch (check_fmt(ms, desc)) { 553 case -1: 554 return -1; 555 case 1: 556 (void)snprintf(buf, sizeof(buf), "%u", 557 (unsigned short)v); 558 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 559 return -1; 560 break; 561 default: 562 if (file_printf(ms, F(ms, desc, "%u"), 563 (unsigned short) v) == -1) 564 return -1; 565 break; 566 } 567 t = ms->offset + sizeof(short); 568 break; 569 570 case FILE_LONG: 571 case FILE_BELONG: 572 case FILE_LELONG: 573 case FILE_MELONG: 574 v = file_signextend(ms, m, (uint64_t)p->l); 575 switch (check_fmt(ms, desc)) { 576 case -1: 577 return -1; 578 case 1: 579 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); 580 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 581 return -1; 582 break; 583 default: 584 if (file_printf(ms, F(ms, desc, "%u"), (uint32_t) v) == -1) 585 return -1; 586 break; 587 } 588 t = ms->offset + sizeof(int32_t); 589 break; 590 591 case FILE_QUAD: 592 case FILE_BEQUAD: 593 case FILE_LEQUAD: 594 v = file_signextend(ms, m, p->q); 595 switch (check_fmt(ms, desc)) { 596 case -1: 597 return -1; 598 case 1: 599 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", 600 (unsigned long long)v); 601 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 602 return -1; 603 break; 604 default: 605 if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"), 606 (unsigned long long) v) == -1) 607 return -1; 608 break; 609 } 610 t = ms->offset + sizeof(int64_t); 611 break; 612 613 case FILE_STRING: 614 case FILE_PSTRING: 615 case FILE_BESTRING16: 616 case FILE_LESTRING16: 617 if (m->reln == '=' || m->reln == '!') { 618 if (file_printf(ms, F(ms, desc, "%s"), 619 file_printable(sbuf, sizeof(sbuf), m->value.s)) 620 == -1) 621 return -1; 622 t = ms->offset + m->vallen; 623 } 624 else { 625 char *str = p->s; 626 627 /* compute t before we mangle the string? */ 628 t = ms->offset + strlen(str); 629 630 if (*m->value.s == '\0') 631 str[strcspn(str, "\r\n")] = '\0'; 632 633 if (m->str_flags & STRING_TRIM) { 634 char *last; 635 while (isspace((unsigned char)*str)) 636 str++; 637 last = str; 638 while (*last) 639 last++; 640 --last; 641 while (isspace((unsigned char)*last)) 642 last--; 643 *++last = '\0'; 644 } 645 646 if (file_printf(ms, F(ms, desc, "%s"), 647 file_printable(sbuf, sizeof(sbuf), str)) == -1) 648 return -1; 649 650 if (m->type == FILE_PSTRING) 651 t += file_pstring_length_size(m); 652 } 653 break; 654 655 case FILE_DATE: 656 case FILE_BEDATE: 657 case FILE_LEDATE: 658 case FILE_MEDATE: 659 if (file_printf(ms, F(ms, desc, "%s"), 660 file_fmttime(p->l, 0, tbuf)) == -1) 661 return -1; 662 t = ms->offset + sizeof(uint32_t); 663 break; 664 665 case FILE_LDATE: 666 case FILE_BELDATE: 667 case FILE_LELDATE: 668 case FILE_MELDATE: 669 if (file_printf(ms, F(ms, desc, "%s"), 670 file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1) 671 return -1; 672 t = ms->offset + sizeof(uint32_t); 673 break; 674 675 case FILE_QDATE: 676 case FILE_BEQDATE: 677 case FILE_LEQDATE: 678 if (file_printf(ms, F(ms, desc, "%s"), 679 file_fmttime(p->q, 0, tbuf)) == -1) 680 return -1; 681 t = ms->offset + sizeof(uint64_t); 682 break; 683 684 case FILE_QLDATE: 685 case FILE_BEQLDATE: 686 case FILE_LEQLDATE: 687 if (file_printf(ms, F(ms, desc, "%s"), 688 file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1) 689 return -1; 690 t = ms->offset + sizeof(uint64_t); 691 break; 692 693 case FILE_QWDATE: 694 case FILE_BEQWDATE: 695 case FILE_LEQWDATE: 696 if (file_printf(ms, F(ms, desc, "%s"), 697 file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1) 698 return -1; 699 t = ms->offset + sizeof(uint64_t); 700 break; 701 702 case FILE_FLOAT: 703 case FILE_BEFLOAT: 704 case FILE_LEFLOAT: 705 vf = p->f; 706 switch (check_fmt(ms, desc)) { 707 case -1: 708 return -1; 709 case 1: 710 (void)snprintf(buf, sizeof(buf), "%g", vf); 711 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 712 return -1; 713 break; 714 default: 715 if (file_printf(ms, F(ms, desc, "%g"), vf) == -1) 716 return -1; 717 break; 718 } 719 t = ms->offset + sizeof(float); 720 break; 721 722 case FILE_DOUBLE: 723 case FILE_BEDOUBLE: 724 case FILE_LEDOUBLE: 725 vd = p->d; 726 switch (check_fmt(ms, desc)) { 727 case -1: 728 return -1; 729 case 1: 730 (void)snprintf(buf, sizeof(buf), "%g", vd); 731 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 732 return -1; 733 break; 734 default: 735 if (file_printf(ms, F(ms, desc, "%g"), vd) == -1) 736 return -1; 737 break; 738 } 739 t = ms->offset + sizeof(double); 740 break; 741 742 case FILE_SEARCH: 743 case FILE_REGEX: { 744 char *cp; 745 int rval; 746 747 cp = strndup((const char *)ms->search.s, ms->search.rm_len); 748 if (cp == NULL) { 749 file_oomem(ms, ms->search.rm_len); 750 return -1; 751 } 752 rval = file_printf(ms, F(ms, desc, "%s"), 753 file_printable(sbuf, sizeof(sbuf), cp)); 754 free(cp); 755 756 if (rval == -1) 757 return -1; 758 759 if ((m->str_flags & REGEX_OFFSET_START)) 760 t = ms->search.offset; 761 else 762 t = ms->search.offset + ms->search.rm_len; 763 break; 764 } 765 766 case FILE_DEFAULT: 767 case FILE_CLEAR: 768 if (file_printf(ms, "%s", m->desc) == -1) 769 return -1; 770 t = ms->offset; 771 break; 772 773 case FILE_INDIRECT: 774 case FILE_USE: 775 case FILE_NAME: 776 t = ms->offset; 777 break; 778 case FILE_DER: 779 if (file_printf(ms, F(ms, desc, "%s"), 780 file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1) 781 return -1; 782 t = ms->offset; 783 break; 784 default: 785 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type); 786 return -1; 787 } 788 return (int32_t)t; 789 } 790 791 private int 792 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, 793 int32_t *op) 794 { 795 size_t nbytes = b->flen; 796 int32_t o; 797 798 switch (m->type) { 799 case FILE_BYTE: 800 o = CAST(int32_t, (ms->offset + sizeof(char))); 801 break; 802 803 case FILE_SHORT: 804 case FILE_BESHORT: 805 case FILE_LESHORT: 806 o = CAST(int32_t, (ms->offset + sizeof(short))); 807 break; 808 809 case FILE_LONG: 810 case FILE_BELONG: 811 case FILE_LELONG: 812 case FILE_MELONG: 813 o = CAST(int32_t, (ms->offset + sizeof(int32_t))); 814 break; 815 816 case FILE_QUAD: 817 case FILE_BEQUAD: 818 case FILE_LEQUAD: 819 o = CAST(int32_t, (ms->offset + sizeof(int64_t))); 820 break; 821 822 case FILE_STRING: 823 case FILE_PSTRING: 824 case FILE_BESTRING16: 825 case FILE_LESTRING16: 826 if (m->reln == '=' || m->reln == '!') { 827 o = ms->offset + m->vallen; 828 } else { 829 union VALUETYPE *p = &ms->ms_value; 830 831 if (*m->value.s == '\0') 832 p->s[strcspn(p->s, "\r\n")] = '\0'; 833 o = CAST(uint32_t, (ms->offset + strlen(p->s))); 834 if (m->type == FILE_PSTRING) 835 o += (uint32_t)file_pstring_length_size(m); 836 } 837 break; 838 839 case FILE_DATE: 840 case FILE_BEDATE: 841 case FILE_LEDATE: 842 case FILE_MEDATE: 843 o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); 844 break; 845 846 case FILE_LDATE: 847 case FILE_BELDATE: 848 case FILE_LELDATE: 849 case FILE_MELDATE: 850 o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); 851 break; 852 853 case FILE_QDATE: 854 case FILE_BEQDATE: 855 case FILE_LEQDATE: 856 o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); 857 break; 858 859 case FILE_QLDATE: 860 case FILE_BEQLDATE: 861 case FILE_LEQLDATE: 862 o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); 863 break; 864 865 case FILE_FLOAT: 866 case FILE_BEFLOAT: 867 case FILE_LEFLOAT: 868 o = CAST(int32_t, (ms->offset + sizeof(float))); 869 break; 870 871 case FILE_DOUBLE: 872 case FILE_BEDOUBLE: 873 case FILE_LEDOUBLE: 874 o = CAST(int32_t, (ms->offset + sizeof(double))); 875 break; 876 877 case FILE_REGEX: 878 if ((m->str_flags & REGEX_OFFSET_START) != 0) 879 o = CAST(int32_t, ms->search.offset); 880 else 881 o = CAST(int32_t, 882 (ms->search.offset + ms->search.rm_len)); 883 break; 884 885 case FILE_SEARCH: 886 if ((m->str_flags & REGEX_OFFSET_START) != 0) 887 o = CAST(int32_t, ms->search.offset); 888 else 889 o = CAST(int32_t, (ms->search.offset + m->vallen)); 890 break; 891 892 case FILE_CLEAR: 893 case FILE_DEFAULT: 894 case FILE_INDIRECT: 895 o = ms->offset; 896 break; 897 898 case FILE_DER: 899 { 900 o = der_offs(ms, m, nbytes); 901 if (o == -1 || (size_t)o > nbytes) { 902 if ((ms->flags & MAGIC_DEBUG) != 0) { 903 (void)fprintf(stderr, 904 "Bad DER offset %d nbytes=%zu", 905 o, nbytes); 906 } 907 *op = 0; 908 return 0; 909 } 910 break; 911 } 912 913 default: 914 o = 0; 915 break; 916 } 917 918 if ((size_t)o > nbytes) { 919 #if 0 920 file_error(ms, 0, "Offset out of range %zu > %zu", 921 (size_t)o, nbytes); 922 #endif 923 return -1; 924 } 925 *op = o; 926 return 1; 927 } 928 929 private uint32_t 930 cvt_id3(struct magic_set *ms, uint32_t v) 931 { 932 v = ((((v >> 0) & 0x7f) << 0) | 933 (((v >> 8) & 0x7f) << 7) | 934 (((v >> 16) & 0x7f) << 14) | 935 (((v >> 24) & 0x7f) << 21)); 936 if ((ms->flags & MAGIC_DEBUG) != 0) 937 fprintf(stderr, "id3 offs=%u\n", v); 938 return v; 939 } 940 941 private int 942 cvt_flip(int type, int flip) 943 { 944 if (flip == 0) 945 return type; 946 switch (type) { 947 case FILE_BESHORT: 948 return FILE_LESHORT; 949 case FILE_BELONG: 950 return FILE_LELONG; 951 case FILE_BEDATE: 952 return FILE_LEDATE; 953 case FILE_BELDATE: 954 return FILE_LELDATE; 955 case FILE_BEQUAD: 956 return FILE_LEQUAD; 957 case FILE_BEQDATE: 958 return FILE_LEQDATE; 959 case FILE_BEQLDATE: 960 return FILE_LEQLDATE; 961 case FILE_BEQWDATE: 962 return FILE_LEQWDATE; 963 case FILE_LESHORT: 964 return FILE_BESHORT; 965 case FILE_LELONG: 966 return FILE_BELONG; 967 case FILE_LEDATE: 968 return FILE_BEDATE; 969 case FILE_LELDATE: 970 return FILE_BELDATE; 971 case FILE_LEQUAD: 972 return FILE_BEQUAD; 973 case FILE_LEQDATE: 974 return FILE_BEQDATE; 975 case FILE_LEQLDATE: 976 return FILE_BEQLDATE; 977 case FILE_LEQWDATE: 978 return FILE_BEQWDATE; 979 case FILE_BEFLOAT: 980 return FILE_LEFLOAT; 981 case FILE_LEFLOAT: 982 return FILE_BEFLOAT; 983 case FILE_BEDOUBLE: 984 return FILE_LEDOUBLE; 985 case FILE_LEDOUBLE: 986 return FILE_BEDOUBLE; 987 default: 988 return type; 989 } 990 } 991 #define DO_CVT(fld, cast) \ 992 if (m->num_mask) \ 993 switch (m->mask_op & FILE_OPS_MASK) { \ 994 case FILE_OPAND: \ 995 p->fld &= cast m->num_mask; \ 996 break; \ 997 case FILE_OPOR: \ 998 p->fld |= cast m->num_mask; \ 999 break; \ 1000 case FILE_OPXOR: \ 1001 p->fld ^= cast m->num_mask; \ 1002 break; \ 1003 case FILE_OPADD: \ 1004 p->fld += cast m->num_mask; \ 1005 break; \ 1006 case FILE_OPMINUS: \ 1007 p->fld -= cast m->num_mask; \ 1008 break; \ 1009 case FILE_OPMULTIPLY: \ 1010 p->fld *= cast m->num_mask; \ 1011 break; \ 1012 case FILE_OPDIVIDE: \ 1013 if (cast m->num_mask == 0) \ 1014 return -1; \ 1015 p->fld /= cast m->num_mask; \ 1016 break; \ 1017 case FILE_OPMODULO: \ 1018 if (cast m->num_mask == 0) \ 1019 return -1; \ 1020 p->fld %= cast m->num_mask; \ 1021 break; \ 1022 } \ 1023 if (m->mask_op & FILE_OPINVERSE) \ 1024 p->fld = ~p->fld \ 1025 1026 private int 1027 cvt_8(union VALUETYPE *p, const struct magic *m) 1028 { 1029 DO_CVT(b, (uint8_t)); 1030 return 0; 1031 } 1032 1033 private int 1034 cvt_16(union VALUETYPE *p, const struct magic *m) 1035 { 1036 DO_CVT(h, (uint16_t)); 1037 return 0; 1038 } 1039 1040 private int 1041 cvt_32(union VALUETYPE *p, const struct magic *m) 1042 { 1043 DO_CVT(l, (uint32_t)); 1044 return 0; 1045 } 1046 1047 private int 1048 cvt_64(union VALUETYPE *p, const struct magic *m) 1049 { 1050 DO_CVT(q, (uint64_t)); 1051 return 0; 1052 } 1053 1054 #define DO_CVT2(fld, cast) \ 1055 if (m->num_mask) \ 1056 switch (m->mask_op & FILE_OPS_MASK) { \ 1057 case FILE_OPADD: \ 1058 p->fld += cast m->num_mask; \ 1059 break; \ 1060 case FILE_OPMINUS: \ 1061 p->fld -= cast m->num_mask; \ 1062 break; \ 1063 case FILE_OPMULTIPLY: \ 1064 p->fld *= cast m->num_mask; \ 1065 break; \ 1066 case FILE_OPDIVIDE: \ 1067 if (cast m->num_mask == 0) \ 1068 return -1; \ 1069 p->fld /= cast m->num_mask; \ 1070 break; \ 1071 } \ 1072 1073 private int 1074 cvt_float(union VALUETYPE *p, const struct magic *m) 1075 { 1076 DO_CVT2(f, (float)); 1077 return 0; 1078 } 1079 1080 private int 1081 cvt_double(union VALUETYPE *p, const struct magic *m) 1082 { 1083 DO_CVT2(d, (double)); 1084 return 0; 1085 } 1086 1087 /* 1088 * Convert the byte order of the data we are looking at 1089 * While we're here, let's apply the mask operation 1090 * (unless you have a better idea) 1091 */ 1092 private int 1093 mconvert(struct magic_set *ms, struct magic *m, int flip) 1094 { 1095 union VALUETYPE *p = &ms->ms_value; 1096 1097 switch (cvt_flip(m->type, flip)) { 1098 case FILE_BYTE: 1099 if (cvt_8(p, m) == -1) 1100 goto out; 1101 return 1; 1102 case FILE_SHORT: 1103 if (cvt_16(p, m) == -1) 1104 goto out; 1105 return 1; 1106 case FILE_LONG: 1107 case FILE_DATE: 1108 case FILE_LDATE: 1109 if (cvt_32(p, m) == -1) 1110 goto out; 1111 return 1; 1112 case FILE_QUAD: 1113 case FILE_QDATE: 1114 case FILE_QLDATE: 1115 case FILE_QWDATE: 1116 if (cvt_64(p, m) == -1) 1117 goto out; 1118 return 1; 1119 case FILE_STRING: 1120 case FILE_BESTRING16: 1121 case FILE_LESTRING16: { 1122 /* Null terminate and eat *trailing* return */ 1123 p->s[sizeof(p->s) - 1] = '\0'; 1124 return 1; 1125 } 1126 case FILE_PSTRING: { 1127 size_t sz = file_pstring_length_size(m); 1128 char *ptr1 = p->s, *ptr2 = ptr1 + sz; 1129 size_t len = file_pstring_get_length(m, ptr1); 1130 sz = sizeof(p->s) - sz; /* maximum length of string */ 1131 if (len >= sz) { 1132 /* 1133 * The size of the pascal string length (sz) 1134 * is 1, 2, or 4. We need at least 1 byte for NUL 1135 * termination, but we've already truncated the 1136 * string by p->s, so we need to deduct sz. 1137 * Because we can use one of the bytes of the length 1138 * after we shifted as NUL termination. 1139 */ 1140 len = sz; 1141 } 1142 while (len--) 1143 *ptr1++ = *ptr2++; 1144 *ptr1 = '\0'; 1145 return 1; 1146 } 1147 case FILE_BESHORT: 1148 p->h = (short)BE16(p); 1149 if (cvt_16(p, m) == -1) 1150 goto out; 1151 return 1; 1152 case FILE_BELONG: 1153 case FILE_BEDATE: 1154 case FILE_BELDATE: 1155 p->l = (int32_t)BE32(p); 1156 if (cvt_32(p, m) == -1) 1157 goto out; 1158 return 1; 1159 case FILE_BEQUAD: 1160 case FILE_BEQDATE: 1161 case FILE_BEQLDATE: 1162 case FILE_BEQWDATE: 1163 p->q = (uint64_t)BE64(p); 1164 if (cvt_64(p, m) == -1) 1165 goto out; 1166 return 1; 1167 case FILE_LESHORT: 1168 p->h = (short)LE16(p); 1169 if (cvt_16(p, m) == -1) 1170 goto out; 1171 return 1; 1172 case FILE_LELONG: 1173 case FILE_LEDATE: 1174 case FILE_LELDATE: 1175 p->l = (int32_t)LE32(p); 1176 if (cvt_32(p, m) == -1) 1177 goto out; 1178 return 1; 1179 case FILE_LEQUAD: 1180 case FILE_LEQDATE: 1181 case FILE_LEQLDATE: 1182 case FILE_LEQWDATE: 1183 p->q = (uint64_t)LE64(p); 1184 if (cvt_64(p, m) == -1) 1185 goto out; 1186 return 1; 1187 case FILE_MELONG: 1188 case FILE_MEDATE: 1189 case FILE_MELDATE: 1190 p->l = (int32_t)ME32(p); 1191 if (cvt_32(p, m) == -1) 1192 goto out; 1193 return 1; 1194 case FILE_FLOAT: 1195 if (cvt_float(p, m) == -1) 1196 goto out; 1197 return 1; 1198 case FILE_BEFLOAT: 1199 p->l = BE32(p); 1200 if (cvt_float(p, m) == -1) 1201 goto out; 1202 return 1; 1203 case FILE_LEFLOAT: 1204 p->l = LE32(p); 1205 if (cvt_float(p, m) == -1) 1206 goto out; 1207 return 1; 1208 case FILE_DOUBLE: 1209 if (cvt_double(p, m) == -1) 1210 goto out; 1211 return 1; 1212 case FILE_BEDOUBLE: 1213 p->q = BE64(p); 1214 if (cvt_double(p, m) == -1) 1215 goto out; 1216 return 1; 1217 case FILE_LEDOUBLE: 1218 p->q = LE64(p); 1219 if (cvt_double(p, m) == -1) 1220 goto out; 1221 return 1; 1222 case FILE_REGEX: 1223 case FILE_SEARCH: 1224 case FILE_DEFAULT: 1225 case FILE_CLEAR: 1226 case FILE_NAME: 1227 case FILE_USE: 1228 case FILE_DER: 1229 return 1; 1230 default: 1231 file_magerror(ms, "invalid type %d in mconvert()", m->type); 1232 return 0; 1233 } 1234 out: 1235 file_magerror(ms, "zerodivide in mconvert()"); 1236 return 0; 1237 } 1238 1239 1240 private void 1241 mdebug(uint32_t offset, const char *str, size_t len) 1242 { 1243 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset); 1244 file_showstr(stderr, str, len); 1245 (void) fputc('\n', stderr); 1246 (void) fputc('\n', stderr); 1247 } 1248 1249 private int 1250 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, 1251 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) 1252 { 1253 /* 1254 * Note: FILE_SEARCH and FILE_REGEX do not actually copy 1255 * anything, but setup pointers into the source 1256 */ 1257 if (indir == 0) { 1258 switch (type) { 1259 case FILE_DER: 1260 case FILE_SEARCH: 1261 if (offset > nbytes) 1262 offset = CAST(uint32_t, nbytes); 1263 ms->search.s = RCAST(const char *, s) + offset; 1264 ms->search.s_len = nbytes - offset; 1265 ms->search.offset = offset; 1266 return 0; 1267 1268 case FILE_REGEX: { 1269 const char *b; 1270 const char *c; 1271 const char *last; /* end of search region */ 1272 const char *buf; /* start of search region */ 1273 const char *end; 1274 size_t lines, linecnt, bytecnt; 1275 1276 if (s == NULL || nbytes < offset) { 1277 ms->search.s_len = 0; 1278 ms->search.s = NULL; 1279 return 0; 1280 } 1281 1282 if (m->str_flags & REGEX_LINE_COUNT) { 1283 linecnt = m->str_range; 1284 bytecnt = linecnt * 80; 1285 } else { 1286 linecnt = 0; 1287 bytecnt = m->str_range; 1288 } 1289 1290 if (bytecnt == 0 || bytecnt > nbytes - offset) 1291 bytecnt = nbytes - offset; 1292 if (bytecnt > ms->regex_max) 1293 bytecnt = ms->regex_max; 1294 1295 buf = RCAST(const char *, s) + offset; 1296 end = last = RCAST(const char *, s) + bytecnt + offset; 1297 /* mget() guarantees buf <= last */ 1298 for (lines = linecnt, b = buf; lines && b < end && 1299 ((b = CAST(const char *, 1300 memchr(c = b, '\n', CAST(size_t, (end - b))))) 1301 || (b = CAST(const char *, 1302 memchr(c, '\r', CAST(size_t, (end - c)))))); 1303 lines--, b++) { 1304 last = b; 1305 if (b < end - 1 && b[0] == '\r' && b[1] == '\n') 1306 b++; 1307 } 1308 if (lines) 1309 last = end; 1310 1311 ms->search.s = buf; 1312 ms->search.s_len = last - buf; 1313 ms->search.offset = offset; 1314 ms->search.rm_len = 0; 1315 return 0; 1316 } 1317 case FILE_BESTRING16: 1318 case FILE_LESTRING16: { 1319 const unsigned char *src = s + offset; 1320 const unsigned char *esrc = s + nbytes; 1321 char *dst = p->s; 1322 char *edst = &p->s[sizeof(p->s) - 1]; 1323 1324 if (type == FILE_BESTRING16) 1325 src++; 1326 1327 /* check that offset is within range */ 1328 if (offset >= nbytes) 1329 break; 1330 for (/*EMPTY*/; src < esrc; src += 2, dst++) { 1331 if (dst < edst) 1332 *dst = *src; 1333 else 1334 break; 1335 if (*dst == '\0') { 1336 if (type == FILE_BESTRING16 ? 1337 *(src - 1) != '\0' : 1338 ((src + 1 < esrc) && 1339 *(src + 1) != '\0')) 1340 *dst = ' '; 1341 } 1342 } 1343 *edst = '\0'; 1344 return 0; 1345 } 1346 case FILE_STRING: /* XXX - these two should not need */ 1347 case FILE_PSTRING: /* to copy anything, but do anyway. */ 1348 default: 1349 break; 1350 } 1351 } 1352 1353 if (offset >= nbytes) { 1354 (void)memset(p, '\0', sizeof(*p)); 1355 return 0; 1356 } 1357 if (nbytes - offset < sizeof(*p)) 1358 nbytes = nbytes - offset; 1359 else 1360 nbytes = sizeof(*p); 1361 1362 (void)memcpy(p, s + offset, nbytes); 1363 1364 /* 1365 * the usefulness of padding with zeroes eludes me, it 1366 * might even cause problems 1367 */ 1368 if (nbytes < sizeof(*p)) 1369 (void)memset(((char *)(void *)p) + nbytes, '\0', 1370 sizeof(*p) - nbytes); 1371 return 0; 1372 } 1373 1374 private uint32_t 1375 do_ops(struct magic *m, intmax_t lhs, intmax_t off) 1376 { 1377 intmax_t offset; 1378 if (off) { 1379 switch (m->in_op & FILE_OPS_MASK) { 1380 case FILE_OPAND: 1381 offset = lhs & off; 1382 break; 1383 case FILE_OPOR: 1384 offset = lhs | off; 1385 break; 1386 case FILE_OPXOR: 1387 offset = lhs ^ off; 1388 break; 1389 case FILE_OPADD: 1390 offset = lhs + off; 1391 break; 1392 case FILE_OPMINUS: 1393 offset = lhs - off; 1394 break; 1395 case FILE_OPMULTIPLY: 1396 offset = lhs * off; 1397 break; 1398 case FILE_OPDIVIDE: 1399 offset = lhs / off; 1400 break; 1401 case FILE_OPMODULO: 1402 offset = lhs % off; 1403 break; 1404 } 1405 } else 1406 offset = lhs; 1407 if (m->in_op & FILE_OPINVERSE) 1408 offset = ~offset; 1409 1410 return (uint32_t)offset; 1411 } 1412 1413 private int 1414 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb, 1415 const struct buffer *b, size_t o, unsigned int cont_level) 1416 { 1417 if (m->offset < 0) { 1418 if (cont_level > 0) { 1419 if (m->flag & (OFFADD|INDIROFFADD)) 1420 goto normal; 1421 #if 0 1422 file_error(ms, 0, "negative offset %d at continuation" 1423 "level %u", m->offset, cont_level); 1424 return -1; 1425 #endif 1426 } 1427 if (buffer_fill(b) == -1) 1428 return -1; 1429 if (o != 0) { 1430 // Not yet! 1431 file_magerror(ms, "non zero offset %zu at" 1432 " level %u", o, cont_level); 1433 return -1; 1434 } 1435 if ((size_t)-m->offset > b->elen) 1436 return -1; 1437 buffer_init(bb, -1, b->ebuf, b->elen); 1438 ms->eoffset = ms->offset = b->elen + m->offset; 1439 } else { 1440 if (cont_level == 0) { 1441 normal: 1442 // XXX: Pass real fd, then who frees bb? 1443 buffer_init(bb, -1, b->fbuf, b->flen); 1444 ms->offset = m->offset; 1445 ms->eoffset = 0; 1446 } else { 1447 ms->offset = ms->eoffset + m->offset; 1448 } 1449 } 1450 if ((ms->flags & MAGIC_DEBUG) != 0) { 1451 fprintf(stderr, "bb=[%p,%zu], %d [b=%p,%zu], [o=%#x, c=%d]\n", 1452 bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen, 1453 m->offset, cont_level); 1454 } 1455 return 0; 1456 } 1457 1458 private int 1459 mget(struct magic_set *ms, struct magic *m, const struct buffer *b, 1460 const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level, 1461 int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, 1462 int *printed_something, int *need_separator, int *returnval) 1463 { 1464 uint32_t offset = ms->offset; 1465 struct buffer bb; 1466 intmax_t lhs; 1467 file_pushbuf_t *pb; 1468 int rv, oneed_separator, in_type; 1469 char *rbuf; 1470 union VALUETYPE *p = &ms->ms_value; 1471 struct mlist ml; 1472 1473 if (*indir_count >= ms->indir_max) { 1474 file_error(ms, 0, "indirect count (%hu) exceeded", 1475 *indir_count); 1476 return -1; 1477 } 1478 1479 if (*name_count >= ms->name_max) { 1480 file_error(ms, 0, "name use count (%hu) exceeded", 1481 *name_count); 1482 return -1; 1483 } 1484 1485 1486 1487 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), 1488 (uint32_t)nbytes, m) == -1) 1489 return -1; 1490 1491 if ((ms->flags & MAGIC_DEBUG) != 0) { 1492 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%" 1493 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT 1494 "u, il=%hu, nc=%hu)\n", 1495 m->type, m->flag, offset, o, nbytes, 1496 *indir_count, *name_count); 1497 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); 1498 #ifndef COMPILE_ONLY 1499 file_mdump(m); 1500 #endif 1501 } 1502 1503 if (m->flag & INDIR) { 1504 intmax_t off = m->in_offset; 1505 const int sgn = m->in_op & FILE_OPSIGNED; 1506 if (m->in_op & FILE_OPINDIRECT) { 1507 const union VALUETYPE *q = CAST(const union VALUETYPE *, 1508 ((const void *)(s + offset + off))); 1509 if (OFFSET_OOB(nbytes, offset + off, sizeof(*q))) 1510 return 0; 1511 switch (cvt_flip(m->in_type, flip)) { 1512 case FILE_BYTE: 1513 off = SEXT(sgn,8,q->b); 1514 break; 1515 case FILE_SHORT: 1516 off = SEXT(sgn,16,q->h); 1517 break; 1518 case FILE_BESHORT: 1519 off = SEXT(sgn,16,BE16(q)); 1520 break; 1521 case FILE_LESHORT: 1522 off = SEXT(sgn,16,LE16(q)); 1523 break; 1524 case FILE_LONG: 1525 off = SEXT(sgn,32,q->l); 1526 break; 1527 case FILE_BELONG: 1528 case FILE_BEID3: 1529 off = SEXT(sgn,32,BE32(q)); 1530 break; 1531 case FILE_LEID3: 1532 case FILE_LELONG: 1533 off = SEXT(sgn,32,LE32(q)); 1534 break; 1535 case FILE_MELONG: 1536 off = SEXT(sgn,32,ME32(q)); 1537 break; 1538 case FILE_BEQUAD: 1539 off = SEXT(sgn,64,BE64(q)); 1540 break; 1541 case FILE_LEQUAD: 1542 off = SEXT(sgn,64,LE64(q)); 1543 break; 1544 default: 1545 abort(); 1546 } 1547 if ((ms->flags & MAGIC_DEBUG) != 0) 1548 fprintf(stderr, "indirect offs=%jd\n", off); 1549 } 1550 switch (in_type = cvt_flip(m->in_type, flip)) { 1551 case FILE_BYTE: 1552 if (OFFSET_OOB(nbytes, offset, 1)) 1553 return 0; 1554 offset = do_ops(m, SEXT(sgn,8,p->b), off); 1555 break; 1556 case FILE_BESHORT: 1557 if (OFFSET_OOB(nbytes, offset, 2)) 1558 return 0; 1559 offset = do_ops(m, SEXT(sgn,16,BE16(p)), off); 1560 break; 1561 case FILE_LESHORT: 1562 if (OFFSET_OOB(nbytes, offset, 2)) 1563 return 0; 1564 offset = do_ops(m, SEXT(sgn,16,LE16(p)), off); 1565 break; 1566 case FILE_SHORT: 1567 if (OFFSET_OOB(nbytes, offset, 2)) 1568 return 0; 1569 offset = do_ops(m, SEXT(sgn,16,p->h), off); 1570 break; 1571 case FILE_BELONG: 1572 case FILE_BEID3: 1573 if (OFFSET_OOB(nbytes, offset, 4)) 1574 return 0; 1575 lhs = BE32(p); 1576 if (in_type == FILE_BEID3) 1577 lhs = cvt_id3(ms, (uint32_t)lhs); 1578 offset = do_ops(m, SEXT(sgn,32,lhs), off); 1579 break; 1580 case FILE_LELONG: 1581 case FILE_LEID3: 1582 if (OFFSET_OOB(nbytes, offset, 4)) 1583 return 0; 1584 lhs = LE32(p); 1585 if (in_type == FILE_LEID3) 1586 lhs = cvt_id3(ms, (uint32_t)lhs); 1587 offset = do_ops(m, SEXT(sgn,32,lhs), off); 1588 break; 1589 case FILE_MELONG: 1590 if (OFFSET_OOB(nbytes, offset, 4)) 1591 return 0; 1592 offset = do_ops(m, SEXT(sgn,32,ME32(p)), off); 1593 break; 1594 case FILE_LONG: 1595 if (OFFSET_OOB(nbytes, offset, 4)) 1596 return 0; 1597 offset = do_ops(m, SEXT(sgn,32,p->l), off); 1598 break; 1599 case FILE_LEQUAD: 1600 if (OFFSET_OOB(nbytes, offset, 8)) 1601 return 0; 1602 offset = do_ops(m, SEXT(sgn,64,LE64(p)), off); 1603 break; 1604 case FILE_BEQUAD: 1605 if (OFFSET_OOB(nbytes, offset, 8)) 1606 return 0; 1607 offset = do_ops(m, SEXT(sgn,64,BE64(p)), off); 1608 break; 1609 default: 1610 abort(); 1611 } 1612 1613 if (m->flag & INDIROFFADD) { 1614 offset += ms->c.li[cont_level-1].off; 1615 if (offset == 0) { 1616 if ((ms->flags & MAGIC_DEBUG) != 0) 1617 fprintf(stderr, 1618 "indirect *zero* offset\n"); 1619 return 0; 1620 } 1621 if ((ms->flags & MAGIC_DEBUG) != 0) 1622 fprintf(stderr, "indirect +offs=%u\n", offset); 1623 } 1624 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1) 1625 return -1; 1626 ms->offset = offset; 1627 1628 if ((ms->flags & MAGIC_DEBUG) != 0) { 1629 mdebug(offset, (char *)(void *)p, 1630 sizeof(union VALUETYPE)); 1631 #ifndef COMPILE_ONLY 1632 file_mdump(m); 1633 #endif 1634 } 1635 } 1636 1637 /* Verify we have enough data to match magic type */ 1638 switch (m->type) { 1639 case FILE_BYTE: 1640 if (OFFSET_OOB(nbytes, offset, 1)) 1641 return 0; 1642 break; 1643 1644 case FILE_SHORT: 1645 case FILE_BESHORT: 1646 case FILE_LESHORT: 1647 if (OFFSET_OOB(nbytes, offset, 2)) 1648 return 0; 1649 break; 1650 1651 case FILE_LONG: 1652 case FILE_BELONG: 1653 case FILE_LELONG: 1654 case FILE_MELONG: 1655 case FILE_DATE: 1656 case FILE_BEDATE: 1657 case FILE_LEDATE: 1658 case FILE_MEDATE: 1659 case FILE_LDATE: 1660 case FILE_BELDATE: 1661 case FILE_LELDATE: 1662 case FILE_MELDATE: 1663 case FILE_FLOAT: 1664 case FILE_BEFLOAT: 1665 case FILE_LEFLOAT: 1666 if (OFFSET_OOB(nbytes, offset, 4)) 1667 return 0; 1668 break; 1669 1670 case FILE_DOUBLE: 1671 case FILE_BEDOUBLE: 1672 case FILE_LEDOUBLE: 1673 if (OFFSET_OOB(nbytes, offset, 8)) 1674 return 0; 1675 break; 1676 1677 case FILE_STRING: 1678 case FILE_PSTRING: 1679 case FILE_SEARCH: 1680 if (OFFSET_OOB(nbytes, offset, m->vallen)) 1681 return 0; 1682 break; 1683 1684 case FILE_REGEX: 1685 if (nbytes < offset) 1686 return 0; 1687 break; 1688 1689 case FILE_INDIRECT: 1690 if (m->str_flags & INDIRECT_RELATIVE) 1691 offset += CAST(uint32_t, o); 1692 if (offset == 0) 1693 return 0; 1694 1695 if (nbytes < offset) 1696 return 0; 1697 1698 if ((pb = file_push_buffer(ms)) == NULL) 1699 return -1; 1700 1701 (*indir_count)++; 1702 bb = *b; 1703 bb.fbuf = s + offset; 1704 bb.flen = nbytes - offset; 1705 rv = file_softmagic(ms, &bb, 1706 indir_count, name_count, BINTEST, text); 1707 1708 if ((ms->flags & MAGIC_DEBUG) != 0) 1709 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); 1710 1711 rbuf = file_pop_buffer(ms, pb); 1712 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR) 1713 return -1; 1714 1715 if (rv == 1) { 1716 if ((ms->flags & MAGIC_NODESC) == 0 && 1717 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) { 1718 free(rbuf); 1719 return -1; 1720 } 1721 if (file_printf(ms, "%s", rbuf) == -1) { 1722 free(rbuf); 1723 return -1; 1724 } 1725 } 1726 free(rbuf); 1727 return rv; 1728 1729 case FILE_USE: 1730 if (nbytes < offset) 1731 return 0; 1732 rbuf = m->value.s; 1733 if (*rbuf == '^') { 1734 rbuf++; 1735 flip = !flip; 1736 } 1737 if (file_magicfind(ms, rbuf, &ml) == -1) { 1738 file_error(ms, 0, "cannot find entry `%s'", rbuf); 1739 return -1; 1740 } 1741 (*name_count)++; 1742 oneed_separator = *need_separator; 1743 if (m->flag & NOSPACE) 1744 *need_separator = 0; 1745 rv = match(ms, ml.magic, ml.nmagic, b, offset + o, 1746 mode, text, flip, indir_count, name_count, 1747 printed_something, need_separator, returnval); 1748 if (rv != 1) 1749 *need_separator = oneed_separator; 1750 return rv; 1751 1752 case FILE_NAME: 1753 if (ms->flags & MAGIC_NODESC) 1754 return 1; 1755 if (file_printf(ms, "%s", m->desc) == -1) 1756 return -1; 1757 return 1; 1758 case FILE_DER: 1759 case FILE_DEFAULT: /* nothing to check */ 1760 case FILE_CLEAR: 1761 default: 1762 break; 1763 } 1764 if (!mconvert(ms, m, flip)) 1765 return 0; 1766 return 1; 1767 } 1768 1769 private uint64_t 1770 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) 1771 { 1772 /* 1773 * Convert the source args to unsigned here so that (1) the 1774 * compare will be unsigned as it is in strncmp() and (2) so 1775 * the ctype functions will work correctly without extra 1776 * casting. 1777 */ 1778 const unsigned char *a = (const unsigned char *)s1; 1779 const unsigned char *b = (const unsigned char *)s2; 1780 const unsigned char *eb = b + len; 1781 uint64_t v; 1782 1783 /* 1784 * What we want here is v = strncmp(s1, s2, len), 1785 * but ignoring any nulls. 1786 */ 1787 v = 0; 1788 if (0L == flags) { /* normal string: do it fast */ 1789 while (len-- > 0) 1790 if ((v = *b++ - *a++) != '\0') 1791 break; 1792 } 1793 else { /* combine the others */ 1794 while (len-- > 0) { 1795 if (b >= eb) { 1796 v = 1; 1797 break; 1798 } 1799 if ((flags & STRING_IGNORE_LOWERCASE) && 1800 islower(*a)) { 1801 if ((v = tolower(*b++) - *a++) != '\0') 1802 break; 1803 } 1804 else if ((flags & STRING_IGNORE_UPPERCASE) && 1805 isupper(*a)) { 1806 if ((v = toupper(*b++) - *a++) != '\0') 1807 break; 1808 } 1809 else if ((flags & STRING_COMPACT_WHITESPACE) && 1810 isspace(*a)) { 1811 a++; 1812 if (isspace(*b++)) { 1813 if (!isspace(*a)) 1814 while (b < eb && isspace(*b)) 1815 b++; 1816 } 1817 else { 1818 v = 1; 1819 break; 1820 } 1821 } 1822 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) && 1823 isspace(*a)) { 1824 a++; 1825 while (b < eb && isspace(*b)) 1826 b++; 1827 } 1828 else { 1829 if ((v = *b++ - *a++) != '\0') 1830 break; 1831 } 1832 } 1833 } 1834 return v; 1835 } 1836 1837 private uint64_t 1838 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) 1839 { 1840 /* 1841 * XXX - The 16-bit string compare probably needs to be done 1842 * differently, especially if the flags are to be supported. 1843 * At the moment, I am unsure. 1844 */ 1845 flags = 0; 1846 return file_strncmp(a, b, len, flags); 1847 } 1848 1849 private int 1850 magiccheck(struct magic_set *ms, struct magic *m) 1851 { 1852 uint64_t l = m->value.q; 1853 uint64_t v; 1854 float fl, fv; 1855 double dl, dv; 1856 int matched; 1857 union VALUETYPE *p = &ms->ms_value; 1858 1859 switch (m->type) { 1860 case FILE_BYTE: 1861 v = p->b; 1862 break; 1863 1864 case FILE_SHORT: 1865 case FILE_BESHORT: 1866 case FILE_LESHORT: 1867 v = p->h; 1868 break; 1869 1870 case FILE_LONG: 1871 case FILE_BELONG: 1872 case FILE_LELONG: 1873 case FILE_MELONG: 1874 case FILE_DATE: 1875 case FILE_BEDATE: 1876 case FILE_LEDATE: 1877 case FILE_MEDATE: 1878 case FILE_LDATE: 1879 case FILE_BELDATE: 1880 case FILE_LELDATE: 1881 case FILE_MELDATE: 1882 v = p->l; 1883 break; 1884 1885 case FILE_QUAD: 1886 case FILE_LEQUAD: 1887 case FILE_BEQUAD: 1888 case FILE_QDATE: 1889 case FILE_BEQDATE: 1890 case FILE_LEQDATE: 1891 case FILE_QLDATE: 1892 case FILE_BEQLDATE: 1893 case FILE_LEQLDATE: 1894 case FILE_QWDATE: 1895 case FILE_BEQWDATE: 1896 case FILE_LEQWDATE: 1897 v = p->q; 1898 break; 1899 1900 case FILE_FLOAT: 1901 case FILE_BEFLOAT: 1902 case FILE_LEFLOAT: 1903 fl = m->value.f; 1904 fv = p->f; 1905 switch (m->reln) { 1906 case 'x': 1907 matched = 1; 1908 break; 1909 1910 case '!': 1911 matched = fv != fl; 1912 break; 1913 1914 case '=': 1915 matched = fv == fl; 1916 break; 1917 1918 case '>': 1919 matched = fv > fl; 1920 break; 1921 1922 case '<': 1923 matched = fv < fl; 1924 break; 1925 1926 default: 1927 file_magerror(ms, "cannot happen with float: invalid relation `%c'", 1928 m->reln); 1929 return -1; 1930 } 1931 return matched; 1932 1933 case FILE_DOUBLE: 1934 case FILE_BEDOUBLE: 1935 case FILE_LEDOUBLE: 1936 dl = m->value.d; 1937 dv = p->d; 1938 switch (m->reln) { 1939 case 'x': 1940 matched = 1; 1941 break; 1942 1943 case '!': 1944 matched = dv != dl; 1945 break; 1946 1947 case '=': 1948 matched = dv == dl; 1949 break; 1950 1951 case '>': 1952 matched = dv > dl; 1953 break; 1954 1955 case '<': 1956 matched = dv < dl; 1957 break; 1958 1959 default: 1960 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); 1961 return -1; 1962 } 1963 return matched; 1964 1965 case FILE_DEFAULT: 1966 case FILE_CLEAR: 1967 l = 0; 1968 v = 0; 1969 break; 1970 1971 case FILE_STRING: 1972 case FILE_PSTRING: 1973 l = 0; 1974 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1975 break; 1976 1977 case FILE_BESTRING16: 1978 case FILE_LESTRING16: 1979 l = 0; 1980 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1981 break; 1982 1983 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */ 1984 size_t slen; 1985 size_t idx; 1986 1987 if (ms->search.s == NULL) 1988 return 0; 1989 1990 slen = MIN(m->vallen, sizeof(m->value.s)); 1991 l = 0; 1992 v = 0; 1993 1994 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) { 1995 if (slen + idx > ms->search.s_len) 1996 return 0; 1997 1998 v = file_strncmp(m->value.s, ms->search.s + idx, slen, 1999 m->str_flags); 2000 if (v == 0) { /* found match */ 2001 ms->search.offset += idx; 2002 ms->search.rm_len = ms->search.s_len - idx; 2003 break; 2004 } 2005 } 2006 break; 2007 } 2008 case FILE_REGEX: { 2009 int rc; 2010 file_regex_t rx; 2011 const char *search; 2012 2013 if (ms->search.s == NULL) 2014 return 0; 2015 2016 l = 0; 2017 rc = file_regcomp(&rx, m->value.s, 2018 REG_EXTENDED|REG_NEWLINE| 2019 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 2020 if (rc) { 2021 file_regerror(&rx, rc, ms); 2022 v = (uint64_t)-1; 2023 } else { 2024 regmatch_t pmatch; 2025 size_t slen = ms->search.s_len; 2026 char *copy; 2027 if (slen != 0) { 2028 copy = CAST(char *, malloc(slen)); 2029 if (copy == NULL) { 2030 file_regfree(&rx); 2031 file_error(ms, errno, 2032 "can't allocate %" SIZE_T_FORMAT "u bytes", 2033 slen); 2034 return -1; 2035 } 2036 memcpy(copy, ms->search.s, slen); 2037 copy[--slen] = '\0'; 2038 search = copy; 2039 } else { 2040 search = CCAST(char *, ""); 2041 copy = NULL; 2042 } 2043 rc = file_regexec(&rx, (const char *)search, 2044 1, &pmatch, 0); 2045 free(copy); 2046 switch (rc) { 2047 case 0: 2048 ms->search.s += (int)pmatch.rm_so; 2049 ms->search.offset += (size_t)pmatch.rm_so; 2050 ms->search.rm_len = 2051 (size_t)(pmatch.rm_eo - pmatch.rm_so); 2052 v = 0; 2053 break; 2054 2055 case REG_NOMATCH: 2056 v = 1; 2057 break; 2058 2059 default: 2060 file_regerror(&rx, rc, ms); 2061 v = (uint64_t)-1; 2062 break; 2063 } 2064 } 2065 file_regfree(&rx); 2066 if (v == (uint64_t)-1) 2067 return -1; 2068 break; 2069 } 2070 case FILE_INDIRECT: 2071 case FILE_USE: 2072 case FILE_NAME: 2073 return 1; 2074 case FILE_DER: 2075 matched = der_cmp(ms, m); 2076 if (matched == -1) { 2077 if ((ms->flags & MAGIC_DEBUG) != 0) { 2078 (void) fprintf(stderr, 2079 "EOF comparing DER entries"); 2080 } 2081 return 0; 2082 } 2083 return matched; 2084 default: 2085 file_magerror(ms, "invalid type %d in magiccheck()", m->type); 2086 return -1; 2087 } 2088 2089 v = file_signextend(ms, m, v); 2090 2091 switch (m->reln) { 2092 case 'x': 2093 if ((ms->flags & MAGIC_DEBUG) != 0) 2094 (void) fprintf(stderr, "%" INT64_T_FORMAT 2095 "u == *any* = 1\n", (unsigned long long)v); 2096 matched = 1; 2097 break; 2098 2099 case '!': 2100 matched = v != l; 2101 if ((ms->flags & MAGIC_DEBUG) != 0) 2102 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %" 2103 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 2104 (unsigned long long)l, matched); 2105 break; 2106 2107 case '=': 2108 matched = v == l; 2109 if ((ms->flags & MAGIC_DEBUG) != 0) 2110 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %" 2111 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 2112 (unsigned long long)l, matched); 2113 break; 2114 2115 case '>': 2116 if (m->flag & UNSIGNED) { 2117 matched = v > l; 2118 if ((ms->flags & MAGIC_DEBUG) != 0) 2119 (void) fprintf(stderr, "%" INT64_T_FORMAT 2120 "u > %" INT64_T_FORMAT "u = %d\n", 2121 (unsigned long long)v, 2122 (unsigned long long)l, matched); 2123 } 2124 else { 2125 matched = (int64_t) v > (int64_t) l; 2126 if ((ms->flags & MAGIC_DEBUG) != 0) 2127 (void) fprintf(stderr, "%" INT64_T_FORMAT 2128 "d > %" INT64_T_FORMAT "d = %d\n", 2129 (long long)v, (long long)l, matched); 2130 } 2131 break; 2132 2133 case '<': 2134 if (m->flag & UNSIGNED) { 2135 matched = v < l; 2136 if ((ms->flags & MAGIC_DEBUG) != 0) 2137 (void) fprintf(stderr, "%" INT64_T_FORMAT 2138 "u < %" INT64_T_FORMAT "u = %d\n", 2139 (unsigned long long)v, 2140 (unsigned long long)l, matched); 2141 } 2142 else { 2143 matched = (int64_t) v < (int64_t) l; 2144 if ((ms->flags & MAGIC_DEBUG) != 0) 2145 (void) fprintf(stderr, "%" INT64_T_FORMAT 2146 "d < %" INT64_T_FORMAT "d = %d\n", 2147 (long long)v, (long long)l, matched); 2148 } 2149 break; 2150 2151 case '&': 2152 matched = (v & l) == l; 2153 if ((ms->flags & MAGIC_DEBUG) != 0) 2154 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2155 INT64_T_FORMAT "x) == %" INT64_T_FORMAT 2156 "x) = %d\n", (unsigned long long)v, 2157 (unsigned long long)l, (unsigned long long)l, 2158 matched); 2159 break; 2160 2161 case '^': 2162 matched = (v & l) != l; 2163 if ((ms->flags & MAGIC_DEBUG) != 0) 2164 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2165 INT64_T_FORMAT "x) != %" INT64_T_FORMAT 2166 "x) = %d\n", (unsigned long long)v, 2167 (unsigned long long)l, (unsigned long long)l, 2168 matched); 2169 break; 2170 2171 default: 2172 file_magerror(ms, "cannot happen: invalid relation `%c'", 2173 m->reln); 2174 return -1; 2175 } 2176 2177 return matched; 2178 } 2179 2180 private int 2181 handle_annotation(struct magic_set *ms, struct magic *m, int firstline) 2182 { 2183 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { 2184 if (!firstline && file_printf(ms, "\n- ") == -1) 2185 return -1; 2186 if (file_printf(ms, "%.8s", m->apple) == -1) 2187 return -1; 2188 return 1; 2189 } 2190 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) { 2191 if (!firstline && file_printf(ms, "\n- ") == -1) 2192 return -1; 2193 if (file_printf(ms, "%s", m->ext) == -1) 2194 return -1; 2195 return 1; 2196 } 2197 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { 2198 char buf[1024]; 2199 const char *p; 2200 if (!firstline && file_printf(ms, "\n- ") == -1) 2201 return -1; 2202 if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1) 2203 p = m->mimetype; 2204 else 2205 p = buf; 2206 if (file_printf(ms, "%s", p) == -1) 2207 return -1; 2208 return 1; 2209 } 2210 return 0; 2211 } 2212 2213 private int 2214 print_sep(struct magic_set *ms, int firstline) 2215 { 2216 // if (ms->flags & MAGIC_NODESC) 2217 // return 0; 2218 if (firstline) 2219 return 0; 2220 /* 2221 * we found another match 2222 * put a newline and '-' to do some simple formatting 2223 */ 2224 return file_printf(ms, "\n- "); 2225 } 2226