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