1 /* $NetBSD: funcs.c,v 1.22 2026/06/10 20:54:16 christos Exp $ */ 2 3 /* 4 * Copyright (c) Christos Zoulas 2003. 5 * All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include "file.h" 30 31 #ifndef lint 32 #if 0 33 FILE_RCSID("@(#)$File: funcs.c,v 1.153 2026/05/25 14:07:05 christos Exp $") 34 #else 35 __RCSID("$NetBSD: funcs.c,v 1.22 2026/06/10 20:54:16 christos Exp $"); 36 #endif 37 #endif /* lint */ 38 39 #include "magic.h" 40 #include "swap.h" 41 #include <assert.h> 42 #include <stdarg.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <ctype.h> 46 #ifdef HAVE_UNISTD_H 47 #include <unistd.h> /* for pipe2() */ 48 #endif 49 #if defined(HAVE_WCHAR_H) 50 #include <wchar.h> 51 #endif 52 #if defined(HAVE_WCTYPE_H) 53 #include <wctype.h> 54 #endif 55 #include <limits.h> 56 57 #ifndef SIZE_MAX 58 #define SIZE_MAX ((size_t)~0) 59 #endif 60 61 file_protected int 62 file_bigendian(void) 63 { 64 union { 65 unsigned short x; 66 unsigned char s[sizeof(unsigned short)]; 67 } u; 68 69 u.x = 1; 70 return u.s[0] != 1; 71 } 72 73 file_protected char * 74 file_copystr(char *buf, size_t blen, size_t width, const char *str) 75 { 76 if (blen == 0) 77 return buf; 78 if (width >= blen) 79 width = blen - 1; 80 memcpy(buf, str, width); 81 buf[width] = '\0'; 82 return buf; 83 } 84 85 file_private void 86 file_clearbuf(struct magic_set *ms) 87 { 88 free(ms->o.buf); 89 ms->o.buf = NULL; 90 ms->o.blen = 0; 91 } 92 93 file_private int 94 file_checkfield(char *msg, size_t mlen, const char *what, const char **pp) 95 { 96 const char *p = *pp; 97 int fw = 0; 98 99 while (*p && isdigit((unsigned char)*p)) { 100 fw = fw * 10 + (*p++ - '0'); 101 if (fw > 1024) 102 break; 103 } 104 105 *pp = p; 106 107 if (fw < 1024) 108 return 1; 109 if (msg) 110 snprintf(msg, mlen, "field %s too large: %d", what, fw); 111 112 return 0; 113 } 114 115 file_protected int 116 file_checkfmt(char *msg, size_t mlen, const char *fmt) 117 { 118 const char *p; 119 for (p = fmt; *p; p++) { 120 if (*p != '%') 121 continue; 122 if (*++p == '%') 123 continue; 124 if (*p == '\0') { 125 if (msg) 126 snprintf(msg, mlen, "incomplete %% format"); 127 return -1; 128 } 129 // Skip uninteresting. 130 while (*p != '\0' && strchr("#0.'+- ", *p) != NULL) 131 p++; 132 if (*p == '*') { 133 if (msg) 134 snprintf(msg, mlen, "* not allowed in format"); 135 return -1; 136 } 137 138 if (!file_checkfield(msg, mlen, "width", &p)) 139 return -1; 140 141 if (*p == '.') { 142 p++; 143 if (!file_checkfield(msg, mlen, "precision", &p)) 144 return -1; 145 } 146 147 if (!isalpha((unsigned char)*p)) { 148 if (msg) 149 snprintf(msg, mlen, "bad format char: %c", *p); 150 return -1; 151 } 152 } 153 return 0; 154 } 155 156 /* 157 * Like printf, only we append to a buffer. 158 */ 159 file_protected int 160 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) 161 { 162 int len; 163 char *buf, *newstr; 164 char tbuf[1024]; 165 166 if (ms->event_flags & EVENT_HAD_ERR) 167 return 0; 168 169 if (file_checkfmt(tbuf, sizeof(tbuf), fmt)) { 170 file_clearbuf(ms); 171 file_error(ms, 0, "Bad magic format `%s' (%s)", fmt, tbuf); 172 return -1; 173 } 174 175 len = vasprintf(&buf, fmt, ap); 176 if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) { 177 size_t blen = ms->o.blen; 178 free(buf); 179 file_clearbuf(ms); 180 file_error(ms, 0, "Output buffer space exceeded %d+%" 181 SIZE_T_FORMAT "u", len, blen); 182 return -1; 183 } 184 185 if (ms->o.buf != NULL) { 186 len = asprintf(&newstr, "%s%s", ms->o.buf, buf); 187 free(buf); 188 if (len < 0) 189 goto out; 190 free(ms->o.buf); 191 buf = newstr; 192 } 193 ms->o.buf = buf; 194 ms->o.blen = len; 195 return 0; 196 out: 197 file_clearbuf(ms); 198 file_error(ms, errno, "vasprintf failed"); 199 return -1; 200 } 201 202 file_protected int 203 file_printf(struct magic_set *ms, const char *fmt, ...) 204 { 205 int rv; 206 va_list ap; 207 208 va_start(ap, fmt); 209 rv = file_vprintf(ms, fmt, ap); 210 va_end(ap); 211 return rv; 212 } 213 214 /* 215 * error - print best error message possible 216 */ 217 /*VARARGS*/ 218 __attribute__((__format__(__printf__, 3, 0))) 219 file_private void 220 file_error_core(struct magic_set *ms, int error, const char *f, va_list va, 221 size_t lineno) 222 { 223 /* Only the first error is ok */ 224 if (ms->event_flags & EVENT_HAD_ERR) 225 return; 226 if (lineno != 0) { 227 file_clearbuf(ms); 228 (void)file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno); 229 } 230 if (ms->o.buf && *ms->o.buf) 231 (void)file_printf(ms, " "); 232 (void)file_vprintf(ms, f, va); 233 if (error > 0) 234 (void)file_printf(ms, " (%s)", strerror(error)); 235 ms->event_flags |= EVENT_HAD_ERR; 236 ms->error = error; 237 } 238 239 /*VARARGS*/ 240 file_protected void 241 file_error(struct magic_set *ms, int error, const char *f, ...) 242 { 243 va_list va; 244 va_start(va, f); 245 file_error_core(ms, error, f, va, 0); 246 va_end(va); 247 } 248 249 /* 250 * Print an error with magic line number. 251 */ 252 /*VARARGS*/ 253 file_protected void 254 file_magerror(struct magic_set *ms, const char *f, ...) 255 { 256 va_list va; 257 va_start(va, f); 258 file_error_core(ms, 0, f, va, ms->line); 259 va_end(va); 260 } 261 262 file_protected void 263 file_oomem(struct magic_set *ms, size_t len) 264 { 265 file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes", 266 len); 267 } 268 269 file_protected void 270 file_badseek(struct magic_set *ms) 271 { 272 file_error(ms, errno, "error seeking"); 273 } 274 275 file_protected void 276 file_badread(struct magic_set *ms) 277 { 278 file_error(ms, errno, "error reading"); 279 } 280 281 #ifndef COMPILE_ONLY 282 #define FILE_SEPARATOR "\n- " 283 284 file_protected int 285 file_separator(struct magic_set *ms) 286 { 287 return file_printf(ms, FILE_SEPARATOR); 288 } 289 290 static void 291 trim_separator(struct magic_set *ms) 292 { 293 size_t l; 294 295 if (ms->o.buf == NULL) 296 return; 297 298 l = strlen(ms->o.buf); 299 if (l < sizeof(FILE_SEPARATOR)) 300 return; 301 302 l -= sizeof(FILE_SEPARATOR) - 1; 303 if (strcmp(ms->o.buf + l, FILE_SEPARATOR) != 0) 304 return; 305 306 ms->o.buf[l] = '\0'; 307 } 308 309 static int 310 checkdone(struct magic_set *ms, int *rv) 311 { 312 if ((ms->flags & MAGIC_CONTINUE) == 0) 313 return 1; 314 if (file_separator(ms) == -1) 315 *rv = -1; 316 return 0; 317 } 318 319 file_protected int 320 file_default(struct magic_set *ms, size_t nb) 321 { 322 if (ms->flags & MAGIC_MIME) { 323 if ((ms->flags & MAGIC_MIME_TYPE) && 324 file_printf(ms, "application/%s", 325 nb ? "octet-stream" : "x-empty") == -1) 326 return -1; 327 return 1; 328 } 329 if (ms->flags & MAGIC_APPLE) { 330 // This is not a typo: Type: UNKN Creator: UNKN 331 if (file_printf(ms, "UNKNUNKN") == -1) 332 return -1; 333 return 1; 334 } 335 if (ms->flags & MAGIC_EXTENSION) { 336 if (file_printf(ms, "???") == -1) 337 return -1; 338 return 1; 339 } 340 return 0; 341 } 342 343 /* 344 * The magic detection functions return: 345 * 1: found 346 * 0: not found 347 * -1: error 348 */ 349 /*ARGSUSED*/ 350 file_protected int 351 file_buffer(struct magic_set *ms, int fd, struct stat *st, 352 const char *inname __attribute__ ((__unused__)), 353 const void *buf, size_t nb) 354 { 355 int m = 0, rv = 0, looks_text = 0; 356 const char *code = NULL; 357 const char *code_mime = "binary"; 358 const char *def = "data"; 359 const char *ftype = NULL; 360 char *rbuf = NULL; 361 struct buffer b; 362 363 buffer_init(&b, fd, st, buf, nb); 364 ms->mode = b.st.st_mode; 365 366 if (nb == 0) { 367 def = "empty"; 368 goto simple; 369 } else if (nb == 1) { 370 def = "very short file (no magic)"; 371 goto simple; 372 } 373 374 if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) { 375 looks_text = file_encoding(ms, &b, NULL, 0, 376 &code, &code_mime, &ftype); 377 } 378 379 #ifdef __EMX__ 380 if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) { 381 m = file_os2_apptype(ms, inname, &b); 382 if ((ms->flags & MAGIC_DEBUG) != 0) 383 (void)fprintf(stderr, "[try os2_apptype %d]\n", m); 384 switch (m) { 385 case -1: 386 return -1; 387 case 0: 388 break; 389 default: 390 return 1; 391 } 392 } 393 #endif 394 #if HAVE_FORK 395 /* try compression stuff */ 396 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) { 397 m = file_zmagic(ms, &b, inname); 398 if ((ms->flags & MAGIC_DEBUG) != 0) 399 (void)fprintf(stderr, "[try zmagic %d]\n", m); 400 if (m) { 401 goto done_encoding; 402 } 403 } 404 #endif 405 /* Check if we have a tar file */ 406 if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) { 407 m = file_is_tar(ms, &b); 408 if ((ms->flags & MAGIC_DEBUG) != 0) 409 (void)fprintf(stderr, "[try tar %d]\n", m); 410 if (m) { 411 if (checkdone(ms, &rv)) 412 goto done; 413 } 414 } 415 416 /* Check if we have a JSON file */ 417 if ((ms->flags & MAGIC_NO_CHECK_JSON) == 0) { 418 m = file_is_json(ms, &b); 419 if ((ms->flags & MAGIC_DEBUG) != 0) 420 (void)fprintf(stderr, "[try json %d]\n", m); 421 if (m) { 422 if (checkdone(ms, &rv)) 423 goto done; 424 } 425 } 426 427 /* Check if we have a CSV file */ 428 if ((ms->flags & MAGIC_NO_CHECK_CSV) == 0) { 429 m = file_is_csv(ms, &b, looks_text, code); 430 if ((ms->flags & MAGIC_DEBUG) != 0) 431 (void)fprintf(stderr, "[try csv %d]\n", m); 432 if (m) { 433 if (checkdone(ms, &rv)) 434 goto done; 435 } 436 } 437 438 /* Check if we have a SIMH tape file */ 439 if ((ms->flags & MAGIC_NO_CHECK_SIMH) == 0) { 440 m = file_is_simh(ms, &b); 441 if ((ms->flags & MAGIC_DEBUG) != 0) 442 (void)fprintf(stderr, "[try simh %d]\n", m); 443 if (m) { 444 if (checkdone(ms, &rv)) 445 goto done; 446 } 447 } 448 449 /* Check if we have a CDF file */ 450 if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) { 451 m = file_trycdf(ms, &b); 452 if ((ms->flags & MAGIC_DEBUG) != 0) 453 (void)fprintf(stderr, "[try cdf %d]\n", m); 454 if (m) { 455 if (checkdone(ms, &rv)) 456 goto done; 457 } 458 } 459 #ifdef BUILTIN_ELF 460 if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) { 461 file_pushbuf_t *pb; 462 /* 463 * We matched something in the file, so this 464 * *might* be an ELF file, and the file is at 465 * least 5 bytes long, so if it's an ELF file 466 * it has at least one byte past the ELF magic 467 * number - try extracting information from the 468 * ELF headers that cannot easily be extracted 469 * with rules in the magic file. We we don't 470 * print the information yet. 471 */ 472 if ((pb = file_push_buffer(ms)) == NULL) 473 return -1; 474 475 rv = file_tryelf(ms, &b); 476 rbuf = file_pop_buffer(ms, pb); 477 if (rv == -1) { 478 free(rbuf); 479 rbuf = NULL; 480 } 481 if ((ms->flags & MAGIC_DEBUG) != 0) 482 (void)fprintf(stderr, "[try elf %d]\n", m); 483 } 484 #endif 485 486 /* try soft magic tests */ 487 if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) { 488 m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text); 489 if ((ms->flags & MAGIC_DEBUG) != 0) 490 (void)fprintf(stderr, "[try softmagic %d]\n", m); 491 if (m == 1 && rbuf) { 492 if (file_printf(ms, "%s", rbuf) == -1) 493 goto done; 494 } 495 if (m) { 496 if (checkdone(ms, &rv)) 497 goto done; 498 } 499 } 500 501 /* try text properties */ 502 if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) { 503 504 m = file_ascmagic(ms, &b, looks_text); 505 if ((ms->flags & MAGIC_DEBUG) != 0) 506 (void)fprintf(stderr, "[try ascmagic %d]\n", m); 507 if (m) { 508 goto done; 509 } 510 } 511 512 simple: 513 /* give up */ 514 if (m == 0) { 515 m = 1; 516 rv = file_default(ms, nb); 517 if (rv == 0) 518 if (file_printf(ms, "%s", def) == -1) 519 rv = -1; 520 } 521 done: 522 trim_separator(ms); 523 if ((ms->flags & MAGIC_MIME_ENCODING) != 0) { 524 if (ms->flags & MAGIC_MIME_TYPE) 525 if (file_printf(ms, "; charset=") == -1) 526 rv = -1; 527 if (file_printf(ms, "%s", code_mime) == -1) 528 rv = -1; 529 } 530 #if HAVE_FORK 531 done_encoding: 532 #endif 533 free(rbuf); 534 buffer_fini(&b); 535 if (rv) 536 return rv; 537 538 return m; 539 } 540 #endif 541 542 file_protected int 543 file_reset(struct magic_set *ms, int checkloaded) 544 { 545 if (checkloaded && ms->mlist[0] == NULL) { 546 file_error(ms, 0, "no magic files loaded"); 547 return -1; 548 } 549 file_clearbuf(ms); 550 if (ms->o.pbuf) { 551 free(ms->o.pbuf); 552 ms->o.pbuf = NULL; 553 } 554 ms->event_flags &= ~EVENT_HAD_ERR; 555 ms->error = -1; 556 return 0; 557 } 558 559 #define OCTALIFY(n, o) \ 560 /*LINTED*/ \ 561 (void)(*(n)++ = '\\', \ 562 *(n)++ = ((CAST(uint32_t, *(o)) >> 6) & 3) + '0', \ 563 *(n)++ = ((CAST(uint32_t, *(o)) >> 3) & 7) + '0', \ 564 *(n)++ = ((CAST(uint32_t, *(o)) >> 0) & 7) + '0', \ 565 (o)++) 566 567 file_protected const char * 568 file_getbuffer(struct magic_set *ms) 569 { 570 char *pbuf, *op, *np; 571 size_t psize, len; 572 573 if (ms->event_flags & EVENT_HAD_ERR) 574 return NULL; 575 576 if (ms->flags & MAGIC_RAW) 577 return ms->o.buf; 578 579 if (ms->o.buf == NULL) 580 return NULL; 581 582 /* * 4 is for octal representation, + 1 is for NUL */ 583 len = strlen(ms->o.buf); 584 if (len > (SIZE_MAX - 1) / 4) { 585 file_oomem(ms, len); 586 return NULL; 587 } 588 psize = len * 4 + 1; 589 if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) { 590 file_oomem(ms, psize); 591 return NULL; 592 } 593 ms->o.pbuf = pbuf; 594 595 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) 596 { 597 mbstate_t state; 598 wchar_t nextchar; 599 int mb_conv = 1; 600 size_t bytesconsumed; 601 char *eop; 602 (void)memset(&state, 0, sizeof(mbstate_t)); 603 604 np = ms->o.pbuf; 605 op = ms->o.buf; 606 eop = op + len; 607 608 while (op < eop) { 609 bytesconsumed = mbrtowc(&nextchar, op, 610 CAST(size_t, eop - op), &state); 611 if (bytesconsumed == CAST(size_t, -1) || 612 bytesconsumed == CAST(size_t, -2)) { 613 mb_conv = 0; 614 break; 615 } 616 617 if (iswprint(nextchar)) { 618 (void)memcpy(np, op, bytesconsumed); 619 op += bytesconsumed; 620 np += bytesconsumed; 621 } else { 622 while (bytesconsumed-- > 0) 623 OCTALIFY(np, op); 624 } 625 } 626 *np = '\0'; 627 628 /* Parsing succeeded as a multi-byte sequence */ 629 if (mb_conv != 0) 630 return ms->o.pbuf; 631 } 632 #endif 633 634 for (np = ms->o.pbuf, op = ms->o.buf; *op;) { 635 if (isprint(CAST(unsigned char, *op))) { 636 *np++ = *op++; 637 } else { 638 OCTALIFY(np, op); 639 } 640 } 641 *np = '\0'; 642 return ms->o.pbuf; 643 } 644 645 file_protected int 646 file_check_mem(struct magic_set *ms, unsigned int level) 647 { 648 size_t len; 649 650 if (level >= ms->c.len) { 651 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li); 652 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? 653 malloc(len) : 654 realloc(ms->c.li, len)); 655 if (ms->c.li == NULL) { 656 file_oomem(ms, len); 657 return -1; 658 } 659 } 660 ms->c.li[level].got_match = 0; 661 #ifdef ENABLE_CONDITIONALS 662 ms->c.li[level].last_match = 0; 663 ms->c.li[level].last_cond = COND_NONE; 664 #endif /* ENABLE_CONDITIONALS */ 665 return 0; 666 } 667 668 file_protected size_t 669 file_printedlen(const struct magic_set *ms) 670 { 671 return ms->o.blen; 672 } 673 674 file_protected int 675 file_replace(struct magic_set *ms, const char *pat, const char *rep) 676 { 677 file_regex_t rx; 678 int nm; 679 regmatch_t rm; 680 681 nm = file_regcomp(ms, &rx, pat, REG_EXTENDED); 682 if (nm != 0) 683 return -1; 684 685 while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) { 686 ms->o.buf[rm.rm_so] = '\0'; 687 if (file_printf(ms, "%s%s", rep, 688 rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) 689 goto out; 690 nm++; 691 } 692 out: 693 file_regfree(&rx); 694 return nm; 695 } 696 697 file_private int 698 check_regex(struct magic_set *ms, const char *pat) 699 { 700 char sbuf[512]; 701 unsigned char oc = '\0'; 702 const char *p; 703 unsigned long l; 704 static const char wild[] = "?*+{"; 705 706 for (p = pat; *p; p++) { 707 unsigned char c = *p; 708 // Avoid repetition of wild characters 709 if (strchr(wild, oc) != NULL && strchr(wild, c) != NULL) { 710 size_t len = strlen(pat); 711 file_magwarn(ms, 712 "repetition-operator operand `%c%c' " 713 "invalid in regex `%s'", oc, c, 714 file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 715 return -1; 716 } 717 if (c == '{') { 718 char *ep, *eep; 719 720 if (oc == '}') { 721 file_magwarn(ms, "cascading repetition " 722 "operators in regex `%s'", pat); 723 return -1; 724 } 725 errno = 0; 726 l = strtoul(p + 1, &ep, 10); 727 if (ep != p + 1 && l > 1000) 728 goto bounds; 729 if (*ep == ',') { 730 l = strtoul(ep + 1, &eep, 10); 731 if (eep != ep + 1 && l > 1000) 732 goto bounds; 733 } 734 } 735 oc = c; 736 if (isprint(c) || isspace(c) || c == '\b' 737 || c == 0x8a) // XXX: apple magic fixme 738 continue; 739 size_t len = strlen(pat); 740 file_magwarn(ms, 741 "non-ascii characters in regex \\%#o `%s'", 742 c, file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 743 return -1; 744 } 745 return 0; 746 bounds: 747 file_magwarn(ms, "bounds too large %ld in regex `%s'", l, pat); 748 return -1; 749 } 750 751 file_protected int 752 file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx, 753 const char *pat, int flags) 754 { 755 if (check_regex(ms, pat) == -1) 756 return -1; 757 758 #ifdef USE_C_LOCALE 759 locale_t old = uselocale(ms->c_lc_ctype); 760 assert(old != NULL); 761 #else 762 char old[1024]; 763 strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 764 (void)setlocale(LC_CTYPE, "C"); 765 #endif 766 int rc; 767 rc = regcomp(rx, pat, flags); 768 769 #ifdef USE_C_LOCALE 770 uselocale(old); 771 #else 772 (void)setlocale(LC_CTYPE, old); 773 #endif 774 if (rc > 0 && (ms->flags & MAGIC_CHECK)) { 775 char errmsg[512], buf[512]; 776 777 (void)regerror(rc, rx, errmsg, sizeof(errmsg)); 778 file_magerror(ms, "regex error %d for `%s', (%s)", rc, 779 file_printable(ms, buf, sizeof(buf), pat, strlen(pat)), 780 errmsg); 781 } 782 return rc; 783 } 784 785 /*ARGSUSED*/ 786 file_protected int 787 file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx, 788 const char *str, size_t nmatch, regmatch_t* pmatch, int eflags) 789 { 790 #ifdef USE_C_LOCALE 791 locale_t old = uselocale(ms->c_lc_ctype); 792 assert(old != NULL); 793 #else 794 char old[1024]; 795 strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 796 (void)setlocale(LC_CTYPE, "C"); 797 #endif 798 int rc; 799 /* XXX: force initialization because glibc does not always do this */ 800 if (nmatch != 0) 801 memset(pmatch, 0, nmatch * sizeof(*pmatch)); 802 rc = regexec(rx, str, nmatch, pmatch, eflags); 803 #ifdef USE_C_LOCALE 804 uselocale(old); 805 #else 806 (void)setlocale(LC_CTYPE, old); 807 #endif 808 return rc; 809 } 810 811 file_protected void 812 file_regfree(file_regex_t *rx) 813 { 814 regfree(rx); 815 } 816 817 file_protected file_pushbuf_t * 818 file_push_buffer(struct magic_set *ms) 819 { 820 file_pushbuf_t *pb; 821 822 if (ms->event_flags & EVENT_HAD_ERR) 823 return NULL; 824 825 if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) 826 return NULL; 827 828 pb->buf = ms->o.buf; 829 pb->blen = ms->o.blen; 830 pb->offset = ms->offset; 831 832 ms->o.buf = NULL; 833 ms->o.blen = 0; 834 ms->offset = 0; 835 836 return pb; 837 } 838 839 file_protected char * 840 file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb) 841 { 842 char *rbuf; 843 844 if (ms->event_flags & EVENT_HAD_ERR) { 845 free(pb->buf); 846 free(pb); 847 return NULL; 848 } 849 850 rbuf = ms->o.buf; 851 852 ms->o.buf = pb->buf; 853 ms->o.blen = pb->blen; 854 ms->offset = pb->offset; 855 856 free(pb); 857 return rbuf; 858 } 859 860 /* 861 * convert string to ascii printable format. 862 */ 863 file_protected char * 864 file_printable(struct magic_set *ms, char *buf, size_t bufsiz, 865 const char *str, size_t slen) 866 { 867 char *ptr, *eptr = buf + bufsiz - 1; 868 const unsigned char *s = RCAST(const unsigned char *, str); 869 const unsigned char *es = s + slen; 870 871 for (ptr = buf; ptr < eptr && s < es && *s; s++) { 872 if ((ms->flags & MAGIC_RAW) != 0 || isprint(*s)) { 873 *ptr++ = *s; 874 continue; 875 } 876 if (ptr >= eptr - 3) 877 break; 878 *ptr++ = '\\'; 879 *ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0'; 880 *ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0'; 881 *ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0'; 882 } 883 *ptr = '\0'; 884 return buf; 885 } 886 887 struct guid { 888 uint32_t data1; 889 uint16_t data2; 890 uint16_t data3; 891 uint8_t data4[8]; 892 }; 893 894 static char XDIGIT[] = "0123456789abcdef"; 895 static int 896 atox(const uint8_t c) 897 { 898 uint8_t d = isupper(c) ? tolower(c) : c; 899 const char *q = d ? strchr(XDIGIT, isupper(c) ? tolower(c) : c) : NULL; 900 if (q == NULL) 901 return -1; 902 return q - XDIGIT; 903 } 904 905 static int 906 getxvalue(void *p, const char *s, size_t n) 907 { 908 uint64_t v = 0; 909 for (size_t i = 0; i < n; i++) { 910 int x = atox(s[i]); 911 if (x == -1) 912 return 0; 913 v = (v << 4) | x; 914 } 915 switch (n) { 916 case 8: 917 *(uint32_t *)p = v; 918 return 1; 919 case 4: 920 *(uint16_t *)p = v; 921 return 1; 922 case 2: 923 *(uint8_t *)p = v; 924 return 1; 925 default: 926 return 0; 927 } 928 } 929 930 file_protected int 931 file_parse_guid(const char *s, uint64_t *guid) 932 { 933 struct guid *g = CAST(struct guid *, CAST(void *, guid)); 934 935 if (!getxvalue(&g->data1, s, 8) || s[8] != '-') 936 return -1; 937 s += 9; 938 if (!getxvalue(&g->data2, s, 4) || s[4] != '-') 939 return -1; 940 s += 5; 941 if (!getxvalue(&g->data3, s, 4) || s[4] != '-') 942 return -1; 943 s += 5; 944 if (!getxvalue(&g->data4[0], s, 2) || 945 !getxvalue(&g->data4[1], s + 2, 2) || s[4] != '-') 946 return -1; 947 s += 5; 948 if (!getxvalue(&g->data4[2], s, 2) || 949 !getxvalue(&g->data4[3], s + 2, 2) || 950 !getxvalue(&g->data4[4], s + 4, 2) || 951 !getxvalue(&g->data4[5], s + 6, 2) || 952 !getxvalue(&g->data4[6], s + 8, 2) || 953 !getxvalue(&g->data4[7], s + 10, 2)) 954 return -1; 955 956 if (file_bigendian()) { 957 g->data1 = file_swap4(g->data1); 958 g->data2 = file_swap2(g->data2); 959 g->data3 = file_swap2(g->data3); 960 961 } 962 return 0; 963 } 964 965 file_private int 966 file_print_guid(char *str, size_t len, const struct guid *g) 967 { 968 #ifndef WIN32 969 return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hhX%.2hhX-" 970 "%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX", 971 g->data1, g->data2, g->data3, g->data4[0], g->data4[1], 972 g->data4[2], g->data4[3], g->data4[4], g->data4[5], 973 g->data4[6], g->data4[7]); 974 #else 975 return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hX%.2hX-" 976 "%.2hX%.2hX%.2hX%.2hX%.2hX%.2hX", 977 g->data1, g->data2, g->data3, g->data4[0], g->data4[1], 978 g->data4[2], g->data4[3], g->data4[4], g->data4[5], 979 g->data4[6], g->data4[7]); 980 #endif 981 } 982 983 file_protected int 984 file_print_leguid(char *str, size_t len, const uint64_t *guid) 985 { 986 const struct guid *g = CAST(const struct guid *, 987 CAST(const void *, guid)); 988 return file_print_guid(str, len, g); 989 } 990 991 file_protected int 992 file_print_beguid(char *str, size_t len, const uint64_t *guid) 993 { 994 const struct guid *g = CAST(const struct guid *, 995 CAST(const void *, guid)); 996 struct guid gg = *g; 997 gg.data1 = file_swap4(gg.data1); 998 gg.data2 = file_swap2(gg.data2); 999 gg.data3 = file_swap2(gg.data3); 1000 return file_print_guid(str, len, &gg); 1001 } 1002 1003 file_protected int 1004 file_pipe_closexec(int *fds) 1005 { 1006 #ifdef __MINGW32__ 1007 return 0; 1008 #elif defined(HAVE_PIPE2) 1009 return pipe2(fds, O_CLOEXEC); 1010 #else 1011 if (pipe(fds) == -1) 1012 return -1; 1013 # ifdef F_SETFD 1014 (void)fcntl(fds[0], F_SETFD, FD_CLOEXEC); 1015 (void)fcntl(fds[1], F_SETFD, FD_CLOEXEC); 1016 # endif 1017 return 0; 1018 #endif 1019 } 1020 1021 file_protected int 1022 file_clear_closexec(int fd) { 1023 #ifdef F_SETFD 1024 return fcntl(fd, F_SETFD, 0); 1025 #else 1026 return 0; 1027 #endif 1028 } 1029 1030 file_protected char * 1031 file_strtrim(char *str) 1032 { 1033 char *last; 1034 1035 while (isspace(CAST(unsigned char, *str))) 1036 str++; 1037 last = str; 1038 while (*last) 1039 last++; 1040 if (last == str) 1041 return str; 1042 --last; 1043 while (isspace(CAST(unsigned char, *last))) 1044 last--; 1045 *++last = '\0'; 1046 return str; 1047 } 1048