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