xref: /freebsd/contrib/file/src/funcs.c (revision 898496ee09ed2b7d25f6807edc4515628196ec0a)
1b6cee71dSXin LI /*
2b6cee71dSXin LI  * Copyright (c) Christos Zoulas 2003.
3b6cee71dSXin LI  * All Rights Reserved.
4b6cee71dSXin LI  *
5b6cee71dSXin LI  * Redistribution and use in source and binary forms, with or without
6b6cee71dSXin LI  * modification, are permitted provided that the following conditions
7b6cee71dSXin LI  * are met:
8b6cee71dSXin LI  * 1. Redistributions of source code must retain the above copyright
9b6cee71dSXin LI  *    notice immediately at the beginning of the file, without modification,
10b6cee71dSXin LI  *    this list of conditions, and the following disclaimer.
11b6cee71dSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
12b6cee71dSXin LI  *    notice, this list of conditions and the following disclaimer in the
13b6cee71dSXin LI  *    documentation and/or other materials provided with the distribution.
14b6cee71dSXin LI  *
15b6cee71dSXin LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16b6cee71dSXin LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17b6cee71dSXin LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18b6cee71dSXin LI  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19b6cee71dSXin LI  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20b6cee71dSXin LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21b6cee71dSXin LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22b6cee71dSXin LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23b6cee71dSXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24b6cee71dSXin LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25b6cee71dSXin LI  * SUCH DAMAGE.
26b6cee71dSXin LI  */
27b6cee71dSXin LI #include "file.h"
28b6cee71dSXin LI 
29b6cee71dSXin LI #ifndef	lint
30*898496eeSXin LI FILE_RCSID("@(#)$File: funcs.c,v 1.140 2023/05/21 17:08:34 christos Exp $")
31b6cee71dSXin LI #endif	/* lint */
32b6cee71dSXin LI 
33b6cee71dSXin LI #include "magic.h"
34b6cee71dSXin LI #include <assert.h>
35b6cee71dSXin LI #include <stdarg.h>
36b6cee71dSXin LI #include <stdlib.h>
37b6cee71dSXin LI #include <string.h>
38b6cee71dSXin LI #include <ctype.h>
3943a5ec4eSXin LI #ifdef HAVE_UNISTD_H
4043a5ec4eSXin LI #include <unistd.h>	/* for pipe2() */
4143a5ec4eSXin LI #endif
42b6cee71dSXin LI #if defined(HAVE_WCHAR_H)
43b6cee71dSXin LI #include <wchar.h>
44b6cee71dSXin LI #endif
45b6cee71dSXin LI #if defined(HAVE_WCTYPE_H)
46b6cee71dSXin LI #include <wctype.h>
47b6cee71dSXin LI #endif
48b6cee71dSXin LI #include <limits.h>
49b6cee71dSXin LI 
50b6cee71dSXin LI #ifndef SIZE_MAX
51b6cee71dSXin LI #define SIZE_MAX	((size_t)~0)
52b6cee71dSXin LI #endif
53b6cee71dSXin LI 
54*898496eeSXin LI file_protected char *
file_copystr(char * buf,size_t blen,size_t width,const char * str)552726a701SXin LI file_copystr(char *buf, size_t blen, size_t width, const char *str)
562726a701SXin LI {
57a4d6d3b8SXin LI 	if (blen == 0)
58a4d6d3b8SXin LI 		return buf;
59a4d6d3b8SXin LI 	if (width >= blen)
60a4d6d3b8SXin LI 		width = blen - 1;
61a4d6d3b8SXin LI 	memcpy(buf, str, width);
62a4d6d3b8SXin LI 	buf[width] = '\0';
632726a701SXin LI 	return buf;
642726a701SXin LI }
652726a701SXin LI 
66*898496eeSXin LI file_private void
file_clearbuf(struct magic_set * ms)672726a701SXin LI file_clearbuf(struct magic_set *ms)
682726a701SXin LI {
692726a701SXin LI 	free(ms->o.buf);
702726a701SXin LI 	ms->o.buf = NULL;
712726a701SXin LI 	ms->o.blen = 0;
722726a701SXin LI }
732726a701SXin LI 
74*898496eeSXin LI file_private int
file_checkfield(char * msg,size_t mlen,const char * what,const char ** pp)752726a701SXin LI file_checkfield(char *msg, size_t mlen, const char *what, const char **pp)
762726a701SXin LI {
772726a701SXin LI 	const char *p = *pp;
782726a701SXin LI 	int fw = 0;
792726a701SXin LI 
802726a701SXin LI 	while (*p && isdigit((unsigned char)*p))
812726a701SXin LI 		fw = fw * 10 + (*p++ - '0');
822726a701SXin LI 
832726a701SXin LI 	*pp = p;
842726a701SXin LI 
852726a701SXin LI 	if (fw < 1024)
862726a701SXin LI 		return 1;
872726a701SXin LI 	if (msg)
882726a701SXin LI 		snprintf(msg, mlen, "field %s too large: %d", what, fw);
892726a701SXin LI 
902726a701SXin LI 	return 0;
912726a701SXin LI }
922726a701SXin LI 
93*898496eeSXin LI file_protected int
file_checkfmt(char * msg,size_t mlen,const char * fmt)942726a701SXin LI file_checkfmt(char *msg, size_t mlen, const char *fmt)
952726a701SXin LI {
96a4d6d3b8SXin LI 	const char *p;
97a4d6d3b8SXin LI 	for (p = fmt; *p; p++) {
982726a701SXin LI 		if (*p != '%')
992726a701SXin LI 			continue;
1002726a701SXin LI 		if (*++p == '%')
1012726a701SXin LI 			continue;
1022726a701SXin LI 		// Skip uninteresting.
10343a5ec4eSXin LI 		while (strchr("#0.'+- ", *p) != NULL)
1042726a701SXin LI 			p++;
1052726a701SXin LI 		if (*p == '*') {
1062726a701SXin LI 			if (msg)
1072726a701SXin LI 				snprintf(msg, mlen, "* not allowed in format");
1082726a701SXin LI 			return -1;
1092726a701SXin LI 		}
1102726a701SXin LI 
1112726a701SXin LI 		if (!file_checkfield(msg, mlen, "width", &p))
1122726a701SXin LI 			return -1;
1132726a701SXin LI 
1142726a701SXin LI 		if (*p == '.') {
1152726a701SXin LI 			p++;
1162726a701SXin LI 			if (!file_checkfield(msg, mlen, "precision", &p))
1172726a701SXin LI 				return -1;
1182726a701SXin LI 		}
1192726a701SXin LI 
1202726a701SXin LI 		if (!isalpha((unsigned char)*p)) {
1212726a701SXin LI 			if (msg)
1222726a701SXin LI 				snprintf(msg, mlen, "bad format char: %c", *p);
1232726a701SXin LI 			return -1;
1242726a701SXin LI 		}
1252726a701SXin LI 	}
1262726a701SXin LI 	return 0;
1272726a701SXin LI }
1282726a701SXin LI 
129b6cee71dSXin LI /*
130b6cee71dSXin LI  * Like printf, only we append to a buffer.
131b6cee71dSXin LI  */
132*898496eeSXin LI file_protected int
file_vprintf(struct magic_set * ms,const char * fmt,va_list ap)133b6cee71dSXin LI file_vprintf(struct magic_set *ms, const char *fmt, va_list ap)
134b6cee71dSXin LI {
135b6cee71dSXin LI 	int len;
136b6cee71dSXin LI 	char *buf, *newstr;
1372726a701SXin LI 	char tbuf[1024];
138b6cee71dSXin LI 
139b6cee71dSXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
140b6cee71dSXin LI 		return 0;
1412726a701SXin LI 
1422726a701SXin LI 	if (file_checkfmt(tbuf, sizeof(tbuf), fmt)) {
1432726a701SXin LI 		file_clearbuf(ms);
1442726a701SXin LI 		file_error(ms, 0, "Bad magic format `%s' (%s)", fmt, tbuf);
1452726a701SXin LI 		return -1;
1462726a701SXin LI 	}
1472726a701SXin LI 
148b6cee71dSXin LI 	len = vasprintf(&buf, fmt, ap);
1492726a701SXin LI 	if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) {
1502726a701SXin LI 		size_t blen = ms->o.blen;
1512726a701SXin LI 		free(buf);
1522726a701SXin LI 		file_clearbuf(ms);
153a4d6d3b8SXin LI 		file_error(ms, 0, "Output buffer space exceeded %d+%"
154a4d6d3b8SXin LI 		    SIZE_T_FORMAT "u", len, blen);
1552726a701SXin LI 		return -1;
1562726a701SXin LI 	}
157b6cee71dSXin LI 
158b6cee71dSXin LI 	if (ms->o.buf != NULL) {
159b6cee71dSXin LI 		len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
160b6cee71dSXin LI 		free(buf);
161b6cee71dSXin LI 		if (len < 0)
162b6cee71dSXin LI 			goto out;
163b6cee71dSXin LI 		free(ms->o.buf);
164b6cee71dSXin LI 		buf = newstr;
165b6cee71dSXin LI 	}
166b6cee71dSXin LI 	ms->o.buf = buf;
1672726a701SXin LI 	ms->o.blen = len;
168b6cee71dSXin LI 	return 0;
169b6cee71dSXin LI out:
1702726a701SXin LI 	file_clearbuf(ms);
1712726a701SXin LI 	file_error(ms, errno, "vasprintf failed");
172b6cee71dSXin LI 	return -1;
173b6cee71dSXin LI }
174b6cee71dSXin LI 
175*898496eeSXin LI file_protected int
file_printf(struct magic_set * ms,const char * fmt,...)176b6cee71dSXin LI file_printf(struct magic_set *ms, const char *fmt, ...)
177b6cee71dSXin LI {
178b6cee71dSXin LI 	int rv;
179b6cee71dSXin LI 	va_list ap;
180b6cee71dSXin LI 
181b6cee71dSXin LI 	va_start(ap, fmt);
182b6cee71dSXin LI 	rv = file_vprintf(ms, fmt, ap);
183b6cee71dSXin LI 	va_end(ap);
184b6cee71dSXin LI 	return rv;
185b6cee71dSXin LI }
186b6cee71dSXin LI 
187b6cee71dSXin LI /*
188b6cee71dSXin LI  * error - print best error message possible
189b6cee71dSXin LI  */
190b6cee71dSXin LI /*VARARGS*/
191b6cee71dSXin LI __attribute__((__format__(__printf__, 3, 0)))
192*898496eeSXin LI file_private void
file_error_core(struct magic_set * ms,int error,const char * f,va_list va,size_t lineno)193b6cee71dSXin LI file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
194b6cee71dSXin LI     size_t lineno)
195b6cee71dSXin LI {
196b6cee71dSXin LI 	/* Only the first error is ok */
197b6cee71dSXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
198b6cee71dSXin LI 		return;
199b6cee71dSXin LI 	if (lineno != 0) {
2002726a701SXin LI 		file_clearbuf(ms);
20148c779cdSXin LI 		(void)file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno);
202b6cee71dSXin LI 	}
2039fc5c47fSXin LI 	if (ms->o.buf && *ms->o.buf)
20448c779cdSXin LI 		(void)file_printf(ms, " ");
20548c779cdSXin LI 	(void)file_vprintf(ms, f, va);
206b6cee71dSXin LI 	if (error > 0)
20748c779cdSXin LI 		(void)file_printf(ms, " (%s)", strerror(error));
208b6cee71dSXin LI 	ms->event_flags |= EVENT_HAD_ERR;
209b6cee71dSXin LI 	ms->error = error;
210b6cee71dSXin LI }
211b6cee71dSXin LI 
212b6cee71dSXin LI /*VARARGS*/
213*898496eeSXin LI file_protected void
file_error(struct magic_set * ms,int error,const char * f,...)214b6cee71dSXin LI file_error(struct magic_set *ms, int error, const char *f, ...)
215b6cee71dSXin LI {
216b6cee71dSXin LI 	va_list va;
217b6cee71dSXin LI 	va_start(va, f);
218b6cee71dSXin LI 	file_error_core(ms, error, f, va, 0);
219b6cee71dSXin LI 	va_end(va);
220b6cee71dSXin LI }
221b6cee71dSXin LI 
222b6cee71dSXin LI /*
223b6cee71dSXin LI  * Print an error with magic line number.
224b6cee71dSXin LI  */
225b6cee71dSXin LI /*VARARGS*/
226*898496eeSXin LI file_protected void
file_magerror(struct magic_set * ms,const char * f,...)227b6cee71dSXin LI file_magerror(struct magic_set *ms, const char *f, ...)
228b6cee71dSXin LI {
229b6cee71dSXin LI 	va_list va;
230b6cee71dSXin LI 	va_start(va, f);
231b6cee71dSXin LI 	file_error_core(ms, 0, f, va, ms->line);
232b6cee71dSXin LI 	va_end(va);
233b6cee71dSXin LI }
234b6cee71dSXin LI 
235*898496eeSXin LI file_protected void
file_oomem(struct magic_set * ms,size_t len)236b6cee71dSXin LI file_oomem(struct magic_set *ms, size_t len)
237b6cee71dSXin LI {
238b6cee71dSXin LI 	file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
239b6cee71dSXin LI 	    len);
240b6cee71dSXin LI }
241b6cee71dSXin LI 
242*898496eeSXin LI file_protected void
file_badseek(struct magic_set * ms)243b6cee71dSXin LI file_badseek(struct magic_set *ms)
244b6cee71dSXin LI {
245b6cee71dSXin LI 	file_error(ms, errno, "error seeking");
246b6cee71dSXin LI }
247b6cee71dSXin LI 
248*898496eeSXin LI file_protected void
file_badread(struct magic_set * ms)249b6cee71dSXin LI file_badread(struct magic_set *ms)
250b6cee71dSXin LI {
251b6cee71dSXin LI 	file_error(ms, errno, "error reading");
252b6cee71dSXin LI }
253b6cee71dSXin LI 
254b6cee71dSXin LI #ifndef COMPILE_ONLY
25543a5ec4eSXin LI #define FILE_SEPARATOR "\n- "
2565f0216bdSXin LI 
257*898496eeSXin LI file_protected int
file_separator(struct magic_set * ms)25848c779cdSXin LI file_separator(struct magic_set *ms)
25948c779cdSXin LI {
26043a5ec4eSXin LI 	return file_printf(ms, FILE_SEPARATOR);
26143a5ec4eSXin LI }
26243a5ec4eSXin LI 
26343a5ec4eSXin LI static void
trim_separator(struct magic_set * ms)26443a5ec4eSXin LI trim_separator(struct magic_set *ms)
26543a5ec4eSXin LI {
26643a5ec4eSXin LI 	size_t l;
26743a5ec4eSXin LI 
26843a5ec4eSXin LI 	if (ms->o.buf == NULL)
26943a5ec4eSXin LI 		return;
27043a5ec4eSXin LI 
27143a5ec4eSXin LI 	l = strlen(ms->o.buf);
27243a5ec4eSXin LI 	if (l < sizeof(FILE_SEPARATOR))
27343a5ec4eSXin LI 		return;
27443a5ec4eSXin LI 
27543a5ec4eSXin LI 	l -= sizeof(FILE_SEPARATOR) - 1;
27643a5ec4eSXin LI 	if (strcmp(ms->o.buf + l, FILE_SEPARATOR) != 0)
27743a5ec4eSXin LI 		return;
27843a5ec4eSXin LI 
27943a5ec4eSXin LI 	ms->o.buf[l] = '\0';
28048c779cdSXin LI }
28148c779cdSXin LI 
2825f0216bdSXin LI static int
checkdone(struct magic_set * ms,int * rv)2835f0216bdSXin LI checkdone(struct magic_set *ms, int *rv)
2845f0216bdSXin LI {
2855f0216bdSXin LI 	if ((ms->flags & MAGIC_CONTINUE) == 0)
2865f0216bdSXin LI 		return 1;
28748c779cdSXin LI 	if (file_separator(ms) == -1)
2885f0216bdSXin LI 		*rv = -1;
2895f0216bdSXin LI 	return 0;
2905f0216bdSXin LI }
2915f0216bdSXin LI 
292*898496eeSXin LI file_protected int
file_default(struct magic_set * ms,size_t nb)29348c779cdSXin LI file_default(struct magic_set *ms, size_t nb)
29448c779cdSXin LI {
29548c779cdSXin LI 	if (ms->flags & MAGIC_MIME) {
29648c779cdSXin LI 		if ((ms->flags & MAGIC_MIME_TYPE) &&
29748c779cdSXin LI 		    file_printf(ms, "application/%s",
29848c779cdSXin LI 			nb ? "octet-stream" : "x-empty") == -1)
29948c779cdSXin LI 			return -1;
30048c779cdSXin LI 		return 1;
30148c779cdSXin LI 	}
30248c779cdSXin LI 	if (ms->flags & MAGIC_APPLE) {
30348c779cdSXin LI 		if (file_printf(ms, "UNKNUNKN") == -1)
30448c779cdSXin LI 			return -1;
30548c779cdSXin LI 		return 1;
30648c779cdSXin LI 	}
30748c779cdSXin LI 	if (ms->flags & MAGIC_EXTENSION) {
30848c779cdSXin LI 		if (file_printf(ms, "???") == -1)
30948c779cdSXin LI 			return -1;
31048c779cdSXin LI 		return 1;
31148c779cdSXin LI 	}
31248c779cdSXin LI 	return 0;
31348c779cdSXin LI }
31448c779cdSXin LI 
31548c779cdSXin LI /*
31648c779cdSXin LI  * The magic detection functions return:
31748c779cdSXin LI  *	 1: found
31848c779cdSXin LI  *	 0: not found
31948c779cdSXin LI  *	-1: error
32048c779cdSXin LI  */
3215f0216bdSXin LI /*ARGSUSED*/
322*898496eeSXin LI file_protected int
file_buffer(struct magic_set * ms,int fd,struct stat * st,const char * inname,const void * buf,size_t nb)32348c779cdSXin LI file_buffer(struct magic_set *ms, int fd, struct stat *st,
32448c779cdSXin LI     const char *inname __attribute__ ((__unused__)),
325b6cee71dSXin LI     const void *buf, size_t nb)
326b6cee71dSXin LI {
327b6cee71dSXin LI 	int m = 0, rv = 0, looks_text = 0;
328b6cee71dSXin LI 	const char *code = NULL;
329b6cee71dSXin LI 	const char *code_mime = "binary";
330b6cee71dSXin LI 	const char *def = "data";
331b6cee71dSXin LI 	const char *ftype = NULL;
3322dc4dbb9SEitan Adler 	char *rbuf = NULL;
33358a0f0d0SEitan Adler 	struct buffer b;
33458a0f0d0SEitan Adler 
33548c779cdSXin LI 	buffer_init(&b, fd, st, buf, nb);
3362dc4dbb9SEitan Adler 	ms->mode = b.st.st_mode;
337b6cee71dSXin LI 
338b6cee71dSXin LI 	if (nb == 0) {
339b6cee71dSXin LI 		def = "empty";
340b6cee71dSXin LI 		goto simple;
341b6cee71dSXin LI 	} else if (nb == 1) {
342b6cee71dSXin LI 		def = "very short file (no magic)";
343b6cee71dSXin LI 		goto simple;
344b6cee71dSXin LI 	}
345b6cee71dSXin LI 
346b6cee71dSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
34758a0f0d0SEitan Adler 		looks_text = file_encoding(ms, &b, NULL, 0,
348b6cee71dSXin LI 		    &code, &code_mime, &ftype);
349b6cee71dSXin LI 	}
350b6cee71dSXin LI 
351b6cee71dSXin LI #ifdef __EMX__
352b6cee71dSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
35358a0f0d0SEitan Adler 		m = file_os2_apptype(ms, inname, &b);
3549ce06829SXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
3559ce06829SXin LI 			(void)fprintf(stderr, "[try os2_apptype %d]\n", m);
3569ce06829SXin LI 		switch (m) {
357b6cee71dSXin LI 		case -1:
358b6cee71dSXin LI 			return -1;
359b6cee71dSXin LI 		case 0:
360b6cee71dSXin LI 			break;
361b6cee71dSXin LI 		default:
362b6cee71dSXin LI 			return 1;
363b6cee71dSXin LI 		}
364b6cee71dSXin LI 	}
365b6cee71dSXin LI #endif
366b6cee71dSXin LI #if HAVE_FORK
367b6cee71dSXin LI 	/* try compression stuff */
3689ce06829SXin LI 	if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) {
36958a0f0d0SEitan Adler 		m = file_zmagic(ms, &b, inname);
370b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
3719ce06829SXin LI 			(void)fprintf(stderr, "[try zmagic %d]\n", m);
3729ce06829SXin LI 		if (m) {
373b6cee71dSXin LI 			goto done_encoding;
374b6cee71dSXin LI 		}
3759ce06829SXin LI 	}
376b6cee71dSXin LI #endif
377b6cee71dSXin LI 	/* Check if we have a tar file */
3789ce06829SXin LI 	if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) {
37958a0f0d0SEitan Adler 		m = file_is_tar(ms, &b);
380b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
3819ce06829SXin LI 			(void)fprintf(stderr, "[try tar %d]\n", m);
3829ce06829SXin LI 		if (m) {
3835f0216bdSXin LI 			if (checkdone(ms, &rv))
384b6cee71dSXin LI 				goto done;
385b6cee71dSXin LI 		}
3869ce06829SXin LI 	}
387b6cee71dSXin LI 
38848c779cdSXin LI 	/* Check if we have a JSON file */
38948c779cdSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_JSON) == 0) {
39048c779cdSXin LI 		m = file_is_json(ms, &b);
39148c779cdSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
39248c779cdSXin LI 			(void)fprintf(stderr, "[try json %d]\n", m);
39348c779cdSXin LI 		if (m) {
39448c779cdSXin LI 			if (checkdone(ms, &rv))
39548c779cdSXin LI 				goto done;
39648c779cdSXin LI 		}
39748c779cdSXin LI 	}
39848c779cdSXin LI 
399d38c30c0SXin LI 	/* Check if we have a CSV file */
400d38c30c0SXin LI 	if ((ms->flags & MAGIC_NO_CHECK_CSV) == 0) {
401*898496eeSXin LI 		m = file_is_csv(ms, &b, looks_text, code);
402d38c30c0SXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
403d38c30c0SXin LI 			(void)fprintf(stderr, "[try csv %d]\n", m);
404d38c30c0SXin LI 		if (m) {
405d38c30c0SXin LI 			if (checkdone(ms, &rv))
406d38c30c0SXin LI 				goto done;
407d38c30c0SXin LI 		}
408d38c30c0SXin LI 	}
409d38c30c0SXin LI 
410*898496eeSXin LI 	/* Check if we have a SIMH tape file */
411*898496eeSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_SIMH) == 0) {
412*898496eeSXin LI 		m = file_is_simh(ms, &b);
413*898496eeSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
414*898496eeSXin LI 			(void)fprintf(stderr, "[try simh %d]\n", m);
415*898496eeSXin LI 		if (m) {
416*898496eeSXin LI 			if (checkdone(ms, &rv))
417*898496eeSXin LI 				goto done;
418*898496eeSXin LI 		}
419*898496eeSXin LI 	}
420*898496eeSXin LI 
421b6cee71dSXin LI 	/* Check if we have a CDF file */
4229ce06829SXin LI 	if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
42358a0f0d0SEitan Adler 		m = file_trycdf(ms, &b);
424b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4259ce06829SXin LI 			(void)fprintf(stderr, "[try cdf %d]\n", m);
4269ce06829SXin LI 		if (m) {
4275f0216bdSXin LI 			if (checkdone(ms, &rv))
428b6cee71dSXin LI 				goto done;
429b6cee71dSXin LI 		}
4309ce06829SXin LI 	}
431b6cee71dSXin LI #ifdef BUILTIN_ELF
4322dc4dbb9SEitan Adler 	if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) {
4332dc4dbb9SEitan Adler 		file_pushbuf_t *pb;
434b6cee71dSXin LI 		/*
435b6cee71dSXin LI 		 * We matched something in the file, so this
436b6cee71dSXin LI 		 * *might* be an ELF file, and the file is at
437b6cee71dSXin LI 		 * least 5 bytes long, so if it's an ELF file
438b6cee71dSXin LI 		 * it has at least one byte past the ELF magic
439b6cee71dSXin LI 		 * number - try extracting information from the
4402dc4dbb9SEitan Adler 		 * ELF headers that cannot easily be  extracted
4412dc4dbb9SEitan Adler 		 * with rules in the magic file. We we don't
4422dc4dbb9SEitan Adler 		 * print the information yet.
443b6cee71dSXin LI 		 */
4442dc4dbb9SEitan Adler 		if ((pb = file_push_buffer(ms)) == NULL)
4452dc4dbb9SEitan Adler 			return -1;
4462dc4dbb9SEitan Adler 
4472dc4dbb9SEitan Adler 		rv = file_tryelf(ms, &b);
4482dc4dbb9SEitan Adler 		rbuf = file_pop_buffer(ms, pb);
44948c779cdSXin LI 		if (rv == -1) {
4502dc4dbb9SEitan Adler 			free(rbuf);
4512dc4dbb9SEitan Adler 			rbuf = NULL;
4522dc4dbb9SEitan Adler 		}
453b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4542dc4dbb9SEitan Adler 			(void)fprintf(stderr, "[try elf %d]\n", m);
455b6cee71dSXin LI 	}
456b6cee71dSXin LI #endif
4572dc4dbb9SEitan Adler 
4582dc4dbb9SEitan Adler 	/* try soft magic tests */
4592dc4dbb9SEitan Adler 	if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
4602dc4dbb9SEitan Adler 		m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text);
4612dc4dbb9SEitan Adler 		if ((ms->flags & MAGIC_DEBUG) != 0)
4622dc4dbb9SEitan Adler 			(void)fprintf(stderr, "[try softmagic %d]\n", m);
4632dc4dbb9SEitan Adler 		if (m == 1 && rbuf) {
4642dc4dbb9SEitan Adler 			if (file_printf(ms, "%s", rbuf) == -1)
4652dc4dbb9SEitan Adler 				goto done;
4662dc4dbb9SEitan Adler 		}
4672dc4dbb9SEitan Adler 		if (m) {
4685f0216bdSXin LI 			if (checkdone(ms, &rv))
469b6cee71dSXin LI 				goto done;
470b6cee71dSXin LI 		}
471a5d223e6SXin LI 	}
472b6cee71dSXin LI 
473b6cee71dSXin LI 	/* try text properties */
474b6cee71dSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
475b6cee71dSXin LI 
47658a0f0d0SEitan Adler 		m = file_ascmagic(ms, &b, looks_text);
477b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4789ce06829SXin LI 			(void)fprintf(stderr, "[try ascmagic %d]\n", m);
4799ce06829SXin LI 		if (m) {
480b6cee71dSXin LI 			goto done;
481b6cee71dSXin LI 		}
482b6cee71dSXin LI 	}
483b6cee71dSXin LI 
484b6cee71dSXin LI simple:
485b6cee71dSXin LI 	/* give up */
48648c779cdSXin LI 	if (m == 0) {
487b6cee71dSXin LI 		m = 1;
48848c779cdSXin LI 		rv = file_default(ms, nb);
48948c779cdSXin LI 		if (rv == 0)
4903e41d09dSXin LI 			if (file_printf(ms, "%s", def) == -1)
491b6cee71dSXin LI 				rv = -1;
492b6cee71dSXin LI 	}
493b6cee71dSXin LI  done:
49443a5ec4eSXin LI 	trim_separator(ms);
495b6cee71dSXin LI 	if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
496b6cee71dSXin LI 		if (ms->flags & MAGIC_MIME_TYPE)
497b6cee71dSXin LI 			if (file_printf(ms, "; charset=") == -1)
498b6cee71dSXin LI 				rv = -1;
499b6cee71dSXin LI 		if (file_printf(ms, "%s", code_mime) == -1)
500b6cee71dSXin LI 			rv = -1;
501b6cee71dSXin LI 	}
502b6cee71dSXin LI #if HAVE_FORK
503b6cee71dSXin LI  done_encoding:
504b6cee71dSXin LI #endif
5052dc4dbb9SEitan Adler 	free(rbuf);
50658a0f0d0SEitan Adler 	buffer_fini(&b);
507b6cee71dSXin LI 	if (rv)
508b6cee71dSXin LI 		return rv;
509b6cee71dSXin LI 
510b6cee71dSXin LI 	return m;
511b6cee71dSXin LI }
512b6cee71dSXin LI #endif
513b6cee71dSXin LI 
514*898496eeSXin LI file_protected int
file_reset(struct magic_set * ms,int checkloaded)51540427ccaSGordon Tetlow file_reset(struct magic_set *ms, int checkloaded)
516b6cee71dSXin LI {
51740427ccaSGordon Tetlow 	if (checkloaded && ms->mlist[0] == NULL) {
518b6cee71dSXin LI 		file_error(ms, 0, "no magic files loaded");
519b6cee71dSXin LI 		return -1;
520b6cee71dSXin LI 	}
5212726a701SXin LI 	file_clearbuf(ms);
522b6cee71dSXin LI 	if (ms->o.pbuf) {
523b6cee71dSXin LI 		free(ms->o.pbuf);
524b6cee71dSXin LI 		ms->o.pbuf = NULL;
525b6cee71dSXin LI 	}
526b6cee71dSXin LI 	ms->event_flags &= ~EVENT_HAD_ERR;
527b6cee71dSXin LI 	ms->error = -1;
528b6cee71dSXin LI 	return 0;
529b6cee71dSXin LI }
530b6cee71dSXin LI 
531b6cee71dSXin LI #define OCTALIFY(n, o)	\
532b6cee71dSXin LI 	/*LINTED*/ \
533b6cee71dSXin LI 	(void)(*(n)++ = '\\', \
53448c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 6) & 3) + '0', \
53548c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 3) & 7) + '0', \
53648c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 0) & 7) + '0', \
537b6cee71dSXin LI 	(o)++)
538b6cee71dSXin LI 
539*898496eeSXin LI file_protected const char *
file_getbuffer(struct magic_set * ms)540b6cee71dSXin LI file_getbuffer(struct magic_set *ms)
541b6cee71dSXin LI {
542b6cee71dSXin LI 	char *pbuf, *op, *np;
543b6cee71dSXin LI 	size_t psize, len;
544b6cee71dSXin LI 
545b6cee71dSXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
546b6cee71dSXin LI 		return NULL;
547b6cee71dSXin LI 
548b6cee71dSXin LI 	if (ms->flags & MAGIC_RAW)
549b6cee71dSXin LI 		return ms->o.buf;
550b6cee71dSXin LI 
551b6cee71dSXin LI 	if (ms->o.buf == NULL)
552b6cee71dSXin LI 		return NULL;
553b6cee71dSXin LI 
554b6cee71dSXin LI 	/* * 4 is for octal representation, + 1 is for NUL */
555b6cee71dSXin LI 	len = strlen(ms->o.buf);
556b6cee71dSXin LI 	if (len > (SIZE_MAX - 1) / 4) {
557b6cee71dSXin LI 		file_oomem(ms, len);
558b6cee71dSXin LI 		return NULL;
559b6cee71dSXin LI 	}
560b6cee71dSXin LI 	psize = len * 4 + 1;
561b6cee71dSXin LI 	if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) {
562b6cee71dSXin LI 		file_oomem(ms, psize);
563b6cee71dSXin LI 		return NULL;
564b6cee71dSXin LI 	}
565b6cee71dSXin LI 	ms->o.pbuf = pbuf;
566b6cee71dSXin LI 
567b6cee71dSXin LI #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
568b6cee71dSXin LI 	{
569b6cee71dSXin LI 		mbstate_t state;
570b6cee71dSXin LI 		wchar_t nextchar;
571b6cee71dSXin LI 		int mb_conv = 1;
572b6cee71dSXin LI 		size_t bytesconsumed;
573b6cee71dSXin LI 		char *eop;
574b6cee71dSXin LI 		(void)memset(&state, 0, sizeof(mbstate_t));
575b6cee71dSXin LI 
576b6cee71dSXin LI 		np = ms->o.pbuf;
577b6cee71dSXin LI 		op = ms->o.buf;
578b6cee71dSXin LI 		eop = op + len;
579b6cee71dSXin LI 
580b6cee71dSXin LI 		while (op < eop) {
581b6cee71dSXin LI 			bytesconsumed = mbrtowc(&nextchar, op,
58248c779cdSXin LI 			    CAST(size_t, eop - op), &state);
58348c779cdSXin LI 			if (bytesconsumed == CAST(size_t, -1) ||
58448c779cdSXin LI 			    bytesconsumed == CAST(size_t, -2)) {
585b6cee71dSXin LI 				mb_conv = 0;
586b6cee71dSXin LI 				break;
587b6cee71dSXin LI 			}
588b6cee71dSXin LI 
589b6cee71dSXin LI 			if (iswprint(nextchar)) {
590b6cee71dSXin LI 				(void)memcpy(np, op, bytesconsumed);
591b6cee71dSXin LI 				op += bytesconsumed;
592b6cee71dSXin LI 				np += bytesconsumed;
593b6cee71dSXin LI 			} else {
594b6cee71dSXin LI 				while (bytesconsumed-- > 0)
595b6cee71dSXin LI 					OCTALIFY(np, op);
596b6cee71dSXin LI 			}
597b6cee71dSXin LI 		}
598b6cee71dSXin LI 		*np = '\0';
599b6cee71dSXin LI 
600b6cee71dSXin LI 		/* Parsing succeeded as a multi-byte sequence */
601b6cee71dSXin LI 		if (mb_conv != 0)
602b6cee71dSXin LI 			return ms->o.pbuf;
603b6cee71dSXin LI 	}
604b6cee71dSXin LI #endif
605b6cee71dSXin LI 
606b6cee71dSXin LI 	for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
60748c779cdSXin LI 		if (isprint(CAST(unsigned char, *op))) {
608b6cee71dSXin LI 			*np++ = *op++;
609b6cee71dSXin LI 		} else {
610b6cee71dSXin LI 			OCTALIFY(np, op);
611b6cee71dSXin LI 		}
612b6cee71dSXin LI 	}
613b6cee71dSXin LI 	*np = '\0';
614b6cee71dSXin LI 	return ms->o.pbuf;
615b6cee71dSXin LI }
616b6cee71dSXin LI 
617*898496eeSXin LI file_protected int
file_check_mem(struct magic_set * ms,unsigned int level)618b6cee71dSXin LI file_check_mem(struct magic_set *ms, unsigned int level)
619b6cee71dSXin LI {
620b6cee71dSXin LI 	size_t len;
621b6cee71dSXin LI 
622b6cee71dSXin LI 	if (level >= ms->c.len) {
6235f0216bdSXin LI 		len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
624b6cee71dSXin LI 		ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
625b6cee71dSXin LI 		    malloc(len) :
626b6cee71dSXin LI 		    realloc(ms->c.li, len));
627b6cee71dSXin LI 		if (ms->c.li == NULL) {
628b6cee71dSXin LI 			file_oomem(ms, len);
629b6cee71dSXin LI 			return -1;
630b6cee71dSXin LI 		}
631b6cee71dSXin LI 	}
632b6cee71dSXin LI 	ms->c.li[level].got_match = 0;
633b6cee71dSXin LI #ifdef ENABLE_CONDITIONALS
634b6cee71dSXin LI 	ms->c.li[level].last_match = 0;
635b6cee71dSXin LI 	ms->c.li[level].last_cond = COND_NONE;
636b6cee71dSXin LI #endif /* ENABLE_CONDITIONALS */
637b6cee71dSXin LI 	return 0;
638b6cee71dSXin LI }
639b6cee71dSXin LI 
640*898496eeSXin LI file_protected size_t
file_printedlen(const struct magic_set * ms)641b6cee71dSXin LI file_printedlen(const struct magic_set *ms)
642b6cee71dSXin LI {
6432726a701SXin LI 	return ms->o.blen;
644b6cee71dSXin LI }
645b6cee71dSXin LI 
646*898496eeSXin LI file_protected int
file_replace(struct magic_set * ms,const char * pat,const char * rep)647b6cee71dSXin LI file_replace(struct magic_set *ms, const char *pat, const char *rep)
648b6cee71dSXin LI {
649b6cee71dSXin LI 	file_regex_t rx;
650b6cee71dSXin LI 	int rc, rv = -1;
651b6cee71dSXin LI 
652a4d6d3b8SXin LI 	rc = file_regcomp(ms, &rx, pat, REG_EXTENDED);
653a4d6d3b8SXin LI 	if (rc == 0) {
654b6cee71dSXin LI 		regmatch_t rm;
655b6cee71dSXin LI 		int nm = 0;
656a4d6d3b8SXin LI 		while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) {
657b6cee71dSXin LI 			ms->o.buf[rm.rm_so] = '\0';
658b6cee71dSXin LI 			if (file_printf(ms, "%s%s", rep,
659b6cee71dSXin LI 			    rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1)
660b6cee71dSXin LI 				goto out;
661b6cee71dSXin LI 			nm++;
662b6cee71dSXin LI 		}
663b6cee71dSXin LI 		rv = nm;
664b6cee71dSXin LI 	}
665b6cee71dSXin LI out:
666b6cee71dSXin LI 	file_regfree(&rx);
667b6cee71dSXin LI 	return rv;
668b6cee71dSXin LI }
669b6cee71dSXin LI 
670*898496eeSXin LI file_private int
check_regex(struct magic_set * ms,const char * pat)671*898496eeSXin LI check_regex(struct magic_set *ms, const char *pat)
672*898496eeSXin LI {
673*898496eeSXin LI 	char sbuf[512];
674*898496eeSXin LI 	unsigned char oc = '\0';
675*898496eeSXin LI 	const char *p;
676*898496eeSXin LI 
677*898496eeSXin LI 	for (p = pat; *p; p++) {
678*898496eeSXin LI 		unsigned char c = *p;
679*898496eeSXin LI 		// Avoid repetition
680*898496eeSXin LI 		if (c == oc && strchr("?*+{", c) != NULL) {
681*898496eeSXin LI 			size_t len = strlen(pat);
682*898496eeSXin LI 			file_magwarn(ms,
683*898496eeSXin LI 			    "repetition-operator operand `%c' "
684*898496eeSXin LI 			    "invalid in regex `%s'", c,
685*898496eeSXin LI 			    file_printable(ms, sbuf, sizeof(sbuf), pat, len));
686*898496eeSXin LI 			return -1;
687*898496eeSXin LI 		}
688*898496eeSXin LI 		oc = c;
689*898496eeSXin LI 		if (isprint(c) || isspace(c) || c == '\b'
690*898496eeSXin LI 		    || c == 0x8a) // XXX: apple magic fixme
691*898496eeSXin LI 			continue;
692*898496eeSXin LI 		size_t len = strlen(pat);
693*898496eeSXin LI 		file_magwarn(ms,
694*898496eeSXin LI 		    "non-ascii characters in regex \\%#o `%s'",
695*898496eeSXin LI 		    c, file_printable(ms, sbuf, sizeof(sbuf), pat, len));
696*898496eeSXin LI 		return -1;
697*898496eeSXin LI 	}
698*898496eeSXin LI 	return 0;
699*898496eeSXin LI }
700*898496eeSXin LI 
701*898496eeSXin LI file_protected int
file_regcomp(struct magic_set * ms file_locale_used,file_regex_t * rx,const char * pat,int flags)702a4d6d3b8SXin LI file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx,
703a4d6d3b8SXin LI     const char *pat, int flags)
704b6cee71dSXin LI {
705*898496eeSXin LI 	if (check_regex(ms, pat) == -1)
706*898496eeSXin LI 		return -1;
707*898496eeSXin LI 
708c2931133SXin LI #ifdef USE_C_LOCALE
709a4d6d3b8SXin LI 	locale_t old = uselocale(ms->c_lc_ctype);
710a4d6d3b8SXin LI 	assert(old != NULL);
7113e41d09dSXin LI #else
712a4d6d3b8SXin LI 	char old[1024];
713a4d6d3b8SXin LI 	strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old));
714d38c30c0SXin LI 	(void)setlocale(LC_CTYPE, "C");
715c2931133SXin LI #endif
716a4d6d3b8SXin LI 	int rc;
717a4d6d3b8SXin LI 	rc = regcomp(rx, pat, flags);
718b6cee71dSXin LI 
719a4d6d3b8SXin LI #ifdef USE_C_LOCALE
720a4d6d3b8SXin LI 	uselocale(old);
721a4d6d3b8SXin LI #else
722a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, old);
723a4d6d3b8SXin LI #endif
724a4d6d3b8SXin LI 	if (rc > 0 && (ms->flags & MAGIC_CHECK)) {
725*898496eeSXin LI 		char errmsg[512], buf[512];
726a4d6d3b8SXin LI 
727a4d6d3b8SXin LI 		(void)regerror(rc, rx, errmsg, sizeof(errmsg));
728*898496eeSXin LI 		file_magerror(ms, "regex error %d for `%s', (%s)", rc,
729*898496eeSXin LI 		    file_printable(ms, buf, sizeof(buf), pat, strlen(pat)),
730a4d6d3b8SXin LI 		    errmsg);
731a4d6d3b8SXin LI 	}
732a4d6d3b8SXin LI 	return rc;
733b6cee71dSXin LI }
734b6cee71dSXin LI 
735a2dfb722SXin LI /*ARGSUSED*/
736*898496eeSXin LI file_protected int
file_regexec(struct magic_set * ms file_locale_used,file_regex_t * rx,const char * str,size_t nmatch,regmatch_t * pmatch,int eflags)737a4d6d3b8SXin LI file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx,
738a4d6d3b8SXin LI     const char *str, size_t nmatch, regmatch_t* pmatch, int eflags)
739b6cee71dSXin LI {
740a4d6d3b8SXin LI #ifdef USE_C_LOCALE
741a4d6d3b8SXin LI 	locale_t old = uselocale(ms->c_lc_ctype);
742a4d6d3b8SXin LI 	assert(old != NULL);
743a4d6d3b8SXin LI #else
744a4d6d3b8SXin LI 	char old[1024];
745a4d6d3b8SXin LI 	strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old));
746a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, "C");
747a4d6d3b8SXin LI #endif
748a4d6d3b8SXin LI 	int rc;
74940427ccaSGordon Tetlow 	/* XXX: force initialization because glibc does not always do this */
750d38c30c0SXin LI 	if (nmatch != 0)
75140427ccaSGordon Tetlow 		memset(pmatch, 0, nmatch * sizeof(*pmatch));
752a4d6d3b8SXin LI 	rc = regexec(rx, str, nmatch, pmatch, eflags);
753a4d6d3b8SXin LI #ifdef USE_C_LOCALE
754a4d6d3b8SXin LI 	uselocale(old);
755a4d6d3b8SXin LI #else
756a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, old);
757a4d6d3b8SXin LI #endif
758a4d6d3b8SXin LI 	return rc;
759b6cee71dSXin LI }
760b6cee71dSXin LI 
761*898496eeSXin LI file_protected void
file_regfree(file_regex_t * rx)762b6cee71dSXin LI file_regfree(file_regex_t *rx)
763b6cee71dSXin LI {
764a4d6d3b8SXin LI 	regfree(rx);
765b6cee71dSXin LI }
7662c4f1647SXin LI 
767*898496eeSXin LI file_protected file_pushbuf_t *
file_push_buffer(struct magic_set * ms)7682c4f1647SXin LI file_push_buffer(struct magic_set *ms)
7692c4f1647SXin LI {
7702c4f1647SXin LI 	file_pushbuf_t *pb;
7712c4f1647SXin LI 
7722c4f1647SXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
7732c4f1647SXin LI 		return NULL;
7742c4f1647SXin LI 
7752c4f1647SXin LI 	if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
7762c4f1647SXin LI 		return NULL;
7772c4f1647SXin LI 
7782c4f1647SXin LI 	pb->buf = ms->o.buf;
7792726a701SXin LI 	pb->blen = ms->o.blen;
7802c4f1647SXin LI 	pb->offset = ms->offset;
7812c4f1647SXin LI 
7822c4f1647SXin LI 	ms->o.buf = NULL;
7832726a701SXin LI 	ms->o.blen = 0;
7842c4f1647SXin LI 	ms->offset = 0;
7852c4f1647SXin LI 
7862c4f1647SXin LI 	return pb;
7872c4f1647SXin LI }
7882c4f1647SXin LI 
789*898496eeSXin LI file_protected char *
file_pop_buffer(struct magic_set * ms,file_pushbuf_t * pb)7902c4f1647SXin LI file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
7912c4f1647SXin LI {
7922c4f1647SXin LI 	char *rbuf;
7932c4f1647SXin LI 
7942c4f1647SXin LI 	if (ms->event_flags & EVENT_HAD_ERR) {
7952c4f1647SXin LI 		free(pb->buf);
7962c4f1647SXin LI 		free(pb);
7972c4f1647SXin LI 		return NULL;
7982c4f1647SXin LI 	}
7992c4f1647SXin LI 
8002c4f1647SXin LI 	rbuf = ms->o.buf;
8012c4f1647SXin LI 
8022c4f1647SXin LI 	ms->o.buf = pb->buf;
8032726a701SXin LI 	ms->o.blen = pb->blen;
8042c4f1647SXin LI 	ms->offset = pb->offset;
8052c4f1647SXin LI 
8062c4f1647SXin LI 	free(pb);
8072c4f1647SXin LI 	return rbuf;
8082c4f1647SXin LI }
8094460e5b0SXin LI 
8104460e5b0SXin LI /*
8114460e5b0SXin LI  * convert string to ascii printable format.
8124460e5b0SXin LI  */
813*898496eeSXin LI file_protected char *
file_printable(struct magic_set * ms,char * buf,size_t bufsiz,const char * str,size_t slen)81443a5ec4eSXin LI file_printable(struct magic_set *ms, char *buf, size_t bufsiz,
81543a5ec4eSXin LI     const char *str, size_t slen)
8164460e5b0SXin LI {
81748c779cdSXin LI 	char *ptr, *eptr = buf + bufsiz - 1;
81848c779cdSXin LI 	const unsigned char *s = RCAST(const unsigned char *, str);
81948c779cdSXin LI 	const unsigned char *es = s + slen;
8204460e5b0SXin LI 
82148c779cdSXin LI 	for (ptr = buf;  ptr < eptr && s < es && *s; s++) {
82243a5ec4eSXin LI 		if ((ms->flags & MAGIC_RAW) != 0 || isprint(*s)) {
8234460e5b0SXin LI 			*ptr++ = *s;
8244460e5b0SXin LI 			continue;
8254460e5b0SXin LI 		}
8264460e5b0SXin LI 		if (ptr >= eptr - 3)
8274460e5b0SXin LI 			break;
8284460e5b0SXin LI 		*ptr++ = '\\';
8295f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
8305f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
8315f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
8324460e5b0SXin LI 	}
8334460e5b0SXin LI 	*ptr = '\0';
8344460e5b0SXin LI 	return buf;
8354460e5b0SXin LI }
8362726a701SXin LI 
8372726a701SXin LI struct guid {
8382726a701SXin LI 	uint32_t data1;
8392726a701SXin LI 	uint16_t data2;
8402726a701SXin LI 	uint16_t data3;
8412726a701SXin LI 	uint8_t data4[8];
8422726a701SXin LI };
8432726a701SXin LI 
844*898496eeSXin LI file_protected int
file_parse_guid(const char * s,uint64_t * guid)8452726a701SXin LI file_parse_guid(const char *s, uint64_t *guid)
8462726a701SXin LI {
84743a5ec4eSXin LI 	struct guid *g = CAST(struct guid *, CAST(void *, guid));
848a4d6d3b8SXin LI #ifndef WIN32
8492726a701SXin LI 	return sscanf(s,
8502726a701SXin LI 	    "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
8512726a701SXin LI 	    &g->data1, &g->data2, &g->data3, &g->data4[0], &g->data4[1],
8522726a701SXin LI 	    &g->data4[2], &g->data4[3], &g->data4[4], &g->data4[5],
8532726a701SXin LI 	    &g->data4[6], &g->data4[7]) == 11 ? 0 : -1;
854a4d6d3b8SXin LI #else
855a4d6d3b8SXin LI 	/* MS-Windows runtime doesn't support %hhx, except under
856a4d6d3b8SXin LI 	   non-default __USE_MINGW_ANSI_STDIO.  */
857a4d6d3b8SXin LI 	uint16_t data16[8];
858a4d6d3b8SXin LI 	int rv = sscanf(s, "%8x-%4hx-%4hx-%2hx%2hx-%2hx%2hx%2hx%2hx%2hx%2hx",
859a4d6d3b8SXin LI 	    &g->data1, &g->data2, &g->data3, &data16[0], &data16[1],
860a4d6d3b8SXin LI 	    &data16[2], &data16[3], &data16[4], &data16[5],
861a4d6d3b8SXin LI 	    &data16[6], &data16[7]) == 11 ? 0 : -1;
862a4d6d3b8SXin LI 	int i;
863a4d6d3b8SXin LI 	for (i = 0; i < 8; i++)
864a4d6d3b8SXin LI 	    g->data4[i] = data16[i];
865a4d6d3b8SXin LI 	return rv;
866a4d6d3b8SXin LI #endif
8672726a701SXin LI }
8682726a701SXin LI 
869*898496eeSXin LI file_protected int
file_print_guid(char * str,size_t len,const uint64_t * guid)8702726a701SXin LI file_print_guid(char *str, size_t len, const uint64_t *guid)
8712726a701SXin LI {
87243a5ec4eSXin LI 	const struct guid *g = CAST(const struct guid *,
87343a5ec4eSXin LI 	    CAST(const void *, guid));
8742726a701SXin LI 
875a4d6d3b8SXin LI #ifndef WIN32
8762726a701SXin LI 	return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hhX%.2hhX-"
8772726a701SXin LI 	    "%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX",
8782726a701SXin LI 	    g->data1, g->data2, g->data3, g->data4[0], g->data4[1],
8792726a701SXin LI 	    g->data4[2], g->data4[3], g->data4[4], g->data4[5],
8802726a701SXin LI 	    g->data4[6], g->data4[7]);
881a4d6d3b8SXin LI #else
882a4d6d3b8SXin LI 	return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hX%.2hX-"
883a4d6d3b8SXin LI 	    "%.2hX%.2hX%.2hX%.2hX%.2hX%.2hX",
884a4d6d3b8SXin LI 	    g->data1, g->data2, g->data3, g->data4[0], g->data4[1],
885a4d6d3b8SXin LI 	    g->data4[2], g->data4[3], g->data4[4], g->data4[5],
886a4d6d3b8SXin LI 	    g->data4[6], g->data4[7]);
887a4d6d3b8SXin LI #endif
8882726a701SXin LI }
88943a5ec4eSXin LI 
890*898496eeSXin LI file_protected int
file_pipe_closexec(int * fds)89143a5ec4eSXin LI file_pipe_closexec(int *fds)
89243a5ec4eSXin LI {
893*898496eeSXin LI #ifdef __MINGW32__
894*898496eeSXin LI 	return 0;
895*898496eeSXin LI #elif defined(HAVE_PIPE2)
89643a5ec4eSXin LI 	return pipe2(fds, O_CLOEXEC);
89743a5ec4eSXin LI #else
89843a5ec4eSXin LI 	if (pipe(fds) == -1)
89943a5ec4eSXin LI 		return -1;
900a4d6d3b8SXin LI # ifdef F_SETFD
90143a5ec4eSXin LI 	(void)fcntl(fds[0], F_SETFD, FD_CLOEXEC);
90243a5ec4eSXin LI 	(void)fcntl(fds[1], F_SETFD, FD_CLOEXEC);
903a4d6d3b8SXin LI # endif
90443a5ec4eSXin LI 	return 0;
90543a5ec4eSXin LI #endif
90643a5ec4eSXin LI }
90743a5ec4eSXin LI 
908*898496eeSXin LI file_protected int
file_clear_closexec(int fd)90943a5ec4eSXin LI file_clear_closexec(int fd) {
910a4d6d3b8SXin LI #ifdef F_SETFD
91143a5ec4eSXin LI 	return fcntl(fd, F_SETFD, 0);
912a4d6d3b8SXin LI #else
913a4d6d3b8SXin LI 	return 0;
914a4d6d3b8SXin LI #endif
91543a5ec4eSXin LI }
91643a5ec4eSXin LI 
917*898496eeSXin LI file_protected char *
file_strtrim(char * str)91843a5ec4eSXin LI file_strtrim(char *str)
91943a5ec4eSXin LI {
92043a5ec4eSXin LI 	char *last;
92143a5ec4eSXin LI 
92243a5ec4eSXin LI 	while (isspace(CAST(unsigned char, *str)))
92343a5ec4eSXin LI 		str++;
92443a5ec4eSXin LI 	last = str;
92543a5ec4eSXin LI 	while (*last)
92643a5ec4eSXin LI 		last++;
92743a5ec4eSXin LI 	--last;
92843a5ec4eSXin LI 	while (isspace(CAST(unsigned char, *last)))
92943a5ec4eSXin LI 		last--;
93043a5ec4eSXin LI 	*++last = '\0';
93143a5ec4eSXin LI 	return str;
93243a5ec4eSXin LI }
933