#endif
#ifndef lint
-FILE_RCSID("@(#)$File: apprentice.c,v 1.100 2006/12/11 21:48:49 christos Exp $")
+FILE_RCSID("@(#)$File: apprentice.c,v 1.101 2007/01/12 17:38:27 christos Exp $")
#endif /* lint */
#define EATAB {while (isascii((unsigned char) *l) && \
#define MAXPATHLEN 1024
#endif
-#define IS_PLAINSTRING(t) ((t) == FILE_STRING || (t) == FILE_PSTRING || \
- (t) == FILE_BESTRING16 || (t) == FILE_LESTRING16)
-
-#define IS_STRING(t) (IS_PLAINSTRING(t) || (t) == FILE_REGEX || \
- (t) == FILE_SEARCH)
-
struct magic_entry {
struct magic *mp;
uint32_t cont_count;
const char *file_names[] = { FILE_FORMAT_NAME };
const size_t file_nnames = sizeof(file_names) / sizeof(file_names[0]);
-private int getvalue(struct magic_set *ms, struct magic *, const char **);
+private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
private int hextoint(int);
private const char *getstr(struct magic_set *, const char *, char *, int,
- int *);
+ int *, int);
private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
const char *, size_t, int);
private void eatsize(const char **);
size_t val = 2 * MULT; /* baseline strength */
switch (m->type) {
+ case FILE_DEFAULT: /* make sure this sorts last */
+ return 0;
+
case FILE_BYTE:
val += 1 * MULT;
break;
(void)fprintf(stderr, "Bad relation %c\n", m->reln);
abort();
}
+
+ if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
+ val = 1;
+
return val;
}
#ifndef NOORDER
qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
+ /*
+ * Make sure that any level 0 "default" line is last (if one exists).
+ */
+ for (i = 0; i < marraycount; i++) {
+ if (marray[i].mp->cont_level == 0 &&
+ marray[i].mp->type == FILE_DEFAULT) {
+ while (++i < marraycount)
+ if (marray[i].mp->cont_level == 0)
+ break;
+ if (i != marraycount) {
+ ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
+ file_magwarn(ms,
+ "level 0 \"default\" did not sort last");
+ }
+ break;
+ }
+ }
#endif
for (i = 0; i < marraycount; i++)
protected uint64_t
file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
{
- if (!(m->flag & UNSIGNED))
+ if (!(m->flag & UNSIGNED)) {
switch(m->type) {
/*
* Do not remove the casts below. They are
case FILE_LESTRING16:
case FILE_REGEX:
case FILE_SEARCH:
+ case FILE_DEFAULT:
break;
default:
if (ms->flags & MAGIC_CHECK)
m->type);
return ~0U;
}
+ }
return v;
}
+private int
+string_modifier_check(struct magic_set *ms, struct magic const *m)
+{
+ if ((ms->flags & MAGIC_CHECK) == 0)
+ return 0;
+
+ switch (m->type) {
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ if (m->str_flags != 0) {
+ file_magwarn(ms, "no modifiers allowed for 16-bit strings\n");
+ return -1;
+ }
+ break;
+ case FILE_STRING:
+ case FILE_PSTRING:
+ if ((m->str_flags & REGEX_OFFSET_START) != 0) {
+ file_magwarn(ms, "'/%c' only allowed on regex and search\n",
+ CHAR_REGEX_OFFSET_START);
+ return -1;
+ }
+ break;
+ case FILE_SEARCH:
+ break;
+ case FILE_REGEX:
+ if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
+ file_magwarn(ms, "'/%c' not allowed on regex\n",
+ CHAR_COMPACT_BLANK);
+ return -1;
+ }
+ if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
+ file_magwarn(ms, "'/%c' not allowed on regex\n",
+ CHAR_COMPACT_OPTIONAL_BLANK);
+ return -1;
+ }
+ break;
+ default:
+ file_magwarn(ms, "coding error: m->type=%d\n",
+ m->type);
+ return -1;
+ }
+ return 0;
+}
+
+private int
+get_op(char c)
+{
+ switch (c) {
+ case '&':
+ return FILE_OPAND;
+ case '|':
+ return FILE_OPOR;
+ case '^':
+ return FILE_OPXOR;
+ case '+':
+ return FILE_OPADD;
+ case '-':
+ return FILE_OPMINUS;
+ case '*':
+ return FILE_OPMULTIPLY;
+ case '/':
+ return FILE_OPDIVIDE;
+ case '%':
+ return FILE_OPMODULO;
+ default:
+ return -1;
+ }
+}
+
/*
* parse one line from magic file, put into magic[index++] if valid
*/
struct magic *m;
const char *l = line;
char *t;
- private const char *fops = FILE_OPS;
- uint64_t val;
+ int op;
uint32_t cont_level;
cont_level = 0;
me->max_count = cnt;
}
m = &me->mp[me->cont_count++];
- memset(m, 0, sizeof(*m));
+ (void)memset(m, 0, sizeof(*m));
m->cont_level = cont_level;
} else {
if (*nmentryp == maxmagic) {
me->max_count = ALLOC_CHUNK;
} else
m = me->mp;
- memset(m, 0, sizeof(*m));
+ (void)memset(m, 0, sizeof(*m));
m->cont_level = 0;
me->cont_count = 1;
}
m->lineno = lineno;
- if (m->cont_level != 0 && *l == '&') {
+ if (*l == '&') { /* m->cont_level == 0 checked below. */
++l; /* step over */
m->flag |= OFFADD;
}
- if (m->cont_level != 0 && *l == '(') {
+ if (*l == '(') {
++l; /* step over */
m->flag |= INDIR;
if (m->flag & OFFADD)
m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
+
+ if (*l == '&') { /* m->cont_level == 0 checked below */
+ ++l; /* step over */
+ m->flag |= OFFADD;
+ }
}
- if (m->cont_level != 0 && *l == '&') {
- ++l; /* step over */
- m->flag |= OFFADD;
- }
+ /* Indirect offsets are not valid at level 0. */
+ if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "relative offset at level 0");
/* get offset, then skip over it */
m->offset = (uint32_t)strtoul(l, &t, 0);
}
l++;
}
+
+ m->in_op = 0;
if (*l == '~') {
m->in_op |= FILE_OPINVERSE;
l++;
}
- switch (*l) {
- case '&':
- m->in_op |= FILE_OPAND;
- l++;
- break;
- case '|':
- m->in_op |= FILE_OPOR;
+ if ((op = get_op(*l)) != -1) {
+ m->in_op |= op;
l++;
- break;
- case '^':
- m->in_op |= FILE_OPXOR;
- l++;
- break;
- case '+':
- m->in_op |= FILE_OPADD;
- l++;
- break;
- case '-':
- m->in_op |= FILE_OPMINUS;
- l++;
- break;
- case '*':
- m->in_op |= FILE_OPMULTIPLY;
- l++;
- break;
- case '/':
- m->in_op |= FILE_OPDIVIDE;
- l++;
- break;
- case '%':
- m->in_op |= FILE_OPMODULO;
- l++;
- break;
}
if (*l == '(') {
m->in_op |= FILE_OPINDIRECT;
}
if (isdigit((unsigned char)*l) || *l == '-') {
m->in_offset = (int32_t)strtol(l, &t, 0);
+ if (l == t)
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "in_offset `%s' invalid", l);
l = t;
}
if (*l++ != ')' ||
file_magwarn(ms,
"missing ')' in indirect offset");
}
-
-
- while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
- ++l;
EATAB;
if (*l == 'u') {
file_magwarn(ms, "type `%s' invalid", l);
return -1;
}
+
/* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
/* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
+
+ m->mask_op = 0;
if (*l == '~') {
if (!IS_STRING(m->type))
m->mask_op |= FILE_OPINVERSE;
+ else if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "'~' invalid for string types");
++l;
}
- if ((t = strchr(fops, *l)) != NULL) {
- uint32_t op = (uint32_t)(t - fops);
- if (op != FILE_OPDIVIDE || !IS_PLAINSTRING(m->type)) {
+ m->str_count = 0;
+ m->str_flags = 0;
+ m->num_mask = 0;
+ if ((op = get_op(*l)) != -1) {
+ if (!IS_STRING(m->type)) {
+ uint64_t val;
++l;
m->mask_op |= op;
val = (uint64_t)strtoull(l, &t, 0);
l = t;
- m->mask = file_signextend(ms, m, val);
+ m->num_mask = file_signextend(ms, m, val);
eatsize(&l);
- } else {
- m->mask = 0L;
+ }
+ else if (op == FILE_OPDIVIDE) {
+ int have_count = 0;
while (!isspace((unsigned char)*++l)) {
switch (*l) {
- case CHAR_IGNORE_LOWERCASE:
- m->mask |= STRING_IGNORE_LOWERCASE;
+ /* for portability avoid "case '0' ... '9':" */
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9': {
+ if (have_count && ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "multiple counts");
+ have_count = 1;
+ m->str_count = strtoul(l, &t, 0);
+ l = t - 1;
break;
+ }
case CHAR_COMPACT_BLANK:
- m->mask |= STRING_COMPACT_BLANK;
+ m->str_flags |= STRING_COMPACT_BLANK;
break;
case CHAR_COMPACT_OPTIONAL_BLANK:
- m->mask |=
+ m->str_flags |=
STRING_COMPACT_OPTIONAL_BLANK;
break;
+ case CHAR_IGNORE_LOWERCASE:
+ m->str_flags |= STRING_IGNORE_LOWERCASE;
+ break;
+ case CHAR_IGNORE_UPPERCASE:
+ m->str_flags |= STRING_IGNORE_UPPERCASE;
+ break;
+ case CHAR_REGEX_OFFSET_START:
+ m->str_flags |= REGEX_OFFSET_START;
+ break;
default:
if (ms->flags & MAGIC_CHECK)
file_magwarn(ms,
*l);
return -1;
}
+ /* allow multiple '/' for readability */
+ if (l[1] == '/' && !isspace((unsigned char)l[2]))
+ l++;
}
- ++l;
+ if (string_modifier_check(ms, m) == -1)
+ return -1;
+ }
+ else {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "invalid string op: %c", *t);
+ return -1;
}
}
/*
++l;
break;
default:
+ m->reln = '='; /* the default relation */
if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
isspace((unsigned char)l[1])) || !l[1])) {
m->reln = *l;
++l;
- goto GetDesc; /* Bill The Cat */
}
- m->reln = '=';
break;
}
- EATAB;
-
- if (getvalue(ms, m, &l))
+ /*
+ * Grab the value part, except for an 'x' reln.
+ */
+ if (m->reln != 'x' && getvalue(ms, m, &l, action))
return -1;
+
/*
* TODO finish this macro and start using it!
* #define offsetcheck {if (offset > HOWMANY-1)
*/
/*
- * now get last part - the description
+ * Now get last part - the description
*/
-GetDesc:
EATAB;
if (l[0] == '\b') {
++l;
* just after the number read. Return 0 for success, non-zero for failure.
*/
private int
-getvalue(struct magic_set *ms, struct magic *m, const char **p)
+getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
{
int slen;
case FILE_PSTRING:
case FILE_REGEX:
case FILE_SEARCH:
- *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
+ *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
if (*p == NULL) {
if (ms->flags & MAGIC_CHECK)
file_magwarn(ms, "cannot get string from `%s'",
* Return updated scan pointer as function result.
*/
private const char *
-getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen)
+getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
{
const char *origs = s;
char *origp = p;
file_error(ms, 0, "string too long: `%s'", origs);
return NULL;
}
- if(c == '\\') {
+ if (c == '\\') {
switch(c = *s++) {
case '\0':
+ if (action == FILE_COMPILE)
+ file_magwarn(ms, "incomplete escape");
goto out;
default:
+ if (action == FILE_COMPILE)
+ file_magwarn(ms,
+ "unknown escape sequence: \\%03o", c);
+ /*FALLTHROUGH*/
+ case '\'':
+ case '"':
+ case '?':
+ case '\\':
*p++ = (char) c;
break;
+ case 'a':
+ *p++ = '\a';
+ break;
+
+ case 'b':
+ *p++ = '\b';
+ break;
+
+ case 'f':
+ *p++ = '\f';
+ break;
+
case 'n':
*p++ = '\n';
break;
*p++ = '\r';
break;
- case 'b':
- *p++ = '\b';
- break;
-
case 't':
*p++ = '\t';
break;
- case 'f':
- *p++ = '\f';
- break;
-
case 'v':
*p++ = '\v';
break;
case '7':
val = c - '0';
c = *s++; /* try for 2 */
- if(c >= '0' && c <= '7') {
- val = (val<<3) | (c - '0');
+ if (c >= '0' && c <= '7') {
+ val = (val << 3) | (c - '0');
c = *s++; /* try for 3 */
- if(c >= '0' && c <= '7')
- val = (val<<3) | (c-'0');
+ if (c >= '0' && c <= '7')
+ val = (val << 3) | (c-'0');
else
--s;
}
return -1;
if (isdigit((unsigned char) c))
return c - '0';
- if ((c >= 'a')&&(c <= 'f'))
+ if ((c >= 'a') && (c <= 'f'))
return c + 10 - 'a';
- if (( c>= 'A')&&(c <= 'F'))
+ if (( c>= 'A') && (c <= 'F'))
return c + 10 - 'A';
return -1;
}
if (len-- == 0)
break;
}
- if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
+ if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
(void) fputc(c, fp);
else {
(void) fputc('\\', fp);
switch (c) {
-
+ case '\a':
+ (void) fputc('a', fp);
+ break;
+
+ case '\b':
+ (void) fputc('b', fp);
+ break;
+
+ case '\f':
+ (void) fputc('f', fp);
+ break;
+
case '\n':
(void) fputc('n', fp);
break;
(void) fputc('r', fp);
break;
- case '\b':
- (void) fputc('b', fp);
- break;
-
case '\t':
(void) fputc('t', fp);
break;
- case '\f':
- (void) fputc('f', fp);
- break;
-
case '\v':
(void) fputc('v', fp);
break;
m->cont_level = swap2(m->cont_level);
m->offset = swap4((uint32_t)m->offset);
m->in_offset = swap4((uint32_t)m->in_offset);
- if (!IS_STRING(m->type))
+ m->lineno = swap4((uint32_t)m->lineno);
+ if (IS_STRING(m->type)) {
+ m->str_count = swap4(m->str_count);
+ m->str_flags = swap4(m->str_flags);
+ }
+ else {
m->value.q = swap8(m->value.q);
- m->mask = swap8(m->mask);
+ m->num_mask = swap8(m->num_mask);
+ }
}
*/
/*
* file.h - definitions for file(1) program
- * @(#)$File: file.h,v 1.83 2006/12/11 21:48:49 christos Exp $
+ * @(#)$File: file.h,v 1.84 2007/01/12 17:38:28 christos Exp $
*/
#ifndef __file_h__
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
+#include <regex.h>
#include <sys/types.h>
/* Do this here and now, because struct stat gets re-defined on solaris */
#include <sys/stat.h>
#endif
#define public
+#ifndef __GNUC_PREREQ__
+#ifdef __GNUC__
+#define __GNUC_PREREQ__(x, y) \
+ ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
+ (__GNUC__ > (x)))
+#else
+#define __GNUC_PREREQ__(x, y) 0
+#endif
+#endif
+
+#ifndef __unused
+#if __GNUC_PREREQ__(2, 7)
+#define __unused __attribute__((__unused__))
+#else
+#define __unused /* delete */
+#endif
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
#ifndef HOWMANY
# define HOWMANY (256 * 1024) /* how much of the file to look at */
#endif
#define MAXstring 32 /* max leng of "string" types */
#define MAGICNO 0xF11E041C
-#define VERSIONNO 3
+#define VERSIONNO 4
#define FILE_MAGICSIZE (32 * 4)
#define FILE_LOAD 0
uint16_t cont_level; /* level of ">" */
uint8_t nospflag; /* supress space character */
uint8_t flag;
-#define INDIR 1 /* if '>(...)' appears, */
-#define UNSIGNED 2 /* comparison is unsigned */
-#define OFFADD 4 /* if '>&' appears, */
-#define INDIROFFADD 8 /* if '>&(' appears, */
+#define INDIR 1 /* if '(...)' appears */
+#define OFFADD 2 /* if '>&' or '>...(&' appears */
+#define INDIROFFADD 4 /* if '>&(' appears */
+#define UNSIGNED 8 /* comparison is unsigned */
/* Word 2 */
uint8_t reln; /* relation (0=eq, '>'=gt, etc) */
uint8_t vallen; /* length of string value, if any */
uint8_t in_type; /* type of indirrection */
#define FILE_BYTE 1
#define FILE_SHORT 2
+#define FILE_DEFAULT 3
#define FILE_LONG 4
#define FILE_STRING 5
#define FILE_DATE 6
#define FILE_LEQLDATE 31
#define FILE_BEQLDATE 32
+#define IS_PLAINSTRING(t) \
+ ((t) == FILE_STRING || \
+ (t) == FILE_PSTRING || \
+ (t) == FILE_BESTRING16 || \
+ (t) == FILE_LESTRING16)
+
+#define IS_STRING(t) \
+ (IS_PLAINSTRING(t) || \
+ (t) == FILE_REGEX || \
+ (t) == FILE_SEARCH || \
+ (t) == FILE_DEFAULT)
+
#define FILE_FORMAT_NAME \
/* 0 */ "invalid 0", \
/* 1 */ "byte", \
/* 2 */ "short", \
-/* 3 */ "invalid 3", \
+/* 3 */ "default", \
/* 4 */ "long", \
/* 5 */ "string", \
/* 6 */ "date", \
/* 31 */ "leqldate", \
/* 32 */ "beqldate",
-
#define FILE_FMT_NONE 0
#define FILE_FMT_NUM 1 /* "cduxXi" */
#define FILE_FMT_STR 2 /* "s" */
/* 0 */ FILE_FMT_NONE, \
/* 1 */ FILE_FMT_NUM, \
/* 2 */ FILE_FMT_NUM, \
-/* 3 */ FILE_FMT_NONE, \
+/* 3 */ FILE_FMT_STR, \
/* 4 */ FILE_FMT_NUM, \
/* 5 */ FILE_FMT_STR, \
/* 6 */ FILE_FMT_STR, \
/* 31 */ FILE_FMT_STR, \
/* 32 */ FILE_FMT_STR,
-
/* Word 3 */
uint8_t in_op; /* operator for indirection */
uint8_t mask_op; /* operator for mask */
uint8_t dummy1;
uint8_t dummy2;
+
#define FILE_OPS "&|^+-*/%"
#define FILE_OPAND 0
#define FILE_OPOR 1
#define FILE_OPMULTIPLY 5
#define FILE_OPDIVIDE 6
#define FILE_OPMODULO 7
+#define FILE_OPS_MASK 0x07 /* mask for above ops */
+#define FILE_UNUSED_1 0x08
+#define FILE_UNUSED_2 0x10
+#define FILE_UNUSED_3 0x20
#define FILE_OPINVERSE 0x40
#define FILE_OPINDIRECT 0x80
+
/* Word 4 */
uint32_t offset; /* offset to magic number */
/* Word 5 */
/* Word 6 */
uint32_t lineno; /* line number in magic file */
/* Word 7,8 */
- uint64_t mask; /* mask before comparison with value */
+ union {
+ uint64_t _mask; /* for use with numeric and date types */
+ struct {
+ uint32_t _count; /* repeat/line count */
+ uint32_t _flags; /* modifier flags */
+ } _s; /* for use with string types */
+ } _u;
+#define num_mask _u._mask
+#define str_count _u._s._count
+#define str_flags _u._s._flags
+
/* Words 9-16 */
union VALUETYPE {
- uint8_t b;
- uint16_t h;
- uint32_t l;
- uint64_t q;
- char s[MAXstring];
- struct {
- char *buf;
- size_t buflen;
- } search;
- uint8_t hs[2]; /* 2 bytes of a fixed-endian "short" */
- uint8_t hl[4]; /* 4 bytes of a fixed-endian "long" */
- uint8_t hq[8]; /* 8 bytes of a fixed-endian "quad" */
+// union NUMTYPE {
+ uint8_t b;
+ uint16_t h;
+ uint32_t l;
+ uint64_t q;
+ uint8_t hs[2]; /* 2 bytes of a fixed-endian "short" */
+ uint8_t hl[4]; /* 4 bytes of a fixed-endian "long" */
+ uint8_t hq[8]; /* 8 bytes of a fixed-endian "quad" */
+// } n;
+ char s[MAXstring]; /* the search string or regex pattern */
} value; /* either number or string */
/* Words 17..31 */
char desc[MAXDESC]; /* description */
};
#define BIT(A) (1 << (A))
-#define STRING_IGNORE_LOWERCASE BIT(0)
-#define STRING_COMPACT_BLANK BIT(1)
-#define STRING_COMPACT_OPTIONAL_BLANK BIT(2)
-#define CHAR_IGNORE_LOWERCASE 'c'
+#define STRING_COMPACT_BLANK BIT(0)
+#define STRING_COMPACT_OPTIONAL_BLANK BIT(1)
+#define STRING_IGNORE_LOWERCASE BIT(2)
+#define STRING_IGNORE_UPPERCASE BIT(3)
+#define REGEX_OFFSET_START BIT(4)
#define CHAR_COMPACT_BLANK 'B'
#define CHAR_COMPACT_OPTIONAL_BLANK 'b'
+#define CHAR_IGNORE_LOWERCASE 'c'
+#define CHAR_IGNORE_UPPERCASE 'C'
+#define CHAR_REGEX_OFFSET_START 's'
+#define STRING_IGNORE_CASE (STRING_IGNORE_LOWERCASE|STRING_IGNORE_UPPERCASE)
/* list of magic entries */
};
struct magic_set {
- struct mlist *mlist;
- struct cont {
- size_t len;
- int32_t *off;
- } c;
- struct out {
- /* Accumulation buffer */
- char *buf;
- char *ptr;
- size_t len;
- size_t size;
- /* Printable buffer */
- char *pbuf;
- size_t psize;
- } o;
- uint32_t offset;
- int error;
- int flags;
- int haderr;
- const char *file;
- size_t line;
+ struct mlist *mlist;
+ struct cont {
+ size_t len;
+ struct level_info {
+ int32_t off;
+ int got_match;
+ } *li;
+ } c;
+ struct out {
+ /* Accumulation buffer */
+ char *buf;
+ char *ptr;
+ size_t len;
+ size_t size;
+ /* Printable buffer */
+ char *pbuf;
+ size_t psize;
+ } o;
+ uint32_t offset;
+ int error;
+ int flags;
+ int haderr;
+ const char *file;
+ size_t line; /* current magic line number */
+
+ /* data for searches */
+ struct {
+ const char *s; /* start of search in original source */
+ size_t s_len; /* length of search region */
+ size_t offset; /* starting offset in source: XXX - should this be off_t? */
+ size_t rm_len; /* match length */
+ } search;
+
+ union VALUETYPE ms_value; /* either number or string */
};
struct stat;
protected void file_badseek(struct magic_set *);
protected void file_oomem(struct magic_set *, size_t);
protected void file_error(struct magic_set *, int, const char *, ...);
+protected void file_magerror(struct magic_set *, const char *, ...);
protected void file_magwarn(struct magic_set *, const char *, ...);
protected void file_mdump(struct magic *);
protected void file_showstr(FILE *, const char *, size_t);
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
-#include <regex.h>
#ifndef lint
-FILE_RCSID("@(#)$File: softmagic.c,v 1.87 2006/12/11 21:48:49 christos Exp $")
+FILE_RCSID("@(#)$File: softmagic.c,v 1.88 2007/01/12 17:38:28 christos Exp $")
#endif /* lint */
private int match(struct magic_set *, struct magic *, uint32_t,
const unsigned char *, size_t);
-private int mget(struct magic_set *, union VALUETYPE *, const unsigned char *,
+private int mget(struct magic_set *, const unsigned char *,
struct magic *, size_t, unsigned int);
-private int magiccheck(struct magic_set *, union VALUETYPE *, struct magic *);
-private int32_t mprint(struct magic_set *, union VALUETYPE *, struct magic *);
+private int magiccheck(struct magic_set *, struct magic *);
+private int32_t mprint(struct magic_set *, struct magic *);
private void mdebug(uint32_t, const char *, size_t);
private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
- const unsigned char *, uint32_t, size_t);
-private int mconvert(struct magic_set *, union VALUETYPE *, struct magic *);
+ const unsigned char *, uint32_t, size_t, size_t);
+private int mconvert(struct magic_set *, struct magic *);
private int check_mem(struct magic_set *, unsigned int);
private int print_sep(struct magic_set *, int);
private void cvt_8(union VALUETYPE *, const struct magic *);
uint32_t magindex = 0;
unsigned int cont_level = 0;
int need_separator = 0;
- union VALUETYPE p;
- int32_t oldoff = 0;
int returnval = 0; /* if a match is found it is set to 1*/
int firstline = 1; /* a flag to print X\n X\n- X */
int printed_something = 0;
return -1;
for (magindex = 0; magindex < nmagic; magindex++) {
- /* if main entry matches, print it... */
+ int flush;
+
ms->offset = magic[magindex].offset;
- int flush = !mget(ms, &p, s, &magic[magindex], nbytes,
- cont_level);
+ ms->line = magic[magindex].lineno;
+
+ /* if main entry matches, print it... */
+ flush = !mget(ms, s, &magic[magindex], nbytes, cont_level);
if (flush) {
if (magic[magindex].reln == '!')
flush = 0;
} else {
- switch (magiccheck(ms, &p, &magic[magindex])) {
+ switch (magiccheck(ms, &magic[magindex])) {
case -1:
return -1;
case 0:
* flush its continuations
*/
while (magindex < nmagic - 1 &&
- magic[magindex + 1].cont_level != 0)
- magindex++;
+ magic[magindex + 1].cont_level != 0)
+ magindex++;
continue;
}
return -1;
}
- if ((ms->c.off[cont_level] = mprint(ms, &p, &magic[magindex]))
+ if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex]))
== -1)
return -1;
if (check_mem(ms, ++cont_level) == -1)
return -1;
- while (magic[magindex+1].cont_level != 0 &&
- ++magindex < nmagic) {
+ while (magic[magindex+1].cont_level != 0 &&
+ ++magindex < nmagic) {
+ ms->line = magic[magindex].lineno; /* for messages */
+
if (cont_level < magic[magindex].cont_level)
continue;
if (cont_level > magic[magindex].cont_level) {
ms->offset = magic[magindex].offset;
if (magic[magindex].flag & OFFADD) {
ms->offset +=
- ms->c.off[cont_level - 1];
+ ms->c.li[cont_level - 1].off;
}
- flush = !mget(ms, &p, s, &magic[magindex], nbytes,
+ flush = !mget(ms, s, &magic[magindex], nbytes,
cont_level);
if (flush && magic[magindex].reln != '!')
continue;
- switch (flush ? 1 : magiccheck(ms, &p, &magic[magindex])) {
+ switch (flush ? 1 : magiccheck(ms, &magic[magindex])) {
case -1:
return -1;
case 0:
break;
default:
+ if (magic[magindex].type != FILE_DEFAULT)
+ ms->c.li[cont_level].got_match = 1;
+ else if (ms->c.li[cont_level].got_match) {
+ ms->c.li[cont_level].got_match = 0;
+ break;
+ }
/*
* If we are going to print something,
* make sure that we have a separator first.
return -1;
need_separator = 0;
}
- if ((ms->c.off[cont_level] = mprint(ms, &p,
- &magic[magindex])) == -1)
+ if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex])) == -1)
return -1;
if (magic[magindex].desc[0])
need_separator = 1;
*/
if (check_mem(ms, ++cont_level) == -1)
return -1;
+ break;
}
}
firstline = 0;
if (level < ms->c.len)
return 0;
- len = (ms->c.len += 20) * sizeof(*ms->c.off);
- ms->c.off = (ms->c.off == NULL) ? malloc(len) : realloc(ms->c.off, len);
- if (ms->c.off != NULL)
+ len = (ms->c.len += 20) * sizeof(*ms->c.li);
+ ms->c.li = (ms->c.li == NULL) ? malloc(len) : realloc(ms->c.li, len);
+ if (ms->c.li != NULL) {
+ ms->c.li[level].got_match = 0;
return 0;
+ }
file_oomem(ms, len);
return -1;
}
rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
if (rc) {
char errmsg[512];
- regerror(rc, &rx, errmsg, sizeof(errmsg));
- file_error(ms, 0, "regex error %d, (%s)", rc, errmsg);
+ (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
+ file_magerror(ms, "regex error %d, (%s)", rc, errmsg);
return -1;
} else {
rc = regexec(&rx, m->desc, 0, 0, 0);
}
}
+#ifndef HAVE_STRNDUP
+char * strndup(const char *, size_t);
+
+char *
+strndup(const char *str, size_t n)
+{
+ size_t len;
+ char *copy;
+
+ len = strlen(str);
+ if (len > n)
+ len = n;
+ if (!(copy = malloc(len + 1)))
+ return (NULL);
+ (void) memcpy(copy, str, len + 1);
+ copy[len] = '\0';
+ return (copy);
+}
+#endif /* HAVE_STRNDUP */
+
private int32_t
-mprint(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
+mprint(struct magic_set *ms, struct magic *m)
{
uint64_t v;
int32_t t = 0;
char buf[512];
-
+ union VALUETYPE *p = &ms->ms_value;
switch (m->type) {
case FILE_BYTE:
return -1;
t = ms->offset + sizeof(int64_t);
break;
+
case FILE_STRING:
case FILE_PSTRING:
case FILE_BESTRING16:
t = ms->offset + sizeof(uint64_t);
break;
- case FILE_REGEX:
- if (file_printf(ms, m->desc, p->s) == -1)
+ case FILE_REGEX: {
+ char *cp;
+ int rval;
+
+ cp = strndup((const char *)ms->search.s, ms->search.rm_len);
+ if (cp == NULL) {
+ file_oomem(ms, ms->search.rm_len);
return -1;
- t = ms->offset + strlen(p->s);
+ }
+ rval = file_printf(ms, m->desc, cp);
+ free(cp);
+
+ if (rval == -1)
+ return -1;
+
+ if ((m->str_flags & REGEX_OFFSET_START))
+ t = ms->search.offset;
+ else
+ t = ms->search.offset + ms->search.rm_len;
break;
+ }
case FILE_SEARCH:
if (file_printf(ms, m->desc, m->value.s) == -1)
return -1;
- t = ms->offset + m->vallen;
+ if ((m->str_flags & REGEX_OFFSET_START))
+ t = ms->search.offset;
+ else
+ t = ms->search.offset + m->vallen;
+ break;
+
+ case FILE_DEFAULT:
+ if (file_printf(ms, m->desc, m->value.s) == -1)
+ return -1;
+ t = ms->offset;
break;
default:
- file_error(ms, 0, "invalid m->type (%d) in mprint()", m->type);
+ file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
return -1;
}
return(t);
#define DO_CVT(fld, cast) \
- if (m->mask) \
- switch (m->mask_op & 0x7F) { \
+ if (m->num_mask) \
+ switch (m->mask_op & FILE_OPS_MASK) { \
case FILE_OPAND: \
- p->fld &= cast m->mask; \
+ p->fld &= cast m->num_mask; \
break; \
case FILE_OPOR: \
- p->fld |= cast m->mask; \
+ p->fld |= cast m->num_mask; \
break; \
case FILE_OPXOR: \
- p->fld ^= cast m->mask; \
+ p->fld ^= cast m->num_mask; \
break; \
case FILE_OPADD: \
- p->fld += cast m->mask; \
+ p->fld += cast m->num_mask; \
break; \
case FILE_OPMINUS: \
- p->fld -= cast m->mask; \
+ p->fld -= cast m->num_mask; \
break; \
case FILE_OPMULTIPLY: \
- p->fld *= cast m->mask; \
+ p->fld *= cast m->num_mask; \
break; \
case FILE_OPDIVIDE: \
- p->fld /= cast m->mask; \
+ p->fld /= cast m->num_mask; \
break; \
case FILE_OPMODULO: \
- p->fld %= cast m->mask; \
+ p->fld %= cast m->num_mask; \
break; \
} \
if (m->mask_op & FILE_OPINVERSE) \
* (unless you have a better idea)
*/
private int
-mconvert(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
+mconvert(struct magic_set *ms, struct magic *m)
{
+ union VALUETYPE *p = &ms->ms_value;
+
switch (m->type) {
case FILE_BYTE:
cvt_8(p, m);
return 1;
case FILE_STRING:
case FILE_BESTRING16:
- case FILE_LESTRING16:
- {
- size_t len;
-
- /* Null terminate and eat *trailing* return */
- p->s[sizeof(p->s) - 1] = '\0';
- len = strlen(p->s);
- if (len-- && p->s[len] == '\n')
- p->s[len] = '\0';
- return 1;
- }
- case FILE_PSTRING:
- {
- char *ptr1 = p->s, *ptr2 = ptr1 + 1;
- size_t len = *p->s;
- if (len >= sizeof(p->s))
- len = sizeof(p->s) - 1;
- while (len--)
- *ptr1++ = *ptr2++;
- *ptr1 = '\0';
- len = strlen(p->s);
- if (len-- && p->s[len] == '\n')
- p->s[len] = '\0';
- return 1;
- }
+ case FILE_LESTRING16: {
+ size_t len;
+
+ /* Null terminate and eat *trailing* return */
+ p->s[sizeof(p->s) - 1] = '\0';
+ len = strlen(p->s);
+ if (len-- && p->s[len] == '\n')
+ p->s[len] = '\0';
+ return 1;
+ }
+ case FILE_PSTRING: {
+ char *ptr1 = p->s, *ptr2 = ptr1 + 1;
+ size_t len = *p->s;
+ if (len >= sizeof(p->s))
+ len = sizeof(p->s) - 1;
+ while (len--)
+ *ptr1++ = *ptr2++;
+ *ptr1 = '\0';
+ len = strlen(p->s);
+ if (len-- && p->s[len] == '\n')
+ p->s[len] = '\0';
+ return 1;
+ }
case FILE_BESHORT:
p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
cvt_16(p, m);
return 1;
case FILE_REGEX:
case FILE_SEARCH:
+ case FILE_DEFAULT:
return 1;
default:
- file_error(ms, 0, "invalid type %d in mconvert()", m->type);
+ file_magerror(ms, "invalid type %d in mconvert()", m->type);
return 0;
}
}
private int
mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
- const unsigned char *s, uint32_t offset, size_t nbytes)
+ const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
{
- if (type == FILE_REGEX && indir == 0) {
- /*
- * offset is interpreted as last line to search,
- * (starting at 1), not as bytes-from start-of-file
- */
- char *b, *c, *last = NULL;
- if (s == NULL) {
- p->search.buflen = 0;
- p->search.buf = NULL;
+ /*
+ * Note: FILE_SEARCH and FILE_REGEX do not actually copy
+ * anything, but setup pointers into the source
+ */
+ if (indir == 0) {
+ switch (type) {
+ case FILE_SEARCH:
+ ms->search.s = (const char *)s + offset;
+ ms->search.s_len = nbytes - offset;
return 0;
- }
- if ((p->search.buf = strdup((const char *)s)) == NULL) {
- file_oomem(ms, strlen((const char *)s));
- return -1;
- }
- for (b = p->search.buf; offset &&
- ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
- offset--, b++) {
- last = b;
- if (b[0] == '\r' && b[1] == '\n') b++;
- }
- if (last != NULL)
- *last = '\0';
- p->search.buflen = last - p->search.buf;
- return 0;
- }
-
- if (indir == 0 && (type == FILE_BESTRING16 || type == FILE_LESTRING16))
- {
- const unsigned char *src = s + offset;
- const unsigned char *esrc = s + nbytes;
- char *dst = p->s, *edst = &p->s[sizeof(p->s) - 1];
- if (type == FILE_BESTRING16)
- src++;
-
- /* check for pointer overflow */
- if (src < s) {
- file_error(ms, 0, "invalid offset %zu in mcopy()",
- offset);
- return -1;
+ case FILE_REGEX: {
+ /*
+ * offset is interpreted as last line to search,
+ * (starting at 1), not as bytes-from start-of-file
+ */
+ const char *b;
+ const char *c;
+ const char *last; /* end of search region */
+ const char *buf; /* start of search region */
+ size_t lines;
+
+ if (s == NULL) {
+ ms->search.s_len = 0;
+ ms->search.s = NULL;
+ return 0;
+ }
+ buf = (const char *)s + offset;
+ last = (const char *)s + nbytes;
+ /* mget() guarantees buf <= last */
+ for (lines = linecnt, b = buf;
+ lines && ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
+ lines--, b++) {
+ last = b;
+ if (b[0] == '\r' && b[1] == '\n')
+ b++;
+ }
+ if (lines)
+ last = (const char *)s + nbytes;
+
+ ms->search.s = buf;
+ ms->search.s_len = last - buf;
+ ms->search.offset = offset;
+ ms->search.rm_len = 0;
+ return 0;
}
-
- for (;src < esrc; src++, dst++) {
- if (dst < edst)
- *dst = *src++;
- else
- break;
- if (*dst == '\0')
- *dst = ' ';
+ case FILE_BESTRING16:
+ case FILE_LESTRING16: {
+ const unsigned char *src = s + offset;
+ const unsigned char *esrc = s + nbytes;
+ char *dst = p->s;
+ char *edst = &p->s[sizeof(p->s) - 1];
+
+ if (type == FILE_BESTRING16)
+ src++;
+
+ /* check for pointer overflow */
+ if (src < s) {
+ file_magerror(ms, "invalid offset %zu in mcopy()",
+ offset);
+ return -1;
+ }
+ for (/*EMPTY*/; src < esrc; src++, dst++) {
+ if (dst < edst)
+ *dst = *src++;
+ else
+ break;
+ if (*dst == '\0')
+ *dst = ' ';
+ }
+ *edst = '\0';
+ return 0;
+ }
+ case FILE_STRING: /* XXX - these two should not need */
+ case FILE_PSTRING: /* to copy anything, but do anyway. */
+ default:
+ break;
}
- *edst = '\0';
- return 0;
}
if (offset >= nbytes) {
}
private int
-mget(struct magic_set *ms, union VALUETYPE *p, const unsigned char *s,
+mget(struct magic_set *ms, const unsigned char *s,
struct magic *m, size_t nbytes, unsigned int cont_level)
{
uint32_t offset = ms->offset;
+ uint32_t count = m->str_count;
+ union VALUETYPE *p = &ms->ms_value;
- if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes) == -1)
+ if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
return -1;
if ((ms->flags & MAGIC_DEBUG) != 0) {
}
switch (m->in_type) {
case FILE_BYTE:
- if (nbytes < (offset + 1)) return 0;
+ if (nbytes < (offset + 1))
+ return 0;
if (off) {
- switch (m->in_op & 0x3F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = p->b & off;
break;
if (nbytes < (offset + 2))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = (short)((p->hs[0]<<8)|
(p->hs[1])) &
if (nbytes < (offset + 2))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = (short)((p->hs[1]<<8)|
(p->hs[0])) &
if (nbytes < (offset + 2))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = p->h & off;
break;
if (nbytes < (offset + 4))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = (int32_t)((p->hl[0]<<24)|
(p->hl[1]<<16)|
if (nbytes < (offset + 4))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = (int32_t)((p->hl[3]<<24)|
(p->hl[2]<<16)|
if (nbytes < (offset + 4))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = (int32_t)((p->hl[1]<<24)|
(p->hl[0]<<16)|
if (nbytes < (offset + 4))
return 0;
if (off) {
- switch (m->in_op & 0x7F) {
+ switch (m->in_op & FILE_OPS_MASK) {
case FILE_OPAND:
offset = p->l & off;
break;
break;
}
- if (m->flag & INDIROFFADD) offset += ms->c.off[cont_level-1];
- if (mcopy(ms, p, m->type, 0, s, offset, nbytes) == -1)
+ if (m->flag & INDIROFFADD)
+ offset += ms->c.li[cont_level-1].off;
+ if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
return -1;
ms->offset = offset;
/* Verify we have enough data to match magic type */
switch (m->type) {
- case FILE_BYTE:
- if (nbytes < (offset + 1)) /* should alway be true */
- return 0;
- break;
-
- case FILE_SHORT:
- case FILE_BESHORT:
- case FILE_LESHORT:
- if (nbytes < (offset + 2))
- return 0;
- break;
+ case FILE_BYTE:
+ if (nbytes < (offset + 1)) /* should alway be true */
+ return 0;
+ break;
+
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ if (nbytes < (offset + 2))
+ return 0;
+ break;
+
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ if (nbytes < (offset + 4))
+ return 0;
+ break;
+
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_SEARCH:
+ if (nbytes < (offset + m->vallen))
+ return 0;
+ break;
- case FILE_LONG:
- case FILE_BELONG:
- case FILE_LELONG:
- case FILE_MELONG:
- case FILE_DATE:
- case FILE_BEDATE:
- case FILE_LEDATE:
- case FILE_MEDATE:
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MELDATE:
- if (nbytes < (offset + 4))
- return 0;
- break;
+ case FILE_REGEX:
+ if (nbytes < offset)
+ return 0;
+ break;
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_SEARCH:
- if (nbytes < (offset + m->vallen))
- return 0;
- break;
- default: break;
+ case FILE_DEFAULT: /* nothing to check */
+ default:
+ break;
}
+ if (!mconvert(ms, m))
+ return 0;
+ return 1;
+}
- if (m->type == FILE_SEARCH) {
- size_t mlen = (size_t)(m->mask + m->vallen);
- size_t flen = nbytes - offset;
- if (flen < mlen)
- mlen = flen;
- p->search.buflen = mlen;
- p->search.buf = malloc(mlen + 1);
- if (p->search.buf == NULL) {
- file_error(ms, errno, "Cannot allocate search buffer");
- return 0;
+private uint64_t
+file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
+{
+ /*
+ * Convert the source args to unsigned here so that (1) the
+ * compare will be unsigned as it is in strncmp() and (2) so
+ * the ctype functions will work correctly without extra
+ * casting.
+ */
+ const unsigned char *a = (const unsigned char *)s1;
+ const unsigned char *b = (const unsigned char *)s2;
+ uint64_t v;
+
+ /*
+ * What we want here is:
+ * v = strncmp(m->value.s, p->s, m->vallen);
+ * but ignoring any nulls. bcmp doesn't give -/+/0
+ * and isn't universally available anyway.
+ */
+ v = 0;
+ if (0L == flags) { /* normal string: do it fast */
+ while (len-- > 0)
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
+ else { /* combine the others */
+ while (len-- > 0) {
+ if ((flags & STRING_IGNORE_LOWERCASE) &&
+ islower(*a)) {
+ if ((v = tolower(*b++) - *a++) != '\0')
+ break;
+ }
+ else if ((flags & STRING_IGNORE_UPPERCASE) &&
+ isupper(*a)) {
+ if ((v = toupper(*b++) - *a++) != '\0')
+ break;
+ }
+ else if ((flags & STRING_COMPACT_BLANK) &&
+ isspace(*a)) {
+ a++;
+ if (isspace(*b++)) {
+ while (isspace(*b))
+ b++;
+ }
+ else {
+ v = 1;
+ break;
+ }
+ }
+ else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
+ isspace(*a)) {
+ a++;
+ while (isspace(*b))
+ b++;
+ }
+ else {
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
}
- (void)memcpy(p->search.buf, s + offset, mlen);
- p->search.buf[mlen] = '\0';
}
- if (!mconvert(ms, p, m))
- return 0;
- return 1;
+ return v;
+}
+
+private uint64_t
+file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
+{
+ /*
+ * XXX - The 16-bit string compare probably needs to be done
+ * differently, especially if the flags are to be supported.
+ * At the moment, I am unsure.
+ */
+ flags = 0;
+ return file_strncmp(a, b, len, flags);
}
private int
-magiccheck(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
+magiccheck(struct magic_set *ms, struct magic *m)
{
uint64_t l = m->value.q;
uint64_t v;
int matched;
-
- if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
- return 1;
- }
-
+ union VALUETYPE *p = &ms->ms_value;
switch (m->type) {
case FILE_BYTE:
v = p->q;
break;
+ case FILE_DEFAULT:
+ l = 0;
+ v = 0;
+ break;
+
case FILE_STRING:
+ case FILE_PSTRING:
+ l = 0;
+ v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
+ break;
+
case FILE_BESTRING16:
case FILE_LESTRING16:
- case FILE_PSTRING:
- {
- /*
- * What we want here is:
- * v = strncmp(m->value.s, p->s, m->vallen);
- * but ignoring any nulls. bcmp doesn't give -/+/0
- * and isn't universally available anyway.
- */
- unsigned char *a = (unsigned char*)m->value.s;
- unsigned char *b = (unsigned char*)p->s;
- int len = m->vallen;
+ l = 0;
+ v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
+ break;
+
+ case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
+ size_t slen;
+ size_t idx;
+
+ if (ms->search.s == NULL)
+ return 0;
+
+ slen = MIN(m->vallen, sizeof(m->value.s));
l = 0;
v = 0;
- if (0L == m->mask) { /* normal string: do it fast */
- while (--len >= 0)
- if ((v = *b++ - *a++) != '\0')
- break;
- } else { /* combine the others */
- while (--len >= 0) {
- if ((m->mask & STRING_IGNORE_LOWERCASE) &&
- islower(*a)) {
- if ((v = tolower(*b++) - *a++) != '\0')
- break;
- } else if ((m->mask & STRING_COMPACT_BLANK) &&
- isspace(*a)) {
- a++;
- if (isspace(*b++)) {
- while (isspace(*b))
- b++;
- } else {
- v = 1;
- break;
- }
- } else if (isspace(*a) &&
- (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
- a++;
- while (isspace(*b))
- b++;
- } else {
- if ((v = *b++ - *a++) != '\0')
- break;
- }
+ ms->search.offset = m->offset;
+
+ for (idx = 0; m->str_count == 0 || idx < m->str_count; idx++) {
+ if (slen + idx > ms->search.s_len)
+ break;
+
+ v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
+ if (v == 0) { /* found match */
+ ms->search.offset = m->offset + idx;
+ break;
}
}
break;
}
- case FILE_REGEX:
- {
+ case FILE_REGEX: {
int rc;
regex_t rx;
char errmsg[512];
- if (p->search.buf == NULL)
+ if (ms->search.s == NULL)
return 0;
+ l = 0;
rc = regcomp(&rx, m->value.s,
- REG_EXTENDED|REG_NOSUB|REG_NEWLINE|
- ((m->mask & STRING_IGNORE_LOWERCASE) ? REG_ICASE : 0));
+ REG_EXTENDED|REG_NEWLINE|
+ ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
if (rc) {
- free(p->search.buf);
- p->search.buf = NULL;
- regerror(rc, &rx, errmsg, sizeof(errmsg));
- file_error(ms, 0, "regex error %d, (%s)", rc, errmsg);
- return -1;
- } else {
- rc = regexec(&rx, p->search.buf, 0, 0, 0);
- regfree(&rx);
- free(p->search.buf);
- p->search.buf = NULL;
- return !rc;
+ (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
+ file_magerror(ms, "regex error %d, (%s)",
+ rc, errmsg);
+ v = (uint64_t)-1;
}
- }
- case FILE_SEARCH:
- {
- /*
- * search for a string in a certain range
- */
- unsigned char *a = (unsigned char*)m->value.s;
- unsigned char *b = (unsigned char*)p->search.buf;
- size_t len, slen = m->vallen;
- size_t range = 0;
- if (slen > sizeof(m->value.s))
- slen = sizeof(m->value.s);
- l = 0;
- v = 0;
- if (b == NULL)
- return 0;
- len = slen;
- while (++range <= m->mask) {
- while (len-- > 0 && (v = *b++ - *a++) == 0)
- continue;
- if (!v) {
- ms->offset += range - 1;
+ else {
+ regmatch_t pmatch[1];
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = ms->search.s_len;
+ rc = regexec(&rx, (const char *)ms->search.s,
+ 1, pmatch, REG_STARTEND);
+ switch (rc) {
+ case 0:
+ ms->search.s += (int)pmatch[0].rm_so;
+ ms->search.offset += (size_t)pmatch[0].rm_so;
+ ms->search.rm_len =
+ (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
+ v = 0;
break;
- }
- if (range + slen >= p->search.buflen) {
+
+ case REG_NOMATCH:
v = 1;
break;
+
+ default:
+ (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
+ file_magerror(ms, "regexec error %d, (%s)",
+ rc, errmsg);
+ v = (uint64_t)-1;
+ break;
}
- len = slen;
- a = (unsigned char*)m->value.s;
- b = (unsigned char*)p->search.buf + range;
+ regfree(&rx);
}
- free(p->search.buf);
- p->search.buf = NULL;
- if (v)
- return 0;
+ if (v == (uint64_t)-1)
+ return -1;
break;
}
default:
- file_error(ms, 0, "invalid type %d in magiccheck()", m->type);
+ file_magerror(ms, "invalid type %d in magiccheck()", m->type);
return -1;
}
- if (m->type != FILE_STRING && m->type != FILE_PSTRING)
- v = file_signextend(ms, m, v);
+ v = file_signextend(ms, m, v);
switch (m->reln) {
case 'x':
(unsigned long long)l, matched);
}
else {
- matched = (int32_t) v > (int32_t) l;
+ matched = (int64_t) v > (int64_t) l;
if ((ms->flags & MAGIC_DEBUG) != 0)
(void) fprintf(stderr, "%lld > %lld = %d\n",
(long long)v, (long long)l, matched);
(unsigned long long)l, matched);
}
else {
- matched = (int32_t) v < (int32_t) l;
+ matched = (int64_t) v < (int64_t) l;
if ((ms->flags & MAGIC_DEBUG) != 0)
(void) fprintf(stderr, "%lld < %lld = %d\n",
(long long)v, (long long)l, matched);
default:
matched = 0;
- file_error(ms, 0, "cannot happen: invalid relation `%c'",
+ file_magerror(ms, "cannot happen: invalid relation `%c'",
m->reln);
return -1;
}