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