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