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