xref: /freebsd/contrib/file/src/funcs.c (revision a2dfb7224ec9933ee804cae54d51848dce938b6b)
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*a2dfb722SXin LI FILE_RCSID("@(#)$File: funcs.c,v 1.131 2022/09/13 18:46:07 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 
542726a701SXin LI protected char *
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 
662726a701SXin LI private void
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 
742726a701SXin LI private int
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 
932726a701SXin LI protected int
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  */
132b6cee71dSXin LI protected int
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 
175b6cee71dSXin LI protected int
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)))
192b6cee71dSXin LI private void
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*/
213b6cee71dSXin LI protected void
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*/
226b6cee71dSXin LI protected void
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 
235b6cee71dSXin LI protected void
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 
242b6cee71dSXin LI protected void
243b6cee71dSXin LI file_badseek(struct magic_set *ms)
244b6cee71dSXin LI {
245b6cee71dSXin LI 	file_error(ms, errno, "error seeking");
246b6cee71dSXin LI }
247b6cee71dSXin LI 
248b6cee71dSXin LI protected void
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 
25748c779cdSXin LI protected int
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
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
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 
29248c779cdSXin LI protected int
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*/
322b6cee71dSXin LI protected int
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) {
401d38c30c0SXin LI 		m = file_is_csv(ms, &b, looks_text);
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 
410b6cee71dSXin LI 	/* Check if we have a CDF file */
4119ce06829SXin LI 	if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
41258a0f0d0SEitan Adler 		m = file_trycdf(ms, &b);
413b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4149ce06829SXin LI 			(void)fprintf(stderr, "[try cdf %d]\n", m);
4159ce06829SXin LI 		if (m) {
4165f0216bdSXin LI 			if (checkdone(ms, &rv))
417b6cee71dSXin LI 				goto done;
418b6cee71dSXin LI 		}
4199ce06829SXin LI 	}
420b6cee71dSXin LI #ifdef BUILTIN_ELF
4212dc4dbb9SEitan Adler 	if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) {
4222dc4dbb9SEitan Adler 		file_pushbuf_t *pb;
423b6cee71dSXin LI 		/*
424b6cee71dSXin LI 		 * We matched something in the file, so this
425b6cee71dSXin LI 		 * *might* be an ELF file, and the file is at
426b6cee71dSXin LI 		 * least 5 bytes long, so if it's an ELF file
427b6cee71dSXin LI 		 * it has at least one byte past the ELF magic
428b6cee71dSXin LI 		 * number - try extracting information from the
4292dc4dbb9SEitan Adler 		 * ELF headers that cannot easily be  extracted
4302dc4dbb9SEitan Adler 		 * with rules in the magic file. We we don't
4312dc4dbb9SEitan Adler 		 * print the information yet.
432b6cee71dSXin LI 		 */
4332dc4dbb9SEitan Adler 		if ((pb = file_push_buffer(ms)) == NULL)
4342dc4dbb9SEitan Adler 			return -1;
4352dc4dbb9SEitan Adler 
4362dc4dbb9SEitan Adler 		rv = file_tryelf(ms, &b);
4372dc4dbb9SEitan Adler 		rbuf = file_pop_buffer(ms, pb);
43848c779cdSXin LI 		if (rv == -1) {
4392dc4dbb9SEitan Adler 			free(rbuf);
4402dc4dbb9SEitan Adler 			rbuf = NULL;
4412dc4dbb9SEitan Adler 		}
442b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4432dc4dbb9SEitan Adler 			(void)fprintf(stderr, "[try elf %d]\n", m);
444b6cee71dSXin LI 	}
445b6cee71dSXin LI #endif
4462dc4dbb9SEitan Adler 
4472dc4dbb9SEitan Adler 	/* try soft magic tests */
4482dc4dbb9SEitan Adler 	if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
4492dc4dbb9SEitan Adler 		m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text);
4502dc4dbb9SEitan Adler 		if ((ms->flags & MAGIC_DEBUG) != 0)
4512dc4dbb9SEitan Adler 			(void)fprintf(stderr, "[try softmagic %d]\n", m);
4522dc4dbb9SEitan Adler 		if (m == 1 && rbuf) {
4532dc4dbb9SEitan Adler 			if (file_printf(ms, "%s", rbuf) == -1)
4542dc4dbb9SEitan Adler 				goto done;
4552dc4dbb9SEitan Adler 		}
4562dc4dbb9SEitan Adler 		if (m) {
4575f0216bdSXin LI 			if (checkdone(ms, &rv))
458b6cee71dSXin LI 				goto done;
459b6cee71dSXin LI 		}
460a5d223e6SXin LI 	}
461b6cee71dSXin LI 
462b6cee71dSXin LI 	/* try text properties */
463b6cee71dSXin LI 	if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
464b6cee71dSXin LI 
46558a0f0d0SEitan Adler 		m = file_ascmagic(ms, &b, looks_text);
466b6cee71dSXin LI 		if ((ms->flags & MAGIC_DEBUG) != 0)
4679ce06829SXin LI 			(void)fprintf(stderr, "[try ascmagic %d]\n", m);
4689ce06829SXin LI 		if (m) {
469b6cee71dSXin LI 			goto done;
470b6cee71dSXin LI 		}
471b6cee71dSXin LI 	}
472b6cee71dSXin LI 
473b6cee71dSXin LI simple:
474b6cee71dSXin LI 	/* give up */
47548c779cdSXin LI 	if (m == 0) {
476b6cee71dSXin LI 		m = 1;
47748c779cdSXin LI 		rv = file_default(ms, nb);
47848c779cdSXin LI 		if (rv == 0)
4793e41d09dSXin LI 			if (file_printf(ms, "%s", def) == -1)
480b6cee71dSXin LI 				rv = -1;
481b6cee71dSXin LI 	}
482b6cee71dSXin LI  done:
48343a5ec4eSXin LI 	trim_separator(ms);
484b6cee71dSXin LI 	if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
485b6cee71dSXin LI 		if (ms->flags & MAGIC_MIME_TYPE)
486b6cee71dSXin LI 			if (file_printf(ms, "; charset=") == -1)
487b6cee71dSXin LI 				rv = -1;
488b6cee71dSXin LI 		if (file_printf(ms, "%s", code_mime) == -1)
489b6cee71dSXin LI 			rv = -1;
490b6cee71dSXin LI 	}
491b6cee71dSXin LI #if HAVE_FORK
492b6cee71dSXin LI  done_encoding:
493b6cee71dSXin LI #endif
4942dc4dbb9SEitan Adler 	free(rbuf);
49558a0f0d0SEitan Adler 	buffer_fini(&b);
496b6cee71dSXin LI 	if (rv)
497b6cee71dSXin LI 		return rv;
498b6cee71dSXin LI 
499b6cee71dSXin LI 	return m;
500b6cee71dSXin LI }
501b6cee71dSXin LI #endif
502b6cee71dSXin LI 
503b6cee71dSXin LI protected int
50440427ccaSGordon Tetlow file_reset(struct magic_set *ms, int checkloaded)
505b6cee71dSXin LI {
50640427ccaSGordon Tetlow 	if (checkloaded && ms->mlist[0] == NULL) {
507b6cee71dSXin LI 		file_error(ms, 0, "no magic files loaded");
508b6cee71dSXin LI 		return -1;
509b6cee71dSXin LI 	}
5102726a701SXin LI 	file_clearbuf(ms);
511b6cee71dSXin LI 	if (ms->o.pbuf) {
512b6cee71dSXin LI 		free(ms->o.pbuf);
513b6cee71dSXin LI 		ms->o.pbuf = NULL;
514b6cee71dSXin LI 	}
515b6cee71dSXin LI 	ms->event_flags &= ~EVENT_HAD_ERR;
516b6cee71dSXin LI 	ms->error = -1;
517b6cee71dSXin LI 	return 0;
518b6cee71dSXin LI }
519b6cee71dSXin LI 
520b6cee71dSXin LI #define OCTALIFY(n, o)	\
521b6cee71dSXin LI 	/*LINTED*/ \
522b6cee71dSXin LI 	(void)(*(n)++ = '\\', \
52348c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 6) & 3) + '0', \
52448c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 3) & 7) + '0', \
52548c779cdSXin LI 	*(n)++ = ((CAST(uint32_t, *(o)) >> 0) & 7) + '0', \
526b6cee71dSXin LI 	(o)++)
527b6cee71dSXin LI 
528b6cee71dSXin LI protected const char *
529b6cee71dSXin LI file_getbuffer(struct magic_set *ms)
530b6cee71dSXin LI {
531b6cee71dSXin LI 	char *pbuf, *op, *np;
532b6cee71dSXin LI 	size_t psize, len;
533b6cee71dSXin LI 
534b6cee71dSXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
535b6cee71dSXin LI 		return NULL;
536b6cee71dSXin LI 
537b6cee71dSXin LI 	if (ms->flags & MAGIC_RAW)
538b6cee71dSXin LI 		return ms->o.buf;
539b6cee71dSXin LI 
540b6cee71dSXin LI 	if (ms->o.buf == NULL)
541b6cee71dSXin LI 		return NULL;
542b6cee71dSXin LI 
543b6cee71dSXin LI 	/* * 4 is for octal representation, + 1 is for NUL */
544b6cee71dSXin LI 	len = strlen(ms->o.buf);
545b6cee71dSXin LI 	if (len > (SIZE_MAX - 1) / 4) {
546b6cee71dSXin LI 		file_oomem(ms, len);
547b6cee71dSXin LI 		return NULL;
548b6cee71dSXin LI 	}
549b6cee71dSXin LI 	psize = len * 4 + 1;
550b6cee71dSXin LI 	if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) {
551b6cee71dSXin LI 		file_oomem(ms, psize);
552b6cee71dSXin LI 		return NULL;
553b6cee71dSXin LI 	}
554b6cee71dSXin LI 	ms->o.pbuf = pbuf;
555b6cee71dSXin LI 
556b6cee71dSXin LI #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
557b6cee71dSXin LI 	{
558b6cee71dSXin LI 		mbstate_t state;
559b6cee71dSXin LI 		wchar_t nextchar;
560b6cee71dSXin LI 		int mb_conv = 1;
561b6cee71dSXin LI 		size_t bytesconsumed;
562b6cee71dSXin LI 		char *eop;
563b6cee71dSXin LI 		(void)memset(&state, 0, sizeof(mbstate_t));
564b6cee71dSXin LI 
565b6cee71dSXin LI 		np = ms->o.pbuf;
566b6cee71dSXin LI 		op = ms->o.buf;
567b6cee71dSXin LI 		eop = op + len;
568b6cee71dSXin LI 
569b6cee71dSXin LI 		while (op < eop) {
570b6cee71dSXin LI 			bytesconsumed = mbrtowc(&nextchar, op,
57148c779cdSXin LI 			    CAST(size_t, eop - op), &state);
57248c779cdSXin LI 			if (bytesconsumed == CAST(size_t, -1) ||
57348c779cdSXin LI 			    bytesconsumed == CAST(size_t, -2)) {
574b6cee71dSXin LI 				mb_conv = 0;
575b6cee71dSXin LI 				break;
576b6cee71dSXin LI 			}
577b6cee71dSXin LI 
578b6cee71dSXin LI 			if (iswprint(nextchar)) {
579b6cee71dSXin LI 				(void)memcpy(np, op, bytesconsumed);
580b6cee71dSXin LI 				op += bytesconsumed;
581b6cee71dSXin LI 				np += bytesconsumed;
582b6cee71dSXin LI 			} else {
583b6cee71dSXin LI 				while (bytesconsumed-- > 0)
584b6cee71dSXin LI 					OCTALIFY(np, op);
585b6cee71dSXin LI 			}
586b6cee71dSXin LI 		}
587b6cee71dSXin LI 		*np = '\0';
588b6cee71dSXin LI 
589b6cee71dSXin LI 		/* Parsing succeeded as a multi-byte sequence */
590b6cee71dSXin LI 		if (mb_conv != 0)
591b6cee71dSXin LI 			return ms->o.pbuf;
592b6cee71dSXin LI 	}
593b6cee71dSXin LI #endif
594b6cee71dSXin LI 
595b6cee71dSXin LI 	for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
59648c779cdSXin LI 		if (isprint(CAST(unsigned char, *op))) {
597b6cee71dSXin LI 			*np++ = *op++;
598b6cee71dSXin LI 		} else {
599b6cee71dSXin LI 			OCTALIFY(np, op);
600b6cee71dSXin LI 		}
601b6cee71dSXin LI 	}
602b6cee71dSXin LI 	*np = '\0';
603b6cee71dSXin LI 	return ms->o.pbuf;
604b6cee71dSXin LI }
605b6cee71dSXin LI 
606b6cee71dSXin LI protected int
607b6cee71dSXin LI file_check_mem(struct magic_set *ms, unsigned int level)
608b6cee71dSXin LI {
609b6cee71dSXin LI 	size_t len;
610b6cee71dSXin LI 
611b6cee71dSXin LI 	if (level >= ms->c.len) {
6125f0216bdSXin LI 		len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
613b6cee71dSXin LI 		ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
614b6cee71dSXin LI 		    malloc(len) :
615b6cee71dSXin LI 		    realloc(ms->c.li, len));
616b6cee71dSXin LI 		if (ms->c.li == NULL) {
617b6cee71dSXin LI 			file_oomem(ms, len);
618b6cee71dSXin LI 			return -1;
619b6cee71dSXin LI 		}
620b6cee71dSXin LI 	}
621b6cee71dSXin LI 	ms->c.li[level].got_match = 0;
622b6cee71dSXin LI #ifdef ENABLE_CONDITIONALS
623b6cee71dSXin LI 	ms->c.li[level].last_match = 0;
624b6cee71dSXin LI 	ms->c.li[level].last_cond = COND_NONE;
625b6cee71dSXin LI #endif /* ENABLE_CONDITIONALS */
626b6cee71dSXin LI 	return 0;
627b6cee71dSXin LI }
628b6cee71dSXin LI 
629b6cee71dSXin LI protected size_t
630b6cee71dSXin LI file_printedlen(const struct magic_set *ms)
631b6cee71dSXin LI {
6322726a701SXin LI 	return ms->o.blen;
633b6cee71dSXin LI }
634b6cee71dSXin LI 
635b6cee71dSXin LI protected int
636b6cee71dSXin LI file_replace(struct magic_set *ms, const char *pat, const char *rep)
637b6cee71dSXin LI {
638b6cee71dSXin LI 	file_regex_t rx;
639b6cee71dSXin LI 	int rc, rv = -1;
640b6cee71dSXin LI 
641a4d6d3b8SXin LI 	rc = file_regcomp(ms, &rx, pat, REG_EXTENDED);
642a4d6d3b8SXin LI 	if (rc == 0) {
643b6cee71dSXin LI 		regmatch_t rm;
644b6cee71dSXin LI 		int nm = 0;
645a4d6d3b8SXin LI 		while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) {
646b6cee71dSXin LI 			ms->o.buf[rm.rm_so] = '\0';
647b6cee71dSXin LI 			if (file_printf(ms, "%s%s", rep,
648b6cee71dSXin LI 			    rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1)
649b6cee71dSXin LI 				goto out;
650b6cee71dSXin LI 			nm++;
651b6cee71dSXin LI 		}
652b6cee71dSXin LI 		rv = nm;
653b6cee71dSXin LI 	}
654b6cee71dSXin LI out:
655b6cee71dSXin LI 	file_regfree(&rx);
656b6cee71dSXin LI 	return rv;
657b6cee71dSXin LI }
658b6cee71dSXin LI 
659b6cee71dSXin LI protected int
660a4d6d3b8SXin LI file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx,
661a4d6d3b8SXin LI     const char *pat, int flags)
662b6cee71dSXin LI {
663c2931133SXin LI #ifdef USE_C_LOCALE
664a4d6d3b8SXin LI 	locale_t old = uselocale(ms->c_lc_ctype);
665a4d6d3b8SXin LI 	assert(old != NULL);
6663e41d09dSXin LI #else
667a4d6d3b8SXin LI 	char old[1024];
668a4d6d3b8SXin LI 	strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old));
669d38c30c0SXin LI 	(void)setlocale(LC_CTYPE, "C");
670c2931133SXin LI #endif
671a4d6d3b8SXin LI 	int rc;
672a4d6d3b8SXin LI 	rc = regcomp(rx, pat, flags);
673b6cee71dSXin LI 
674a4d6d3b8SXin LI #ifdef USE_C_LOCALE
675a4d6d3b8SXin LI 	uselocale(old);
676a4d6d3b8SXin LI #else
677a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, old);
678a4d6d3b8SXin LI #endif
679a4d6d3b8SXin LI 	if (rc > 0 && (ms->flags & MAGIC_CHECK)) {
680a4d6d3b8SXin LI 		char errmsg[512];
681a4d6d3b8SXin LI 
682a4d6d3b8SXin LI 		(void)regerror(rc, rx, errmsg, sizeof(errmsg));
683a4d6d3b8SXin LI 		file_magerror(ms, "regex error %d for `%s', (%s)", rc, pat,
684a4d6d3b8SXin LI 		    errmsg);
685a4d6d3b8SXin LI 	}
686a4d6d3b8SXin LI 	return rc;
687b6cee71dSXin LI }
688b6cee71dSXin LI 
689*a2dfb722SXin LI /*ARGSUSED*/
690b6cee71dSXin LI protected int
691a4d6d3b8SXin LI file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx,
692a4d6d3b8SXin LI     const char *str, size_t nmatch, regmatch_t* pmatch, int eflags)
693b6cee71dSXin LI {
694a4d6d3b8SXin LI #ifdef USE_C_LOCALE
695a4d6d3b8SXin LI 	locale_t old = uselocale(ms->c_lc_ctype);
696a4d6d3b8SXin LI 	assert(old != NULL);
697a4d6d3b8SXin LI #else
698a4d6d3b8SXin LI 	char old[1024];
699a4d6d3b8SXin LI 	strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old));
700a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, "C");
701a4d6d3b8SXin LI #endif
702a4d6d3b8SXin LI 	int rc;
70340427ccaSGordon Tetlow 	/* XXX: force initialization because glibc does not always do this */
704d38c30c0SXin LI 	if (nmatch != 0)
70540427ccaSGordon Tetlow 		memset(pmatch, 0, nmatch * sizeof(*pmatch));
706a4d6d3b8SXin LI 	rc = regexec(rx, str, nmatch, pmatch, eflags);
707a4d6d3b8SXin LI #ifdef USE_C_LOCALE
708a4d6d3b8SXin LI 	uselocale(old);
709a4d6d3b8SXin LI #else
710a4d6d3b8SXin LI 	(void)setlocale(LC_CTYPE, old);
711a4d6d3b8SXin LI #endif
712a4d6d3b8SXin LI 	return rc;
713b6cee71dSXin LI }
714b6cee71dSXin LI 
715b6cee71dSXin LI protected void
716b6cee71dSXin LI file_regfree(file_regex_t *rx)
717b6cee71dSXin LI {
718a4d6d3b8SXin LI 	regfree(rx);
719b6cee71dSXin LI }
7202c4f1647SXin LI 
7212c4f1647SXin LI protected file_pushbuf_t *
7222c4f1647SXin LI file_push_buffer(struct magic_set *ms)
7232c4f1647SXin LI {
7242c4f1647SXin LI 	file_pushbuf_t *pb;
7252c4f1647SXin LI 
7262c4f1647SXin LI 	if (ms->event_flags & EVENT_HAD_ERR)
7272c4f1647SXin LI 		return NULL;
7282c4f1647SXin LI 
7292c4f1647SXin LI 	if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
7302c4f1647SXin LI 		return NULL;
7312c4f1647SXin LI 
7322c4f1647SXin LI 	pb->buf = ms->o.buf;
7332726a701SXin LI 	pb->blen = ms->o.blen;
7342c4f1647SXin LI 	pb->offset = ms->offset;
7352c4f1647SXin LI 
7362c4f1647SXin LI 	ms->o.buf = NULL;
7372726a701SXin LI 	ms->o.blen = 0;
7382c4f1647SXin LI 	ms->offset = 0;
7392c4f1647SXin LI 
7402c4f1647SXin LI 	return pb;
7412c4f1647SXin LI }
7422c4f1647SXin LI 
7432c4f1647SXin LI protected char *
7442c4f1647SXin LI file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
7452c4f1647SXin LI {
7462c4f1647SXin LI 	char *rbuf;
7472c4f1647SXin LI 
7482c4f1647SXin LI 	if (ms->event_flags & EVENT_HAD_ERR) {
7492c4f1647SXin LI 		free(pb->buf);
7502c4f1647SXin LI 		free(pb);
7512c4f1647SXin LI 		return NULL;
7522c4f1647SXin LI 	}
7532c4f1647SXin LI 
7542c4f1647SXin LI 	rbuf = ms->o.buf;
7552c4f1647SXin LI 
7562c4f1647SXin LI 	ms->o.buf = pb->buf;
7572726a701SXin LI 	ms->o.blen = pb->blen;
7582c4f1647SXin LI 	ms->offset = pb->offset;
7592c4f1647SXin LI 
7602c4f1647SXin LI 	free(pb);
7612c4f1647SXin LI 	return rbuf;
7622c4f1647SXin LI }
7634460e5b0SXin LI 
7644460e5b0SXin LI /*
7654460e5b0SXin LI  * convert string to ascii printable format.
7664460e5b0SXin LI  */
767*a2dfb722SXin LI protected char *
76843a5ec4eSXin LI file_printable(struct magic_set *ms, char *buf, size_t bufsiz,
76943a5ec4eSXin LI     const char *str, size_t slen)
7704460e5b0SXin LI {
77148c779cdSXin LI 	char *ptr, *eptr = buf + bufsiz - 1;
77248c779cdSXin LI 	const unsigned char *s = RCAST(const unsigned char *, str);
77348c779cdSXin LI 	const unsigned char *es = s + slen;
7744460e5b0SXin LI 
77548c779cdSXin LI 	for (ptr = buf;  ptr < eptr && s < es && *s; s++) {
77643a5ec4eSXin LI 		if ((ms->flags & MAGIC_RAW) != 0 || isprint(*s)) {
7774460e5b0SXin LI 			*ptr++ = *s;
7784460e5b0SXin LI 			continue;
7794460e5b0SXin LI 		}
7804460e5b0SXin LI 		if (ptr >= eptr - 3)
7814460e5b0SXin LI 			break;
7824460e5b0SXin LI 		*ptr++ = '\\';
7835f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
7845f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
7855f0216bdSXin LI 		*ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
7864460e5b0SXin LI 	}
7874460e5b0SXin LI 	*ptr = '\0';
7884460e5b0SXin LI 	return buf;
7894460e5b0SXin LI }
7902726a701SXin LI 
7912726a701SXin LI struct guid {
7922726a701SXin LI 	uint32_t data1;
7932726a701SXin LI 	uint16_t data2;
7942726a701SXin LI 	uint16_t data3;
7952726a701SXin LI 	uint8_t data4[8];
7962726a701SXin LI };
7972726a701SXin LI 
7982726a701SXin LI protected int
7992726a701SXin LI file_parse_guid(const char *s, uint64_t *guid)
8002726a701SXin LI {
80143a5ec4eSXin LI 	struct guid *g = CAST(struct guid *, CAST(void *, guid));
802a4d6d3b8SXin LI #ifndef WIN32
8032726a701SXin LI 	return sscanf(s,
8042726a701SXin LI 	    "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
8052726a701SXin LI 	    &g->data1, &g->data2, &g->data3, &g->data4[0], &g->data4[1],
8062726a701SXin LI 	    &g->data4[2], &g->data4[3], &g->data4[4], &g->data4[5],
8072726a701SXin LI 	    &g->data4[6], &g->data4[7]) == 11 ? 0 : -1;
808a4d6d3b8SXin LI #else
809a4d6d3b8SXin LI 	/* MS-Windows runtime doesn't support %hhx, except under
810a4d6d3b8SXin LI 	   non-default __USE_MINGW_ANSI_STDIO.  */
811a4d6d3b8SXin LI 	uint16_t data16[8];
812a4d6d3b8SXin LI 	int rv = sscanf(s, "%8x-%4hx-%4hx-%2hx%2hx-%2hx%2hx%2hx%2hx%2hx%2hx",
813a4d6d3b8SXin LI 	    &g->data1, &g->data2, &g->data3, &data16[0], &data16[1],
814a4d6d3b8SXin LI 	    &data16[2], &data16[3], &data16[4], &data16[5],
815a4d6d3b8SXin LI 	    &data16[6], &data16[7]) == 11 ? 0 : -1;
816a4d6d3b8SXin LI 	int i;
817a4d6d3b8SXin LI 	for (i = 0; i < 8; i++)
818a4d6d3b8SXin LI 	    g->data4[i] = data16[i];
819a4d6d3b8SXin LI 	return rv;
820a4d6d3b8SXin LI #endif
8212726a701SXin LI }
8222726a701SXin LI 
8232726a701SXin LI protected int
8242726a701SXin LI file_print_guid(char *str, size_t len, const uint64_t *guid)
8252726a701SXin LI {
82643a5ec4eSXin LI 	const struct guid *g = CAST(const struct guid *,
82743a5ec4eSXin LI 	    CAST(const void *, guid));
8282726a701SXin LI 
829a4d6d3b8SXin LI #ifndef WIN32
8302726a701SXin LI 	return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hhX%.2hhX-"
8312726a701SXin LI 	    "%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX",
8322726a701SXin LI 	    g->data1, g->data2, g->data3, g->data4[0], g->data4[1],
8332726a701SXin LI 	    g->data4[2], g->data4[3], g->data4[4], g->data4[5],
8342726a701SXin LI 	    g->data4[6], g->data4[7]);
835a4d6d3b8SXin LI #else
836a4d6d3b8SXin LI 	return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hX%.2hX-"
837a4d6d3b8SXin LI 	    "%.2hX%.2hX%.2hX%.2hX%.2hX%.2hX",
838a4d6d3b8SXin LI 	    g->data1, g->data2, g->data3, g->data4[0], g->data4[1],
839a4d6d3b8SXin LI 	    g->data4[2], g->data4[3], g->data4[4], g->data4[5],
840a4d6d3b8SXin LI 	    g->data4[6], g->data4[7]);
841a4d6d3b8SXin LI #endif
8422726a701SXin LI }
84343a5ec4eSXin LI 
84443a5ec4eSXin LI protected int
84543a5ec4eSXin LI file_pipe_closexec(int *fds)
84643a5ec4eSXin LI {
84743a5ec4eSXin LI #ifdef HAVE_PIPE2
84843a5ec4eSXin LI 	return pipe2(fds, O_CLOEXEC);
84943a5ec4eSXin LI #else
85043a5ec4eSXin LI 	if (pipe(fds) == -1)
85143a5ec4eSXin LI 		return -1;
852a4d6d3b8SXin LI # ifdef F_SETFD
85343a5ec4eSXin LI 	(void)fcntl(fds[0], F_SETFD, FD_CLOEXEC);
85443a5ec4eSXin LI 	(void)fcntl(fds[1], F_SETFD, FD_CLOEXEC);
855a4d6d3b8SXin LI # endif
85643a5ec4eSXin LI 	return 0;
85743a5ec4eSXin LI #endif
85843a5ec4eSXin LI }
85943a5ec4eSXin LI 
86043a5ec4eSXin LI protected int
86143a5ec4eSXin LI file_clear_closexec(int fd) {
862a4d6d3b8SXin LI #ifdef F_SETFD
86343a5ec4eSXin LI 	return fcntl(fd, F_SETFD, 0);
864a4d6d3b8SXin LI #else
865a4d6d3b8SXin LI 	return 0;
866a4d6d3b8SXin LI #endif
86743a5ec4eSXin LI }
86843a5ec4eSXin LI 
86943a5ec4eSXin LI protected char *
87043a5ec4eSXin LI file_strtrim(char *str)
87143a5ec4eSXin LI {
87243a5ec4eSXin LI 	char *last;
87343a5ec4eSXin LI 
87443a5ec4eSXin LI 	while (isspace(CAST(unsigned char, *str)))
87543a5ec4eSXin LI 		str++;
87643a5ec4eSXin LI 	last = str;
87743a5ec4eSXin LI 	while (*last)
87843a5ec4eSXin LI 		last++;
87943a5ec4eSXin LI 	--last;
88043a5ec4eSXin LI 	while (isspace(CAST(unsigned char, *last)))
88143a5ec4eSXin LI 		last--;
88243a5ec4eSXin LI 	*++last = '\0';
88343a5ec4eSXin LI 	return str;
88443a5ec4eSXin LI }
885