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