xref: /PHP-8.4/ext/fileinfo/libmagic.patch (revision d3901b8c)
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