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