"Fossies" - the Fresh Open Source Software Archive 
Member "file-5.35/src/funcs.c" (1 Oct 2018, 14168 Bytes) of package /linux/misc/file-5.35.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "funcs.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.34_vs_5.35.
1 /*
2 * Copyright (c) Christos Zoulas 2003.
3 * All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice immediately at the beginning of the file, without modification,
10 * this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 #include "file.h"
28
29 #ifndef lint
30 FILE_RCSID("@(#)$File: funcs.c,v 1.100 2018/10/01 18:45:39 christos Exp $")
31 #endif /* lint */
32
33 #include "magic.h"
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 #if defined(HAVE_WCHAR_H)
40 #include <wchar.h>
41 #endif
42 #if defined(HAVE_WCTYPE_H)
43 #include <wctype.h>
44 #endif
45 #include <limits.h>
46
47 #ifndef SIZE_MAX
48 #define SIZE_MAX ((size_t)~0)
49 #endif
50
51 /*
52 * Like printf, only we append to a buffer.
53 */
54 protected int
55 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap)
56 {
57 int len;
58 char *buf, *newstr;
59
60 if (ms->event_flags & EVENT_HAD_ERR)
61 return 0;
62 len = vasprintf(&buf, fmt, ap);
63 if (len < 0)
64 goto out;
65
66 if (ms->o.buf != NULL) {
67 len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
68 free(buf);
69 if (len < 0)
70 goto out;
71 free(ms->o.buf);
72 buf = newstr;
73 }
74 ms->o.buf = buf;
75 return 0;
76 out:
77 fprintf(stderr, "vasprintf failed (%s)", strerror(errno));
78 return -1;
79 }
80
81 protected int
82 file_printf(struct magic_set *ms, const char *fmt, ...)
83 {
84 int rv;
85 va_list ap;
86
87 va_start(ap, fmt);
88 rv = file_vprintf(ms, fmt, ap);
89 va_end(ap);
90 return rv;
91 }
92
93 /*
94 * error - print best error message possible
95 */
96 /*VARARGS*/
97 __attribute__((__format__(__printf__, 3, 0)))
98 private void
99 file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
100 size_t lineno)
101 {
102 /* Only the first error is ok */
103 if (ms->event_flags & EVENT_HAD_ERR)
104 return;
105 if (lineno != 0) {
106 free(ms->o.buf);
107 ms->o.buf = NULL;
108 (void)file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno);
109 }
110 if (ms->o.buf && *ms->o.buf)
111 (void)file_printf(ms, " ");
112 (void)file_vprintf(ms, f, va);
113 if (error > 0)
114 (void)file_printf(ms, " (%s)", strerror(error));
115 ms->event_flags |= EVENT_HAD_ERR;
116 ms->error = error;
117 }
118
119 /*VARARGS*/
120 protected void
121 file_error(struct magic_set *ms, int error, const char *f, ...)
122 {
123 va_list va;
124 va_start(va, f);
125 file_error_core(ms, error, f, va, 0);
126 va_end(va);
127 }
128
129 /*
130 * Print an error with magic line number.
131 */
132 /*VARARGS*/
133 protected void
134 file_magerror(struct magic_set *ms, const char *f, ...)
135 {
136 va_list va;
137 va_start(va, f);
138 file_error_core(ms, 0, f, va, ms->line);
139 va_end(va);
140 }
141
142 protected void
143 file_oomem(struct magic_set *ms, size_t len)
144 {
145 file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
146 len);
147 }
148
149 protected void
150 file_badseek(struct magic_set *ms)
151 {
152 file_error(ms, errno, "error seeking");
153 }
154
155 protected void
156 file_badread(struct magic_set *ms)
157 {
158 file_error(ms, errno, "error reading");
159 }
160
161 #ifndef COMPILE_ONLY
162
163 static int
164 checkdone(struct magic_set *ms, int *rv)
165 {
166 if ((ms->flags & MAGIC_CONTINUE) == 0)
167 return 1;
168 if (file_printf(ms, "\n- ") == -1)
169 *rv = -1;
170 return 0;
171 }
172
173 protected int
174 file_default(struct magic_set *ms, size_t nb)
175 {
176 if (ms->flags & MAGIC_MIME) {
177 if ((ms->flags & MAGIC_MIME_TYPE) &&
178 file_printf(ms, "application/%s",
179 nb ? "octet-stream" : "x-empty") == -1)
180 return -1;
181 return 1;
182 }
183 if (ms->flags & MAGIC_APPLE) {
184 if (file_printf(ms, "UNKNUNKN") == -1)
185 return -1;
186 return 1;
187 }
188 if (ms->flags & MAGIC_EXTENSION) {
189 if (file_printf(ms, "???") == -1)
190 return -1;
191 return 1;
192 }
193 return 0;
194 }
195
196 /*
197 * The magic detection functions return:
198 * 1: found
199 * 0: not found
200 * -1: error
201 */
202 /*ARGSUSED*/
203 protected int
204 file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__unused__)),
205 const void *buf, size_t nb)
206 {
207 int m = 0, rv = 0, looks_text = 0;
208 const char *code = NULL;
209 const char *code_mime = "binary";
210 const char *def = "data";
211 const char *ftype = NULL;
212 char *rbuf = NULL;
213 struct buffer b;
214
215 buffer_init(&b, fd, buf, nb);
216 ms->mode = b.st.st_mode;
217
218 if (nb == 0) {
219 def = "empty";
220 goto simple;
221 } else if (nb == 1) {
222 def = "very short file (no magic)";
223 goto simple;
224 }
225
226 if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
227 looks_text = file_encoding(ms, &b, NULL, 0,
228 &code, &code_mime, &ftype);
229 }
230
231 #ifdef __EMX__
232 if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
233 m = file_os2_apptype(ms, inname, &b);
234 if ((ms->flags & MAGIC_DEBUG) != 0)
235 (void)fprintf(stderr, "[try os2_apptype %d]\n", m);
236 switch (m) {
237 case -1:
238 return -1;
239 case 0:
240 break;
241 default:
242 return 1;
243 }
244 }
245 #endif
246 #if HAVE_FORK
247 /* try compression stuff */
248 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) {
249 m = file_zmagic(ms, &b, inname);
250 if ((ms->flags & MAGIC_DEBUG) != 0)
251 (void)fprintf(stderr, "[try zmagic %d]\n", m);
252 if (m) {
253 goto done_encoding;
254 }
255 }
256 #endif
257 /* Check if we have a tar file */
258 if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) {
259 m = file_is_tar(ms, &b);
260 if ((ms->flags & MAGIC_DEBUG) != 0)
261 (void)fprintf(stderr, "[try tar %d]\n", m);
262 if (m) {
263 if (checkdone(ms, &rv))
264 goto done;
265 }
266 }
267
268 /* Check if we have a JSON file */
269 if ((ms->flags & MAGIC_NO_CHECK_JSON) == 0) {
270 m = file_is_json(ms, &b);
271 if ((ms->flags & MAGIC_DEBUG) != 0)
272 (void)fprintf(stderr, "[try json %d]\n", m);
273 if (m) {
274 if (checkdone(ms, &rv))
275 goto done;
276 }
277 }
278
279 /* Check if we have a CDF file */
280 if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
281 m = file_trycdf(ms, &b);
282 if ((ms->flags & MAGIC_DEBUG) != 0)
283 (void)fprintf(stderr, "[try cdf %d]\n", m);
284 if (m) {
285 if (checkdone(ms, &rv))
286 goto done;
287 }
288 }
289 #ifdef BUILTIN_ELF
290 if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) {
291 file_pushbuf_t *pb;
292 /*
293 * We matched something in the file, so this
294 * *might* be an ELF file, and the file is at
295 * least 5 bytes long, so if it's an ELF file
296 * it has at least one byte past the ELF magic
297 * number - try extracting information from the
298 * ELF headers that cannot easily be extracted
299 * with rules in the magic file. We we don't
300 * print the information yet.
301 */
302 if ((pb = file_push_buffer(ms)) == NULL)
303 return -1;
304
305 rv = file_tryelf(ms, &b);
306 rbuf = file_pop_buffer(ms, pb);
307 if (rv == -1) {
308 free(rbuf);
309 rbuf = NULL;
310 }
311 if ((ms->flags & MAGIC_DEBUG) != 0)
312 (void)fprintf(stderr, "[try elf %d]\n", m);
313 }
314 #endif
315
316 /* try soft magic tests */
317 if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
318 m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text);
319 if ((ms->flags & MAGIC_DEBUG) != 0)
320 (void)fprintf(stderr, "[try softmagic %d]\n", m);
321 if (m == 1 && rbuf) {
322 if (file_printf(ms, "%s", rbuf) == -1)
323 goto done;
324 }
325 if (m) {
326 if (checkdone(ms, &rv))
327 goto done;
328 }
329 }
330
331 /* try text properties */
332 if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
333
334 m = file_ascmagic(ms, &b, looks_text);
335 if ((ms->flags & MAGIC_DEBUG) != 0)
336 (void)fprintf(stderr, "[try ascmagic %d]\n", m);
337 if (m) {
338 if (checkdone(ms, &rv))
339 goto done;
340 }
341 }
342
343 simple:
344 /* give up */
345 if (m == 0) {
346 m = 1;
347 rv = file_default(ms, nb);
348 if (rv == 0)
349 if (file_printf(ms, "%s", def) == -1)
350 rv = -1;
351 }
352 done:
353 if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
354 if (ms->flags & MAGIC_MIME_TYPE)
355 if (file_printf(ms, "; charset=") == -1)
356 rv = -1;
357 if (file_printf(ms, "%s", code_mime) == -1)
358 rv = -1;
359 }
360 #if HAVE_FORK
361 done_encoding:
362 #endif
363 free(rbuf);
364 buffer_fini(&b);
365 if (rv)
366 return rv;
367
368 return m;
369 }
370 #endif
371
372 protected int
373 file_reset(struct magic_set *ms, int checkloaded)
374 {
375 if (checkloaded && ms->mlist[0] == NULL) {
376 file_error(ms, 0, "no magic files loaded");
377 return -1;
378 }
379 if (ms->o.buf) {
380 free(ms->o.buf);
381 ms->o.buf = NULL;
382 }
383 if (ms->o.pbuf) {
384 free(ms->o.pbuf);
385 ms->o.pbuf = NULL;
386 }
387 ms->event_flags &= ~EVENT_HAD_ERR;
388 ms->error = -1;
389 return 0;
390 }
391
392 #define OCTALIFY(n, o) \
393 /*LINTED*/ \
394 (void)(*(n)++ = '\\', \
395 *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
396 *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
397 *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
398 (o)++)
399
400 protected const char *
401 file_getbuffer(struct magic_set *ms)
402 {
403 char *pbuf, *op, *np;
404 size_t psize, len;
405
406 if (ms->event_flags & EVENT_HAD_ERR)
407 return NULL;
408
409 if (ms->flags & MAGIC_RAW)
410 return ms->o.buf;
411
412 if (ms->o.buf == NULL)
413 return NULL;
414
415 /* * 4 is for octal representation, + 1 is for NUL */
416 len = strlen(ms->o.buf);
417 if (len > (SIZE_MAX - 1) / 4) {
418 file_oomem(ms, len);
419 return NULL;
420 }
421 psize = len * 4 + 1;
422 if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) {
423 file_oomem(ms, psize);
424 return NULL;
425 }
426 ms->o.pbuf = pbuf;
427
428 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
429 {
430 mbstate_t state;
431 wchar_t nextchar;
432 int mb_conv = 1;
433 size_t bytesconsumed;
434 char *eop;
435 (void)memset(&state, 0, sizeof(mbstate_t));
436
437 np = ms->o.pbuf;
438 op = ms->o.buf;
439 eop = op + len;
440
441 while (op < eop) {
442 bytesconsumed = mbrtowc(&nextchar, op,
443 (size_t)(eop - op), &state);
444 if (bytesconsumed == (size_t)(-1) ||
445 bytesconsumed == (size_t)(-2)) {
446 mb_conv = 0;
447 break;
448 }
449
450 if (iswprint(nextchar)) {
451 (void)memcpy(np, op, bytesconsumed);
452 op += bytesconsumed;
453 np += bytesconsumed;
454 } else {
455 while (bytesconsumed-- > 0)
456 OCTALIFY(np, op);
457 }
458 }
459 *np = '\0';
460
461 /* Parsing succeeded as a multi-byte sequence */
462 if (mb_conv != 0)
463 return ms->o.pbuf;
464 }
465 #endif
466
467 for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
468 if (isprint((unsigned char)*op)) {
469 *np++ = *op++;
470 } else {
471 OCTALIFY(np, op);
472 }
473 }
474 *np = '\0';
475 return ms->o.pbuf;
476 }
477
478 protected int
479 file_check_mem(struct magic_set *ms, unsigned int level)
480 {
481 size_t len;
482
483 if (level >= ms->c.len) {
484 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
485 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
486 malloc(len) :
487 realloc(ms->c.li, len));
488 if (ms->c.li == NULL) {
489 file_oomem(ms, len);
490 return -1;
491 }
492 }
493 ms->c.li[level].got_match = 0;
494 #ifdef ENABLE_CONDITIONALS
495 ms->c.li[level].last_match = 0;
496 ms->c.li[level].last_cond = COND_NONE;
497 #endif /* ENABLE_CONDITIONALS */
498 return 0;
499 }
500
501 protected size_t
502 file_printedlen(const struct magic_set *ms)
503 {
504 return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
505 }
506
507 protected int
508 file_replace(struct magic_set *ms, const char *pat, const char *rep)
509 {
510 file_regex_t rx;
511 int rc, rv = -1;
512
513 rc = file_regcomp(&rx, pat, REG_EXTENDED);
514 if (rc) {
515 file_regerror(&rx, rc, ms);
516 } else {
517 regmatch_t rm;
518 int nm = 0;
519 while (file_regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) {
520 ms->o.buf[rm.rm_so] = '\0';
521 if (file_printf(ms, "%s%s", rep,
522 rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1)
523 goto out;
524 nm++;
525 }
526 rv = nm;
527 }
528 out:
529 file_regfree(&rx);
530 return rv;
531 }
532
533 protected int
534 file_regcomp(file_regex_t *rx, const char *pat, int flags)
535 {
536 #ifdef USE_C_LOCALE
537 rx->c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
538 assert(rx->c_lc_ctype != NULL);
539 rx->old_lc_ctype = uselocale(rx->c_lc_ctype);
540 assert(rx->old_lc_ctype != NULL);
541 #else
542 rx->old_lc_ctype = setlocale(LC_CTYPE, "C");
543 #endif
544 rx->pat = pat;
545
546 return rx->rc = regcomp(&rx->rx, pat, flags);
547 }
548
549 protected int
550 file_regexec(file_regex_t *rx, const char *str, size_t nmatch,
551 regmatch_t* pmatch, int eflags)
552 {
553 assert(rx->rc == 0);
554 /* XXX: force initialization because glibc does not always do this */
555 memset(pmatch, 0, nmatch * sizeof(*pmatch));
556 return regexec(&rx->rx, str, nmatch, pmatch, eflags);
557 }
558
559 protected void
560 file_regfree(file_regex_t *rx)
561 {
562 if (rx->rc == 0)
563 regfree(&rx->rx);
564 #ifdef USE_C_LOCALE
565 (void)uselocale(rx->old_lc_ctype);
566 freelocale(rx->c_lc_ctype);
567 #else
568 (void)setlocale(LC_CTYPE, rx->old_lc_ctype);
569 #endif
570 }
571
572 protected void
573 file_regerror(file_regex_t *rx, int rc, struct magic_set *ms)
574 {
575 char errmsg[512];
576
577 (void)regerror(rc, &rx->rx, errmsg, sizeof(errmsg));
578 file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat,
579 errmsg);
580 }
581
582 protected file_pushbuf_t *
583 file_push_buffer(struct magic_set *ms)
584 {
585 file_pushbuf_t *pb;
586
587 if (ms->event_flags & EVENT_HAD_ERR)
588 return NULL;
589
590 if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
591 return NULL;
592
593 pb->buf = ms->o.buf;
594 pb->offset = ms->offset;
595
596 ms->o.buf = NULL;
597 ms->offset = 0;
598
599 return pb;
600 }
601
602 protected char *
603 file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
604 {
605 char *rbuf;
606
607 if (ms->event_flags & EVENT_HAD_ERR) {
608 free(pb->buf);
609 free(pb);
610 return NULL;
611 }
612
613 rbuf = ms->o.buf;
614
615 ms->o.buf = pb->buf;
616 ms->offset = pb->offset;
617
618 free(pb);
619 return rbuf;
620 }
621
622 /*
623 * convert string to ascii printable format.
624 */
625 protected char *
626 file_printable(char *buf, size_t bufsiz, const char *str)
627 {
628 char *ptr, *eptr;
629 const unsigned char *s = (const unsigned char *)str;
630
631 for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
632 if (isprint(*s)) {
633 *ptr++ = *s;
634 continue;
635 }
636 if (ptr >= eptr - 3)
637 break;
638 *ptr++ = '\\';
639 *ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
640 *ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
641 *ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
642 }
643 *ptr = '\0';
644 return buf;
645 }