Annotation of src/usr.bin/file/magic-test.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: magic-test.c,v 1.3 2015/04/25 16:35:47 brynet Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <ctype.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <limits.h>
25: #include <stdarg.h>
26: #include <stdio.h>
27: #include <stdint.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <unistd.h>
31: #include <vis.h>
32:
33: #include "magic.h"
34: #include "xmalloc.h"
35:
36: static int
37: magic_one_eq(char a, char b, int cflag)
38: {
39: if (a == b)
40: return (1);
1.4 ! nicm 41: if (cflag && islower((u_char)b) && tolower((u_char)a) == (u_char)b)
1.1 nicm 42: return (1);
43: return (0);
44: }
45:
46: static int
47: magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
48: int cflag, int bflag, int Bflag)
49: {
50: size_t aoff, boff, aspaces, bspaces;
51:
52: aoff = boff = 0;
53: while (aoff != asize && boff != bsize) {
54: if (Bflag && isspace((u_char)ap[aoff])) {
55: aspaces = 0;
56: while (aoff != asize && isspace((u_char)ap[aoff])) {
57: aspaces++;
58: aoff++;
59: }
60: bspaces = 0;
61: while (boff != bsize && isspace((u_char)bp[boff])) {
62: bspaces++;
63: boff++;
64: }
65: if (bspaces >= aspaces)
66: continue;
67: return (1);
68: }
69: if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
70: aoff++;
71: boff++;
72: continue;
73: }
74: if (bflag && isspace((u_char)bp[boff])) {
75: boff++;
76: continue;
77: }
78: if (ap[aoff] < bp[boff])
79: return (-1);
80: return (1);
81: }
82: return (0);
83: }
84:
85: static int
86: magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
87: {
88: if (offset < 0)
89: offset = ms->offset;
90: if (offset + size > ms->size)
91: return (-1);
92: memcpy(dst, ms->base + offset, size);
93: return (0);
94: }
95:
96: static void
97: magic_add_result(struct magic_state *ms, struct magic_line *ml,
98: const char *fmt, ...)
99: {
100: va_list ap;
101: int separate;
102: char *s, *tmp, *add;
103:
104: va_start(ap, fmt);
105: if (ml->stringify) {
106: if (vasprintf(&s, fmt, ap) == -1) {
107: va_end(ap);
108: return;
109: }
110: va_end(ap);
111: if (asprintf(&tmp, ml->result, s) == -1) {
112: free(s);
113: return;
114: }
115: free(s);
116: } else {
117: if (vasprintf(&tmp, ml->result, ap) == -1) {
118: va_end(ap);
119: return;
120: }
121: va_end(ap);
122: }
123:
124: separate = 1;
125: if (tmp[0] == '\\' && tmp[1] == 'b') {
126: separate = 0;
127: add = tmp + 2;
128: } else
129: add = tmp;
130:
131: if (separate && *ms->out != '\0')
132: strlcat(ms->out, " ", sizeof ms->out);
133: strlcat(ms->out, add, sizeof ms->out);
134:
135: free(tmp);
136: }
137:
138: static void
139: magic_add_string(struct magic_state *ms, struct magic_line *ml,
1.2 deraadt 140: const char *s, size_t slen)
1.1 nicm 141: {
142: char *out;
143: size_t outlen, offset;
144:
145: outlen = MAGIC_STRING_SIZE;
146: if (outlen > slen)
147: outlen = slen;
148: for (offset = 0; offset < outlen; offset++) {
149: if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
150: outlen = offset;
151: break;
152: }
153: }
154: out = xreallocarray(NULL, 4, outlen + 1);
155: strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
156: magic_add_result(ms, ml, "%s", out);
157: free(out);
158: }
159:
160: static int
161: magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
162: {
163: switch (ml->test_operator) {
164: case 'x':
165: return (1);
166: case '<':
167: return (value < wanted);
168: case '[':
169: return (value <= wanted);
170: case '>':
171: return (value > wanted);
172: case ']':
173: return (value >= wanted);
174: case '=':
175: return (value == wanted);
176: case '&':
177: return ((value & wanted) == wanted);
178: case '^':
179: return ((~value & wanted) == wanted);
180: }
181: return (-1);
182: }
183:
184: static int
185: magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
186: {
187: switch (ml->test_operator) {
188: case 'x':
189: return (1);
190: case '<':
191: return (value < wanted);
192: case '[':
193: return (value <= wanted);
194: case '>':
195: return (value > wanted);
196: case ']':
197: return (value >= wanted);
198: case '=':
199: return (value == wanted);
200: case '&':
201: return ((value & wanted) == wanted);
202: case '^':
203: return ((~value & wanted) == wanted);
204: }
205: return (-1);
206: }
207:
208: static int
209: magic_test_type_none(__unused struct magic_line *ml,
210: __unused struct magic_state *ms)
211: {
212: return (0);
213: }
214:
215: static int
216: magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
217: {
218: int8_t value;
219: int result;
220:
221: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
222: return (0);
223:
224: if (ml->type_operator == '&')
225: value &= (int8_t)ml->type_operand;
226: else if (ml->type_operator != ' ')
227: return (-1);
228:
229: result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
230: if (result == !ml->test_not && ml->result != NULL) {
231: magic_add_result(ms, ml, "%c", (int)value);
232: ms->offset += sizeof value;
233: }
234: return (result);
235: }
236:
237: static int
238: magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
239: {
240: int16_t value;
241: int result;
242:
243: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
244: return (0);
245: if (ml->type == MAGIC_TYPE_BESHORT)
1.3 brynet 246: value = be16toh(value);
1.1 nicm 247: if (ml->type == MAGIC_TYPE_LESHORT)
1.3 brynet 248: value = le16toh(value);
1.1 nicm 249:
250: if (ml->type_operator == '&')
251: value &= (int16_t)ml->type_operand;
252: else if (ml->type_operator != ' ')
253: return (-1);
254:
255: result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
256: if (result == !ml->test_not && ml->result != NULL) {
257: magic_add_result(ms, ml, "%hd", (int)value);
258: ms->offset += sizeof value;
259: }
260: return (result);
261: }
262:
263: static int
264: magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
265: {
266: int32_t value;
267: int result;
268:
269: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
270: return (0);
271: if (ml->type == MAGIC_TYPE_BELONG)
1.3 brynet 272: value = be32toh(value);
1.1 nicm 273: if (ml->type == MAGIC_TYPE_LELONG)
1.3 brynet 274: value = le32toh(value);
1.1 nicm 275:
276: if (ml->type_operator == '&')
277: value &= (int32_t)ml->type_operand;
278: else if (ml->type_operator != ' ')
279: return (-1);
280:
281: result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
282: if (result == !ml->test_not && ml->result != NULL) {
283: magic_add_result(ms, ml, "%d", (int)value);
284: ms->offset += sizeof value;
285: }
286: return (result);
287: }
288:
289: static int
290: magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
291: {
292: int64_t value;
293: int result;
294:
295: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
296: return (0);
297: if (ml->type == MAGIC_TYPE_BEQUAD)
1.3 brynet 298: value = be64toh(value);
1.1 nicm 299: if (ml->type == MAGIC_TYPE_LEQUAD)
1.3 brynet 300: value = le64toh(value);
1.1 nicm 301:
302: if (ml->type_operator == '&')
303: value &= (int64_t)ml->type_operand;
304: else if (ml->type_operator != ' ')
305: return (-1);
306:
307: result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
308: if (result == !ml->test_not && ml->result != NULL) {
309: magic_add_result(ms, ml, "%lld", (long long)value);
310: ms->offset += sizeof value;
311: }
312: return (result);
313: }
314:
315: static int
316: magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
317: {
318: uint8_t value;
319: int result;
320:
321: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
322: return (0);
323:
324: if (ml->type_operator == '&')
325: value &= (uint8_t)ml->type_operand;
326: else if (ml->type_operator != ' ')
327: return (-1);
328:
329: result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
330: if (result == !ml->test_not && ml->result != NULL) {
331: magic_add_result(ms, ml, "%c", (unsigned int)value);
332: ms->offset += sizeof value;
333: }
334: return (result);
335: }
336:
337: static int
338: magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
339: {
340: uint16_t value;
341: int result;
342:
343: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
344: return (0);
345: if (ml->type == MAGIC_TYPE_UBESHORT)
1.3 brynet 346: value = be16toh(value);
1.1 nicm 347: if (ml->type == MAGIC_TYPE_ULESHORT)
1.3 brynet 348: value = le16toh(value);
1.1 nicm 349:
350: if (ml->type_operator == '&')
351: value &= (uint16_t)ml->type_operand;
352: else if (ml->type_operator != ' ')
353: return (-1);
354:
355: result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
356: if (result == !ml->test_not && ml->result != NULL) {
357: magic_add_result(ms, ml, "%hu", (unsigned int)value);
358: ms->offset += sizeof value;
359: }
360: return (result);
361: }
362:
363: static int
364: magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
365: {
366: uint32_t value;
367: int result;
368:
369: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
370: return (0);
371: if (ml->type == MAGIC_TYPE_UBELONG)
1.3 brynet 372: value = be32toh(value);
1.1 nicm 373: if (ml->type == MAGIC_TYPE_ULELONG)
1.3 brynet 374: value = le32toh(value);
1.1 nicm 375:
376: if (ml->type_operator == '&')
377: value &= (uint32_t)ml->type_operand;
378: else if (ml->type_operator != ' ')
379: return (-1);
380:
381: result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
382: if (result == !ml->test_not && ml->result != NULL) {
383: magic_add_result(ms, ml, "%u", (unsigned int)value);
384: ms->offset += sizeof value;
385: }
386: return (result);
387: }
388:
389: static int
390: magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
391: {
392: uint64_t value;
393: int result;
394:
395: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
396: return (0);
397: if (ml->type == MAGIC_TYPE_UBEQUAD)
1.3 brynet 398: value = be64toh(value);
1.1 nicm 399: if (ml->type == MAGIC_TYPE_ULEQUAD)
1.3 brynet 400: value = le64toh(value);
1.1 nicm 401:
402: if (ml->type_operator == '&')
403: value &= (uint64_t)ml->type_operand;
404: else if (ml->type_operator != ' ')
405: return (-1);
406:
407: result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
408: if (result == !ml->test_not && ml->result != NULL) {
409: magic_add_result(ms, ml, "%llu", (unsigned long long)value);
410: ms->offset += sizeof value;
411: }
412: return (result);
413: }
414:
415: static int
416: magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
417: {
418: uint32_t value0;
419: double value;
420:
421: if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
422: return (0);
423: if (ml->type == MAGIC_TYPE_BEFLOAT)
1.3 brynet 424: value0 = be32toh(value0);
1.1 nicm 425: if (ml->type == MAGIC_TYPE_LEFLOAT)
1.3 brynet 426: value0 = le32toh(value0);
1.1 nicm 427: memcpy(&value, &value0, sizeof value);
428:
429: if (ml->type_operator != ' ')
430: return (-1);
431:
432: if (ml->test_operator != 'x')
433: return (-1);
434:
435: magic_add_result(ms, ml, "%g", value);
436: ms->offset += sizeof value0;
437: return (1);
438: }
439:
440: static int
441: magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
442: {
443: uint64_t value0;
444: double value;
445:
446: if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
447: return (0);
448: if (ml->type == MAGIC_TYPE_BEDOUBLE)
1.3 brynet 449: value0 = be64toh(value0);
1.1 nicm 450: if (ml->type == MAGIC_TYPE_LEDOUBLE)
1.3 brynet 451: value0 = le64toh(value0);
1.1 nicm 452: memcpy(&value, &value0, sizeof value);
453:
454: if (ml->type_operator != ' ')
455: return (-1);
456:
457: if (ml->test_operator != 'x')
458: return (-1);
459:
460: magic_add_result(ms, ml, "%g", value);
461: ms->offset += sizeof value0;
462: return (1);
463: }
464:
465: static int
466: magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
467: {
468: const char *s, *cp;
469: size_t slen;
470: int result, cflag = 0, bflag = 0, Bflag = 0;
471:
472: cp = &ml->type_string[(sizeof "string") - 1];
473: if (*cp != '\0') {
474: if (*cp != '/')
475: return (-1);
476: cp++;
477: for (; *cp != '\0'; cp++) {
478: switch (*cp) {
479: case 'B':
480: Bflag = 1;
481: break;
482: case 'b':
483: bflag = 1;
484: break;
485: case 'c':
486: cflag = 1;
487: break;
488: default:
489: return (-1);
490: }
491: }
492: }
493:
494: s = ms->base + ms->offset;
495: slen = ms->size - ms->offset;
496: if (slen < ml->test_string_size)
497: return (0);
498:
499: result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
500: cflag, bflag, Bflag);
501: switch (ml->test_operator) {
502: case 'x':
503: result = 1;
504: break;
505: case '<':
506: result = result < 0;
507: break;
508: case '>':
509: result = result > 0;
510: break;
511: case '=':
512: result = result == 0;
513: break;
514: default:
515: result = -1;
516: break;
517: }
518: if (result == !ml->test_not) {
519: if (ml->result != NULL)
520: magic_add_string(ms, ml, s, slen);
521: if (result && ml->test_operator == '=')
522: ms->offset = s - ms->base + ml->test_string_size;
523: }
524: return (result);
525: }
526:
527: static int
528: magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
529: {
530: const char *s;
531: size_t slen;
532: int result;
533:
534: s = ms->base + ms->offset;
535: if (ms->size - ms->offset < 1)
536: return (-1);
537: slen = *(u_char *)s;
538: if (slen > ms->size - ms->offset)
539: return (-1);
540: s++;
541:
542: if (slen < ml->test_string_size)
543: result = -1;
544: else if (slen > ml->test_string_size)
545: result = 1;
546: else
547: result = memcmp(s, ml->test_string, ml->test_string_size);
548: switch (ml->test_operator) {
549: case 'x':
550: result = 1;
551: break;
552: case '<':
553: result = result < 0;
554: break;
555: case '>':
556: result = result > 0;
557: break;
558: case '=':
559: result = result == 0;
560: break;
561: default:
562: result = -1;
563: break;
564: }
565: if (result == !ml->test_not) {
566: if (ml->result != NULL)
567: magic_add_string(ms, ml, s, slen);
568: if (result)
569: ms->offset += slen + 1;
570: }
571: return (result);
572: }
573:
574: static int
575: magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
576: {
577: int32_t value;
578: int result;
579: time_t t;
580: char s[64];
581:
582: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
583: return (0);
584: if (ml->type == MAGIC_TYPE_BEDATE ||
585: ml->type == MAGIC_TYPE_BELDATE)
1.3 brynet 586: value = be32toh(value);
1.1 nicm 587: if (ml->type == MAGIC_TYPE_LEDATE ||
588: ml->type == MAGIC_TYPE_LELDATE)
1.3 brynet 589: value = le32toh(value);
1.1 nicm 590:
591: if (ml->type_operator == '&')
592: value &= (int32_t)ml->type_operand;
593: else if (ml->type_operator != ' ')
594: return (-1);
595:
596: result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
597: if (result == !ml->test_not && ml->result != NULL) {
598: t = value;
599: switch (ml->type) {
600: case MAGIC_TYPE_LDATE:
601: case MAGIC_TYPE_LELDATE:
602: case MAGIC_TYPE_BELDATE:
603: ctime_r(&t, s);
604: break;
605: default:
606: asctime_r(localtime(&t), s);
607: break;
608: }
609: s[strcspn(s, "\n")] = '\0';
610: magic_add_result(ms, ml, "%s", s);
611: ms->offset += sizeof value;
612: }
613: return (result);
614: }
615:
616: static int
617: magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
618: {
619: int64_t value;
620: int result;
621: time_t t;
622: char s[64];
623:
624: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
625: return (0);
626: if (ml->type == MAGIC_TYPE_BEQDATE ||
627: ml->type == MAGIC_TYPE_BEQLDATE)
1.3 brynet 628: value = be64toh(value);
1.1 nicm 629: if (ml->type == MAGIC_TYPE_LEQDATE ||
630: ml->type == MAGIC_TYPE_LEQLDATE)
1.3 brynet 631: value = le64toh(value);
1.1 nicm 632:
633: if (ml->type_operator == '&')
634: value &= (int64_t)ml->type_operand;
635: else if (ml->type_operator != ' ')
636: return (-1);
637:
638: result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
639: if (result == !ml->test_not && ml->result != NULL) {
640: t = value;
641: switch (ml->type) {
642: case MAGIC_TYPE_QLDATE:
643: case MAGIC_TYPE_LEQLDATE:
644: case MAGIC_TYPE_BEQLDATE:
645: ctime_r(&t, s);
646: break;
647: default:
648: asctime_r(localtime(&t), s);
649: break;
650: }
651: s[strcspn(s, "\n")] = '\0';
652: magic_add_result(ms, ml, "%s", s);
653: ms->offset += sizeof value;
654: }
655: return (result);
656: }
657:
658: static int
659: magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
660: {
661: uint32_t value;
662: int result;
663: time_t t;
664: char s[64];
665:
666: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
667: return (0);
668: if (ml->type == MAGIC_TYPE_BEDATE ||
669: ml->type == MAGIC_TYPE_BELDATE)
1.3 brynet 670: value = be32toh(value);
1.1 nicm 671: if (ml->type == MAGIC_TYPE_LEDATE ||
672: ml->type == MAGIC_TYPE_LELDATE)
1.3 brynet 673: value = le32toh(value);
1.1 nicm 674:
675: if (ml->type_operator == '&')
676: value &= (uint32_t)ml->type_operand;
677: else if (ml->type_operator != ' ')
678: return (-1);
679:
680: result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
681: if (result == !ml->test_not && ml->result != NULL) {
682: t = value;
683: switch (ml->type) {
684: case MAGIC_TYPE_LDATE:
685: case MAGIC_TYPE_LELDATE:
686: case MAGIC_TYPE_BELDATE:
687: ctime_r(&t, s);
688: break;
689: default:
690: asctime_r(gmtime(&t), s);
691: break;
692: }
693: s[strcspn(s, "\n")] = '\0';
694: magic_add_result(ms, ml, "%s", s);
695: ms->offset += sizeof value;
696: }
697: return (result);
698: }
699:
700: static int
701: magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
702: {
703: uint64_t value;
704: int result;
705: time_t t;
706: char s[64];
707:
708: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
709: return (0);
710: if (ml->type == MAGIC_TYPE_UBEQDATE ||
711: ml->type == MAGIC_TYPE_UBEQLDATE)
1.3 brynet 712: value = be64toh(value);
1.1 nicm 713: if (ml->type == MAGIC_TYPE_ULEQDATE ||
714: ml->type == MAGIC_TYPE_ULEQLDATE)
1.3 brynet 715: value = le64toh(value);
1.1 nicm 716:
717: if (ml->type_operator == '&')
718: value &= (uint64_t)ml->type_operand;
719: else if (ml->type_operator != ' ')
720: return (-1);
721:
722: result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
723: if (result == !ml->test_not && ml->result != NULL) {
724: t = value;
725: switch (ml->type) {
726: case MAGIC_TYPE_UQLDATE:
727: case MAGIC_TYPE_ULEQLDATE:
728: case MAGIC_TYPE_UBEQLDATE:
729: ctime_r(&t, s);
730: break;
731: default:
732: asctime_r(gmtime(&t), s);
733: break;
734: }
735: s[strcspn(s, "\n")] = '\0';
736: magic_add_result(ms, ml, "%s", s);
737: ms->offset += sizeof value;
738: }
739: return (result);
740: }
741:
742: static int
743: magic_test_type_bestring16(__unused struct magic_line *ml,
744: __unused struct magic_state *ms)
745: {
746: return (-2);
747: }
748:
749: static int
750: magic_test_type_lestring16(__unused struct magic_line *ml,
751: __unused struct magic_state *ms)
752: {
753: return (-2);
754: }
755:
756: static int
757: magic_test_type_melong(__unused struct magic_line *ml,
758: __unused struct magic_state *ms)
759: {
760: return (-2);
761: }
762:
763: static int
764: magic_test_type_medate(__unused struct magic_line *ml,
765: __unused struct magic_state *ms)
766: {
767: return (-2);
768: }
769:
770: static int
771: magic_test_type_meldate(__unused struct magic_line *ml,
772: __unused struct magic_state *ms)
773: {
774: return (-2);
775: }
776:
777: static int
778: magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
779: {
780: const char *cp;
781: regex_t re;
782: regmatch_t m;
783: int result, flags = 0, sflag = 0;
784:
785: cp = &ml->type_string[(sizeof "regex") - 1];
786: if (*cp != '\0') {
787: if (*cp != '/')
788: return (-1);
789: cp++;
790: for (; *cp != '\0'; cp++) {
791: switch (*cp) {
792: case 's':
793: sflag = 1;
794: break;
795: case 'c':
796: flags |= REG_ICASE;
797: break;
798: default:
799: return (-1);
800: }
801: }
802: }
803:
804: if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
805: return (-1);
806: m.rm_so = ms->offset;
807: m.rm_eo = ms->size;
808:
809: result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
810: if (result == !ml->test_not && ml->result != NULL) {
811: magic_add_result(ms, ml, "%s", "");
812: if (result) {
813: if (sflag)
814: ms->offset = m.rm_so;
815: else
816: ms->offset = m.rm_eo;
817: }
818: }
819: regfree(&re);
820: return (result);
821: }
822:
823: static int
824: magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
825: {
826: const char *cp, *endptr, *start, *found;
827: size_t size, end, i;
828: uint64_t range;
829: int result, n, cflag = 0, bflag = 0, Bflag = 0;
830:
831: cp = &ml->type_string[(sizeof "search") - 1];
832: if (*cp != '\0') {
833: if (*cp != '/')
834: return (-1);
835: cp++;
836:
837: endptr = magic_strtoull(cp, &range);
838: if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
839: return (-1);
840:
841: if (*endptr == '/') {
842: for (cp = endptr + 1; *cp != '\0'; cp++) {
843: switch (*cp) {
844: case 'B':
845: Bflag = 1;
846: break;
847: case 'b':
848: bflag = 1;
849: break;
850: case 'c':
851: cflag = 1;
852: break;
853: default:
854: return (-1);
855: }
856: }
857: }
858: } else
859: range = UINT64_MAX;
860: if (range > (uint64_t)ms->size - ms->offset)
861: range = ms->size - ms->offset;
862: size = ml->test_string_size;
863:
864: /* Want to search every starting position from up to range + size. */
865: end = range + size;
866: if (end > ms->size - ms->offset) {
867: if (size > ms->size - ms->offset)
868: end = 0;
869: else
870: end = ms->size - ms->offset - size;
871: }
872:
873: /*
874: * < and > and the flags are only in /etc/magic with search/1 so don't
875: * support them with anything else.
876: */
877: start = ms->base + ms->offset;
878: if (end == 0)
879: found = NULL;
880: else if (ml->test_operator == 'x')
881: found = start;
882: else if (range == 1) {
883: n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
884: size, cflag, bflag, Bflag);
885: if (n == -1 && ml->test_operator == '<')
886: found = start;
887: else if (n == 1 && ml->test_operator == '>')
888: found = start;
889: else if (n == 0 && ml->test_operator == '=')
890: found = start;
891: else
892: found = NULL;
893: } else {
894: if (ml->test_operator != '=')
895: return (-2);
896: for (i = 0; i < end; i++) {
897: n = magic_test_eq(start + i, ms->size - ms->offset - i,
898: ml->test_string, size, cflag, bflag, Bflag);
899: if (n == 0) {
900: found = start + i;
901: break;
902: }
903: }
904: if (i == end)
905: found = NULL;
906: }
907: result = (found != NULL);
908:
909: if (result == !ml->test_not && ml->result != NULL && found != NULL) {
910: magic_add_string(ms, ml, found, ms->size - ms->offset);
911: ms->offset = found - start + size;
912: }
913: return (result);
914: }
915:
916: static int
917: magic_test_type_default(__unused struct magic_line *ml,
918: __unused struct magic_state *ms)
919: {
920: return (1);
921: }
922:
923: static int (*magic_test_functions[])(struct magic_line *,
924: struct magic_state *) = {
925: magic_test_type_none,
926: magic_test_type_byte,
927: magic_test_type_short,
928: magic_test_type_long,
929: magic_test_type_quad,
930: magic_test_type_ubyte,
931: magic_test_type_ushort,
932: magic_test_type_ulong,
933: magic_test_type_uquad,
934: magic_test_type_float,
935: magic_test_type_double,
936: magic_test_type_string,
937: magic_test_type_pstring,
938: magic_test_type_date,
939: magic_test_type_qdate,
940: magic_test_type_date,
941: magic_test_type_qdate,
942: magic_test_type_udate,
943: magic_test_type_uqdate,
944: magic_test_type_udate,
945: magic_test_type_qdate,
946: magic_test_type_short,
947: magic_test_type_long,
948: magic_test_type_quad,
949: magic_test_type_ushort,
950: magic_test_type_ulong,
951: magic_test_type_uquad,
952: magic_test_type_float,
953: magic_test_type_double,
954: magic_test_type_date,
955: magic_test_type_qdate,
956: magic_test_type_date,
957: magic_test_type_qdate,
958: magic_test_type_udate,
959: magic_test_type_uqdate,
960: magic_test_type_udate,
961: magic_test_type_uqdate,
962: magic_test_type_bestring16,
963: magic_test_type_short,
964: magic_test_type_long,
965: magic_test_type_quad,
966: magic_test_type_ushort,
967: magic_test_type_ulong,
968: magic_test_type_uquad,
969: magic_test_type_float,
970: magic_test_type_double,
971: magic_test_type_date,
972: magic_test_type_qdate,
973: magic_test_type_date,
974: magic_test_type_qdate,
975: magic_test_type_udate,
976: magic_test_type_uqdate,
977: magic_test_type_udate,
978: magic_test_type_uqdate,
979: magic_test_type_lestring16,
980: magic_test_type_melong,
981: magic_test_type_medate,
982: magic_test_type_meldate,
983: magic_test_type_regex,
984: magic_test_type_search,
985: magic_test_type_default,
986: };
987:
988: static int
989: magic_test_line(struct magic_line *ml, struct magic_state *ms)
990: {
991: struct magic_line *child;
992: int64_t offset, wanted, next;
993: int result;
994: uint8_t b;
995: uint16_t s;
996: uint32_t l;
997:
998: if (ml->indirect_type == ' ')
999: wanted = ml->offset;
1000: else {
1001: wanted = ml->indirect_offset;
1002: if (ml->indirect_relative) {
1003: if (wanted < 0 && -wanted > ms->offset)
1004: return (0);
1005: if (wanted > 0 && ms->offset + wanted > ms->size)
1006: return (0);
1007: next = ms->offset + ml->indirect_offset;
1008: } else
1009: next = wanted;
1010:
1011: switch (ml->indirect_type) {
1012: case 'b':
1013: case 'B':
1014: if (magic_copy_from(ms, next, &b, sizeof b) != 0)
1015: return (0);
1016: wanted = b;
1017: break;
1018: case 's':
1019: if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1020: return (0);
1.3 brynet 1021: wanted = le16toh(s);
1.1 nicm 1022: break;
1023: case 'S':
1024: if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1025: return (0);
1.3 brynet 1026: wanted = be16toh(s);
1.1 nicm 1027: break;
1028: case 'l':
1029: if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1030: return (0);
1.3 brynet 1031: wanted = le16toh(l);
1.1 nicm 1032: break;
1033: case 'L':
1034: if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1035: return (0);
1.3 brynet 1036: wanted = be16toh(l);
1.1 nicm 1037: break;
1038: }
1039:
1040: switch (ml->indirect_operator) {
1041: case '+':
1042: wanted += ml->indirect_operand;
1043: break;
1044: case '-':
1045: wanted -= ml->indirect_operand;
1046: break;
1047: case '*':
1048: wanted *= ml->indirect_operand;
1049: break;
1050: }
1051: }
1052:
1053: if (ml->offset_relative) {
1054: if (wanted < 0 && -wanted > ms->offset)
1055: return (0);
1056: if (wanted > 0 && ms->offset + wanted > ms->size)
1057: return (0);
1058: offset = ms->offset + wanted;
1059: } else
1060: offset = wanted;
1061: if (offset < 0 || offset > ms->size)
1062: return (0);
1063: ms->offset = offset;
1064:
1065: result = magic_test_functions[ml->type](ml, ms);
1066: if (result == -1) {
1067: magic_warn(ml, "test %s/%c failed", ml->type_string,
1068: ml->test_operator);
1069: return (0);
1070: }
1071: if (result == -2) {
1072: magic_warn(ml, "test %s/%c not implemented", ml->type_string,
1073: ml->test_operator);
1074: return (0);
1075: }
1076: if (result == ml->test_not)
1077: return (0);
1078: if (ml->mimetype != NULL)
1079: ms->mimetype = ml->mimetype;
1080:
1081: magic_warn(ml, "test %s/%c matched at offset %llu: '%s'",
1082: ml->type_string, ml->test_operator, ms->offset,
1083: ml->result == NULL ? "" : ml->result);
1084:
1085: offset = ms->offset;
1086: TAILQ_FOREACH(child, &ml->children, entry) {
1087: ms->offset = offset;
1088: magic_test_line(child, ms);
1089: }
1090: return (1);
1091: }
1092:
1093: const char *
1094: magic_test(struct magic *m, const void *base, size_t size, int flags)
1095: {
1096: struct magic_line *ml;
1097: static struct magic_state ms;
1098:
1099: memset(&ms, 0, sizeof ms);
1100:
1101: ms.base = base;
1102: ms.size = size;
1103:
1104: ms.text = !!(flags & MAGIC_TEST_TEXT);
1105:
1106: RB_FOREACH(ml, magic_tree, &m->tree) {
1107: ms.offset = 0;
1108: if (ml->text == ms.text && magic_test_line(ml, &ms))
1109: break;
1110: }
1111:
1112: if (*ms.out != '\0') {
1113: if (flags & MAGIC_TEST_MIME) {
1114: if (ms.mimetype)
1115: return (xstrdup(ms.mimetype));
1116: return (NULL);
1117: }
1118: return (xstrdup(ms.out));
1119: }
1120: return (NULL);
1121: }