1diff -u libmagic.orig/apprentice.c libmagic/apprentice.c 2--- libmagic.orig/apprentice.c 2023-07-17 16:38:35.000000000 +0200 3+++ libmagic/apprentice.c 2024-06-09 00:31:40.345830732 +0200 4@@ -48,7 +48,9 @@ 5 #ifdef QUICK 6 #include <sys/mman.h> 7 #endif 8+#ifdef HAVE_DIRENT_H 9 #include <dirent.h> 10+#endif 11 #include <limits.h> 12 #ifdef HAVE_BYTESWAP_H 13 #include <byteswap.h> 14@@ -146,10 +148,7 @@ 15 #endif 16 17 file_private char *mkdbname(struct magic_set *, const char *, int); 18-file_private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 19- size_t); 20 file_private struct magic_map *apprentice_map(struct magic_set *, const char *); 21-file_private int check_buffer(struct magic_set *, struct magic_map *, const char *); 22 file_private void apprentice_unmap(struct magic_map *); 23 file_private int apprentice_compile(struct magic_set *, struct magic_map *, 24 const char *); 25@@ -185,6 +184,8 @@ 26 { NULL, 0, NULL } 27 }; 28 29+#include "../data_file.c" 30+ 31 #ifdef COMPILE_ONLY 32 33 int main(int, char *[]); 34@@ -445,21 +446,13 @@ 35 struct mlist *ml; 36 37 mlp->map = NULL; 38- if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 39+ if ((ml = CAST(struct mlist *, emalloc(sizeof(*ml)))) == NULL) 40 return -1; 41 42 ml->map = idx == 0 ? map : NULL; 43 ml->magic = map->magic[idx]; 44 ml->nmagic = map->nmagic[idx]; 45- if (ml->nmagic) { 46- ml->magic_rxcomp = CAST(file_regex_t **, 47- calloc(ml->nmagic, sizeof(*ml->magic_rxcomp))); 48- if (ml->magic_rxcomp == NULL) { 49- free(ml); 50- return -1; 51- } 52- } else 53- ml->magic_rxcomp = NULL; 54+ 55 mlp->prev->next = ml; 56 ml->prev = mlp->prev; 57 ml->next = mlp; 58@@ -537,13 +530,19 @@ 59 return; 60 for (i = 0; i < MAGIC_SETS; i++) 61 mlist_free(ms->mlist[i]); 62- free(ms->o.pbuf); 63- free(ms->o.buf); 64- free(ms->c.li); 65+ if (ms->o.pbuf) { 66+ efree(ms->o.pbuf); 67+ } 68+ if (ms->o.buf) { 69+ efree(ms->o.buf); 70+ } 71+ if (ms->c.li) { 72+ efree(ms->c.li); 73+ } 74 #ifdef USE_C_LOCALE 75 freelocale(ms->c_lc_ctype); 76 #endif 77- free(ms); 78+ efree(ms); 79 } 80 81 file_protected struct magic_set * 82@@ -552,7 +551,7 @@ 83 struct magic_set *ms; 84 size_t i, len; 85 86- if ((ms = CAST(struct magic_set *, calloc(CAST(size_t, 1u), 87+ if ((ms = CAST(struct magic_set *, ecalloc(CAST(size_t, 1u), 88 sizeof(*ms)))) == NULL) 89 return NULL; 90 91@@ -565,7 +564,7 @@ 92 ms->o.blen = 0; 93 len = (ms->c.len = 10) * sizeof(*ms->c.li); 94 95- if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 96+ if ((ms->c.li = CAST(struct level_info *, emalloc(len))) == NULL) 97 goto free; 98 99 ms->event_flags = 0; 100@@ -589,49 +588,35 @@ 101 #endif 102 return ms; 103 free: 104- free(ms); 105+ efree(ms); 106 return NULL; 107 } 108 109 file_private void 110 apprentice_unmap(struct magic_map *map) 111 { 112- size_t i; 113- char *p; 114 if (map == NULL) 115 return; 116- 117- switch (map->type) { 118- case MAP_TYPE_USER: 119- break; 120- case MAP_TYPE_MALLOC: 121- p = CAST(char *, map->p); 122- for (i = 0; i < MAGIC_SETS; i++) { 123- char *b = RCAST(char *, map->magic[i]); 124- if (p != NULL && b >= p && b <= p + map->len) 125- continue; 126- free(b); 127+ if (map->p != php_magic_database) { 128+ if (map->p == NULL) { 129+ int j; 130+ for (j = 0; j < MAGIC_SETS; j++) { 131+ if (map->magic[j]) { 132+ efree(map->magic[j]); 133+ } 134+ } 135+ } else { 136+ efree(map->p); 137 } 138- free(p); 139- break; 140-#ifdef QUICK 141- case MAP_TYPE_MMAP: 142- if (map->p && map->p != MAP_FAILED) 143- (void)munmap(map->p, map->len); 144- break; 145-#endif 146- default: 147- fprintf(stderr, "Bad map type %d", map->type); 148- abort(); 149 } 150- free(map); 151+ efree(map); 152 } 153 154 file_private struct mlist * 155 mlist_alloc(void) 156 { 157 struct mlist *mlist; 158- if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 159+ if ((mlist = CAST(struct mlist *, ecalloc(1, sizeof(*mlist)))) == NULL) { 160 return NULL; 161 } 162 mlist->next = mlist->prev = mlist; 163@@ -652,21 +637,9 @@ 164 file_private void 165 mlist_free_one(struct mlist *ml) 166 { 167- size_t i; 168- 169 if (ml->map) 170 apprentice_unmap(CAST(struct magic_map *, ml->map)); 171- 172- for (i = 0; i < ml->nmagic; ++i) { 173- if (ml->magic_rxcomp[i]) { 174- file_regfree(ml->magic_rxcomp[i]); 175- free(ml->magic_rxcomp[i]); 176- ml->magic_rxcomp[i] = NULL; 177- } 178- } 179- free(ml->magic_rxcomp); 180- ml->magic_rxcomp = NULL; 181- free(ml); 182+ efree(ml); 183 } 184 185 file_private void 186@@ -685,50 +658,6 @@ 187 mlist_free_one(mlist); 188 } 189 190-#ifndef COMPILE_ONLY 191-/* void **bufs: an array of compiled magic files */ 192-file_protected int 193-buffer_apprentice(struct magic_set *ms, struct magic **bufs, 194- size_t *sizes, size_t nbufs) 195-{ 196- size_t i, j; 197- struct magic_map *map; 198- 199- if (nbufs == 0) 200- return -1; 201- 202- (void)file_reset(ms, 0); 203- 204- init_file_tables(); 205- 206- for (i = 0; i < MAGIC_SETS; i++) { 207- mlist_free(ms->mlist[i]); 208- if ((ms->mlist[i] = mlist_alloc()) == NULL) { 209- file_oomem(ms, sizeof(*ms->mlist[0])); 210- goto fail; 211- } 212- } 213- 214- for (i = 0; i < nbufs; i++) { 215- map = apprentice_buf(ms, bufs[i], sizes[i]); 216- if (map == NULL) 217- goto fail; 218- 219- for (j = 0; j < MAGIC_SETS; j++) { 220- if (add_mlist(ms->mlist[j], map, j) == -1) { 221- file_oomem(ms, sizeof(*ms->mlist[0])); 222- goto fail; 223- } 224- } 225- } 226- 227- return 0; 228-fail: 229- mlist_free_all(ms); 230- return -1; 231-} 232-#endif 233- 234 /* const char *fn: list of magic files and directories */ 235 file_protected int 236 file_apprentice(struct magic_set *ms, const char *fn, int action) 237@@ -739,12 +668,28 @@ 238 239 (void)file_reset(ms, 0); 240 241+/* XXX disabling default magic loading so the compiled in data is used */ 242+#if 0 243 if ((fn = magic_getpath(fn, action)) == NULL) 244 return -1; 245+#endif 246 247 init_file_tables(); 248 249- if ((mfn = strdup(fn)) == NULL) { 250+ if (fn == NULL) 251+ fn = getenv("MAGIC"); 252+ if (fn == NULL) { 253+ for (i = 0; i < MAGIC_SETS; i++) { 254+ mlist_free(ms->mlist[i]); 255+ if ((ms->mlist[i] = mlist_alloc()) == NULL) { 256+ file_oomem(ms, sizeof(*ms->mlist[i])); 257+ return -1; 258+ } 259+ } 260+ return apprentice_1(ms, fn, action); 261+ } 262+ 263+ if ((mfn = estrdup(fn)) == NULL) { 264 file_oomem(ms, strlen(fn)); 265 return -1; 266 } 267@@ -757,7 +702,7 @@ 268 mlist_free(ms->mlist[j]); 269 ms->mlist[j] = NULL; 270 } 271- free(mfn); 272+ efree(mfn); 273 return -1; 274 } 275 } 276@@ -774,7 +719,7 @@ 277 fn = p; 278 } 279 280- free(mfn); 281+ efree(mfn); 282 283 if (errs == -1) { 284 for (i = 0; i < MAGIC_SETS; i++) { 285@@ -1289,7 +1234,7 @@ 286 287 size_t incr = mset[i].max + ALLOC_INCR; 288 if ((mp = CAST(struct magic_entry *, 289- realloc(mset[i].me, sizeof(*mp) * incr))) == 290+ erealloc(mset[i].me, sizeof(*mp) * incr))) == 291 NULL) { 292 file_oomem(ms, sizeof(*mp) * incr); 293 return -1; 294@@ -1312,13 +1257,19 @@ 295 load_1(struct magic_set *ms, int action, const char *fn, int *errs, 296 struct magic_entry_set *mset) 297 { 298- size_t lineno = 0, llen = 0; 299+ char buffer[BUFSIZ + 1]; 300 char *line = NULL; 301- ssize_t len; 302+ size_t len; 303+ size_t lineno = 0; 304 struct magic_entry me; 305 306- FILE *f = fopen(ms->file = fn, "r"); 307- if (f == NULL) { 308+ php_stream *stream; 309+ 310+ 311+ ms->file = fn; 312+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 313+ 314+ if (stream == NULL) { 315 if (errno != ENOENT) 316 file_error(ms, errno, "cannot read magic file `%s'", 317 fn); 318@@ -1328,8 +1279,7 @@ 319 320 memset(&me, 0, sizeof(me)); 321 /* read and parse this file */ 322- for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 323- ms->line++) { 324+ for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &len)) != NULL; ms->line++) { 325 if (len == 0) /* null line, garbage, etc */ 326 continue; 327 if (line[len - 1] == '\n') { 328@@ -1388,8 +1338,8 @@ 329 } 330 if (me.mp) 331 (void)addentry(ms, &me, mset); 332- free(line); 333- (void)fclose(f); 334+ efree(line); 335+ php_stream_close(stream); 336 } 337 338 /* 339@@ -1474,7 +1424,7 @@ 340 } 341 342 slen = sizeof(**ma) * mentrycount; 343- if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 344+ if ((*ma = CAST(struct magic *, emalloc(slen))) == NULL) { 345 file_oomem(ms, slen); 346 return -1; 347 } 348@@ -1496,8 +1446,8 @@ 349 if (me == NULL) 350 return; 351 for (i = 0; i < nme; i++) 352- free(me[i].mp); 353- free(me); 354+ efree(me[i].mp); 355+ efree(me); 356 } 357 358 file_private struct magic_map * 359@@ -1506,18 +1456,19 @@ 360 int errs = 0; 361 uint32_t i, j; 362 size_t files = 0, maxfiles = 0; 363- char **filearr = NULL, *mfn; 364- struct stat st; 365+ char **filearr = NULL; 366+ zend_stat_t st = {0}; 367 struct magic_map *map; 368 struct magic_entry_set mset[MAGIC_SETS]; 369- DIR *dir; 370- struct dirent *d; 371+ php_stream *dir; 372+ php_stream_dirent d; 373+ 374 375 memset(mset, 0, sizeof(mset)); 376 ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 377 378 379- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 380+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) 381 { 382 file_oomem(ms, sizeof(*map)); 383 return NULL; 384@@ -1529,52 +1480,50 @@ 385 (void)fprintf(stderr, "%s\n", usg_hdr); 386 387 /* load directory or file */ 388- if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 389- dir = opendir(fn); 390+ /* FIXME: Read file names and sort them to prevent 391+ non-determinism. See Debian bug #488562. */ 392+ if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 393+ int mflen; 394+ char mfn[MAXPATHLEN]; 395+ 396+ dir = php_stream_opendir((char *)fn, REPORT_ERRORS, NULL); 397 if (!dir) { 398 errs++; 399 goto out; 400 } 401- while ((d = readdir(dir)) != NULL) { 402- if (d->d_name[0] == '.') 403- continue; 404- if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 405+ while (php_stream_readdir(dir, &d)) { 406+ if ((mflen = snprintf(mfn, sizeof(mfn), "%s/%s", fn, d.d_name)) < 0) { 407 file_oomem(ms, 408- strlen(fn) + strlen(d->d_name) + 2); 409+ strlen(fn) + strlen(d.d_name) + 2); 410 errs++; 411- closedir(dir); 412+ php_stream_closedir(dir); 413 goto out; 414 } 415- if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 416- free(mfn); 417+ if (zend_stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 418 continue; 419 } 420 if (files >= maxfiles) { 421 size_t mlen; 422- char **nfilearr; 423 maxfiles = (maxfiles + 1) * 2; 424 mlen = maxfiles * sizeof(*filearr); 425- if ((nfilearr = CAST(char **, 426- realloc(filearr, mlen))) == NULL) { 427+ if ((filearr = CAST(char **, 428+ erealloc(filearr, mlen))) == NULL) { 429 file_oomem(ms, mlen); 430- free(mfn); 431- closedir(dir); 432+ php_stream_closedir(dir); 433 errs++; 434 goto out; 435 } 436- filearr = nfilearr; 437 } 438- filearr[files++] = mfn; 439+ filearr[files++] = estrndup(mfn, (mflen > sizeof(mfn) - 1)? sizeof(mfn) - 1: mflen); 440 } 441- closedir(dir); 442+ php_stream_closedir(dir); 443 if (filearr) { 444 qsort(filearr, files, sizeof(*filearr), cmpstrp); 445 for (i = 0; i < files; i++) { 446 load_1(ms, action, filearr[i], &errs, mset); 447- free(filearr[i]); 448+ efree(filearr[i]); 449 } 450- free(filearr); 451- filearr = NULL; 452+ efree(filearr); 453 } 454 } else 455 load_1(ms, action, fn, &errs, mset); 456@@ -1612,7 +1561,6 @@ 457 } 458 459 out: 460- free(filearr); 461 for (j = 0; j < MAGIC_SETS; j++) 462 magic_entry_free(mset[j].me, mset[j].count); 463 464@@ -2060,7 +2008,7 @@ 465 if (me->cont_count == me->max_count) { 466 struct magic *nm; 467 size_t cnt = me->max_count + ALLOC_CHUNK; 468- if ((nm = CAST(struct magic *, realloc(me->mp, 469+ if ((nm = CAST(struct magic *, erealloc(me->mp, 470 sizeof(*nm) * cnt))) == NULL) { 471 file_oomem(ms, sizeof(*nm) * cnt); 472 return -1; 473@@ -2075,7 +2023,7 @@ 474 static const size_t len = sizeof(*m) * ALLOC_CHUNK; 475 if (me->mp != NULL) 476 return 1; 477- if ((m = CAST(struct magic *, malloc(len))) == NULL) { 478+ if ((m = CAST(struct magic *, emalloc(len))) == NULL) { 479 file_oomem(ms, len); 480 return -1; 481 } 482@@ -2301,7 +2249,7 @@ 483 484 m->mask_op = 0; 485 if (*l == '~') { 486- if (!IS_STRING(m->type)) 487+ if (!IS_LIBMAGIC_STRING(m->type)) 488 m->mask_op |= FILE_OPINVERSE; 489 else if (ms->flags & MAGIC_CHECK) 490 file_magwarn(ms, "'~' invalid for string types"); 491@@ -2310,7 +2258,7 @@ 492 m->str_range = 0; 493 m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 494 if ((op = get_op(*l)) != -1) { 495- if (IS_STRING(m->type)) { 496+ if (IS_LIBMAGIC_STRING(m->type)) { 497 int r; 498 499 if (op != FILE_OPDIVIDE) { 500@@ -2497,7 +2445,7 @@ 501 502 file_private int 503 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 504- size_t llen, off_t off, size_t len, const char *name, const char *extra, 505+ size_t llen, zend_off_t off, size_t len, const char *name, const char *extra, 506 int nt) 507 { 508 size_t i; 509@@ -2860,13 +2808,19 @@ 510 return -1; 511 } 512 if (m->type == FILE_REGEX) { 513- file_regex_t rx; 514- int rc = 515- file_regcomp(ms, &rx, m->value.s, REG_EXTENDED); 516- if (rc == 0) { 517- file_regfree(&rx); 518+ zend_string *pattern; 519+ int options = 0; 520+ pcre_cache_entry *pce; 521+ 522+ pattern = convert_libmagic_pattern(m->value.s, strlen(m->value.s), options); 523+ 524+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 525+ zend_string_release(pattern); 526+ return -1; 527 } 528- return rc ? -1 : 0; 529+ zend_string_release(pattern); 530+ 531+ return 0; 532 } 533 return 0; 534 default: 535@@ -3245,120 +3199,83 @@ 536 } 537 538 /* 539- * handle a buffer containing a compiled file. 540- */ 541-file_private struct magic_map * 542-apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 543-{ 544- struct magic_map *map; 545- 546- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 547- file_oomem(ms, sizeof(*map)); 548- return NULL; 549- } 550- map->len = len; 551- map->p = buf; 552- map->type = MAP_TYPE_USER; 553- if (check_buffer(ms, map, "buffer") != 0) { 554- apprentice_unmap(map); 555- return NULL; 556- } 557- return map; 558-} 559- 560-/* 561 * handle a compiled file. 562 */ 563 564 file_private struct magic_map * 565 apprentice_map(struct magic_set *ms, const char *fn) 566 { 567- int fd; 568- struct stat st; 569+ uint32_t *ptr; 570+ uint32_t version, entries = 0, nentries; 571+ int needsbyteswap; 572 char *dbname = NULL; 573 struct magic_map *map; 574- struct magic_map *rv = NULL; 575+ size_t i; 576+ php_stream *stream = NULL; 577+ php_stream_statbuf st; 578+ 579+ 580 581- fd = -1; 582- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 583+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) { 584 file_oomem(ms, sizeof(*map)); 585- goto error; 586+ return NULL; 587 } 588- map->type = MAP_TYPE_USER; /* unspecified */ 589+ 590+ if (fn == NULL) { 591+ map->p = (void *)&php_magic_database; 592+ goto internal_loaded; 593+ } 594+ 595+#ifdef PHP_WIN32 596+ /* Don't bother on windows with php_stream_open_wrapper, 597+ return to give apprentice_load() a chance. */ 598+ if (php_stream_stat_path_ex((char *)fn, 0, &st, NULL) == SUCCESS) { 599+ if (st.sb.st_mode & S_IFDIR) { 600+ goto error; 601+ } 602+ } 603+#endif 604 605 dbname = mkdbname(ms, fn, 0); 606 if (dbname == NULL) 607 goto error; 608 609- if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 610+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 611+ 612+ if (!stream) { 613 goto error; 614+ } 615 616- if (fstat(fd, &st) == -1) { 617+#ifndef PHP_WIN32 618+ if (php_stream_stat(stream, &st) < 0) { 619 file_error(ms, errno, "cannot stat `%s'", dbname); 620 goto error; 621 } 622- if (st.st_size < 8 || st.st_size > maxoff_t()) { 623+#endif 624+ if (st.sb.st_size < 8 || st.sb.st_size > maxoff_t()) { 625 file_error(ms, 0, "file `%s' is too %s", dbname, 626- st.st_size < 8 ? "small" : "large"); 627+ st.sb.st_size < 8 ? "small" : "large"); 628 goto error; 629 } 630 631- map->len = CAST(size_t, st.st_size); 632-#ifdef QUICK 633- map->type = MAP_TYPE_MMAP; 634- if ((map->p = mmap(0, CAST(size_t, st.st_size), PROT_READ|PROT_WRITE, 635- MAP_PRIVATE|MAP_FILE, fd, CAST(off_t, 0))) == MAP_FAILED) { 636- file_error(ms, errno, "cannot map `%s'", dbname); 637- goto error; 638- } 639-#else 640 map->type = MAP_TYPE_MALLOC; 641- if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 642- file_oomem(ms, map->len); 643- goto error; 644- } 645- if (read(fd, map->p, map->len) != (ssize_t)map->len) { 646- file_badread(ms); 647- goto error; 648- } 649-#endif 650- (void)close(fd); 651- fd = -1; 652+ map->len = CAST(size_t, st.sb.st_size); 653+ map->p = CAST(void *, emalloc(map->len)); 654 655- if (check_buffer(ms, map, dbname) != 0) { 656- goto error; 657- } 658-#ifdef QUICK 659- if (mprotect(map->p, CAST(size_t, st.st_size), PROT_READ) == -1) { 660- file_error(ms, errno, "cannot mprotect `%s'", dbname); 661+ if (php_stream_read(stream, map->p, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) { 662+ file_badread(ms); 663 goto error; 664 } 665-#endif 666- 667- free(dbname); 668- return map; 669- 670-error: 671- if (fd != -1) 672- (void)close(fd); 673- apprentice_unmap(map); 674- free(dbname); 675- return rv; 676-} 677 678-file_private int 679-check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 680-{ 681- uint32_t *ptr; 682- uint32_t entries, nentries; 683- uint32_t version; 684- int i, needsbyteswap; 685+ php_stream_close(stream); 686+ stream = NULL; 687 688- ptr = CAST(uint32_t *, map->p); 689+internal_loaded: 690+ ptr = (uint32_t *)(void *)map->p; 691 if (*ptr != MAGICNO) { 692 if (swap4(*ptr) != MAGICNO) { 693 file_error(ms, 0, "bad magic in `%s'", dbname); 694- return -1; 695+ goto error; 696 } 697 needsbyteswap = 1; 698 } else 699@@ -3368,17 +3285,29 @@ 700 else 701 version = ptr[1]; 702 if (version != VERSIONNO) { 703- file_error(ms, 0, "File %s supports only version %d magic " 704- "files. `%s' is version %d", VERSION, 705+ file_error(ms, 0, "File %d supports only version %d magic " 706+ "files. `%s' is version %d", MAGIC_VERSION, 707 VERSIONNO, dbname, version); 708- return -1; 709+ goto error; 710 } 711- entries = CAST(uint32_t, map->len / sizeof(struct magic)); 712- if ((entries * sizeof(struct magic)) != map->len) { 713- file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 714- "a multiple of %" SIZE_T_FORMAT "u", 715- dbname, map->len, sizeof(struct magic)); 716- return -1; 717+ 718+ /* php_magic_database is a const, performing writes will segfault. This is for big-endian 719+ machines only, PPC and Sparc specifically. Consider static variable or MINIT in 720+ future. */ 721+ if (needsbyteswap && fn == NULL) { 722+ map->p = emalloc(sizeof(php_magic_database)); 723+ map->p = memcpy(map->p, php_magic_database, sizeof(php_magic_database)); 724+ } 725+ 726+ if (NULL != fn) { 727+ nentries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 728+ entries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 729+ if ((zend_off_t)(entries * sizeof(struct magic)) != st.sb.st_size) { 730+ file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", 731+ dbname, (unsigned long long)st.sb.st_size, 732+ sizeof(struct magic)); 733+ goto error; 734+ } 735 } 736 map->magic[0] = CAST(struct magic *, map->p) + 1; 737 nentries = 0; 738@@ -3391,15 +3320,29 @@ 739 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 740 nentries += map->nmagic[i]; 741 } 742- if (entries != nentries + 1) { 743+ if (NULL != fn && entries != nentries + 1) { 744 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 745 dbname, entries, nentries + 1); 746- return -1; 747+ goto error; 748 } 749 if (needsbyteswap) 750 for (i = 0; i < MAGIC_SETS; i++) 751 byteswap(map->magic[i], map->nmagic[i]); 752- return 0; 753+ 754+ if (dbname) { 755+ efree(dbname); 756+ } 757+ return map; 758+ 759+error: 760+ if (stream) { 761+ php_stream_close(stream); 762+ } 763+ apprentice_unmap(map); 764+ if (dbname) { 765+ efree(dbname); 766+ } 767+ return NULL; 768 } 769 770 /* 771@@ -3410,7 +3353,7 @@ 772 { 773 static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 774 static const size_t m = sizeof(**map->magic); 775- int fd = -1; 776+ php_stream *stream; 777 size_t len; 778 char *dbname; 779 int rv = -1; 780@@ -3425,8 +3368,10 @@ 781 if (dbname == NULL) 782 goto out; 783 784- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 785- { 786+ /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */ 787+ stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL); 788+ 789+ if (!stream) { 790 file_error(ms, errno, "cannot open `%s'", dbname); 791 goto out; 792 } 793@@ -3435,26 +3380,25 @@ 794 hdr.h[1] = VERSIONNO; 795 memcpy(hdr.h + 2, map->nmagic, nm); 796 797- if (write(fd, &hdr, sizeof(hdr)) != CAST(ssize_t, sizeof(hdr))) { 798+ if (php_stream_write(stream,(const char *)&hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 799 file_error(ms, errno, "error writing `%s'", dbname); 800- goto out2; 801+ goto out; 802 } 803 804 for (i = 0; i < MAGIC_SETS; i++) { 805 len = m * map->nmagic[i]; 806- if (write(fd, map->magic[i], len) != CAST(ssize_t, len)) { 807+ if (php_stream_write(stream, (const char *)map->magic[i], len) != (ssize_t)len) { 808 file_error(ms, errno, "error writing `%s'", dbname); 809- goto out2; 810+ goto out; 811 } 812 } 813 814 rv = 0; 815-out2: 816- if (fd != -1) 817- (void)close(fd); 818+ if (stream) { 819+ php_stream_close(stream); 820+ } 821 out: 822- apprentice_unmap(map); 823- free(dbname); 824+ efree(dbname); 825 return rv; 826 } 827 828@@ -3488,17 +3432,18 @@ 829 q++; 830 /* Compatibility with old code that looked in .mime */ 831 if (ms->flags & MAGIC_MIME) { 832- if (asprintf(&buf, "%.*s.mime%s", CAST(int, q - fn), fn, ext) 833- < 0) 834- return NULL; 835- if (access(buf, R_OK) != -1) { 836+ spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", CAST(int, q - fn), fn, ext); 837+#ifdef PHP_WIN32 838+ if (VCWD_ACCESS(buf, R_OK) == 0) { 839+#else 840+ if (VCWD_ACCESS(buf, R_OK) != -1) { 841+#endif 842 ms->flags &= MAGIC_MIME_TYPE; 843 return buf; 844 } 845- free(buf); 846+ efree(buf); 847 } 848- if (asprintf(&buf, "%.*s%s", CAST(int, q - fn), fn, ext) < 0) 849- return NULL; 850+ spprintf(&buf, MAXPATHLEN, "%.*s%s", CAST(int, q - fn), fn, ext); 851 852 /* Compatibility with old code that looked in .mime */ 853 if (strstr(fn, ".mime") != NULL) 854@@ -3620,7 +3565,7 @@ 855 m->offset = swap4(CAST(uint32_t, m->offset)); 856 m->in_offset = swap4(CAST(uint32_t, m->in_offset)); 857 m->lineno = swap4(CAST(uint32_t, m->lineno)); 858- if (IS_STRING(m->type)) { 859+ if (IS_LIBMAGIC_STRING(m->type)) { 860 m->str_range = swap4(m->str_range); 861 m->str_flags = swap4(m->str_flags); 862 } 863@@ -3717,7 +3662,6 @@ 864 continue; 865 if (strcmp(ma[i].value.s, name) == 0) { 866 v->magic = &ma[i]; 867- v->magic_rxcomp = &(ml->magic_rxcomp[i]); 868 for (j = i + 1; j < ml->nmagic; j++) 869 if (ma[j].cont_level == 0) 870 break; 871diff -u libmagic.orig/ascmagic.c libmagic/ascmagic.c 872--- libmagic.orig/ascmagic.c 2023-05-30 22:17:50.000000000 +0200 873+++ libmagic/ascmagic.c 2024-06-09 00:31:40.345830732 +0200 874@@ -96,7 +96,7 @@ 875 rv = file_ascmagic_with_encoding(ms, &bb, 876 ubuf, ulen, code, type, text); 877 878- free(ubuf); 879+ efree(ubuf); 880 881 return rv; 882 } 883@@ -143,7 +143,7 @@ 884 /* malloc size is a conservative overestimate; could be 885 improved, or at least realloced after conversion. */ 886 mlen = ulen * 6; 887- if ((utf8_buf = CAST(unsigned char *, malloc(mlen))) == NULL) { 888+ if ((utf8_buf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 889 file_oomem(ms, mlen); 890 goto done; 891 } 892@@ -267,8 +267,8 @@ 893 goto done; 894 895 if (has_long_lines) 896- if (file_printf(ms, ", with very long lines (%" 897- SIZE_T_FORMAT "u)", has_long_lines) == -1) 898+ if (file_printf(ms, ", with very long lines (%zu)", 899+ has_long_lines) == -1) 900 goto done; 901 902 /* 903@@ -324,7 +324,8 @@ 904 } 905 rv = 1; 906 done: 907- free(utf8_buf); 908+ if (utf8_buf) 909+ efree(utf8_buf); 910 911 return rv; 912 } 913diff -u libmagic.orig/buffer.c libmagic/buffer.c 914--- libmagic.orig/buffer.c 2023-07-02 14:48:39.000000000 +0200 915+++ libmagic/buffer.c 2024-06-09 00:31:40.345830732 +0200 916@@ -31,19 +31,21 @@ 917 #endif /* lint */ 918 919 #include "magic.h" 920+#ifdef HAVE_UNISTD_H 921 #include <unistd.h> 922+#endif 923 #include <string.h> 924 #include <stdlib.h> 925 #include <sys/stat.h> 926 927 void 928-buffer_init(struct buffer *b, int fd, const struct stat *st, const void *data, 929+buffer_init(struct buffer *b, int fd, const zend_stat_t *st, const void *data, 930 size_t len) 931 { 932 b->fd = fd; 933 if (st) 934 memcpy(&b->st, st, sizeof(b->st)); 935- else if (b->fd == -1 || fstat(b->fd, &b->st) == -1) 936+ else if (b->fd == -1 || zend_fstat(b->fd, &b->st) == -1) 937 memset(&b->st, 0, sizeof(b->st)); 938 b->fbuf = data; 939 b->flen = len; 940@@ -55,7 +57,7 @@ 941 void 942 buffer_fini(struct buffer *b) 943 { 944- free(b->ebuf); 945+ efree(b->ebuf); 946 b->ebuf = NULL; 947 b->elen = 0; 948 } 949@@ -74,16 +76,18 @@ 950 b->elen = CAST(size_t, b->st.st_size) < b->flen ? 951 CAST(size_t, b->st.st_size) : b->flen; 952 if (b->elen == 0) { 953- free(b->ebuf); 954+ efree(b->ebuf); 955 b->ebuf = NULL; 956 return 0; 957 } 958- if ((b->ebuf = malloc(b->elen)) == NULL) 959+ if ((b->ebuf = emalloc(b->elen)) == NULL) 960 goto out; 961 962 b->eoff = b->st.st_size - b->elen; 963- if (pread(b->fd, b->ebuf, b->elen, b->eoff) == -1) { 964- free(b->ebuf); 965+ if (FINFO_LSEEK_FUNC(b->fd, b->eoff, SEEK_SET) == (zend_off_t)-1 || 966+ FINFO_READ_FUNC(b->fd, b->ebuf, b->elen) != (ssize_t)b->elen) 967+ { 968+ efree(b->ebuf); 969 b->ebuf = NULL; 970 goto out; 971 } 972diff -u libmagic.orig/cdf.c libmagic/cdf.c 973--- libmagic.orig/cdf.c 2022-09-24 22:56:49.000000000 +0200 974+++ libmagic/cdf.c 2024-06-09 00:31:40.345830732 +0200 975@@ -43,7 +43,9 @@ 976 #include <err.h> 977 #endif 978 #include <stdlib.h> 979+#ifdef HAVE_UNISTD_H 980 #include <unistd.h> 981+#endif 982 #include <string.h> 983 #include <time.h> 984 #include <ctype.h> 985@@ -91,44 +93,9 @@ 986 CDF_TOLE8(CAST(uint64_t, x)))) 987 #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) 988 989-#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) 990-#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) 991-#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) 992- 993- 994-/*ARGSUSED*/ 995-static void * 996-cdf_malloc(const char *file __attribute__((__unused__)), 997- size_t line __attribute__((__unused__)), size_t n) 998-{ 999- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 1000- file, line, __func__, n)); 1001- if (n == 0) 1002- n++; 1003- return malloc(n); 1004-} 1005- 1006-/*ARGSUSED*/ 1007-static void * 1008-cdf_realloc(const char *file __attribute__((__unused__)), 1009- size_t line __attribute__((__unused__)), void *p, size_t n) 1010-{ 1011- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 1012- file, line, __func__, n)); 1013- return realloc(p, n); 1014-} 1015- 1016-/*ARGSUSED*/ 1017-static void * 1018-cdf_calloc(const char *file __attribute__((__unused__)), 1019- size_t line __attribute__((__unused__)), size_t n, size_t u) 1020-{ 1021- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %" 1022- SIZE_T_FORMAT "u\n", file, line, __func__, n, u)); 1023- if (n == 0) 1024- n++; 1025- return calloc(n, u); 1026-} 1027+#define CDF_MALLOC(n) emalloc(n) 1028+#define CDF_REALLOC(p, n) erealloc(p, n) 1029+#define CDF_CALLOC(n, u) ecalloc(n, u) 1030 1031 #if defined(HAVE_BYTESWAP_H) 1032 # define _cdf_tole2(x) bswap_16(x) 1033@@ -334,7 +301,7 @@ 1034 scn->sst_len = 0; 1035 scn->sst_dirlen = 0; 1036 scn->sst_ss = 0; 1037- free(scn->sst_tab); 1038+ efree(scn->sst_tab); 1039 scn->sst_tab = NULL; 1040 return -1; 1041 } 1042@@ -342,9 +309,11 @@ 1043 static size_t 1044 cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) 1045 { 1046+#ifndef NDEBUG 1047 size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? 1048 CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); 1049 assert(ss == sst->sst_ss); 1050+#endif 1051 return sst->sst_ss; 1052 } 1053 1054@@ -367,11 +336,11 @@ 1055 } 1056 1057 static ssize_t 1058-cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) 1059+cdf_read(const cdf_info_t *info, zend_off_t off, void *buf, size_t len) 1060 { 1061 size_t siz = CAST(size_t, off + len); 1062 1063- if (CAST(off_t, off + len) != CAST(off_t, siz)) 1064+ if (CAST(zend_off_t, off + len) != CAST(zend_off_t, siz)) 1065 goto out; 1066 1067 if (info->i_buf != NULL && info->i_len >= siz) { 1068@@ -382,7 +351,10 @@ 1069 if (info->i_fd == -1) 1070 goto out; 1071 1072- if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len)) 1073+ if (FINFO_LSEEK_FUNC(info->i_fd, off, SEEK_SET) == (zend_off_t)-1) 1074+ return -1; 1075+ 1076+ if (FINFO_READ_FUNC(info->i_fd, buf, len) != (ssize_t)len) 1077 return -1; 1078 1079 return CAST(ssize_t, len); 1080@@ -397,7 +369,7 @@ 1081 char buf[512]; 1082 1083 (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); 1084- if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1) 1085+ if (cdf_read(info, CAST(zend_off_t, 0), buf, sizeof(buf)) == -1) 1086 return -1; 1087 cdf_unpack_header(h, buf); 1088 cdf_swap_header(h); 1089@@ -544,14 +516,14 @@ 1090 } 1091 out: 1092 sat->sat_len = i; 1093- free(msa); 1094+ efree(msa); 1095 return 0; 1096 out3: 1097 errno = EFTYPE; 1098 out2: 1099- free(msa); 1100+ efree(msa); 1101 out1: 1102- free(sat->sat_tab); 1103+ efree(sat->sat_tab); 1104 return -1; 1105 } 1106 1107@@ -719,7 +691,7 @@ 1108 return -1; 1109 1110 if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { 1111- free(dir->dir_tab); 1112+ efree(dir->dir_tab); 1113 return -1; 1114 } 1115 1116@@ -742,11 +714,11 @@ 1117 if (NEED_SWAP) 1118 for (i = 0; i < dir->dir_len; i++) 1119 cdf_swap_dir(&dir->dir_tab[i]); 1120- free(buf); 1121+ efree(buf); 1122 return 0; 1123 out: 1124- free(dir->dir_tab); 1125- free(buf); 1126+ efree(dir->dir_tab); 1127+ efree(buf); 1128 errno = EFTYPE; 1129 return -1; 1130 } 1131@@ -791,7 +763,7 @@ 1132 out: 1133 errno = EFTYPE; 1134 out1: 1135- free(ssat->sat_tab); 1136+ efree(ssat->sat_tab); 1137 return -1; 1138 } 1139 1140@@ -953,7 +925,7 @@ 1141 *maxcount = newcount; 1142 return inp; 1143 out: 1144- free(*info); 1145+ efree(*info); 1146 *maxcount = 0; 1147 *info = NULL; 1148 return NULL; 1149@@ -1136,7 +1108,7 @@ 1150 } 1151 return 0; 1152 out: 1153- free(*info); 1154+ efree(*info); 1155 *info = NULL; 1156 *count = 0; 1157 *maxcount = 0; 1158@@ -1428,7 +1400,7 @@ 1159 cdf_directory_t *d; 1160 char name[__arraycount(d->d_name)]; 1161 cdf_stream_t scn; 1162- struct timespec ts; 1163+ struct timeval ts; 1164 1165 static const char *types[] = { "empty", "user storage", 1166 "user stream", "lockbytes", "property", "root storage" }; 1167@@ -1470,7 +1442,7 @@ 1168 break; 1169 } 1170 cdf_dump_stream(&scn); 1171- free(scn.sst_tab); 1172+ efree(scn.sst_tab); 1173 break; 1174 default: 1175 break; 1176@@ -1483,7 +1455,7 @@ 1177 cdf_dump_property_info(const cdf_property_info_t *info, size_t count) 1178 { 1179 cdf_timestamp_t tp; 1180- struct timespec ts; 1181+ struct timeval ts; 1182 char buf[64]; 1183 size_t i, j; 1184 1185@@ -1568,7 +1540,7 @@ 1186 (void)fprintf(stderr, "Class %s\n", buf); 1187 (void)fprintf(stderr, "Count %d\n", ssi.si_count); 1188 cdf_dump_property_info(info, count); 1189- free(info); 1190+ efree(info); 1191 } 1192 1193 1194@@ -1589,7 +1561,7 @@ 1195 cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), 1196 cdf_ctime(&ts.tv_sec, tbuf)); 1197 } 1198- free(cat); 1199+ efree(cat); 1200 } 1201 1202 #endif 1203diff -u libmagic.orig/cdf.h libmagic/cdf.h 1204--- libmagic.orig/cdf.h 2022-09-24 22:56:49.000000000 +0200 1205+++ libmagic/cdf.h 2024-06-04 15:10:40.600783222 +0200 1206@@ -37,8 +37,6 @@ 1207 1208 #ifdef WIN32 1209 #include <winsock2.h> 1210-#define timespec timeval 1211-#define tv_nsec tv_usec 1212 #endif 1213 #ifdef __DJGPP__ 1214 #define timespec timeval 1215diff -u libmagic.orig/compress.c libmagic/compress.c 1216--- libmagic.orig/compress.c 2023-05-21 17:59:58.000000000 +0200 1217+++ libmagic/compress.c 2024-06-09 00:31:40.346830746 +0200 1218@@ -63,13 +63,14 @@ 1219 #if defined(HAVE_SYS_TIME_H) 1220 #include <sys/time.h> 1221 #endif 1222- 1223-#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) 1224+#if defined(HAVE_ZLIB_H) && defined(PHP_FILEINFO_UNCOMPRESS) 1225 #define BUILTIN_DECOMPRESS 1226 #include <zlib.h> 1227 #endif 1228 1229-#if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT) 1230+#undef FIONREAD 1231+ 1232+#if defined(PHP_FILEINFO_UNCOMPRESS) 1233 #define BUILTIN_BZLIB 1234 #include <bzlib.h> 1235 #endif 1236@@ -132,6 +133,8 @@ 1237 } 1238 #endif 1239 1240+#ifdef PHP_FILEINFO_UNCOMPRESS 1241+ 1242 static int 1243 lzmacmp(const unsigned char *buf) 1244 { 1245@@ -307,7 +310,7 @@ 1246 } 1247 1248 nsz = nbytes; 1249- free(newbuf); 1250+ efree(newbuf); 1251 urv = uncompressbuf(fd, ms->bytes_max, i, 1252 (ms->flags & MAGIC_NO_COMPRESS_FORK), buf, &newbuf, &nsz); 1253 DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv, 1254@@ -319,7 +322,7 @@ 1255 if (urv == ERRDATA) 1256 prv = format_decompression_error(ms, i, newbuf); 1257 else 1258- prv = file_buffer(ms, -1, NULL, name, newbuf, 1259+ prv = file_buffer(ms, NULL, NULL, name, newbuf, 1260 nsz); 1261 if (prv == -1) 1262 goto error; 1263@@ -337,7 +340,7 @@ 1264 * XXX: If file_buffer fails here, we overwrite 1265 * the compressed text. FIXME. 1266 */ 1267- if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) 1268+ if (file_buffer(ms, NULL, NULL, NULL, buf, nbytes) == -1) 1269 { 1270 if (file_pop_buffer(ms, pb) != NULL) 1271 abort(); 1272@@ -345,10 +348,10 @@ 1273 } 1274 if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 1275 if (file_printf(ms, "%s", rbuf) == -1) { 1276- free(rbuf); 1277+ efree(rbuf); 1278 goto error; 1279 } 1280- free(rbuf); 1281+ efree(rbuf); 1282 } 1283 if (!mime && file_printf(ms, ")") == -1) 1284 goto error; 1285@@ -369,7 +372,8 @@ 1286 if (sa_saved && sig_act.sa_handler != SIG_IGN) 1287 (void)sigaction(SIGPIPE, &sig_act, NULL); 1288 1289- free(newbuf); 1290+ if (newbuf) 1291+ efree(newbuf); 1292 ms->flags |= MAGIC_COMPRESS; 1293 DPRINTF("Zmagic returns %d\n", rv); 1294 return rv; 1295@@ -452,7 +456,7 @@ 1296 1297 nocheck: 1298 do 1299- switch ((rv = read(fd, buf, n))) { 1300+ switch ((rv = FINFO_READ_FUNC(fd, buf, n))) { 1301 case -1: 1302 if (errno == EINTR) 1303 continue; 1304@@ -545,13 +549,13 @@ 1305 return -1; 1306 } 1307 (void)close(tfd); 1308- if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) { 1309+ if (FINFO_LSEEK_FUNC(fd, (zend_off_t)0, SEEK_SET) == (zend_off_t)-1) { 1310 file_badseek(ms); 1311 return -1; 1312 } 1313 return fd; 1314 } 1315-#if HAVE_FORK 1316+#ifdef PHP_FILEINFO_UNCOMPRESS 1317 #ifdef BUILTIN_DECOMPRESS 1318 1319 #define FHCRC (1 << 1) 1320@@ -1062,7 +1066,7 @@ 1321 int (*decompress)(const unsigned char *, unsigned char **, 1322 size_t, size_t *, int) = getdecompressor(method); 1323 1324- *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 1325+ *newch = CAST(unsigned char *, emalloc(bytes_max + 1)); 1326 if (*newch == NULL) 1327 return makeerror(newch, n, "No buffer, %s", strerror(errno)); 1328 1329@@ -1225,3 +1229,4 @@ 1330 return rv; 1331 } 1332 #endif 1333+#endif 1334diff -u libmagic.orig/der.c libmagic/der.c 1335--- libmagic.orig/der.c 2022-09-24 22:56:49.000000000 +0200 1336+++ libmagic/der.c 2024-06-09 00:31:40.346830746 +0200 1337@@ -54,7 +54,9 @@ 1338 #include "magic.h" 1339 #include "der.h" 1340 #else 1341+#ifdef HAVE_SYS_MMAN_H 1342 #include <sys/mman.h> 1343+#endif 1344 #include <sys/stat.h> 1345 #include <err.h> 1346 #endif 1347diff -u libmagic.orig/encoding.c libmagic/encoding.c 1348--- libmagic.orig/encoding.c 2022-12-26 18:31:56.000000000 +0100 1349+++ libmagic/encoding.c 2024-06-09 00:31:40.346830746 +0200 1350@@ -97,7 +97,7 @@ 1351 nbytes = ms->encoding_max; 1352 1353 mlen = (nbytes + 1) * sizeof((*ubuf)[0]); 1354- *ubuf = CAST(file_unichar_t *, calloc(CAST(size_t, 1), mlen)); 1355+ *ubuf = CAST(file_unichar_t *, ecalloc(CAST(size_t, 1), mlen)); 1356 if (*ubuf == NULL) { 1357 file_oomem(ms, mlen); 1358 goto done; 1359@@ -150,7 +150,7 @@ 1360 unsigned char *nbuf; 1361 1362 mlen = (nbytes + 1) * sizeof(nbuf[0]); 1363- if ((nbuf = CAST(unsigned char *, malloc(mlen))) == NULL) { 1364+ if ((nbuf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 1365 file_oomem(ms, mlen); 1366 goto done; 1367 } 1368@@ -170,12 +170,12 @@ 1369 rv = 0; 1370 *type = "binary"; 1371 } 1372- free(nbuf); 1373+ efree(nbuf); 1374 } 1375 1376 done: 1377 if (ubuf == &udefbuf) 1378- free(udefbuf); 1379+ efree(udefbuf); 1380 1381 return rv; 1382 } 1383diff -u libmagic.orig/file.h libmagic/file.h 1384--- libmagic.orig/file.h 2023-07-27 21:40:22.000000000 +0200 1385+++ libmagic/file.h 2024-06-09 00:31:40.346830746 +0200 1386@@ -27,15 +27,13 @@ 1387 */ 1388 /* 1389 * file.h - definitions for file(1) program 1390- * @(#)$File: file.h,v 1.247 2023/07/27 19:40:22 christos Exp $ 1391+ * @(#)$File: file.h,v 1.248 2023/07/28 14:38:25 christos Exp $ 1392 */ 1393 1394 #ifndef __file_h__ 1395 #define __file_h__ 1396 1397-#ifdef HAVE_CONFIG_H 1398-#include <config.h> 1399-#endif 1400+#include "config.h" 1401 1402 #ifdef HAVE_STDINT_H 1403 #include <stdint.h> 1404@@ -79,8 +77,7 @@ 1405 #include <stdio.h> /* Include that here, to make sure __P gets defined */ 1406 #include <errno.h> 1407 #include <fcntl.h> /* For open and flags */ 1408-#include <regex.h> 1409-#include <time.h> 1410+ 1411 #include <sys/types.h> 1412 #ifndef WIN32 1413 #include <sys/param.h> 1414@@ -88,10 +85,6 @@ 1415 /* Do this here and now, because struct stat gets re-defined on solaris */ 1416 #include <sys/stat.h> 1417 #include <stdarg.h> 1418-#include <locale.h> 1419-#if defined(HAVE_XLOCALE_H) 1420-#include <xlocale.h> 1421-#endif 1422 1423 #define ENABLE_CONDITIONALS 1424 1425@@ -159,9 +152,11 @@ 1426 /* 1427 * Dec 31, 23:59:59 9999 1428 * we need to make sure that we don't exceed 9999 because some libc 1429- * implementations like muslc crash otherwise 1430+ * implementations like muslc crash otherwise. If you are unlucky 1431+ * to be running on a system with a 32 bit time_t, then it is even less. 1432 */ 1433-#define MAX_CTIME CAST(time_t, 0x3afff487cfULL) 1434+#define MAX_CTIME \ 1435+ CAST(time_t, sizeof(time_t) > 4 ? 0x3afff487cfULL : 0x7fffffffULL) 1436 1437 #define FILE_BADSIZE CAST(size_t, ~0ul) 1438 #define MAXDESC 64 /* max len of text description/MIME type */ 1439@@ -179,14 +174,12 @@ 1440 #define FILE_COMPILE 2 1441 #define FILE_LIST 3 1442 1443-typedef regex_t file_regex_t; 1444- 1445 struct buffer { 1446 int fd; 1447- struct stat st; 1448+ zend_stat_t st; 1449 const void *fbuf; 1450 size_t flen; 1451- off_t eoff; 1452+ zend_off_t eoff; 1453 void *ebuf; 1454 size_t elen; 1455 }; 1456@@ -289,7 +282,7 @@ 1457 #define FILE_OCTAL 59 1458 #define FILE_NAMES_SIZE 60 /* size of array to contain all names */ 1459 1460-#define IS_STRING(t) \ 1461+#define IS_LIBMAGIC_STRING(t) \ 1462 ((t) == FILE_STRING || \ 1463 (t) == FILE_PSTRING || \ 1464 (t) == FILE_BESTRING16 || \ 1465@@ -420,7 +413,6 @@ 1466 /* list of magic entries */ 1467 struct mlist { 1468 struct magic *magic; /* array of magic entries */ 1469- file_regex_t **magic_rxcomp; /* array of compiled regexps */ 1470 size_t nmagic; /* number of entries in array */ 1471 void *map; /* internal resources used by entry */ 1472 struct mlist *next, *prev; 1473@@ -525,11 +517,9 @@ 1474 file_protected const char *file_fmtnum(char *, size_t, const char *, int); 1475 file_protected struct magic_set *file_ms_alloc(int); 1476 file_protected void file_ms_free(struct magic_set *); 1477-file_protected int file_default(struct magic_set *, size_t); 1478-file_protected int file_buffer(struct magic_set *, int, struct stat *, 1479- const char *, const void *, size_t); 1480-file_protected int file_fsmagic(struct magic_set *, const char *, 1481- struct stat *); 1482+file_protected int file_buffer(struct magic_set *, php_stream *, zend_stat_t *, const char *, const void *, 1483+ size_t); 1484+file_protected int file_fsmagic(struct magic_set *, const char *, zend_stat_t *); 1485 file_protected int file_pipe2file(struct magic_set *, int, const void *, 1486 size_t); 1487 file_protected int file_vprintf(struct magic_set *, const char *, va_list) 1488@@ -546,7 +536,7 @@ 1489 file_protected int file_reset(struct magic_set *, int); 1490 file_protected int file_tryelf(struct magic_set *, const struct buffer *); 1491 file_protected int file_trycdf(struct magic_set *, const struct buffer *); 1492-#if HAVE_FORK 1493+#ifdef PHP_FILEINFO_UNCOMPRESS 1494 file_protected int file_zmagic(struct magic_set *, const struct buffer *, 1495 const char *); 1496 #endif 1497@@ -605,19 +595,13 @@ 1498 file_protected int file_clear_closexec(int); 1499 file_protected char *file_strtrim(char *); 1500 1501-file_protected void buffer_init(struct buffer *, int, const struct stat *, 1502+file_protected void buffer_init(struct buffer *, int, const zend_stat_t *, 1503 const void *, size_t); 1504 file_protected void buffer_fini(struct buffer *); 1505 file_protected int buffer_fill(const struct buffer *); 1506 1507 1508 1509-file_protected int file_regcomp(struct magic_set *, file_regex_t *, 1510- const char *, int); 1511-file_protected int file_regexec(struct magic_set *, file_regex_t *, 1512- const char *, size_t, regmatch_t *, int); 1513-file_protected void file_regfree(file_regex_t *); 1514- 1515 typedef struct { 1516 char *buf; 1517 size_t blen; 1518@@ -632,23 +616,10 @@ 1519 extern const size_t file_nnames; 1520 #endif 1521 1522-#ifndef HAVE_PREAD 1523-ssize_t pread(int, void *, size_t, off_t); 1524-#endif 1525-#ifndef HAVE_VASPRINTF 1526-int vasprintf(char **, const char *, va_list); 1527-#endif 1528-#ifndef HAVE_ASPRINTF 1529-int asprintf(char **, const char *, ...); 1530-#endif 1531-#ifndef HAVE_DPRINTF 1532-int dprintf(int, const char *, ...); 1533-#endif 1534- 1535-#ifndef HAVE_STRLCPY 1536+#ifndef strlcpy 1537 size_t strlcpy(char *, const char *, size_t); 1538 #endif 1539-#ifndef HAVE_STRLCAT 1540+#ifndef strlcat 1541 size_t strlcat(char *, const char *, size_t); 1542 #endif 1543 #ifndef HAVE_STRCASESTR 1544@@ -664,39 +635,6 @@ 1545 #ifndef HAVE_ASCTIME_R 1546 char *asctime_r(const struct tm *, char *); 1547 #endif 1548-#ifndef HAVE_GMTIME_R 1549-struct tm *gmtime_r(const time_t *, struct tm *); 1550-#endif 1551-#ifndef HAVE_LOCALTIME_R 1552-struct tm *localtime_r(const time_t *, struct tm *); 1553-#endif 1554-#ifndef HAVE_FMTCHECK 1555-const char *fmtcheck(const char *, const char *) 1556- __attribute__((__format_arg__(2))); 1557-#endif 1558- 1559-#ifdef HAVE_LIBSECCOMP 1560-// basic filter 1561-// this mode should not interfere with normal operations 1562-// only some dangerous syscalls are blacklisted 1563-int enable_sandbox_basic(void); 1564- 1565-// enhanced filter 1566-// this mode allows only the necessary syscalls used during normal operation 1567-// extensive testing required !!! 1568-int enable_sandbox_full(void); 1569-#endif 1570- 1571-file_protected const char *file_getprogname(void); 1572-file_protected void file_setprogname(const char *); 1573-file_protected void file_err(int, const char *, ...) 1574- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1575-file_protected void file_errx(int, const char *, ...) 1576- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1577-file_protected void file_warn(const char *, ...) 1578- __attribute__((__format__(__printf__, 1, 2))); 1579-file_protected void file_warnx(const char *, ...) 1580- __attribute__((__format__(__printf__, 1, 2))); 1581 1582 #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK) 1583 #define QUICK 1584diff -u libmagic.orig/fsmagic.c libmagic/fsmagic.c 1585--- libmagic.orig/fsmagic.c 2023-07-27 21:33:24.000000000 +0200 1586+++ libmagic/fsmagic.c 2024-06-09 00:31:40.346830746 +0200 1587@@ -66,26 +66,10 @@ 1588 # define minor(dev) ((dev) & 0xff) 1589 #endif 1590 #undef HAVE_MAJOR 1591-#ifdef S_IFLNK 1592-file_private int 1593-bad_link(struct magic_set *ms, int err, char *buf) 1594-{ 1595- int mime = ms->flags & MAGIC_MIME; 1596- if ((mime & MAGIC_MIME_TYPE) && 1597- file_printf(ms, "inode/symlink") 1598- == -1) 1599- return -1; 1600- else if (!mime) { 1601- if (ms->flags & MAGIC_ERROR) { 1602- file_error(ms, err, 1603- "broken symbolic link to %s", buf); 1604- return -1; 1605- } 1606- if (file_printf(ms, "broken symbolic link to %s", buf) == -1) 1607- return -1; 1608- } 1609- return 1; 1610-} 1611+ 1612+#ifdef PHP_WIN32 1613+ 1614+# undef S_IFIFO 1615 #endif 1616 file_private int 1617 handle_mime(struct magic_set *ms, int mime, const char *str) 1618@@ -103,60 +87,17 @@ 1619 } 1620 1621 file_protected int 1622-file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) 1623+file_fsmagic(struct magic_set *ms, const char *fn, zend_stat_t *sb) 1624 { 1625 int ret, did = 0; 1626 int mime = ms->flags & MAGIC_MIME; 1627 int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION); 1628-#ifdef S_IFLNK 1629- char buf[BUFSIZ+4]; 1630- ssize_t nch; 1631- struct stat tstatbuf; 1632-#endif 1633 1634 if (fn == NULL) 1635 return 0; 1636 1637 #define COMMA (did++ ? ", " : "") 1638- /* 1639- * Fstat is cheaper but fails for files you don't have read perms on. 1640- * On 4.2BSD and similar systems, use lstat() to identify symlinks. 1641- */ 1642-#ifdef S_IFLNK 1643- if ((ms->flags & MAGIC_SYMLINK) == 0) 1644- ret = lstat(fn, sb); 1645- else 1646-#endif 1647- ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 1648- 1649-#ifdef WIN32 1650- { 1651- HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE | 1652- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 1653- NULL); 1654- if (hFile != INVALID_HANDLE_VALUE) { 1655- /* 1656- * Stat failed, but we can still open it - assume it's 1657- * a block device, if nothing else. 1658- */ 1659- if (ret) { 1660- sb->st_mode = S_IFBLK; 1661- ret = 0; 1662- } 1663- switch (GetFileType(hFile)) { 1664- case FILE_TYPE_CHAR: 1665- sb->st_mode |= S_IFCHR; 1666- sb->st_mode &= ~S_IFREG; 1667- break; 1668- case FILE_TYPE_PIPE: 1669- sb->st_mode |= S_IFIFO; 1670- sb->st_mode &= ~S_IFREG; 1671- break; 1672- } 1673- CloseHandle(hFile); 1674- } 1675- } 1676-#endif 1677+ ret = php_sys_stat(fn, sb); 1678 1679 if (ret) { 1680 if (ms->flags & MAGIC_ERROR) { 1681@@ -189,32 +130,24 @@ 1682 } 1683 1684 switch (sb->st_mode & S_IFMT) { 1685- case S_IFDIR: 1686- if (mime) { 1687- if (handle_mime(ms, mime, "directory") == -1) 1688- return -1; 1689- } else if (silent) { 1690- } else if (file_printf(ms, "%sdirectory", COMMA) == -1) 1691- return -1; 1692- break; 1693-#ifdef S_IFCHR 1694- case S_IFCHR: 1695- /* 1696- * If -s has been specified, treat character special files 1697- * like ordinary files. Otherwise, just report that they 1698- * are block special files and go on to the next file. 1699- */ 1700- if ((ms->flags & MAGIC_DEVICES) != 0) { 1701- ret = 0; 1702- break; 1703- } 1704- if (mime) { 1705- if (handle_mime(ms, mime, "chardevice") == -1) 1706- return -1; 1707- } else if (silent) { 1708- } else { 1709-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1710-# ifdef dv_unit 1711+#ifndef PHP_WIN32 1712+# ifdef S_IFCHR 1713+ case S_IFCHR: 1714+ /* 1715+ * If -s has been specified, treat character special files 1716+ * like ordinary files. Otherwise, just report that they 1717+ * are block special files and go on to the next file. 1718+ */ 1719+ if ((ms->flags & MAGIC_DEVICES) != 0) { 1720+ ret = 0; 1721+ break; 1722+ } 1723+ if (mime) { 1724+ if (handle_mime(ms, mime, "chardevice") == -1) 1725+ return -1; 1726+ } else { 1727+# ifdef HAVE_STAT_ST_RDEV 1728+# ifdef dv_unit 1729 if (file_printf(ms, "%scharacter special (%d/%d/%d)", 1730 COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1731 dv_subunit(sb->st_rdev)) == -1) 1732@@ -229,45 +162,11 @@ 1733 if (file_printf(ms, "%scharacter special", COMMA) == -1) 1734 return -1; 1735 #endif 1736- } 1737- break; 1738-#endif 1739-#ifdef S_IFBLK 1740- case S_IFBLK: 1741- /* 1742- * If -s has been specified, treat block special files 1743- * like ordinary files. Otherwise, just report that they 1744- * are block special files and go on to the next file. 1745- */ 1746- if ((ms->flags & MAGIC_DEVICES) != 0) { 1747- ret = 0; 1748- break; 1749- } 1750- if (mime) { 1751- if (handle_mime(ms, mime, "blockdevice") == -1) 1752- return -1; 1753- } else if (silent) { 1754- } else { 1755-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1756-# ifdef dv_unit 1757- if (file_printf(ms, "%sblock special (%d/%d/%d)", 1758- COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1759- dv_subunit(sb->st_rdev)) == -1) 1760- return -1; 1761-# else 1762- if (file_printf(ms, "%sblock special (%ld/%ld)", 1763- COMMA, (long)major(sb->st_rdev), 1764- (long)minor(sb->st_rdev)) == -1) 1765- return -1; 1766+ } 1767+ return 1; 1768 # endif 1769-#else 1770- if (file_printf(ms, "%sblock special", COMMA) == -1) 1771- return -1; 1772 #endif 1773- } 1774- break; 1775-#endif 1776- /* TODO add code to handle V7 MUX and Blit MUX files */ 1777+ 1778 #ifdef S_IFIFO 1779 case S_IFIFO: 1780 if((ms->flags & MAGIC_DEVICES) != 0) 1781@@ -292,92 +191,14 @@ 1782 #endif 1783 #ifdef S_IFLNK 1784 case S_IFLNK: 1785- if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 1786+ /* stat is used, if it made here then the link is broken */ 1787 if (ms->flags & MAGIC_ERROR) { 1788- file_error(ms, errno, "unreadable symlink `%s'", 1789- fn); 1790+ file_error(ms, errno, "unreadable symlink `%s'", fn); 1791 return -1; 1792 } 1793- if (mime) { 1794- if (handle_mime(ms, mime, "symlink") == -1) 1795- return -1; 1796- } else if (silent) { 1797- } else if (file_printf(ms, 1798- "%sunreadable symlink `%s' (%s)", COMMA, fn, 1799- strerror(errno)) == -1) 1800- return -1; 1801- break; 1802- } 1803- buf[nch] = '\0'; /* readlink(2) does not do this */ 1804- 1805- /* If broken symlink, say so and quit early. */ 1806-#ifdef __linux__ 1807- /* 1808- * linux procfs/devfs makes symlinks like pipe:[3515864880] 1809- * that we can't stat their readlink output, so stat the 1810- * original filename instead. 1811- */ 1812- if (stat(fn, &tstatbuf) < 0) 1813- return bad_link(ms, errno, buf); 1814-#else 1815- if (*buf == '/') { 1816- if (stat(buf, &tstatbuf) < 0) 1817- return bad_link(ms, errno, buf); 1818- } else { 1819- char *tmp; 1820- char buf2[BUFSIZ+BUFSIZ+4]; 1821- 1822- if ((tmp = CCAST(char *, strrchr(fn, '/'))) == NULL) { 1823- tmp = buf; /* in current directory anyway */ 1824- } else { 1825- if (tmp - fn + 1 > BUFSIZ) { 1826- if (ms->flags & MAGIC_ERROR) { 1827- file_error(ms, 0, 1828- "path too long: `%s'", buf); 1829- return -1; 1830- } 1831- if (mime) { 1832- if (handle_mime(ms, mime, 1833- "x-path-too-long") == -1) 1834- return -1; 1835- } else if (silent) { 1836- } else if (file_printf(ms, 1837- "%spath too long: `%s'", COMMA, 1838- fn) == -1) 1839- return -1; 1840- break; 1841- } 1842- /* take dir part */ 1843- (void)strlcpy(buf2, fn, sizeof buf2); 1844- buf2[tmp - fn + 1] = '\0'; 1845- /* plus (rel) link */ 1846- (void)strlcat(buf2, buf, sizeof buf2); 1847- tmp = buf2; 1848- } 1849- if (stat(tmp, &tstatbuf) < 0) 1850- return bad_link(ms, errno, buf); 1851- } 1852+ return 1; 1853 #endif 1854 1855- /* Otherwise, handle it. */ 1856- if ((ms->flags & MAGIC_SYMLINK) != 0) { 1857- const char *p; 1858- ms->flags &= MAGIC_SYMLINK; 1859- p = magic_file(ms, buf); 1860- ms->flags |= MAGIC_SYMLINK; 1861- if (p == NULL) 1862- return -1; 1863- } else { /* just print what it points to */ 1864- if (mime) { 1865- if (handle_mime(ms, mime, "symlink") == -1) 1866- return -1; 1867- } else if (silent) { 1868- } else if (file_printf(ms, "%ssymbolic link to %s", 1869- COMMA, buf) == -1) 1870- return -1; 1871- } 1872- break; 1873-#endif 1874 #ifdef S_IFSOCK 1875 #ifndef __COHERENT__ 1876 case S_IFSOCK: 1877diff -u libmagic.orig/funcs.c libmagic/funcs.c 1878--- libmagic.orig/funcs.c 2023-07-27 21:40:12.000000000 +0200 1879+++ libmagic/funcs.c 2024-06-09 17:55:33.549243946 +0200 1880@@ -66,7 +66,7 @@ 1881 file_private void 1882 file_clearbuf(struct magic_set *ms) 1883 { 1884- free(ms->o.buf); 1885+ efree(ms->o.buf); 1886 ms->o.buf = NULL; 1887 ms->o.blen = 0; 1888 } 1889@@ -132,7 +132,7 @@ 1890 file_protected int 1891 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) 1892 { 1893- int len; 1894+ size_t len; 1895 char *buf, *newstr; 1896 char tbuf[1024]; 1897 1898@@ -145,31 +145,25 @@ 1899 return -1; 1900 } 1901 1902- len = vasprintf(&buf, fmt, ap); 1903- if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) { 1904+ len = vspprintf(&buf, 0, fmt, ap); 1905+ if (len > 1024 || len + ms->o.blen > 1024 * 1024) { 1906 size_t blen = ms->o.blen; 1907- free(buf); 1908+ if (buf) efree(buf); 1909 file_clearbuf(ms); 1910- file_error(ms, 0, "Output buffer space exceeded %d+%" 1911+ file_error(ms, 0, "Output buffer space exceeded %" SIZE_T_FORMAT "u+%" 1912 SIZE_T_FORMAT "u", len, blen); 1913 return -1; 1914 } 1915 1916 if (ms->o.buf != NULL) { 1917- len = asprintf(&newstr, "%s%s", ms->o.buf, buf); 1918- free(buf); 1919- if (len < 0) 1920- goto out; 1921- free(ms->o.buf); 1922+ len = spprintf(&newstr, 0, "%s%s", ms->o.buf, buf); 1923+ efree(buf); 1924+ efree(ms->o.buf); 1925 buf = newstr; 1926 } 1927 ms->o.buf = buf; 1928 ms->o.blen = len; 1929 return 0; 1930-out: 1931- file_clearbuf(ms); 1932- file_error(ms, errno, "vasprintf failed"); 1933- return -1; 1934 } 1935 1936 file_protected int 1937@@ -320,7 +314,7 @@ 1938 */ 1939 /*ARGSUSED*/ 1940 file_protected int 1941-file_buffer(struct magic_set *ms, int fd, struct stat *st, 1942+file_buffer(struct magic_set *ms, php_stream *stream, zend_stat_t *st, 1943 const char *inname __attribute__ ((__unused__)), 1944 const void *buf, size_t nb) 1945 { 1946@@ -331,6 +325,19 @@ 1947 const char *ftype = NULL; 1948 char *rbuf = NULL; 1949 struct buffer b; 1950+ int fd = -1; 1951+ 1952+ if (stream) { 1953+#ifdef _WIN64 1954+ php_socket_t _fd = fd; 1955+#else 1956+ int _fd; 1957+#endif 1958+ int _ret = php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&_fd, 0); 1959+ if (SUCCESS == _ret) { 1960+ fd = (int)_fd; 1961+ } 1962+ } 1963 1964 buffer_init(&b, fd, st, buf, nb); 1965 ms->mode = b.st.st_mode; 1966@@ -363,7 +370,8 @@ 1967 } 1968 } 1969 #endif 1970-#if HAVE_FORK 1971+ 1972+#ifdef PHP_FILEINFO_UNCOMPRESS 1973 /* try compression stuff */ 1974 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) { 1975 m = file_zmagic(ms, &b, inname); 1976@@ -447,7 +455,7 @@ 1977 rv = file_tryelf(ms, &b); 1978 rbuf = file_pop_buffer(ms, pb); 1979 if (rv == -1) { 1980- free(rbuf); 1981+ efree(rbuf); 1982 rbuf = NULL; 1983 } 1984 if ((ms->flags & MAGIC_DEBUG) != 0) 1985@@ -499,10 +507,10 @@ 1986 if (file_printf(ms, "%s", code_mime) == -1) 1987 rv = -1; 1988 } 1989-#if HAVE_FORK 1990+#ifdef PHP_FILEINFO_UNCOMPRESS 1991 done_encoding: 1992 #endif 1993- free(rbuf); 1994+ efree(rbuf); 1995 buffer_fini(&b); 1996 if (rv) 1997 return rv; 1998@@ -520,7 +528,7 @@ 1999 } 2000 file_clearbuf(ms); 2001 if (ms->o.pbuf) { 2002- free(ms->o.pbuf); 2003+ efree(ms->o.pbuf); 2004 ms->o.pbuf = NULL; 2005 } 2006 ms->event_flags &= ~EVENT_HAD_ERR; 2007@@ -558,7 +566,7 @@ 2008 return NULL; 2009 } 2010 psize = len * 4 + 1; 2011- if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) { 2012+ if ((pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) { 2013 file_oomem(ms, psize); 2014 return NULL; 2015 } 2016@@ -622,8 +630,8 @@ 2017 if (level >= ms->c.len) { 2018 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li); 2019 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? 2020- malloc(len) : 2021- realloc(ms->c.li, len)); 2022+ emalloc(len) : 2023+ erealloc(ms->c.li, len)); 2024 if (ms->c.li == NULL) { 2025 file_oomem(ms, len); 2026 return -1; 2027@@ -646,122 +654,38 @@ 2028 file_protected int 2029 file_replace(struct magic_set *ms, const char *pat, const char *rep) 2030 { 2031- file_regex_t rx; 2032- int rc, rv = -1; 2033- 2034- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED); 2035- if (rc == 0) { 2036- regmatch_t rm; 2037- int nm = 0; 2038- while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) { 2039- ms->o.buf[rm.rm_so] = '\0'; 2040- if (file_printf(ms, "%s%s", rep, 2041- rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) 2042- goto out; 2043- nm++; 2044- } 2045- rv = nm; 2046+ zend_string *pattern; 2047+ uint32_t opts = 0; 2048+ pcre_cache_entry *pce; 2049+ zend_string *res; 2050+ zend_string *repl; 2051+ size_t rep_cnt = 0; 2052+ 2053+ opts |= PCRE2_MULTILINE; 2054+ pattern = convert_libmagic_pattern((char*)pat, strlen(pat), opts); 2055+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 2056+ zend_string_release(pattern); 2057+ rep_cnt = -1; 2058+ goto out; 2059+ } 2060+ zend_string_release(pattern); 2061+ 2062+ repl = zend_string_init(rep, strlen(rep), 0); 2063+ res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), repl, -1, &rep_cnt); 2064+ 2065+ zend_string_release_ex(repl, 0); 2066+ if (NULL == res) { 2067+ rep_cnt = -1; 2068+ goto out; 2069 } 2070-out: 2071- file_regfree(&rx); 2072- return rv; 2073-} 2074 2075-file_private int 2076-check_regex(struct magic_set *ms, const char *pat) 2077-{ 2078- char sbuf[512]; 2079- unsigned char oc = '\0'; 2080- const char *p; 2081+ memcpy(ms->o.buf, ZSTR_VAL(res), ZSTR_LEN(res)); 2082+ ms->o.buf[ZSTR_LEN(res)] = '\0'; 2083 2084- for (p = pat; *p; p++) { 2085- unsigned char c = *p; 2086- // Avoid repetition 2087- if (c == oc && strchr("?*+{", c) != NULL) { 2088- size_t len = strlen(pat); 2089- file_magwarn(ms, 2090- "repetition-operator operand `%c' " 2091- "invalid in regex `%s'", c, 2092- file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 2093- return -1; 2094- } 2095- oc = c; 2096- if (isprint(c) || isspace(c) || c == '\b' 2097- || c == 0x8a) // XXX: apple magic fixme 2098- continue; 2099- size_t len = strlen(pat); 2100- file_magwarn(ms, 2101- "non-ascii characters in regex \\%#o `%s'", 2102- c, file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 2103- return -1; 2104- } 2105- return 0; 2106-} 2107+ zend_string_release_ex(res, 0); 2108 2109-file_protected int 2110-file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx, 2111- const char *pat, int flags) 2112-{ 2113- if (check_regex(ms, pat) == -1) 2114- return -1; 2115- 2116-#ifdef USE_C_LOCALE 2117- locale_t old = uselocale(ms->c_lc_ctype); 2118- assert(old != NULL); 2119-#else 2120- char old[1024]; 2121- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2122- (void)setlocale(LC_CTYPE, "C"); 2123-#endif 2124- int rc; 2125- rc = regcomp(rx, pat, flags); 2126- 2127-#ifdef USE_C_LOCALE 2128- uselocale(old); 2129-#else 2130- (void)setlocale(LC_CTYPE, old); 2131-#endif 2132- if (rc > 0 && (ms->flags & MAGIC_CHECK)) { 2133- char errmsg[512], buf[512]; 2134- 2135- (void)regerror(rc, rx, errmsg, sizeof(errmsg)); 2136- file_magerror(ms, "regex error %d for `%s', (%s)", rc, 2137- file_printable(ms, buf, sizeof(buf), pat, strlen(pat)), 2138- errmsg); 2139- } 2140- return rc; 2141-} 2142- 2143-/*ARGSUSED*/ 2144-file_protected int 2145-file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx, 2146- const char *str, size_t nmatch, regmatch_t* pmatch, int eflags) 2147-{ 2148-#ifdef USE_C_LOCALE 2149- locale_t old = uselocale(ms->c_lc_ctype); 2150- assert(old != NULL); 2151-#else 2152- char old[1024]; 2153- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2154- (void)setlocale(LC_CTYPE, "C"); 2155-#endif 2156- int rc; 2157- /* XXX: force initialization because glibc does not always do this */ 2158- if (nmatch != 0) 2159- memset(pmatch, 0, nmatch * sizeof(*pmatch)); 2160- rc = regexec(rx, str, nmatch, pmatch, eflags); 2161-#ifdef USE_C_LOCALE 2162- uselocale(old); 2163-#else 2164- (void)setlocale(LC_CTYPE, old); 2165-#endif 2166- return rc; 2167-} 2168- 2169-file_protected void 2170-file_regfree(file_regex_t *rx) 2171-{ 2172- regfree(rx); 2173+out: 2174+ return rep_cnt; 2175 } 2176 2177 file_protected file_pushbuf_t * 2178@@ -772,7 +696,7 @@ 2179 if (ms->event_flags & EVENT_HAD_ERR) 2180 return NULL; 2181 2182- if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) 2183+ if ((pb = (CAST(file_pushbuf_t *, emalloc(sizeof(*pb))))) == NULL) 2184 return NULL; 2185 2186 pb->buf = ms->o.buf; 2187@@ -792,8 +716,8 @@ 2188 char *rbuf; 2189 2190 if (ms->event_flags & EVENT_HAD_ERR) { 2191- free(pb->buf); 2192- free(pb); 2193+ efree(pb->buf); 2194+ efree(pb); 2195 return NULL; 2196 } 2197 2198@@ -803,7 +727,7 @@ 2199 ms->o.blen = pb->blen; 2200 ms->offset = pb->offset; 2201 2202- free(pb); 2203+ efree(pb); 2204 return rbuf; 2205 } 2206 2207@@ -887,6 +811,7 @@ 2208 #endif 2209 } 2210 2211+#if 0 2212 file_protected int 2213 file_pipe_closexec(int *fds) 2214 { 2215@@ -904,6 +829,7 @@ 2216 return 0; 2217 #endif 2218 } 2219+#endif 2220 2221 file_protected int 2222 file_clear_closexec(int fd) { 2223diff -u libmagic.orig/magic.c libmagic/magic.c 2224--- libmagic.orig/magic.c 2023-07-27 21:33:24.000000000 +0200 2225+++ libmagic/magic.c 2024-06-09 00:31:40.347830761 +0200 2226@@ -25,11 +25,6 @@ 2227 * SUCH DAMAGE. 2228 */ 2229 2230-#ifdef WIN32 2231-#include <windows.h> 2232-#include <shlwapi.h> 2233-#endif 2234- 2235 #include "file.h" 2236 2237 #ifndef lint 2238@@ -39,7 +34,9 @@ 2239 #include "magic.h" 2240 2241 #include <stdlib.h> 2242+#ifdef HAVE_UNISTD_H 2243 #include <unistd.h> 2244+#endif 2245 #include <string.h> 2246 #ifdef QUICK 2247 #include <sys/mman.h> 2248@@ -69,200 +66,18 @@ 2249 #endif 2250 #endif 2251 2252-file_private void close_and_restore(const struct magic_set *, const char *, int, 2253- const struct stat *); 2254-file_private int unreadable_info(struct magic_set *, mode_t, const char *); 2255-file_private const char* get_default_magic(void); 2256-#ifndef COMPILE_ONLY 2257-file_private const char *file_or_fd(struct magic_set *, const char *, int); 2258+#ifdef PHP_WIN32 2259+# undef S_IFLNK 2260+# undef S_IFIFO 2261 #endif 2262 2263+file_private int unreadable_info(struct magic_set *, mode_t, const char *); 2264+file_private const char *file_or_stream(struct magic_set *, const char *, php_stream *); 2265+ 2266 #ifndef STDIN_FILENO 2267 #define STDIN_FILENO 0 2268 #endif 2269 2270-#ifdef WIN32 2271-/* HINSTANCE of this shared library. Needed for get_default_magic() */ 2272-static HINSTANCE _w32_dll_instance = NULL; 2273- 2274-static void 2275-_w32_append_path(char **hmagicpath, const char *fmt, ...) 2276-{ 2277- char *tmppath; 2278- char *newpath; 2279- va_list ap; 2280- 2281- va_start(ap, fmt); 2282- if (vasprintf(&tmppath, fmt, ap) < 0) { 2283- va_end(ap); 2284- return; 2285- } 2286- va_end(ap); 2287- 2288- if (access(tmppath, R_OK) == -1) 2289- goto out; 2290- 2291- if (*hmagicpath == NULL) { 2292- *hmagicpath = tmppath; 2293- return; 2294- } 2295- 2296- if (asprintf(&newpath, "%s%c%s", *hmagicpath, PATHSEP, tmppath) < 0) 2297- goto out; 2298- 2299- free(*hmagicpath); 2300- free(tmppath); 2301- *hmagicpath = newpath; 2302- return; 2303-out: 2304- free(tmppath); 2305-} 2306- 2307-static void 2308-_w32_get_magic_relative_to(char **hmagicpath, HINSTANCE module) 2309-{ 2310- static const char *trypaths[] = { 2311- "%s/share/misc/magic.mgc", 2312- "%s/magic.mgc", 2313- }; 2314- LPSTR dllpath; 2315- size_t sp; 2316- 2317- dllpath = calloc(MAX_PATH + 1, sizeof(*dllpath)); 2318- 2319- if (!GetModuleFileNameA(module, dllpath, MAX_PATH)) 2320- goto out; 2321- 2322- PathRemoveFileSpecA(dllpath); 2323- 2324- if (module) { 2325- char exepath[MAX_PATH]; 2326- GetModuleFileNameA(NULL, exepath, MAX_PATH); 2327- PathRemoveFileSpecA(exepath); 2328- if (stricmp(exepath, dllpath) == 0) 2329- goto out; 2330- } 2331- 2332- sp = strlen(dllpath); 2333- if (sp > 3 && stricmp(&dllpath[sp - 3], "bin") == 0) { 2334- _w32_append_path(hmagicpath, 2335- "%s/../share/misc/magic.mgc", dllpath); 2336- goto out; 2337- } 2338- 2339- for (sp = 0; sp < __arraycount(trypaths); sp++) 2340- _w32_append_path(hmagicpath, trypaths[sp], dllpath); 2341-out: 2342- free(dllpath); 2343-} 2344- 2345-#ifndef BUILD_AS_WINDOWS_STATIC_LIBARAY 2346-/* Placate GCC by offering a sacrificial previous prototype */ 2347-BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID); 2348- 2349-BOOL WINAPI 2350-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, 2351- LPVOID lpvReserved __attribute__((__unused__))) 2352-{ 2353- if (fdwReason == DLL_PROCESS_ATTACH) 2354- _w32_dll_instance = hinstDLL; 2355- return 1; 2356-} 2357-#endif 2358-#endif 2359- 2360-file_private const char * 2361-get_default_magic(void) 2362-{ 2363- static const char hmagic[] = "/.magic/magic.mgc"; 2364- static char *default_magic; 2365- char *home, *hmagicpath; 2366- 2367-#ifndef WIN32 2368- struct stat st; 2369- 2370- if (default_magic) { 2371- free(default_magic); 2372- default_magic = NULL; 2373- } 2374- if ((home = getenv("HOME")) == NULL) 2375- return MAGIC; 2376- 2377- if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) 2378- return MAGIC; 2379- if (stat(hmagicpath, &st) == -1) { 2380- free(hmagicpath); 2381- if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 2382- return MAGIC; 2383- if (stat(hmagicpath, &st) == -1) 2384- goto out; 2385- if (S_ISDIR(st.st_mode)) { 2386- free(hmagicpath); 2387- if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 2388- return MAGIC; 2389- if (access(hmagicpath, R_OK) == -1) 2390- goto out; 2391- } 2392- } 2393- 2394- if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 2395- goto out; 2396- free(hmagicpath); 2397- return default_magic; 2398-out: 2399- default_magic = NULL; 2400- free(hmagicpath); 2401- return MAGIC; 2402-#else 2403- hmagicpath = NULL; 2404- 2405- if (default_magic) { 2406- free(default_magic); 2407- default_magic = NULL; 2408- } 2409- 2410- /* Before anything else, try to get a magic file from user HOME */ 2411- if ((home = getenv("HOME")) != NULL) 2412- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2413- 2414- /* First, try to get a magic file from user-application data */ 2415- if ((home = getenv("LOCALAPPDATA")) != NULL) 2416- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2417- 2418- /* Second, try to get a magic file from the user profile data */ 2419- if ((home = getenv("USERPROFILE")) != NULL) 2420- _w32_append_path(&hmagicpath, 2421- "%s/Local Settings/Application Data%s", home, hmagic); 2422- 2423- /* Third, try to get a magic file from Common Files */ 2424- if ((home = getenv("COMMONPROGRAMFILES")) != NULL) 2425- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2426- 2427- /* Fourth, try to get magic file relative to exe location */ 2428- _w32_get_magic_relative_to(&hmagicpath, NULL); 2429- 2430- /* Fifth, try to get magic file relative to dll location */ 2431- _w32_get_magic_relative_to(&hmagicpath, _w32_dll_instance); 2432- 2433- /* Avoid MAGIC constant - it likely points to a file within MSys tree */ 2434- default_magic = hmagicpath; 2435- return default_magic; 2436-#endif 2437-} 2438- 2439-file_public const char * 2440-magic_getpath(const char *magicfile, int action) 2441-{ 2442- if (magicfile != NULL) 2443- return magicfile; 2444- 2445- magicfile = getenv("MAGIC"); 2446- if (magicfile != NULL) 2447- return magicfile; 2448- 2449- return action == FILE_LOAD ? get_default_magic() : MAGIC; 2450-} 2451- 2452 file_public struct magic_set * 2453 magic_open(int flags) 2454 { 2455@@ -321,21 +136,6 @@ 2456 return file_apprentice(ms, magicfile, FILE_LOAD); 2457 } 2458 2459-#ifndef COMPILE_ONLY 2460-/* 2461- * Install a set of compiled magic buffers. 2462- */ 2463-file_public int 2464-magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, 2465- size_t nbufs) 2466-{ 2467- if (ms == NULL) 2468- return -1; 2469- return buffer_apprentice(ms, RCAST(struct magic **, bufs), 2470- sizes, nbufs); 2471-} 2472-#endif 2473- 2474 file_public int 2475 magic_compile(struct magic_set *ms, const char *magicfile) 2476 { 2477@@ -360,39 +160,6 @@ 2478 return file_apprentice(ms, magicfile, FILE_LIST); 2479 } 2480 2481-file_private void 2482-close_and_restore(const struct magic_set *ms, const char *name, int fd, 2483- const struct stat *sb) 2484-{ 2485- if (fd == STDIN_FILENO || name == NULL) 2486- return; 2487- (void) close(fd); 2488- 2489- if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 2490- /* 2491- * Try to restore access, modification times if read it. 2492- * This is really *bad* because it will modify the status 2493- * time of the file... And of course this will affect 2494- * backup programs 2495- */ 2496-#ifdef HAVE_UTIMES 2497- struct timeval utsbuf[2]; 2498- (void)memset(utsbuf, 0, sizeof(utsbuf)); 2499- utsbuf[0].tv_sec = sb->st_atime; 2500- utsbuf[1].tv_sec = sb->st_mtime; 2501- 2502- (void) utimes(name, utsbuf); /* don't care if loses */ 2503-#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 2504- struct utimbuf utbuf; 2505- 2506- (void)memset(&utbuf, 0, sizeof(utbuf)); 2507- utbuf.actime = sb->st_atime; 2508- utbuf.modtime = sb->st_mtime; 2509- (void) utime(name, &utbuf); /* don't care if loses */ 2510-#endif 2511- } 2512-} 2513- 2514 #ifndef COMPILE_ONLY 2515 2516 /* 2517@@ -403,7 +170,7 @@ 2518 { 2519 if (ms == NULL) 2520 return NULL; 2521- return file_or_fd(ms, NULL, fd); 2522+ return file_or_stream(ms, NULL, NULL); 2523 } 2524 2525 /* 2526@@ -414,19 +181,25 @@ 2527 { 2528 if (ms == NULL) 2529 return NULL; 2530- return file_or_fd(ms, inname, STDIN_FILENO); 2531+ return file_or_stream(ms, inname, NULL); 2532+} 2533+ 2534+file_public const char * 2535+magic_stream(struct magic_set *ms, php_stream *stream) 2536+{ 2537+ if (ms == NULL) 2538+ return NULL; 2539+ return file_or_stream(ms, NULL, stream); 2540 } 2541 2542 file_private const char * 2543-file_or_fd(struct magic_set *ms, const char *inname, int fd) 2544+file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream) 2545 { 2546 int rv = -1; 2547 unsigned char *buf; 2548- struct stat sb; 2549+ zend_stat_t sb = {0}; 2550 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 2551- int ispipe = 0; 2552- int okstat = 0; 2553- off_t pos = CAST(off_t, -1); 2554+ int no_in_stream = 0; 2555 2556 if (file_reset(ms, 1) == -1) 2557 goto out; 2558@@ -436,7 +209,7 @@ 2559 * some overlapping space for matches near EOF 2560 */ 2561 #define SLOP (1 + sizeof(union VALUETYPE)) 2562- if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) 2563+ if ((buf = CAST(unsigned char *, emalloc(ms->bytes_max + SLOP))) == NULL) 2564 return NULL; 2565 2566 switch (file_fsmagic(ms, inname, &sb)) { 2567@@ -449,96 +222,46 @@ 2568 goto done; 2569 } 2570 2571-#ifdef WIN32 2572- /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ 2573- if (fd == STDIN_FILENO) 2574- _setmode(STDIN_FILENO, O_BINARY); 2575-#endif 2576- if (inname != NULL) { 2577- int flags = O_RDONLY|O_BINARY|O_NONBLOCK|O_CLOEXEC; 2578- errno = 0; 2579- if ((fd = open(inname, flags)) < 0) { 2580- okstat = stat(inname, &sb) == 0; 2581-#ifdef WIN32 2582- /* 2583- * Can't stat, can't open. It may have been opened in 2584- * fsmagic, so if the user doesn't have read permission, 2585- * allow it to say so; otherwise an error was probably 2586- * displayed in fsmagic. 2587- */ 2588- if (!okstat && errno == EACCES) { 2589- sb.st_mode = S_IFBLK; 2590- okstat = 1; 2591- } 2592-#endif 2593- if (okstat && 2594- unreadable_info(ms, sb.st_mode, inname) == -1) 2595+ errno = 0; 2596+ 2597+ if (inname && !stream) { 2598+ no_in_stream = 1; 2599+ stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL); 2600+ if (!stream) { 2601+ if (unreadable_info(ms, sb.st_mode, inname) == -1) 2602 goto done; 2603- rv = 0; 2604+ rv = -1; 2605 goto done; 2606 } 2607-#if O_CLOEXEC == 0 && defined(F_SETFD) 2608- (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 2609-#endif 2610 } 2611 2612- if (fd != -1) { 2613- okstat = fstat(fd, &sb) == 0; 2614- if (okstat && S_ISFIFO(sb.st_mode)) 2615- ispipe = 1; 2616- if (inname == NULL) 2617- pos = lseek(fd, CAST(off_t, 0), SEEK_CUR); 2618+ php_stream_statbuf ssb; 2619+ if (php_stream_stat(stream, &ssb) < 0) { 2620+ if (ms->flags & MAGIC_ERROR) { 2621+ file_error(ms, errno, "cannot stat `%s'", inname); 2622+ rv = -1; 2623+ goto done; 2624+ } 2625 } 2626+ memcpy(&sb, &ssb.sb, sizeof(zend_stat_t)); 2627 2628 /* 2629 * try looking at the first ms->bytes_max bytes 2630 */ 2631- if (ispipe) { 2632- if (fd != -1) { 2633- ssize_t r = 0; 2634- 2635- while ((r = sread(fd, RCAST(void *, &buf[nbytes]), 2636- CAST(size_t, ms->bytes_max - nbytes), 1)) > 0) { 2637- nbytes += r; 2638- if (r < PIPE_BUF) break; 2639- } 2640- } 2641- 2642- if (nbytes == 0 && inname) { 2643- /* We can not read it, but we were able to stat it. */ 2644- if (unreadable_info(ms, sb.st_mode, inname) == -1) 2645- goto done; 2646- rv = 0; 2647- goto done; 2648- } 2649- 2650- } else if (fd != -1) { 2651- /* Windows refuses to read from a big console buffer. */ 2652- size_t howmany = 2653-#ifdef WIN32 2654- _isatty(fd) ? 8 * 1024 : 2655-#endif 2656- ms->bytes_max; 2657- if ((nbytes = read(fd, RCAST(void *, buf), howmany)) == -1) { 2658- if (inname == NULL && fd != STDIN_FILENO) 2659- file_error(ms, errno, "cannot read fd %d", fd); 2660- else 2661- file_error(ms, errno, "cannot read `%s'", 2662- inname == NULL ? "/dev/stdin" : inname); 2663- goto done; 2664- } 2665+ if ((nbytes = php_stream_read(stream, (char *)buf, ms->bytes_max - nbytes)) < 0) { 2666+ file_error(ms, errno, "cannot read `%s'", inname); 2667+ goto done; 2668 } 2669 2670 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 2671- if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf, CAST(size_t, nbytes)) == -1) 2672+ if (file_buffer(ms, stream, &sb, inname, buf, CAST(size_t, nbytes)) == -1) 2673 goto done; 2674 rv = 0; 2675 done: 2676- free(buf); 2677- if (fd != -1) { 2678- if (pos != CAST(off_t, -1)) 2679- (void)lseek(fd, pos, SEEK_SET); 2680- close_and_restore(ms, inname, fd, &sb); 2681+ efree(buf); 2682+ 2683+ if (no_in_stream && stream) { 2684+ php_stream_close(stream); 2685 } 2686 out: 2687 return rv == 0 ? file_getbuffer(ms) : NULL; 2688@@ -556,7 +279,7 @@ 2689 * The main work is done here! 2690 * We have the file name and/or the data buffer to be identified. 2691 */ 2692- if (file_buffer(ms, -1, NULL, NULL, buf, nb) == -1) { 2693+ if (file_buffer(ms, NULL, NULL, NULL, buf, nb) == -1) { 2694 return NULL; 2695 } 2696 return file_getbuffer(ms); 2697diff -u libmagic.orig/magic.h libmagic/magic.h 2698--- libmagic.orig/magic.h 2024-06-09 17:55:50.382419678 +0200 2699+++ libmagic/magic.h 2024-06-09 00:31:40.347830761 +0200 2700@@ -47,8 +47,6 @@ 2701 * extensions */ 2702 #define MAGIC_COMPRESS_TRANSP 0x2000000 /* Check inside compressed files 2703 * but not report compression */ 2704-#define MAGIC_NO_COMPRESS_FORK 0x4000000 /* Don't allow decompression that 2705- * needs to fork */ 2706 #define MAGIC_NODESC (MAGIC_EXTENSION|MAGIC_MIME|MAGIC_APPLE) 2707 2708 #define MAGIC_NO_CHECK_COMPRESS 0x0001000 /* Don't check for compressed files */ 2709@@ -77,7 +75,7 @@ 2710 MAGIC_NO_CHECK_TOKENS | \ 2711 MAGIC_NO_CHECK_ENCODING | \ 2712 MAGIC_NO_CHECK_JSON | \ 2713- MAGIC_NO_CHECK_SIMH | \ 2714+ MAGIC_NO_CHECK_SIMH | \ 2715 0 \ 2716 ) 2717 2718@@ -101,11 +99,11 @@ 2719 b\20no_check_elf\0\ 2720 b\21no_check_text\0\ 2721 b\22no_check_cdf\0\ 2722-b\23no_check_csv\0\ 2723+b\23no_check_reserved0\0\ 2724 b\24no_check_tokens\0\ 2725 b\25no_check_encoding\0\ 2726 b\26no_check_json\0\ 2727-b\27no_check_simh\0\ 2728+b\27no_check_reserved2\0\ 2729 b\30extension\0\ 2730 b\31transp_compression\0\ 2731 " 2732@@ -130,6 +128,7 @@ 2733 2734 const char *magic_getpath(const char *, int); 2735 const char *magic_file(magic_t, const char *); 2736+const char *magic_stream(magic_t, php_stream *); 2737 const char *magic_descriptor(magic_t, int); 2738 const char *magic_buffer(magic_t, const void *, size_t); 2739 2740@@ -154,7 +153,8 @@ 2741 #define MAGIC_PARAM_REGEX_MAX 5 2742 #define MAGIC_PARAM_BYTES_MAX 6 2743 #define MAGIC_PARAM_ENCODING_MAX 7 2744-#define MAGIC_PARAM_ELF_SHSIZE_MAX 8 2745+#define MAGIC_PARAM_ELF_SHSIZE_MAX 8 2746+#define MAGIC_PARAM_MAGWARN_MAX 9 2747 2748 int magic_setparam(magic_t, int, const void *); 2749 int magic_getparam(magic_t, int, void *); 2750diff -u libmagic.orig/print.c libmagic/print.c 2751--- libmagic.orig/print.c 2023-07-27 20:04:45.000000000 +0200 2752+++ libmagic/print.c 2024-06-09 00:31:40.347830761 +0200 2753@@ -73,7 +73,7 @@ 2754 if (m->mask_op & FILE_OPINVERSE) 2755 (void) fputc('~', stderr); 2756 2757- if (IS_STRING(m->type)) { 2758+ if (IS_LIBMAGIC_STRING(m->type)) { 2759 if (m->str_flags) { 2760 (void) fputc('/', stderr); 2761 if (m->str_flags & STRING_COMPACT_WHITESPACE) 2762@@ -246,18 +246,18 @@ 2763 file_magwarn(struct magic_set *ms, const char *f, ...) 2764 { 2765 va_list va; 2766+ char *expanded_format = NULL; 2767+ int expanded_len; 2768 2769- /* cuz we use stdout for most, stderr here */ 2770- (void) fflush(stdout); 2771- 2772- if (ms && ms->file) 2773- (void) fprintf(stderr, "%s, %lu: ", ms->file, 2774- CAST(unsigned long, ms->line)); 2775- (void) fprintf(stderr, "Warning: "); 2776 va_start(va, f); 2777- (void) vfprintf(stderr, f, va); 2778+ expanded_len = vasprintf(&expanded_format, f, va); 2779 va_end(va); 2780- (void) fputc('\n', stderr); 2781+ 2782+ if (expanded_len >= 0 && expanded_format) { 2783+ php_error_docref(NULL, E_WARNING, "%s", expanded_format); 2784+ 2785+ free(expanded_format); 2786+ } 2787 } 2788 2789 file_protected const char * 2790@@ -289,13 +289,13 @@ 2791 goto out; 2792 2793 if (flags & FILE_T_LOCAL) { 2794- tm = localtime_r(&t, &tmz); 2795+ tm = php_localtime_r(&t, &tmz); 2796 } else { 2797- tm = gmtime_r(&t, &tmz); 2798+ tm = php_gmtime_r(&t, &tmz); 2799 } 2800 if (tm == NULL) 2801 goto out; 2802- pp = asctime_r(tm, buf); 2803+ pp = php_asctime_r(tm, buf); 2804 2805 if (pp == NULL) 2806 goto out; 2807diff -u libmagic.orig/readcdf.c libmagic/readcdf.c 2808--- libmagic.orig/readcdf.c 2023-02-09 18:43:53.000000000 +0100 2809+++ libmagic/readcdf.c 2024-06-09 00:31:40.347830761 +0200 2810@@ -31,7 +31,9 @@ 2811 2812 #include <assert.h> 2813 #include <stdlib.h> 2814+#ifdef HAVE_UNISTD_H 2815 #include <unistd.h> 2816+#endif 2817 #include <string.h> 2818 #include <time.h> 2819 #include <ctype.h> 2820@@ -100,10 +102,6 @@ 2821 if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) 2822 return cv[i].mime; 2823 } 2824-#ifdef CDF_DEBUG 2825- fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], 2826- clsid[1]); 2827-#endif 2828 return NULL; 2829 } 2830 2831@@ -112,35 +110,24 @@ 2832 { 2833 size_t i; 2834 const char *rv = NULL; 2835-#ifdef USE_C_LOCALE 2836- locale_t old_lc_ctype, c_lc_ctype; 2837+ char *vbuf_lower; 2838 2839- c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 2840- assert(c_lc_ctype != NULL); 2841- old_lc_ctype = uselocale(c_lc_ctype); 2842- assert(old_lc_ctype != NULL); 2843-#else 2844- char *old_lc_ctype = setlocale(LC_CTYPE, NULL); 2845- assert(old_lc_ctype != NULL); 2846- old_lc_ctype = strdup(old_lc_ctype); 2847- assert(old_lc_ctype != NULL); 2848- (void)setlocale(LC_CTYPE, "C"); 2849-#endif 2850- for (i = 0; nv[i].pattern != NULL; i++) 2851- if (strcasestr(vbuf, nv[i].pattern) != NULL) { 2852+ vbuf_lower = zend_str_tolower_dup(vbuf, strlen(vbuf)); 2853+ for (i = 0; nv[i].pattern != NULL; i++) { 2854+ char *pattern_lower; 2855+ int found; 2856+ 2857+ pattern_lower = zend_str_tolower_dup(nv[i].pattern, strlen(nv[i].pattern)); 2858+ found = (strstr(vbuf_lower, pattern_lower) != NULL); 2859+ efree(pattern_lower); 2860+ 2861+ if (found) { 2862 rv = nv[i].mime; 2863 break; 2864 } 2865-#ifdef CDF_DEBUG 2866- fprintf(stderr, "unknown app %s\n", vbuf); 2867-#endif 2868-#ifdef USE_C_LOCALE 2869- (void)uselocale(old_lc_ctype); 2870- freelocale(c_lc_ctype); 2871-#else 2872- (void)setlocale(LC_CTYPE, old_lc_ctype); 2873- free(old_lc_ctype); 2874-#endif 2875+ } 2876+ 2877+ efree(vbuf_lower); 2878 return rv; 2879 } 2880 2881@@ -156,6 +143,8 @@ 2882 const char *s, *e; 2883 int len; 2884 2885+ memset(&ts, 0, sizeof(ts)); 2886+ 2887 if (!NOTMIME(ms) && root_storage) 2888 str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 2889 clsid2mime); 2890@@ -282,10 +271,10 @@ 2891 if (file_printf(ms, "%s%s", 2892 cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), 2893 i == cat->cat_num - 1 ? "]" : ", ") == -1) { 2894- free(cat); 2895+ efree(cat); 2896 return -1; 2897 } 2898- free(cat); 2899+ efree(cat); 2900 } else if (ms->flags & MAGIC_MIME_TYPE) { 2901 if (file_printf(ms, "application/CDFV2") == -1) 2902 return -1; 2903@@ -346,7 +335,7 @@ 2904 } 2905 2906 m = cdf_file_property_info(ms, info, count, root_storage); 2907- free(info); 2908+ efree(info); 2909 2910 return m == -1 ? -2 : m; 2911 } 2912@@ -656,11 +645,11 @@ 2913 cdf_zero_stream(&scn); 2914 cdf_zero_stream(&sst); 2915 out3: 2916- free(dir.dir_tab); 2917+ efree(dir.dir_tab); 2918 out2: 2919- free(ssat.sat_tab); 2920+ efree(ssat.sat_tab); 2921 out1: 2922- free(sat.sat_tab); 2923+ efree(sat.sat_tab); 2924 out0: 2925 /* If we handled it already, return */ 2926 if (i != -1) 2927diff -u libmagic.orig/softmagic.c libmagic/softmagic.c 2928--- libmagic.orig/softmagic.c 2023-07-27 21:40:12.000000000 +0200 2929+++ libmagic/softmagic.c 2024-06-09 00:31:40.347830761 +0200 2930@@ -45,7 +45,7 @@ 2931 #include <time.h> 2932 #include "der.h" 2933 2934-file_private int match(struct magic_set *, struct magic *, file_regex_t **, size_t, 2935+file_private int match(struct magic_set *, struct magic *, size_t, 2936 const struct buffer *, size_t, int, int, int, uint16_t *, 2937 uint16_t *, int *, int *, int *, int *, int *); 2938 file_private int mget(struct magic_set *, struct magic *, const struct buffer *, 2939@@ -54,7 +54,7 @@ 2940 uint16_t *, int *, int *, int *, int *, int *); 2941 file_private int msetoffset(struct magic_set *, struct magic *, struct buffer *, 2942 const struct buffer *, size_t, unsigned int); 2943-file_private int magiccheck(struct magic_set *, struct magic *, file_regex_t **); 2944+file_private int magiccheck(struct magic_set *, struct magic *); 2945 file_private int mprint(struct magic_set *, struct magic *); 2946 file_private int moffset(struct magic_set *, struct magic *, const struct buffer *, 2947 int32_t *); 2948@@ -133,7 +133,7 @@ 2949 } 2950 2951 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) { 2952- int ret = match(ms, ml->magic, ml->magic_rxcomp, ml->nmagic, b, 2953+ int ret = match(ms, ml->magic, ml->nmagic, b, 2954 0, mode, text, 0, indir_count, name_count, 2955 &printed_something, &need_separator, &firstline, 2956 NULL, NULL); 2957@@ -153,8 +153,8 @@ 2958 return rv; 2959 } 2960 2961-#define FILE_FMTDEBUG 2962-#ifdef FILE_FMTDEBUG 2963+ 2964+#if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK) 2965 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 2966 2967 file_private const char * __attribute__((__format_arg__(3))) 2968@@ -173,10 +173,14 @@ 2969 " with `%s'", file, line, desc, def); 2970 return ptr; 2971 } 2972-#else 2973+#elif defined(HAVE_FMTCHECK) 2974 #define F(a, b, c) fmtcheck((b), (c)) 2975+#else 2976+#define F(a, b, c) ((b)) 2977 #endif 2978 2979+/* NOTE this function has been kept an the state of 5.39 for BC. Observe 2980+ * further as the upgrade to 5.41 or above goes. */ 2981 /* 2982 * Go through the whole list, stopping if you find a match. Process all 2983 * the continuations of that match before returning. 2984@@ -205,7 +209,7 @@ 2985 * so that higher-level continuations are processed. 2986 */ 2987 file_private int 2988-match(struct magic_set *ms, struct magic *magic, file_regex_t **magic_rxcomp, 2989+match(struct magic_set *ms, struct magic *magic, 2990 size_t nmagic, const struct buffer *b, size_t offset, int mode, int text, 2991 int flip, uint16_t *indir_count, uint16_t *name_count, 2992 int *printed_something, int *need_separator, int *firstline, 2993@@ -233,10 +237,9 @@ 2994 for (magindex = 0; magindex < nmagic; magindex++) { 2995 int flush = 0; 2996 struct magic *m = &magic[magindex]; 2997- file_regex_t **m_rxcomp = &magic_rxcomp[magindex]; 2998 2999 if (m->type != FILE_NAME) 3000- if ((IS_STRING(m->type) && 3001+ if ((IS_LIBMAGIC_STRING(m->type) && 3002 #define FLT (STRING_BINTEST | STRING_TEXTTEST) 3003 ((text && (m->str_flags & FLT) == STRING_BINTEST) || 3004 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 3005@@ -272,7 +275,7 @@ 3006 *returnval = 1; 3007 } 3008 3009- switch (magiccheck(ms, m, m_rxcomp)) { 3010+ switch (magiccheck(ms, m)) { 3011 case -1: 3012 return -1; 3013 case 0: 3014@@ -334,7 +337,6 @@ 3015 while (magindex + 1 < nmagic && 3016 magic[magindex + 1].cont_level != 0) { 3017 m = &magic[++magindex]; 3018- m_rxcomp = &magic_rxcomp[magindex]; 3019 ms->line = m->lineno; /* for messages */ 3020 3021 if (cont_level < m->cont_level) 3022@@ -388,7 +390,7 @@ 3023 break; 3024 } 3025 3026- switch (flush ? 1 : magiccheck(ms, m, m_rxcomp)) { 3027+ switch (flush ? 1 : magiccheck(ms, m)) { 3028 case -1: 3029 return -1; 3030 case 0: 3031@@ -487,19 +489,25 @@ 3032 file_private int 3033 check_fmt(struct magic_set *ms, const char *fmt) 3034 { 3035- file_regex_t rx; 3036- int rc, rv = -1; 3037- const char* pat = "%[-0-9\\.]*s"; 3038+ pcre_cache_entry *pce; 3039+ int rv = -1; 3040+ zend_string *pattern; 3041 3042 if (strchr(fmt, '%') == NULL) 3043 return 0; 3044 3045- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED|REG_NOSUB); 3046- if (rc == 0) { 3047- rc = file_regexec(ms, &rx, fmt, 0, 0, 0); 3048- rv = !rc; 3049+ pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0); 3050+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 3051+ rv = -1; 3052+ } else { 3053+ pcre2_code *re = php_pcre_pce_re(pce); 3054+ pcre2_match_data *match_data = php_pcre_create_match_data(0, re); 3055+ if (match_data) { 3056+ rv = pcre2_match(re, (PCRE2_SPTR)fmt, strlen(fmt), 0, 0, match_data, php_pcre_mctx()) > 0; 3057+ php_pcre_free_match_data(match_data); 3058+ } 3059 } 3060- file_regfree(&rx); 3061+ zend_string_release_ex(pattern, 0); 3062 return rv; 3063 } 3064 3065@@ -517,7 +525,7 @@ 3066 3067 for (len = 0; len < n && str[len]; len++) 3068 continue; 3069- if ((copy = CAST(char *, malloc(len + 1))) == NULL) 3070+ if ((copy = CAST(char *, emalloc(len + 1))) == NULL) 3071 return NULL; 3072 (void)memcpy(copy, str, len); 3073 copy[len] = '\0'; 3074@@ -767,7 +775,7 @@ 3075 char *cp, *scp; 3076 int rval; 3077 3078- cp = strndup(RCAST(const char *, ms->search.s), 3079+ cp = estrndup(RCAST(const char *, ms->search.s), 3080 ms->search.rm_len); 3081 if (cp == NULL) { 3082 file_oomem(ms, ms->search.rm_len); 3083@@ -777,7 +785,7 @@ 3084 3085 rval = file_printf(ms, F(ms, desc, "%s"), file_printable(ms, 3086 sbuf, sizeof(sbuf), scp, ms->search.rm_len)); 3087- free(cp); 3088+ efree(cp); 3089 3090 if (rval == -1) 3091 return -1; 3092@@ -1565,7 +1573,7 @@ 3093 size_t len; 3094 *c = ms->c; 3095 len = c->len * sizeof(*c->li); 3096- ms->c.li = CAST(struct level_info *, malloc(len)); 3097+ ms->c.li = CAST(struct level_info *, emalloc(len)); 3098 if (ms->c.li == NULL) { 3099 ms->c = *c; 3100 return -1; 3101@@ -1577,7 +1585,7 @@ 3102 file_private void 3103 restore_cont(struct magic_set *ms, struct cont *c) 3104 { 3105- free(ms->c.li); 3106+ efree(ms->c.li); 3107 ms->c = *c; 3108 } 3109 3110@@ -1894,7 +1902,7 @@ 3111 for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0]; 3112 mlp = mlp->next) 3113 { 3114- if ((rv = match(ms, mlp->magic, mlp->magic_rxcomp, 3115+ if ((rv = match(ms, mlp->magic, 3116 mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count, 3117 name_count, printed_something, need_separator, 3118 firstline, NULL, NULL)) != 0) 3119@@ -1913,15 +1921,15 @@ 3120 if ((ms->flags & MAGIC_NODESC) == 0 && 3121 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) 3122 { 3123- free(rbuf); 3124+ if (rbuf) efree(rbuf); 3125 return -1; 3126 } 3127 if (file_printf(ms, "%s", rbuf) == -1) { 3128- free(rbuf); 3129+ if (rbuf) efree(rbuf); 3130 return -1; 3131 } 3132 } 3133- free(rbuf); 3134+ if (rbuf) efree(rbuf); 3135 return rv; 3136 3137 case FILE_USE: 3138@@ -1948,7 +1956,7 @@ 3139 nfound_match = 0; 3140 (*name_count)++; 3141 eoffset = ms->eoffset; 3142- rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b, 3143+ rv = match(ms, ml.magic, ml.nmagic, b, 3144 offset + o, mode, text, flip, indir_count, name_count, 3145 printed_something, need_separator, firstline, returnval, 3146 &nfound_match); 3147@@ -2027,11 +2035,13 @@ 3148 } 3149 else if ((flags & STRING_COMPACT_WHITESPACE) && 3150 isspace(*a)) { 3151+ /* XXX Dirty. The data and the pattern is what is causing this. 3152+ Revert _i for the next port and see if it still matters. */ 3153+ uint32_t _i = 0; 3154 a++; 3155- if (isspace(*b)) { 3156- b++; 3157+ if (isspace(*b++)) { 3158 if (!isspace(*a)) 3159- while (b < eb && isspace(*b)) 3160+ while (EXPECTED(_i++ < 2048) && b < eb && isspace(*b)) 3161 b++; 3162 } 3163 else { 3164@@ -2071,29 +2081,8 @@ 3165 return file_strncmp(a, b, len, maxlen, flags); 3166 } 3167 3168-file_private file_regex_t * 3169-alloc_regex(struct magic_set *ms, struct magic *m) 3170-{ 3171- int rc; 3172- file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx))); 3173- 3174- if (rx == NULL) { 3175- file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT 3176- "u bytes", sizeof(*rx)); 3177- return NULL; 3178- } 3179- 3180- rc = file_regcomp(ms, rx, m->value.s, REG_EXTENDED | REG_NEWLINE | 3181- ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 3182- if (rc == 0) 3183- return rx; 3184- 3185- free(rx); 3186- return NULL; 3187-} 3188- 3189 file_private int 3190-magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache) 3191+magiccheck(struct magic_set *ms, struct magic *m) 3192 { 3193 uint64_t l = m->value.q; 3194 uint64_t v; 3195@@ -2247,28 +2236,14 @@ 3196 slen = MIN(m->vallen, sizeof(m->value.s)); 3197 l = 0; 3198 v = 0; 3199- if ((ms->flags & MAGIC_DEBUG) != 0) { 3200- size_t xlen = ms->search.s_len > 100 ? 100 3201- : ms->search.s_len; 3202- 3203- fprintf(stderr, "search: ["); 3204- file_showstr(stderr, ms->search.s, xlen); 3205- fprintf(stderr, "%s] for [", ms->search.s_len == xlen 3206- ? "" : "..."); 3207- file_showstr(stderr, m->value.s, slen); 3208- } 3209 #ifdef HAVE_MEMMEM 3210 if (slen > 0 && m->str_flags == 0) { 3211 const char *found; 3212 idx = m->str_range + slen; 3213 if (m->str_range == 0 || ms->search.s_len < idx) 3214 idx = ms->search.s_len; 3215- found = CAST(const char *, memmem(ms->search.s, idx, 3216- m->value.s, slen)); 3217- if ((ms->flags & MAGIC_DEBUG) != 0) { 3218- fprintf(stderr, "] %sfound\n", 3219- found ? "" : "not "); 3220- } 3221+ found = CAST(const char *, php_memnstr(ms->search.s, 3222+ m->value.s, slen, ms->search.s + idx)); 3223 if (!found) { 3224 v = 1; 3225 break; 3226@@ -2294,61 +2269,79 @@ 3227 break; 3228 } 3229 } 3230- if ((ms->flags & MAGIC_DEBUG) != 0) { 3231- fprintf(stderr, "] %sfound\n", v == 0 ? "" : "not "); 3232- } 3233 break; 3234 } 3235 case FILE_REGEX: { 3236- int rc; 3237- file_regex_t *rx = *m_cache; 3238- const char *search; 3239- regmatch_t pmatch; 3240- size_t slen = ms->search.s_len; 3241- char *copy; 3242+ zend_string *pattern; 3243+ uint32_t options = 0; 3244+ pcre_cache_entry *pce; 3245 3246- if (ms->search.s == NULL) 3247- return 0; 3248+ options |= PCRE2_MULTILINE; 3249 3250- if (rx == NULL) { 3251- rx = *m_cache = alloc_regex(ms, m); 3252- if (rx == NULL) 3253- return -1; 3254+ if (m->str_flags & STRING_IGNORE_CASE) { 3255+ options |= PCRE2_CASELESS; 3256 } 3257- l = 0; 3258- if (slen != 0) { 3259- copy = CAST(char *, malloc(slen)); 3260- if (copy == NULL) { 3261- file_error(ms, errno, 3262- "can't allocate %" SIZE_T_FORMAT "u bytes", 3263- slen); 3264- return -1; 3265- } 3266- memcpy(copy, ms->search.s, slen); 3267- copy[--slen] = '\0'; 3268- search = copy; 3269- } else { 3270- search = CCAST(char *, ""); 3271- copy = NULL; 3272- } 3273- rc = file_regexec(ms, rx, RCAST(const char *, search), 3274- 1, &pmatch, 0); 3275- free(copy); 3276- switch (rc) { 3277- case 0: 3278- ms->search.s += CAST(int, pmatch.rm_so); 3279- ms->search.offset += CAST(size_t, pmatch.rm_so); 3280- ms->search.rm_len = CAST(size_t, 3281- pmatch.rm_eo - pmatch.rm_so); 3282- v = 0; 3283- break; 3284 3285- case REG_NOMATCH: 3286- v = 1; 3287- break; 3288+ pattern = convert_libmagic_pattern((char *)m->value.s, m->vallen, options); 3289 3290- default: 3291+ l = v = 0; 3292+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 3293+ zend_string_release(pattern); 3294 return -1; 3295+ } else { 3296+ /* pce now contains the compiled regex */ 3297+ zval retval; 3298+ zval subpats; 3299+ zend_string *haystack; 3300+ 3301+ ZVAL_NULL(&retval); 3302+ ZVAL_NULL(&subpats); 3303+ 3304+ /* Cut the search len from haystack, equals to REG_STARTEND */ 3305+ haystack = zend_string_init(ms->search.s, ms->search.s_len, 0); 3306+ 3307+ /* match v = 0, no match v = 1 */ 3308+ php_pcre_match_impl(pce, haystack, &retval, &subpats, 0, PREG_OFFSET_CAPTURE, 0); 3309+ /* Free haystack */ 3310+ zend_string_release(haystack); 3311+ 3312+ if (Z_LVAL(retval) < 0) { 3313+ zval_ptr_dtor(&subpats); 3314+ zend_string_release(pattern); 3315+ return -1; 3316+ } else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) { 3317+ /* Need to fetch global match which equals pmatch[0] */ 3318+ zval *pzval; 3319+ HashTable *ht = Z_ARRVAL(subpats); 3320+ if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) { 3321+ /* If everything goes according to the master plan 3322+ tmpcopy now contains two elements: 3323+ 0 = the match 3324+ 1 = starting position of the match */ 3325+ zval *match, *offset; 3326+ if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) && 3327+ (offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) { 3328+ if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) { 3329+ goto error_out; 3330+ } 3331+ ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */ 3332+ ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */ 3333+ ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */; 3334+ v = 0; 3335+ } else { 3336+ goto error_out; 3337+ } 3338+ } else { 3339+error_out: 3340+ zval_ptr_dtor(&subpats); 3341+ zend_string_release(pattern); 3342+ return -1; 3343+ } 3344+ } else { 3345+ v = 1; 3346+ } 3347+ zval_ptr_dtor(&subpats); 3348+ zend_string_release(pattern); 3349 } 3350 break; 3351 } 3352