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