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