diff options
author | Anatol Belski <ab@php.net> | 2013-04-07 22:15:56 +0200 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2013-04-07 22:15:56 +0200 |
commit | 10367fa7c6a4a2cf9bee02d8905e284185428f09 (patch) | |
tree | 380b04df159e9f46f91283d5b26171b5a4a8394c /ext/fileinfo/libmagic | |
parent | 39bc1bd25f765726e6cdf15fd663b2c1430d2c8a (diff) | |
download | php-git-10367fa7c6a4a2cf9bee02d8905e284185428f09.tar.gz |
upgraded libmagic to 5.14
Diffstat (limited to 'ext/fileinfo/libmagic')
-rw-r--r-- | ext/fileinfo/libmagic/apprentice.c | 993 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/ascmagic.c | 11 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/cdf.c | 8 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/cdf.h | 4 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/cdf_time.c | 18 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/compress.c | 24 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/elfclass.h | 3 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/file.h | 58 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/fsmagic.c | 73 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/funcs.c | 26 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/magic.c | 104 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/magic.h | 3 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/patchlevel.h | 6 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/print.c | 23 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/readcdf.c | 24 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/readelf.c | 36 | ||||
-rw-r--r-- | ext/fileinfo/libmagic/softmagic.c | 333 |
17 files changed, 1210 insertions, 537 deletions
diff --git a/ext/fileinfo/libmagic/apprentice.c b/ext/fileinfo/libmagic/apprentice.c index 09e1812156..ef65a7ecc0 100644 --- a/ext/fileinfo/libmagic/apprentice.c +++ b/ext/fileinfo/libmagic/apprentice.c @@ -34,7 +34,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.173 2011/12/08 12:38:24 rrt Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.191 2013/02/26 21:02:48 christos Exp $") #endif /* lint */ #include "magic.h" @@ -58,7 +58,6 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.173 2011/12/08 12:38:24 rrt Exp $") #else #include <unistd.h> #endif - #include <string.h> #include <assert.h> #include <ctype.h> @@ -86,12 +85,22 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.173 2011/12/08 12:38:24 rrt Exp $") #define MAP_FILE 0 #endif +#define ALLOC_CHUNK (size_t)10 +#define ALLOC_INCR (size_t)200 + struct magic_entry { struct magic *mp; uint32_t cont_count; uint32_t max_count; }; +struct magic_map { + void *p; + size_t len; + struct magic *magic[MAGIC_SETS]; + uint32_t nmagic[MAGIC_SETS]; +}; + int file_formats[FILE_NAMES_SIZE]; const size_t file_nformats = FILE_NAMES_SIZE; const char *file_names[FILE_NAMES_SIZE]; @@ -101,24 +110,26 @@ private int getvalue(struct magic_set *ms, struct magic *, const char **, int); private int hextoint(int); private const char *getstr(struct magic_set *, struct magic *, const char *, int); -private int parse(struct magic_set *, struct magic_entry **, uint32_t *, - const char *, size_t, int); +private int parse(struct magic_set *, struct magic_entry *, const char *, + size_t, int); private void eatsize(const char **); -private int apprentice_1(struct magic_set *, const char *, int, struct mlist *); +private int apprentice_1(struct magic_set *, const char *, int); private size_t apprentice_magic_strength(const struct magic *); private int apprentice_sort(const void *, const void *); private void apprentice_list(struct mlist *, int ); -private int apprentice_load(struct magic_set *, struct magic **, uint32_t *, +private struct magic_map *apprentice_load(struct magic_set *, const char *, int); +private struct mlist *mlist_alloc(void); +private void mlist_free(struct mlist *); private void byteswap(struct magic *, uint32_t); private void bs1(struct magic *); private uint16_t swap2(uint16_t); private uint32_t swap4(uint32_t); private uint64_t swap8(uint64_t); private char *mkdbname(struct magic_set *, const char *, int); -private int apprentice_map(struct magic_set *, struct magic **, uint32_t *, - const char *); -private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *, +private struct magic_map *apprentice_map(struct magic_set *, const char *); +private void apprentice_unmap(struct magic_map *); +private int apprentice_compile(struct magic_set *, struct magic_map *, const char *); private int check_format_type(const char *, int); private int check_format(struct magic_set *, struct magic *); @@ -127,10 +138,12 @@ private int parse_mime(struct magic_set *, struct magic_entry *, const char *); private int parse_strength(struct magic_set *, struct magic_entry *, const char *); private int parse_apple(struct magic_set *, struct magic_entry *, const char *); -private size_t maxmagic = 0; + +private size_t maxmagic[MAGIC_SETS] = { 0 }; private size_t magicsize = sizeof(struct magic); private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; + private struct { const char *name; size_t len; @@ -146,14 +159,24 @@ private struct { #include "../data_file.c" -static const struct type_tbl_s { +struct type_tbl_s { const char name[16]; const size_t len; const int type; const int format; -} type_tbl[] = { +}; + +/* + * XXX - the actual Single UNIX Specification says that "long" means "long", + * as in the C data type, but we treat it as meaning "4-byte integer". + * Given that the OS X version of file 5.04 did the same, I guess that passes + * the actual test; having "long" be dependent on how big a "long" is on + * the machine running "file" is silly. + */ +static const struct type_tbl_s type_tbl[] = { # define XX(s) s, (sizeof(s) - 1) # define XX_NULL "", 0 + { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, { XX("short"), FILE_SHORT, FILE_FMT_NUM }, { XX("default"), FILE_DEFAULT, FILE_FMT_STR }, @@ -194,22 +217,37 @@ static const struct type_tbl_s { { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, { XX("leid3"), FILE_LEID3, FILE_FMT_NUM }, { XX("beid3"), FILE_BEID3, FILE_FMT_NUM }, - { XX("indirect"), FILE_INDIRECT, FILE_FMT_NONE }, + { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM }, + { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, + { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, + { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, + { XX("name"), FILE_NAME, FILE_FMT_NONE }, + { XX("use"), FILE_USE, FILE_FMT_NONE }, + { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, +}; + +/* + * These are not types, and cannot be preceded by "u" to make them + * unsigned. + */ +static const struct type_tbl_s special_tbl[] = { + { XX("name"), FILE_NAME, FILE_FMT_STR }, + { XX("use"), FILE_USE, FILE_FMT_STR }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, +}; # undef XX # undef XX_NULL -}; #ifndef S_ISDIR #define S_ISDIR(mode) ((mode) & _S_IFDIR) #endif private int -get_type(const char *l, const char **t) +get_type(const struct type_tbl_s *tbl, const char *l, const char **t) { const struct type_tbl_s *p; - for (p = type_tbl; p->len; p++) { + for (p = tbl; p->len; p++) { if (strncmp(l, p->name, p->len) == 0) { if (t) *t = l + p->len; @@ -219,6 +257,91 @@ get_type(const char *l, const char **t) return p->type; } +private int +get_standard_integer_type(const char *l, const char **t) +{ + int type; + + if (isalpha((unsigned char)l[1])) { + switch (l[1]) { + case 'C': + /* "dC" and "uC" */ + type = FILE_BYTE; + break; + case 'S': + /* "dS" and "uS" */ + type = FILE_SHORT; + break; + case 'I': + case 'L': + /* + * "dI", "dL", "uI", and "uL". + * + * XXX - the actual Single UNIX Specification says + * that "L" means "long", as in the C data type, + * but we treat it as meaning "4-byte integer". + * Given that the OS X version of file 5.04 did + * the same, I guess that passes the actual SUS + * validation suite; having "dL" be dependent on + * how big a "long" is on the machine running + * "file" is silly. + */ + type = FILE_LONG; + break; + case 'Q': + /* "dQ" and "uQ" */ + type = FILE_QUAD; + break; + default: + /* "d{anything else}", "u{anything else}" */ + return FILE_INVALID; + } + l += 2; + } else if (isdigit((unsigned char)l[1])) { + /* + * "d{num}" and "u{num}"; we only support {num} values + * of 1, 2, 4, and 8 - the Single UNIX Specification + * doesn't say anything about whether arbitrary + * values should be supported, but both the Solaris 10 + * and OS X Mountain Lion versions of file passed the + * Single UNIX Specification validation suite, and + * neither of them support values bigger than 8 or + * non-power-of-2 values. + */ + if (isdigit((unsigned char)l[2])) { + /* Multi-digit, so > 9 */ + return FILE_INVALID; + } + switch (l[1]) { + case '1': + type = FILE_BYTE; + break; + case '2': + type = FILE_SHORT; + break; + case '4': + type = FILE_LONG; + break; + case '8': + type = FILE_QUAD; + break; + default: + /* XXX - what about 3, 5, 6, or 7? */ + return FILE_INVALID; + } + l += 2; + } else { + /* + * "d" or "u" by itself. + */ + type = FILE_LONG; + ++l; + } + if (t) + *t = l; + return type; +} + private void init_file_tables(void) { @@ -234,110 +357,187 @@ init_file_tables(void) file_names[p->type] = p->name; file_formats[p->type] = p->format; } + assert(p - type_tbl == FILE_NAMES_SIZE); +} + +private int +add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) +{ + struct mlist *ml; + + if ((ml = CAST(struct mlist *, emalloc(sizeof(*ml)))) == NULL) + return -1; + + ml->map = idx == 0 ? map : NULL; + ml->magic = map->magic[idx]; + ml->nmagic = map->nmagic[idx]; + + mlp->prev->next = ml; + ml->prev = mlp->prev; + ml->next = mlp; + mlp->prev = ml; + return 0; } /* * Handle one file or directory. */ private int -apprentice_1(struct magic_set *ms, const char *fn, int action, - struct mlist *mlist) +apprentice_1(struct magic_set *ms, const char *fn, int action) { - struct magic *magic = NULL; - uint32_t nmagic = 0; struct mlist *ml; - int rv = -1; - int mapped; + struct magic_map *map; + size_t i; if (magicsize != FILE_MAGICSIZE) { file_error(ms, 0, "magic element size %lu != %lu", - (unsigned long)sizeof(*magic), + (unsigned long)sizeof(*map->magic[0]), (unsigned long)FILE_MAGICSIZE); return -1; } if (action == FILE_COMPILE) { - rv = apprentice_load(ms, &magic, &nmagic, fn, action); - if (rv != 0) + map = apprentice_load(ms, fn, action); + if (map == NULL) return -1; - rv = apprentice_compile(ms, &magic, &nmagic, fn); - efree(magic); - return rv; + return apprentice_compile(ms, map, fn); } - if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { + map = apprentice_map(ms, fn); + if (map == NULL) { if (fn) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "using regular magic file `%s'", fn); - rv = apprentice_load(ms, &magic, &nmagic, fn, action); + map = apprentice_load(ms, fn, action); } - - if (rv != 0) + if (map == NULL) return -1; } - mapped = rv; - - if (magic == NULL) { - file_delmagic(magic, mapped, nmagic); - return -1; + for (i = 0; i < MAGIC_SETS; i++) { + if (add_mlist(ms->mlist[i], map, i) == -1) { + file_oomem(ms, sizeof(*ml)); + apprentice_unmap(map); + return -1; + } } - ml = emalloc(sizeof(*ml)); - - ml->magic = magic; - ml->nmagic = nmagic; - ml->mapped = mapped; - - mlist->prev->next = ml; - ml->prev = mlist->prev; - ml->next = mlist; - mlist->prev = ml; - if (action == FILE_LIST) { - printf("Binary patterns:\n"); - apprentice_list(mlist, BINTEST); - printf("Text patterns:\n"); - apprentice_list(mlist, TEXTTEST); + for (i = 0; i < MAGIC_SETS; i++) { + printf("Set %zu:\nBinary patterns:\n", i); + apprentice_list(ms->mlist[i], BINTEST); + printf("Text patterns:\n"); + apprentice_list(ms->mlist[i], TEXTTEST); + } } return 0; } protected void -file_delmagic(struct magic *p, int type, size_t entries) +file_ms_free(struct magic_set *ms) { - if (p == NULL) + size_t i; + if (ms == NULL) return; - switch (type) { - case 3: - /* Do nothing, it's part of the code segment */ - break; + for (i = 0; i < MAGIC_SETS; i++) + mlist_free(ms->mlist[i]); + if (ms->o.pbuf) { + efree(ms->o.pbuf); + } + if (ms->o.buf) { + efree(ms->o.buf); + } + if (ms->c.li) { + efree(ms->c.li); + } + efree(ms); +} - case 1: - p--; - /*FALLTHROUGH*/ +protected struct magic_set * +file_ms_alloc(int flags) +{ + struct magic_set *ms; + size_t i, len; - case 0: - efree(p); - break; + if ((ms = CAST(struct magic_set *, ecalloc((size_t)1, + sizeof(struct magic_set)))) == NULL) + return NULL; - default: - abort(); + if (magic_setflags(ms, flags) == -1) { + errno = EINVAL; + goto free; + } + + ms->o.buf = ms->o.pbuf = NULL; + len = (ms->c.len = 10) * sizeof(*ms->c.li); + + if ((ms->c.li = CAST(struct level_info *, emalloc(len))) == NULL) + goto free; + + ms->event_flags = 0; + ms->error = -1; + for (i = 0; i < MAGIC_SETS; i++) + ms->mlist[i] = NULL; + ms->file = "unknown"; + ms->line = 0; + return ms; +free: + efree(ms); + return NULL; +} + +private void +apprentice_unmap(struct magic_map *map) +{ + if (map == NULL) + return; + if (map->p != NULL && map->p != php_magic_database) { + efree(map->p); + } + efree(map); +} + +private struct mlist * +mlist_alloc(void) +{ + struct mlist *mlist; + if ((mlist = CAST(struct mlist *, ecalloc(1, sizeof(*mlist)))) == NULL) { + return NULL; } + mlist->next = mlist->prev = mlist; + return mlist; +} + +private void +mlist_free(struct mlist *mlist) +{ + struct mlist *ml; + + if (mlist == NULL) + return; + + for (ml = mlist->next; ml != mlist;) { + struct mlist *next = ml->next; + if (ml->map) + apprentice_unmap(ml->map); + efree(ml); + ml = next; + } + efree(ml); } /* const char *fn: list of magic files and directories */ -protected struct mlist * +protected int file_apprentice(struct magic_set *ms, const char *fn, int action) { char *p, *mfn; int file_err, errs = -1; - struct mlist *mlist; + size_t i; /* XXX disabling default magic loading so the compiled in data is used */ #if 0 if ((fn = magic_getpath(fn, action)) == NULL) - return NULL; + return -1; #endif init_file_tables(); @@ -345,17 +545,36 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) if (fn == NULL) fn = getenv("MAGIC"); if (fn == NULL) { - mlist = emalloc(sizeof(*mlist)); - mlist->next = mlist->prev = mlist; - apprentice_1(ms, fn, action, mlist); - return mlist; + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + if ((ms->mlist[i] = mlist_alloc()) == NULL) { + file_oomem(ms, sizeof(*ms->mlist[i])); + return -1; + } + } + return apprentice_1(ms, fn, action); } - mfn = estrdup(fn); - fn = mfn; + if ((mfn = estrdup(fn)) == NULL) { + file_oomem(ms, strlen(fn)); + return -1; + } - mlist = emalloc(sizeof(*mlist)); - mlist->next = mlist->prev = mlist; + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + if ((ms->mlist[i] = mlist_alloc()) == NULL) { + file_oomem(ms, sizeof(*ms->mlist[i])); + if (i != 0) { + --i; + do + mlist_free(ms->mlist[i]); + while (i != 0); + } + efree(mfn); + return -1; + } + } + fn = mfn; while (fn) { p = strchr(fn, PATHSEP); @@ -363,19 +582,39 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) *p++ = '\0'; if (*fn == '\0') break; - file_err = apprentice_1(ms, fn, action, mlist); + file_err = apprentice_1(ms, fn, action); errs = MAX(errs, file_err); fn = p; } + + efree(mfn); + if (errs == -1) { - efree(mfn); - efree(mlist); - mlist = NULL; - file_error(ms, 0, "could not find any magic files!"); - return NULL; + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } + file_error(ms, 0, "could not find any valid magic files!"); + return -1; + } + + if (action == FILE_LOAD) + return 0; + + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } + + switch (action) { + case FILE_COMPILE: + case FILE_CHECK: + case FILE_LIST: + return 0; + default: + file_error(ms, 0, "Invalid action %d", action); + return -1; } - efree(mfn); - return mlist; } /* @@ -448,12 +687,20 @@ apprentice_magic_strength(const struct magic *m) case FILE_QLDATE: case FILE_LEQLDATE: case FILE_BEQLDATE: + case FILE_QWDATE: + case FILE_LEQWDATE: + case FILE_BEQWDATE: case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: val += 8 * MULT; break; + case FILE_INDIRECT: + case FILE_NAME: + case FILE_USE: + break; + default: val = 0; (void)fprintf(stderr, "Bad type %d\n", m->type); @@ -507,7 +754,6 @@ apprentice_magic_strength(const struct magic *m) abort(); } - /* * Magic entries with no description get a bonus because they depend * on subsequent magic entries to print something. @@ -523,8 +769,8 @@ apprentice_magic_strength(const struct magic *m) private int apprentice_sort(const void *a, const void *b) { - const struct magic_entry *ma = a; - const struct magic_entry *mb = b; + const struct magic_entry *ma = CAST(const struct magic_entry *, a); + const struct magic_entry *mb = CAST(const struct magic_entry *, b); size_t sa = apprentice_magic_strength(ma->mp); size_t sb = apprentice_magic_strength(mb->mp); if (sa == sb) @@ -601,6 +847,9 @@ set_test_type(struct magic *mstart, struct magic *m) case FILE_QLDATE: case FILE_LEQLDATE: case FILE_BEQLDATE: + case FILE_QWDATE: + case FILE_LEQWDATE: + case FILE_BEQWDATE: case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: @@ -648,22 +897,48 @@ set_test_type(struct magic *mstart, struct magic *m) } } +private int +addentry(struct magic_set *ms, struct magic_entry *me, + struct magic_entry **mentry, uint32_t *mentrycount) +{ + size_t i = me->mp->type == FILE_NAME ? 1 : 0; + if (mentrycount[i] == maxmagic[i]) { + struct magic_entry *mp; + + maxmagic[i] += ALLOC_INCR; + if ((mp = CAST(struct magic_entry *, + erealloc(mentry[i], sizeof(*mp) * maxmagic[i]))) == + NULL) { + file_oomem(ms, sizeof(*mp) * maxmagic[i]); + return -1; + } + (void)memset(&mp[mentrycount[i]], 0, sizeof(*mp) * + ALLOC_INCR); + mentry[i] = mp; + } + mentry[i][mentrycount[i]++] = *me; + memset(me, 0, sizeof(*me)); + return 0; +} + /* * Load and parse one file. */ private void load_1(struct magic_set *ms, int action, const char *fn, int *errs, - struct magic_entry **marray, uint32_t *marraycount) + struct magic_entry **mentry, uint32_t *mentrycount) { char buffer[BUFSIZ + 1]; char *line = NULL; size_t len; size_t lineno = 0; + struct magic_entry me; php_stream *stream; TSRMLS_FETCH(); + ms->file = fn; #if PHP_API_VERSION < 20100412 stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); #else @@ -678,12 +953,9 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, return; } - /* read and parse this file */ -#if (PHP_MAJOR_VERSION < 6) + memset(&me, 0, sizeof(me)); + /* read and parse this file */ for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &len)) != NULL; ms->line++) { -#else - for (ms->line = 1; (line = php_stream_get_line(stream, ZSTR(buffer), BUFSIZ, &len)) != NULL; ms->line++) { -#endif if (len == 0) /* null line, garbage, etc */ continue; if (line[len - 1] == '\n') { @@ -710,15 +982,14 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, (*errs)++; continue; } - if (*marraycount == 0) { + if (me.mp == NULL) { file_error(ms, 0, "No current entry for :!%s type", bang[i].name); (*errs)++; continue; } - if ((*bang[i].fun)(ms, - &(*marray)[*marraycount - 1], + if ((*bang[i].fun)(ms, &me, line + bang[i].len + 2) != 0) { (*errs)++; continue; @@ -727,12 +998,21 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, } /*FALLTHROUGH*/ default: - if (parse(ms, marray, marraycount, line, lineno, - action) != 0) + again: + switch (parse(ms, &me, line, lineno, action)) { + case 0: + continue; + case 1: + (void)addentry(ms, &me, mentry, mentrycount); + goto again; + default: (*errs)++; break; } } + } + if (me.mp) + (void)addentry(ms, &me, mentry, mentrycount); php_stream_close(stream); } @@ -746,16 +1026,109 @@ cmpstrp(const void *p1, const void *p2) return strcmp(*(char *const *)p1, *(char *const *)p2); } + +private uint32_t +set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, + uint32_t starttest) +{ + static const char text[] = "text"; + static const char binary[] = "binary"; + static const size_t len = sizeof(text); + + uint32_t i = starttest; + + do { + set_test_type(me[starttest].mp, me[i].mp); + if ((ms->flags & MAGIC_DEBUG) == 0) + continue; + (void)fprintf(stderr, "%s%s%s: %s\n", + me[i].mp->mimetype, + me[i].mp->mimetype[0] == '\0' ? "" : "; ", + me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", + me[i].mp->flag & BINTEST ? binary : text); + if (me[i].mp->flag & BINTEST) { + char *p = strstr(me[i].mp->desc, text); + if (p && (p == me[i].mp->desc || + isspace((unsigned char)p[-1])) && + (p + len - me[i].mp->desc == MAXstring + || (p[len] == '\0' || + isspace((unsigned char)p[len])))) + (void)fprintf(stderr, "*** Possible " + "binary test for text type\n"); + } + } while (++i < nme && me[i].mp->cont_level != 0); + return i; +} + +private void +set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) +{ + uint32_t i; + for (i = 0; i < nme; i++) { + if (me[i].mp->cont_level == 0 && + me[i].mp->type == FILE_DEFAULT) { + while (++i < nme) + if (me[i].mp->cont_level == 0) + break; + if (i != nme) { + /* XXX - Ugh! */ + ms->line = me[i].mp->lineno; + file_magwarn(ms, + "level 0 \"default\" did not sort last"); + } + return; + } + } +} + private int -apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, - const char *fn, int action) +coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, + struct magic **ma, uint32_t *nma) +{ + uint32_t i, mentrycount = 0; + size_t slen; + + for (i = 0; i < nme; i++) + mentrycount += me[i].cont_count; + + slen = sizeof(**ma) * mentrycount; + if ((*ma = CAST(struct magic *, emalloc(slen))) == NULL) { + file_oomem(ms, slen); + return -1; + } + + mentrycount = 0; + for (i = 0; i < nme; i++) { + (void)memcpy(*ma + mentrycount, me[i].mp, + me[i].cont_count * sizeof(**ma)); + mentrycount += me[i].cont_count; + } + *nma = mentrycount; + return 0; +} + +private void +magic_entry_free(struct magic_entry *me, uint32_t nme) +{ + uint32_t i; + if (me == NULL) + return; + for (i = 0; i < nme; i++) + efree(me[i].mp); + efree(me); +} + +private struct magic_map * +apprentice_load(struct magic_set *ms, const char *fn, int action) { int errs = 0; - struct magic_entry *marray; - uint32_t marraycount, i, mentrycount = 0, starttest; + struct magic_entry *mentry[MAGIC_SETS] = { NULL }; + uint32_t mentrycount[MAGIC_SETS] = { 0 }; + uint32_t i, j; size_t files = 0, maxfiles = 0; - char **filearr = NULL; + char **filearr = NULL, *mfn; struct stat st; + struct magic_map *map; php_stream *dir; php_stream_dirent d; @@ -763,14 +1136,25 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ - maxmagic = MAXMAGIS; - marray = ecalloc(maxmagic, sizeof(*marray)); - marraycount = 0; + if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) { + file_oomem(ms, sizeof(*map)); + return NULL; + } /* print silly verbose header for USG compat. */ if (action == FILE_CHECK) (void)fprintf(stderr, "%s\n", usg_hdr); + {
+ /* XXX the maxmagic has to be reset each time we load some new magic file.
+ Where file commando is used it's not essential as the CLI process
+ ends, multiple loading within the same process wouldn't work. */
+ int k;
+ for (k = 0; k < MAGIC_SETS; k++) {
+ maxmagic[k] = 0;
+ }
+ } + /* load directory or file */ /* FIXME: Read file names and sort them to prevent non-determinism. See Debian bug #488562. */ @@ -799,7 +1183,7 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, maxfiles = (maxfiles + 1) * 2; mlen = maxfiles * sizeof(*filearr); if ((filearr = CAST(char **, - realloc(filearr, mlen))) == NULL) { + erealloc(filearr, mlen))) == NULL) { file_oomem(ms, mlen); php_stream_closedir(dir); errs++; @@ -811,100 +1195,55 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, php_stream_closedir(dir); qsort(filearr, files, sizeof(*filearr), cmpstrp); for (i = 0; i < files; i++) { - load_1(ms, action, filearr[i], &errs, &marray, - &marraycount); + load_1(ms, action, filearr[i], &errs, mentry, + mentrycount); efree(filearr[i]); } - free(filearr); + efree(filearr); } else - load_1(ms, action, fn, &errs, &marray, &marraycount); + load_1(ms, action, fn, &errs, mentry, mentrycount); if (errs) goto out; + for (j = 0; j < MAGIC_SETS; j++) { /* Set types of tests */ - for (i = 0; i < marraycount; ) { - if (marray[i].mp->cont_level != 0) { + for (i = 0; i < mentrycount[j]; ) { + if (mentry[j][i].mp->cont_level != 0) { i++; continue; } - - starttest = i; - do { - static const char text[] = "text"; - static const char binary[] = "binary"; - static const size_t len = sizeof(text); - set_test_type(marray[starttest].mp, marray[i].mp); - if ((ms->flags & MAGIC_DEBUG) == 0) - continue; - (void)fprintf(stderr, "%s%s%s: %s\n", - marray[i].mp->mimetype, - marray[i].mp->mimetype[0] == '\0' ? "" : "; ", - marray[i].mp->desc[0] ? marray[i].mp->desc : - "(no description)", - marray[i].mp->flag & BINTEST ? binary : text); - if (marray[i].mp->flag & BINTEST) { - char *p = strstr(marray[i].mp->desc, text); - if (p && (p == marray[i].mp->desc || - isspace((unsigned char)p[-1])) && - (p + len - marray[i].mp->desc == - MAXstring || (p[len] == '\0' || - isspace((unsigned char)p[len])))) - (void)fprintf(stderr, "*** Possible " - "binary test for text type\n"); + i = set_text_binary(ms, mentry[j], mentrycount[j], i); } - } while (++i < marraycount && marray[i].mp->cont_level != 0); - } - - qsort(marray, marraycount, sizeof(*marray), apprentice_sort); + qsort(mentry[j], mentrycount[j], sizeof(*mentry[j]), + apprentice_sort); /* - * Make sure that any level 0 "default" line is last (if one exists). + * 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) { - /* XXX - Ugh! */ - ms->line = marray[i].mp->lineno; - file_magwarn(ms, - "level 0 \"default\" did not sort last"); - } - break; + set_last_default(ms, mentry[j], mentrycount[j]); + + /* coalesce per file arrays into a single one */ + if (coalesce_entries(ms, mentry[j], mentrycount[j], + &map->magic[j], &map->nmagic[j]) == -1) { + errs++; + goto out; } } - for (i = 0; i < marraycount; i++) - mentrycount += marray[i].cont_count; - - *magicp = emalloc(sizeof(**magicp) * mentrycount); - - mentrycount = 0; - for (i = 0; i < marraycount; i++) { - (void)memcpy(*magicp + mentrycount, marray[i].mp, - marray[i].cont_count * sizeof(**magicp)); - mentrycount += marray[i].cont_count; - } out: - for (i = 0; i < marraycount; i++) { - if (marray[i].mp) { - efree(marray[i].mp); - } - } - if (marray) { - efree(marray); - } + for (j = 0; j < MAGIC_SETS; j++) + magic_entry_free(mentry[j], mentrycount[j]); + if (errs) { - *magicp = NULL; - *nmagicp = 0; - return errs; - } else { - *nmagicp = mentrycount; - return 0; + for (j = 0; j < MAGIC_SETS; j++) { + if (map->magic[j]) + efree(map->magic[j]); + } + efree(map); + return NULL; } - + return map; } /* @@ -950,10 +1289,13 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_LEQUAD: case FILE_QDATE: case FILE_QLDATE: + case FILE_QWDATE: case FILE_BEQDATE: case FILE_BEQLDATE: + case FILE_BEQWDATE: case FILE_LEQDATE: case FILE_LEQLDATE: + case FILE_LEQWDATE: case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: @@ -967,6 +1309,8 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_SEARCH: case FILE_DEFAULT: case FILE_INDIRECT: + case FILE_NAME: + case FILE_USE: break; default: if (ms->flags & MAGIC_CHECK) @@ -1136,22 +1480,25 @@ check_cond(struct magic_set *ms, int cond, uint32_t cont_level) * parse one line from magic file, put into magic[index++] if valid */ private int -parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, - const char *line, size_t lineno, int action) +parse(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t lineno, int action) { #ifdef ENABLE_CONDITIONALS static uint32_t last_cont_level = 0; #endif size_t i; - struct magic_entry *me; struct magic *m; const char *l = line; char *t; int op; uint32_t cont_level; + int32_t diff; cont_level = 0; + /* + * Parse the offset. + */ while (*l == '>') { ++l; /* step over */ cont_level++; @@ -1162,23 +1509,29 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, return -1; last_cont_level = cont_level; #endif - -#define ALLOC_CHUNK (size_t)10 -#define ALLOC_INCR (size_t)200 - if (cont_level != 0) { - if (*nmentryp == 0) { - file_error(ms, 0, "No current entry for continuation"); + if (me->mp == NULL) { + file_magerror(ms, "No current entry for continuation"); return -1; } - me = &(*mentryp)[*nmentryp - 1]; - if (me->mp == NULL) { + if (me->cont_count == 0) { + file_magerror(ms, "Continuations present with 0 count"); return -1; } + m = &me->mp[me->cont_count - 1]; + diff = (int32_t)cont_level - (int32_t)m->cont_level; + if (diff > 1) + file_magwarn(ms, "New continuation level %u is more " + "than one larger than current level %u", cont_level, + m->cont_level); if (me->cont_count == me->max_count) { struct magic *nm; size_t cnt = me->max_count + ALLOC_CHUNK; - nm = erealloc(me->mp, sizeof(*nm) * cnt); + if ((nm = CAST(struct magic *, erealloc(me->mp, + sizeof(*nm) * cnt))) == NULL) { + file_oomem(ms, sizeof(*nm) * cnt); + return -1; + } me->mp = m = nm; me->max_count = CAST(uint32_t, cnt); } @@ -1186,21 +1539,15 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, (void)memset(m, 0, sizeof(*m)); m->cont_level = cont_level; } else { - if (*nmentryp == maxmagic) { - struct magic_entry *mp; - - maxmagic += ALLOC_INCR; - mp = erealloc(*mentryp, sizeof(*mp) * maxmagic); - (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * ALLOC_INCR); - *mentryp = mp; + static const size_t len = sizeof(*m) * ALLOC_CHUNK; + if (me->mp != NULL) + return 1; + if ((m = CAST(struct magic *, emalloc(len))) == NULL) { + file_oomem(ms, len); + return -1; } - me = &(*mentryp)[*nmentryp]; - if (me->mp == NULL) { - m = safe_emalloc(sizeof(*m), ALLOC_CHUNK, 0); - me->mp = m; - me->max_count = ALLOC_CHUNK; - } else - m = me->mp; + me->mp = m; + me->max_count = ALLOC_CHUNK; (void)memset(m, 0, sizeof(*m)); m->factor_op = FILE_FACTOR_OP_NONE; m->cont_level = 0; @@ -1330,12 +1677,54 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, EATAB; #endif + /* + * Parse the type. + */ if (*l == 'u') { + /* + * Try it as a keyword type prefixed by "u"; match what + * follows the "u". If that fails, try it as an SUS + * integer type. + */ + m->type = get_type(type_tbl, l + 1, &l); + if (m->type == FILE_INVALID) { + /* + * Not a keyword type; parse it as an SUS type, + * 'u' possibly followed by a number or C/S/L. + */ + m->type = get_standard_integer_type(l, &l); + } + // It's unsigned. + if (m->type != FILE_INVALID) + m->flag |= UNSIGNED; + } else { + /* + * Try it as a keyword type. If that fails, try it as + * an SUS integer type if it begins with "d" or as an + * SUS string type if it begins with "s". In any case, + * it's not unsigned. + */ + m->type = get_type(type_tbl, l, &l); + if (m->type == FILE_INVALID) { + /* + * Not a keyword type; parse it as an SUS type, + * either 'd' possibly followed by a number or + * C/S/L, or just 's'. + */ + if (*l == 'd') + m->type = get_standard_integer_type(l, &l); + else if (*l == 's' && !isalpha((unsigned char)l[1])) { + m->type = FILE_STRING; ++l; - m->flag |= UNSIGNED; + } + } } - m->type = get_type(l, &l); + if (m->type == FILE_INVALID) { + /* Not found - try it as a special keyword. */ + m->type = get_type(special_tbl, l, &l); + } + if (m->type == FILE_INVALID) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "type `%s' invalid", l); @@ -1412,6 +1801,9 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, case CHAR_TEXTTEST: m->str_flags |= STRING_TEXTTEST; break; + case CHAR_TRIM: + m->str_flags |= STRING_TRIM; + break; case CHAR_PSTRING_1_LE: if (m->type != FILE_PSTRING) goto bad; @@ -1549,8 +1941,6 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, return -1; } m->mimetype[0] = '\0'; /* initialise MIME type to none */ - if (m->cont_level == 0) - ++(*nmentryp); /* make room for next */ return 0; } @@ -1714,6 +2104,7 @@ check_format_type(const char *ptr, int type) case 'i': case 'd': case 'u': + case 'o': case 'x': case 'X': return 0; @@ -1728,6 +2119,7 @@ check_format_type(const char *ptr, int type) case 'i': case 'd': case 'u': + case 'o': case 'x': case 'X': return 0; @@ -1744,6 +2136,7 @@ check_format_type(const char *ptr, int type) case 'c': case 'd': case 'u': + case 'o': case 'x': case 'X': return 0; @@ -1872,6 +2265,8 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) case FILE_PSTRING: case FILE_REGEX: case FILE_SEARCH: + case FILE_NAME: + case FILE_USE: *p = getstr(ms, m, *p, action == FILE_COMPILE); if (*p == NULL) { if (ms->flags & MAGIC_CHECK) @@ -2180,29 +2575,31 @@ eatsize(const char **p) /* * handle a compiled file. - * return -1 = error - * return 1 = memory structure you can free - * return 3 = bundled library from PHP */ -private int -apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, - const char *fn) + +private struct magic_map * +apprentice_map(struct magic_set *ms, const char *fn) { uint32_t *ptr; - uint32_t version; + uint32_t version, entries, nentries; int needsbyteswap; char *dbname = NULL; - void *mm = NULL; - int ret = 0; + struct magic_map *map; + size_t i; php_stream *stream = NULL; php_stream_statbuf st; TSRMLS_FETCH(); + if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) { + file_oomem(ms, sizeof(*map)); + efree(map); + goto error; + } + if (fn == NULL) { - mm = (void *)&php_magic_database; - ret = 3; + map->p = (void *)&php_magic_database; goto internal_loaded; } @@ -2211,14 +2608,14 @@ apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, return to give apprentice_load() a chance. */ if (php_stream_stat_path_ex(fn, 0, &st, NULL) == SUCCESS) { if (st.sb.st_mode & S_IFDIR) { - goto error2; + goto error; } } #endif dbname = mkdbname(ms, fn, 0); if (dbname == NULL) - goto error2; + goto error; #if PHP_API_VERSION < 20100412 stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); @@ -2227,37 +2624,40 @@ apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, #endif if (!stream) { - goto error2; + goto error; } if (php_stream_stat(stream, &st) < 0) { file_error(ms, errno, "cannot stat `%s'", dbname); - goto error1; + goto error; } if (st.sb.st_size < 8) { file_error(ms, 0, "file `%s' is too small", dbname); - goto error1; + goto error; } - mm = emalloc((size_t)st.sb.st_size); - if (php_stream_read(stream, mm, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) { + map->len = (size_t)st.sb.st_size; + if ((map->p = CAST(void *, emalloc(map->len))) == NULL) { + file_oomem(ms, map->len); + goto error; + } + if (php_stream_read(stream, map->p, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) { file_badread(ms); - ret = 1; - goto error1; + goto error; } - ret = 1; + map->len = 0; +#define RET 1 php_stream_close(stream); stream = NULL; internal_loaded: - *magicp = mm; - ptr = (uint32_t *)(void *)*magicp; + ptr = (uint32_t *)(void *)map->p; if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { file_error(ms, 0, "bad magic in `%s'", dbname); - goto error1; + goto error; } needsbyteswap = 1; } else @@ -2270,67 +2670,81 @@ internal_loaded: file_error(ms, 0, "File %d.%d supports only version %d magic " "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel, VERSIONNO, dbname, version); - goto error1; + goto error; } /* php_magic_database is a const, performing writes will segfault. This is for big-endian machines only, PPC and Sparc specifically. Consider static variable or MINIT in future. */ if (needsbyteswap && fn == NULL) { - mm = emalloc(sizeof(php_magic_database)); - mm = memcpy(mm, php_magic_database, sizeof(php_magic_database)); - *magicp = mm; - ret = 1; - } - - if (fn == NULL) { - *nmagicp = (sizeof(php_magic_database) / sizeof(struct magic)); - } else { - *nmagicp = (uint32_t)(st.sb.st_size / sizeof(struct magic)); + map->p = emalloc(sizeof(php_magic_database)); + map->p = memcpy(map->p, php_magic_database, sizeof(php_magic_database)); + } + + if (NULL != fn) { + nentries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); + entries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); + if ((off_t)(entries * sizeof(struct magic)) != st.sb.st_size) { + file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", + dbname, (unsigned long long)st.sb.st_size, + sizeof(struct magic)); + goto error; + } } - if (*nmagicp > 0) { - (*nmagicp)--; + map->magic[0] = CAST(struct magic *, map->p) + 1; + nentries = 0; + for (i = 0; i < MAGIC_SETS; i++) { + if (needsbyteswap) + map->nmagic[i] = swap4(ptr[i + 2]); + else + map->nmagic[i] = ptr[i + 2]; + if (i != MAGIC_SETS - 1) + map->magic[i + 1] = map->magic[i] + map->nmagic[i]; + nentries += map->nmagic[i]; } - (*magicp)++; - if (needsbyteswap) { - byteswap(*magicp, *nmagicp); + if (NULL != fn && entries != nentries + 1) { + file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", + dbname, entries, nentries + 1); + goto error; } + if (needsbyteswap) + for (i = 0; i < MAGIC_SETS; i++) + byteswap(map->magic[i], map->nmagic[i]); + if (dbname) { efree(dbname); } - return ret; + return map; -error1: +error: if (stream) { php_stream_close(stream); } - - if (mm && ret == 1) { - efree(mm); - } else { - *magicp = NULL; - *nmagicp = 0; - } -error2: + apprentice_unmap(map); if (dbname) { efree(dbname); } - return -1; + return NULL; } private const uint32_t ar[] = { MAGICNO, VERSIONNO }; + /* * handle an mmaped file. */ private int -apprentice_compile(struct magic_set *ms, struct magic **magicp, - uint32_t *nmagicp, const char *fn) +apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) { + static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; + static const size_t m = sizeof(**map->magic); + int fd = -1; + size_t len; char *dbname; int rv = -1; + uint32_t i; php_stream *stream; TSRMLS_FETCH(); @@ -2352,22 +2766,34 @@ apprentice_compile(struct magic_set *ms, struct magic **magicp, goto out; } - if (php_stream_write(stream, (char *)ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { + if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { file_error(ms, errno, "error writing `%s'", dbname); goto out; } + if (php_stream_write(stream, map->nmagic, nm) != (ssize_t)nm) { + file_error(ms, errno, "error writing `%s'", dbname); + goto out; + } + + assert(nm + sizeof(ar) < m); + if (php_stream_seek(stream,(off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) { file_error(ms, errno, "error seeking `%s'", dbname); goto out; } - if (php_stream_write(stream, (char *)*magicp, (sizeof(struct magic) * *nmagicp) != (ssize_t)(sizeof(struct magic) * *nmagicp))) { - file_error(ms, errno, "error writing `%s'", dbname); - goto out; + for (i = 0; i < MAGIC_SETS; i++) { + len = m * map->nmagic[i]; + if (php_stream_write(stream, map->magic[i], len) != (ssize_t)len) { + file_error(ms, errno, "error writing `%s'", dbname); + goto out; + } } - php_stream_close(stream); + if (stream) { + php_stream_close(stream); + } rv = 0; out: @@ -2564,3 +2990,30 @@ file_pstring_get_length(const struct magic *m, const char *s) return len; } + +protected int +file_magicfind(struct magic_set *ms, const char *name, struct mlist *v) +{ + uint32_t i, j; + struct mlist *mlist, *ml; + + mlist = ms->mlist[1]; + + for (ml = mlist->next; ml != mlist; ml = ml->next) { + struct magic *ma = ml->magic; + uint32_t nma = ml->nmagic; + for (i = 0; i < nma; i++) { + if (ma[i].type != FILE_NAME) + continue; + if (strcmp(ma[i].value.s, name) == 0) { + v->magic = &ma[i]; + for (j = i + 1; j < nma; j++) + if (ma[j].cont_level == 0) + break; + v->nmagic = j - i; + return 0; + } + } + } + return -1; +} diff --git a/ext/fileinfo/libmagic/ascmagic.c b/ext/fileinfo/libmagic/ascmagic.c index 9d8d15024f..209009764e 100644 --- a/ext/fileinfo/libmagic/ascmagic.c +++ b/ext/fileinfo/libmagic/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.84 2011/12/08 12:38:24 rrt Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.85 2012/08/09 16:33:15 christos Exp $") #endif /* lint */ #include "magic.h" @@ -134,13 +134,15 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, goto done; } - if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) { + if (ulen > 0 && (ms->flags & MAGIC_NO_CHECK_SOFT) == 0) { /* Convert ubuf to UTF-8 and try text soft magic */ /* malloc size is a conservative overestimate; could be improved, or at least realloced after conversion. */ mlen = ulen * 6; - utf8_buf = emalloc(mlen); - + if ((utf8_buf = CAST(unsigned char *, emalloc(mlen))) == NULL) { + file_oomem(ms, mlen); + goto done; + } if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen)) == NULL) goto done; @@ -209,6 +211,7 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, case 0: if (file_printf(ms, ", ") == -1) goto done; + break; case -1: goto done; default: diff --git a/ext/fileinfo/libmagic/cdf.c b/ext/fileinfo/libmagic/cdf.c index 7efa43e00f..dd7177ed90 100644 --- a/ext/fileinfo/libmagic/cdf.c +++ b/ext/fileinfo/libmagic/cdf.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf.c,v 1.50 2012/02/20 22:35:29 christos Exp $") +FILE_RCSID("@(#)$File: cdf.c,v 1.53 2013/02/26 16:20:42 christos Exp $") #endif #include <assert.h> @@ -278,10 +278,10 @@ cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h, const char *b = (const char *)sst->sst_tab; const char *e = ((const char *)p) + tail; (void)&line; - if (e >= b && (size_t)(e - b) < CDF_SEC_SIZE(h) * sst->sst_len) + if (e >= b && (size_t)(e - b) <= CDF_SEC_SIZE(h) * sst->sst_len) return 0; - DPRINTF(("%d: offset begin %p end %p %" SIZE_T_FORMAT "u" - " >= %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %" + DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u" + " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %" SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b), CDF_SEC_SIZE(h) * sst->sst_len, CDF_SEC_SIZE(h), sst->sst_len)); errno = EFTYPE; diff --git a/ext/fileinfo/libmagic/cdf.h b/ext/fileinfo/libmagic/cdf.h index 84a2f95207..70eb519465 100644 --- a/ext/fileinfo/libmagic/cdf.h +++ b/ext/fileinfo/libmagic/cdf.h @@ -39,6 +39,8 @@ #include <winsock2.h> #define timespec timeval #define tv_nsec tv_usec +#define asctime_r php_asctime_r +#define ctime_r php_ctime_r #endif #ifdef __DJGPP__ #define timespec timeval @@ -312,7 +314,7 @@ int cdf_print_elapsed_time(char *, size_t, cdf_timestamp_t); uint16_t cdf_tole2(uint16_t); uint32_t cdf_tole4(uint32_t); uint64_t cdf_tole8(uint64_t); -char *cdf_ctime(const time_t *); +char *cdf_ctime(const time_t *, char *); #ifdef CDF_DEBUG void cdf_dump_header(const cdf_header_t *); diff --git a/ext/fileinfo/libmagic/cdf_time.c b/ext/fileinfo/libmagic/cdf_time.c index b75aa5be98..84b14b86f1 100644 --- a/ext/fileinfo/libmagic/cdf_time.c +++ b/ext/fileinfo/libmagic/cdf_time.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf_time.c,v 1.11 2011/12/13 13:48:41 christos Exp $") +FILE_RCSID("@(#)$File: cdf_time.c,v 1.12 2012/05/15 17:14:36 christos Exp $") #endif #include <time.h> @@ -104,6 +104,7 @@ cdf_timestamp_to_timespec(struct timeval *ts, cdf_timestamp_t t) #endif int rdays; + /* XXX 5.14 at least introdced 100 ns intervals, this is to do */ /* Time interval, in microseconds */ ts->tv_usec = (t % CDF_TIME_PREC) * CDF_TIME_PREC; @@ -166,15 +167,13 @@ cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timeval *ts) } char * -cdf_ctime(const time_t *sec) +cdf_ctime(const time_t *sec, char *buf) { - static char ctbuf[26]; - char *ptr = ctime(sec); + char *ptr = ctime_r(sec, buf); if (ptr != NULL) - return ptr; - (void)snprintf(ctbuf, sizeof(ctbuf), "*Bad* 0x%16.16llx\n", - (long long)*sec); - return ctbuf; + return buf; + (void)snprintf(buf, 26, "*Bad* 0x%16.16llx\n", (long long)*sec); + return buf; } @@ -183,12 +182,13 @@ int main(int argc, char *argv[]) { struct timeval ts; + char buf[25]; static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; static const char *ref = "Sat Apr 23 01:30:00 1977"; char *p, *q; cdf_timestamp_to_timespec(&ts, tst); - p = cdf_ctime(&ts.tv_sec); + p = cdf_ctime(&ts.tv_sec, buf); if ((q = strchr(p, '\n')) != NULL) *q = '\0'; if (strcmp(ref, p) != 0) diff --git a/ext/fileinfo/libmagic/compress.c b/ext/fileinfo/libmagic/compress.c index 4d349cd419..9f26dd03d8 100644 --- a/ext/fileinfo/libmagic/compress.c +++ b/ext/fileinfo/libmagic/compress.c @@ -36,7 +36,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.68 2011/12/08 12:38:24 rrt Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.70 2012/11/07 17:54:48 christos Exp $") #endif #include "magic.h" @@ -188,9 +188,9 @@ sread(int fd, void *buf, size_t n, int canbepipe) goto nocheck; #ifdef FIONREAD - if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) { + if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { #ifdef FD_ZERO - int cnt; + ssize_t cnt; for (cnt = 0;; cnt++) { fd_set check; struct timeval tout = {0, 100 * 1000}; @@ -247,9 +247,6 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, char buf[4096]; ssize_t r; int tfd; -#ifdef HAVE_MKSTEMP - int te; -#endif (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); #ifndef HAVE_MKSTEMP @@ -261,10 +258,13 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, errno = r; } #else - tfd = mkstemp(buf); - te = errno; - (void)unlink(buf); - errno = te; + { + int te; + tfd = mkstemp(buf); + te = errno; + (void)unlink(buf); + errno = te; + } #endif if (tfd == -1) { file_error(ms, errno, @@ -345,7 +345,9 @@ uncompressgzipped(struct magic_set *ms, const unsigned char *old, if (data_start >= n) return 0; - *newch = (unsigned char *)emalloc(HOWMANY + 1)); + if ((*newch = CAST(unsigned char *, emalloc(HOWMANY + 1))) == NULL) { + return 0; + } /* XXX: const castaway, via strchr */ z.next_in = (Bytef *)strchr((const char *)old + data_start, diff --git a/ext/fileinfo/libmagic/elfclass.h b/ext/fileinfo/libmagic/elfclass.h index 2e7741b3fc..010958a429 100644 --- a/ext/fileinfo/libmagic/elfclass.h +++ b/ext/fileinfo/libmagic/elfclass.h @@ -59,7 +59,8 @@ (off_t)elf_getu(swap, elfhdr.e_shoff), elf_getu16(swap, elfhdr.e_shnum), (size_t)elf_getu16(swap, elfhdr.e_shentsize), - fsize, &flags, elf_getu16(swap, elfhdr.e_machine)) == -1) + fsize, &flags, elf_getu16(swap, elfhdr.e_machine), + (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1) return -1; break; diff --git a/ext/fileinfo/libmagic/file.h b/ext/fileinfo/libmagic/file.h index 3879b47564..19b6872b49 100644 --- a/ext/fileinfo/libmagic/file.h +++ b/ext/fileinfo/libmagic/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.135 2011/09/20 15:30:14 christos Exp $ + * @(#)$File: file.h,v 1.144 2013/02/18 15:40:59 christos Exp $ */ #ifndef __file_h__ @@ -90,10 +90,18 @@ #endif #define private static + +#if HAVE_VISIBILITY +#define public __attribute__ ((__visibility__("default"))) #ifndef protected -#define protected +#define protected __attribute__ ((__visibility__("hidden"))) #endif +#else #define public +#ifndef protected +#define protected +#endif +#endif #ifndef __arraycount #define __arraycount(a) (sizeof(a) / sizeof(a[0])) @@ -122,12 +130,13 @@ #endif #define MAXMAGIS 8192 /* max entries in any one magic file or directory */ -#define MAXDESC 64 /* max leng of text description/MIME type */ -#define MAXstring 64 /* max leng of "string" types */ +#define MAXDESC 64 /* max len of text description/MIME type */ +#define MAXMIME 80 /* max len of text MIME type */ +#define MAXstring 64 /* max len of "string" types */ #define MAGICNO 0xF11E041C -#define VERSIONNO 8 -#define FILE_MAGICSIZE 232 +#define VERSIONNO 10 +#define FILE_MAGICSIZE 248 #define FILE_LOAD 0 #define FILE_CHECK 1 @@ -210,7 +219,12 @@ struct magic { #define FILE_BEID3 39 #define FILE_LEID3 40 #define FILE_INDIRECT 41 -#define FILE_NAMES_SIZE 42/* size of array to contain all names */ +#define FILE_QWDATE 42 +#define FILE_LEQWDATE 43 +#define FILE_BEQWDATE 44 +#define FILE_NAME 45 +#define FILE_USE 46 +#define FILE_NAMES_SIZE 47 /* size of array to contain all names */ #define IS_LIBMAGIC_STRING(t) \ ((t) == FILE_STRING || \ @@ -219,6 +233,8 @@ struct magic { (t) == FILE_LESTRING16 || \ (t) == FILE_REGEX || \ (t) == FILE_SEARCH || \ + (t) == FILE_NAME || \ + (t) == FILE_USE || \ (t) == FILE_DEFAULT) #define FILE_FMT_NONE 0 @@ -287,9 +303,9 @@ struct magic { union VALUETYPE value; /* either number or string */ /* Words 17-32 */ char desc[MAXDESC]; /* description */ - /* Words 33-48 */ - char mimetype[MAXDESC]; /* MIME type */ - /* Words 49-50 */ + /* Words 33-52 */ + char mimetype[MAXMIME]; /* MIME type */ + /* Words 53-54 */ char apple[8]; }; @@ -310,12 +326,14 @@ struct magic { #define PSTRING_LEN \ (PSTRING_1_BE|PSTRING_2_LE|PSTRING_2_BE|PSTRING_4_LE|PSTRING_4_BE) #define PSTRING_LENGTH_INCLUDES_ITSELF BIT(12) +#define STRING_TRIM BIT(13) #define CHAR_COMPACT_WHITESPACE 'W' #define CHAR_COMPACT_OPTIONAL_WHITESPACE 'w' #define CHAR_IGNORE_LOWERCASE 'c' #define CHAR_IGNORE_UPPERCASE 'C' #define CHAR_REGEX_OFFSET_START 's' #define CHAR_TEXTTEST 't' +#define CHAR_TRIM 'T' #define CHAR_BINTEST 'b' #define CHAR_PSTRING_1_BE 'B' #define CHAR_PSTRING_1_LE 'B' @@ -332,9 +350,7 @@ struct magic { struct mlist { struct magic *magic; /* array of magic entries */ uint32_t nmagic; /* number of entries in array */ - int mapped; /* allocation type: 0 => apprentice_file - * 1 => apprentice_map + malloc - * 2 => apprentice_map + mmap */ + void *map; /* internal resources used by entry */ struct mlist *next, *prev; }; @@ -354,8 +370,11 @@ struct level_info { int last_cond; /* used for error checking by parse() */ #endif }; + +#define MAGIC_SETS 2 + struct magic_set { - struct mlist *mlist; + struct mlist *mlist[MAGIC_SETS]; /* list of regular entries */ struct cont { size_t len; struct level_info *li; @@ -389,10 +408,14 @@ struct magic_set { typedef unsigned long unichar; struct stat; -protected const char *file_fmttime(uint32_t, int); +#define FILE_T_LOCAL 1 +#define FILE_T_WINDOWS 2 +protected const char *file_fmttime(uint64_t, int, char *); +protected struct magic_set *file_ms_alloc(int); +protected void file_ms_free(struct magic_set *); protected int file_buffer(struct magic_set *, php_stream *, const char *, const void *, size_t); -protected int file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream *stream); +protected int file_fsmagic(struct magic_set *, const char *, struct stat *, php_stream *); protected int file_pipe2file(struct magic_set *, int, const void *, size_t); protected int file_replace(struct magic_set *, const char *, const char *); protected int file_printf(struct magic_set *, const char *, ...); @@ -415,7 +438,8 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t, protected int file_is_tar(struct magic_set *, const unsigned char *, size_t); protected int file_softmagic(struct magic_set *, const unsigned char *, size_t, int, int); -protected struct mlist *file_apprentice(struct magic_set *, const char *, int); +protected int file_apprentice(struct magic_set *, const char *, int); +protected int file_magicfind(struct magic_set *, const char *, struct mlist *); protected uint64_t file_signextend(struct magic_set *, struct magic *, uint64_t); protected void file_delmagic(struct magic *, int type, size_t entries); diff --git a/ext/fileinfo/libmagic/fsmagic.c b/ext/fileinfo/libmagic/fsmagic.c index a762e593de..d1381bd2d5 100644 --- a/ext/fileinfo/libmagic/fsmagic.c +++ b/ext/fileinfo/libmagic/fsmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: fsmagic.c,v 1.64 2011/08/14 09:03:12 christos Exp $") +FILE_RCSID("@(#)$File: fsmagic.c,v 1.67 2013/03/17 15:43:20 christos Exp $") #endif /* lint */ #include "magic.h" @@ -92,16 +92,19 @@ handle_mime(struct magic_set *ms, int mime, const char *str) protected int file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream *stream) { + int ret, did = 0; int mime = ms->flags & MAGIC_MIME; TSRMLS_FETCH(); if (ms->flags & MAGIC_APPLE) return 0; - if (!fn && !stream) { + if (fn == NULL && !stream) { return 0; } +#define COMMA (did++ ? ", " : "") + if (stream) { php_stream_statbuf ssb; if (php_stream_stat(stream, &ssb) < 0) { @@ -122,20 +125,21 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream * } } + ret = 1; if (!mime) { #ifdef S_ISUID if (sb->st_mode & S_ISUID) - if (file_printf(ms, "setuid ") == -1) + if (file_printf(ms, "%ssetuid", COMMA) == -1) return -1; #endif #ifdef S_ISGID if (sb->st_mode & S_ISGID) - if (file_printf(ms, "setgid ") == -1) + if (file_printf(ms, "%ssetgid", COMMA) == -1) return -1; #endif #ifdef S_ISVTX if (sb->st_mode & S_ISVTX) - if (file_printf(ms, "sticky ") == -1) + if (file_printf(ms, "%ssticky", COMMA) == -1) return -1; #endif } @@ -150,6 +154,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream * * are block special files and go on to the next file. */ if ((ms->flags & MAGIC_DEVICES) != 0) { + ret = 0; break; } if (mime) { @@ -158,18 +163,18 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream * } else { # ifdef HAVE_STAT_ST_RDEV # ifdef dv_unit - if (file_printf(ms, "character special (%d/%d/%d)", - major(sb->st_rdev), dv_unit(sb->st_rdev), + if (file_printf(ms, "%scharacter special (%d/%d/%d)", + COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), dv_subunit(sb->st_rdev)) == -1) return -1; # else - if (file_printf(ms, "character special (%ld/%ld)", - (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) - == -1) + if (file_printf(ms, "%scharacter special (%ld/%ld)", + COMMA, (long)major(sb->st_rdev), + (long)minor(sb->st_rdev)) == -1) return -1; # endif # else - if (file_printf(ms, "character special") == -1) + if (file_printf(ms, "%scharacter special", COMMA) == -1) return -1; # endif } @@ -184,18 +189,18 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream * if (mime) { if (handle_mime(ms, mime, "fifo") == -1) return -1; - } else if (file_printf(ms, "fifo (named pipe)") == -1) + } else if (file_printf(ms, "%sfifo (named pipe)", COMMA) == -1) return -1; - return 1; + break; #endif #ifdef S_IFDOOR case S_IFDOOR: if (mime) { if (handle_mime(ms, mime, "door") == -1) return -1; - } else if (file_printf(ms, "door") == -1) + } else if (file_printf(ms, "%sdoor", COMMA) == -1) return -1; - return 1; + break; #endif #ifdef S_IFLNK case S_IFLNK: @@ -213,40 +218,40 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream * if (mime) { if (handle_mime(ms, mime, "socket") == -1) return -1; - } else if (file_printf(ms, "socket") == -1) + } else if (file_printf(ms, "%ssocket", COMMA) == -1) return -1; - return 1; + break; #endif #endif - case S_IFREG: - break; - - default: - file_error(ms, 0, "invalid mode 0%o", sb->st_mode); - return -1; - /*NOTREACHED*/ - } - /* * regular file, check next possibility * * If stat() tells us the file has zero length, report here that * the file is empty, so we can skip all the work of opening and * reading the file. - * But if the -s option has been given, we skip this optimization, - * since on some systems, stat() reports zero size for raw disk - * partitions. (If the block special device really has zero length, - * the fact that it is empty will be detected and reported correctly - * when we read the file.) + * But if the -s option has been given, we skip this + * optimization, since on some systems, stat() reports zero + * size for raw disk partitions. (If the block special device + * really has zero length, the fact that it is empty will be + * detected and reported correctly when we read the file.) */ if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) { if (mime) { if (handle_mime(ms, mime, "x-empty") == -1) return -1; - } else if (file_printf(ms, "empty") == -1) + } else if (file_printf(ms, "%sempty", COMMA) == -1) return -1; - return 1; + break; } - return 0; + ret = 0; + break; + + default: + file_error(ms, 0, "invalid mode 0%o", sb->st_mode); + return -1; + /*NOTREACHED*/ + } + + return ret; } diff --git a/ext/fileinfo/libmagic/funcs.c b/ext/fileinfo/libmagic/funcs.c index 2b379291e4..9c0d2bdb7c 100644 --- a/ext/fileinfo/libmagic/funcs.c +++ b/ext/fileinfo/libmagic/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.60 2011/12/08 12:38:24 rrt Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.61 2012/10/30 23:11:51 christos Exp $") #endif /* lint */ #include "magic.h" @@ -191,7 +191,7 @@ file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const &code, &code_mime, &type); } -#if defined(__EMX__) +#ifdef __EMX__ if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) { switch (file_os2_apptype(ms, inname, buf, nb)) { case -1: @@ -307,7 +307,7 @@ file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const protected int file_reset(struct magic_set *ms) { - if (ms->mlist == NULL) { + if (ms->mlist[0] == NULL) { file_error(ms, 0, "no magic files loaded"); return -1; } @@ -335,7 +335,7 @@ file_reset(struct magic_set *ms) protected const char * file_getbuffer(struct magic_set *ms) { - char *pbuf, *op, *np; + char *op, *np; size_t psize, len; if (ms->event_flags & EVENT_HAD_ERR) @@ -353,8 +353,10 @@ file_getbuffer(struct magic_set *ms) return NULL; } psize = len * 4 + 1; - pbuf = erealloc(ms->o.pbuf, psize); - ms->o.pbuf = pbuf; + if ((ms->o.pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) { + file_oomem(ms, psize); + return NULL; + } #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) { @@ -413,7 +415,13 @@ file_check_mem(struct magic_set *ms, unsigned int level) if (level >= ms->c.len) { len = (ms->c.len += 20) * sizeof(*ms->c.li); - ms->c.li = (ms->c.li == NULL) ? emalloc(len) : erealloc(ms->c.li, len); + ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? + emalloc(len) : + erealloc(ms->c.li, len)); + if (ms->c.li == NULL) { + file_oomem(ms, len); + return -1; + } } ms->c.li[level].got_match = 0; #ifdef ENABLE_CONDITIONALS @@ -445,11 +453,7 @@ file_replace(struct magic_set *ms, const char *pat, const char *rep) ZVAL_STRINGL(patt, pat, strlen(pat), 0); opts |= PCRE_MULTILINE; convert_libmagic_pattern(patt, opts); -#if (PHP_MAJOR_VERSION < 6) if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(patt), Z_STRLEN_P(patt) TSRMLS_CC)) == NULL) { -#else - if ((pce = pcre_get_compiled_regex_cache(IS_STRING, Z_STRVAL_P(patt), Z_STRLEN_P(patt) TSRMLS_CC)) == NULL) { -#endif zval_dtor(patt); FREE_ZVAL(patt); return -1; diff --git a/ext/fileinfo/libmagic/magic.c b/ext/fileinfo/libmagic/magic.c index b4818aed55..15fd6be77f 100644 --- a/ext/fileinfo/libmagic/magic.c +++ b/ext/fileinfo/libmagic/magic.c @@ -28,7 +28,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.74 2011/05/26 01:27:59 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.78 2013/01/07 18:20:19 christos Exp $") #endif /* lint */ #include "magic.h" @@ -110,6 +110,10 @@ get_default_magic(void) if ((home = getenv("HOME")) == NULL) return MAGIC; + if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) + return MAGIC; + if (stat(hmagicpath, &st) == -1) { + free(hmagicpath); if (asprintf(&hmagicpath, "%s/.magic", home) < 0) return MAGIC; if (stat(hmagicpath, &st) == -1) @@ -121,6 +125,7 @@ get_default_magic(void) if (access(hmagicpath, R_OK) == -1) goto out; } + } if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) goto out; @@ -221,46 +226,7 @@ magic_getpath(const char *magicfile, int action) public struct magic_set * magic_open(int flags) { - struct magic_set *ms; - - ms = ecalloc((size_t)1, sizeof(struct magic_set)); - - if (magic_setflags(ms, flags) == -1) { - errno = EINVAL; - goto free; - } - - ms->o.buf = ms->o.pbuf = NULL; - - ms->c.li = emalloc((ms->c.len = 10) * sizeof(*ms->c.li)); - - ms->event_flags = 0; - ms->error = -1; - ms->mlist = NULL; - ms->file = "unknown"; - ms->line = 0; - return ms; -free: - efree(ms); - return NULL; -} - -private void -free_mlist(struct mlist *mlist) -{ - struct mlist *ml; - - if (mlist == NULL) - return; - - for (ml = mlist->next; ml != mlist;) { - struct mlist *next = ml->next; - struct magic *mg = ml->magic; - file_delmagic(mg, ml->mapped, ml->nmagic); - efree(ml); - ml = next; - } - efree(ml); + return file_ms_alloc(flags); } private int @@ -284,19 +250,9 @@ unreadable_info(struct magic_set *ms, mode_t md, const char *file) public void magic_close(struct magic_set *ms) { - if (ms->mlist) { - free_mlist(ms->mlist); - } - if (ms->o.pbuf) { - efree(ms->o.pbuf); - } - if (ms->o.buf) { - efree(ms->o.buf); - } - if (ms->c.li) { - efree(ms->c.li); - } - efree(ms); + if (ms == NULL) + return; + file_ms_free(ms); } /* @@ -305,30 +261,26 @@ magic_close(struct magic_set *ms) public int magic_load(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); - if (ml) { - free_mlist(ms->mlist); - ms->mlist = ml; - return 0; - } + if (ms == NULL) return -1; + return file_apprentice(ms, magicfile, FILE_LOAD); } public int magic_compile(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); - free_mlist(ml); - return ml ? 0 : -1; + if (ms == NULL) + return -1; + return file_apprentice(ms, magicfile, FILE_COMPILE); } public int magic_list(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_LIST); - free_mlist(ml); - return ml ? 0 : -1; + if (ms == NULL) + return -1; + return file_apprentice(ms, magicfile, FILE_LIST); } private void @@ -368,6 +320,8 @@ close_and_restore(const struct magic_set *ms, const char *name, int fd, public const char * magic_descriptor(struct magic_set *ms, int fd) { + if (ms == NULL) + return NULL; return file_or_stream(ms, NULL, NULL); } @@ -377,12 +331,16 @@ magic_descriptor(struct magic_set *ms, int fd) public const char * magic_file(struct magic_set *ms, const char *inname) { + if (ms == NULL) + return NULL; return file_or_stream(ms, inname, NULL); } public const char * magic_stream(struct magic_set *ms, php_stream *stream) { + if (ms == NULL) + return NULL; return file_or_stream(ms, NULL, stream); } @@ -469,6 +427,8 @@ done: public const char * magic_buffer(struct magic_set *ms, const void *buf, size_t nb) { + if (ms == NULL) + return NULL; if (file_reset(ms) == -1) return NULL; /* @@ -484,18 +444,24 @@ magic_buffer(struct magic_set *ms, const void *buf, size_t nb) public const char * magic_error(struct magic_set *ms) { + if (ms == NULL) + return "Magic database is not open"; return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL; } public int magic_errno(struct magic_set *ms) { + if (ms == NULL) + return EINVAL; return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0; } public int magic_setflags(struct magic_set *ms, int flags) { + if (ms == NULL) + return -1; #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) if (flags & MAGIC_PRESERVE_ATIME) return -1; @@ -503,3 +469,9 @@ magic_setflags(struct magic_set *ms, int flags) ms->flags = flags; return 0; } + +public int +magic_version(void) +{ + return MAGIC_VERSION; +} diff --git a/ext/fileinfo/libmagic/magic.h b/ext/fileinfo/libmagic/magic.h index 9996c48d6c..7785a4a39f 100644 --- a/ext/fileinfo/libmagic/magic.h +++ b/ext/fileinfo/libmagic/magic.h @@ -74,6 +74,8 @@ #define MAGIC_NO_CHECK_FORTRAN 0x000000 /* Don't check ascii/fortran */ #define MAGIC_NO_CHECK_TROFF 0x000000 /* Don't check ascii/troff */ +#define MAGIC_VERSION 514 /* This implementation */ + #ifdef __cplusplus extern "C" { @@ -92,6 +94,7 @@ const char *magic_buffer(magic_t, const void *, size_t); const char *magic_error(magic_t); int magic_setflags(magic_t, int); +int magic_version(void); int magic_load(magic_t, const char *); int magic_compile(magic_t, const char *); int magic_list(magic_t, const char *); diff --git a/ext/fileinfo/libmagic/patchlevel.h b/ext/fileinfo/libmagic/patchlevel.h index f4afed6abe..3a7255fa85 100644 --- a/ext/fileinfo/libmagic/patchlevel.h +++ b/ext/fileinfo/libmagic/patchlevel.h @@ -1,11 +1,15 @@ #define FILE_VERSION_MAJOR 5 -#define patchlevel 11 +#define patchlevel 14 /* * Patchlevel file for Ian Darwin's MAGIC command. * $File: patchlevel.h,v 1.68 2008/03/22 21:39:43 christos Exp $ * * $Log$ + * Revision 1.7 2013/03/26 22:27:12 ab + * Update libmagic to 5.14 + * + * $Log$ * Revision 1.6 2012/03/26 21:01:37 ab * Update libmagic to 5.11 * diff --git a/ext/fileinfo/libmagic/print.c b/ext/fileinfo/libmagic/print.c index 8370f50c28..fff258b7ee 100644 --- a/ext/fileinfo/libmagic/print.c +++ b/ext/fileinfo/libmagic/print.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: print.c,v 1.71 2011/09/20 15:28:09 christos Exp $") +FILE_RCSID("@(#)$File: print.c,v 1.76 2013/02/26 18:25:00 christos Exp $") #endif /* lint */ #include <stdio.h> @@ -47,6 +47,11 @@ FILE_RCSID("@(#)$File: print.c,v 1.71 2011/09/20 15:28:09 christos Exp $") #endif #include <time.h> +#ifdef PHP_WIN32 +# define asctime_r php_asctime_r +# define ctime_r php_ctime_r +#endif + #define SZOF(a) (sizeof(a) / sizeof(a[0])) /*VARARGS*/ @@ -67,14 +72,20 @@ file_magwarn(struct magic_set *ms, const char *f, ...) } protected const char * -file_fmttime(uint32_t v, int local) +file_fmttime(uint64_t v, int flags, char *buf) { char *pp; time_t t = (time_t)v; struct tm *tm; - if (local) { - pp = ctime(&t); + if (flags & FILE_T_WINDOWS) { + struct timeval ts; + cdf_timestamp_to_timespec(&ts, t); + t = ts.tv_sec; + } + + if (flags & FILE_T_LOCAL) { + pp = ctime_r(&t, buf); } else { #ifndef HAVE_DAYLIGHT private int daylight = 0; @@ -96,7 +107,7 @@ file_fmttime(uint32_t v, int local) tm = gmtime(&t); if (tm == NULL) goto out; - pp = asctime(tm); + pp = asctime_r(tm, buf); } if (pp == NULL) @@ -104,5 +115,5 @@ file_fmttime(uint32_t v, int local) pp[strcspn(pp, "\n")] = '\0'; return pp; out: - return "*Invalid time*"; + return strcpy(buf, "*Invalid time*"); } diff --git a/ext/fileinfo/libmagic/readcdf.c b/ext/fileinfo/libmagic/readcdf.c index 0c28ffbfa8..3abcc2e62e 100644 --- a/ext/fileinfo/libmagic/readcdf.c +++ b/ext/fileinfo/libmagic/readcdf.c @@ -26,7 +26,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readcdf.c,v 1.29 2012/02/20 20:04:58 christos Exp $") +FILE_RCSID("@(#)$File: readcdf.c,v 1.33 2012/06/20 21:52:36 christos Exp $") #endif #include <stdlib.h> @@ -129,12 +129,12 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, case CDF_FILETIME: tp = info[i].pi_tp; if (tp != 0) { + char tbuf[64]; #if defined(PHP_WIN32) && _MSC_VER <= 1500 if (tp < 1000000000000000i64) { #else if (tp < 1000000000000000LL) { #endif - char tbuf[64]; cdf_print_elapsed_time(tbuf, sizeof(tbuf), tp); if (NOTMIME(ms) && file_printf(ms, @@ -145,7 +145,7 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, if (cdf_timestamp_to_timespec(&ts, tp) == -1) { return -1; } - c = cdf_ctime(&ts.tv_sec); + c = cdf_ctime(&ts.tv_sec, tbuf); if ((ec = strchr(c, '\n')) != NULL) *ec = '\0'; @@ -295,10 +295,14 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, d = &dir.dir_tab[j]; for (k = 0; k < sizeof(name); k++) name[k] = (char)cdf_tole2(d->d_name[k]); - if (strstr(name, "WordDocument") == 0) { + if (strstr(name, "WordDocument") != 0) { str = "msword"; break; } + if (strstr(name, "PowerPoint") != 0) { + str = "vnd.ms-powerpoint"; + break; + } } if (file_printf(ms, "application/%s", str) == -1) return -1; @@ -315,13 +319,19 @@ out1: free(sat.sat_tab); out0: if (i != 1) { - if (i == -1) - if (file_printf(ms, "Composite Document File V2 Document") - == -1) + if (i == -1) { + if (NOTMIME(ms)) { + if (file_printf(ms, + "Composite Document File V2 Document") == -1) return -1; if (*expn) if (file_printf(ms, ", %s%s", corrupt, expn) == -1) return -1; + } else { + if (file_printf(ms, "application/CDFV2-corrupt") == -1) + return -1; + } + } i = 1; } return i; diff --git a/ext/fileinfo/libmagic/readelf.c b/ext/fileinfo/libmagic/readelf.c index f18f7d2294..1c3845fc6b 100644 --- a/ext/fileinfo/libmagic/readelf.c +++ b/ext/fileinfo/libmagic/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.90 2011/08/23 08:01:12 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.97 2013/03/06 03:35:30 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -139,9 +139,9 @@ getu64(int swap, uint64_t value) ? (void *) &sh32 \ : (void *) &sh64) #define xsh_sizeof (clazz == ELFCLASS32 \ - ? sizeof sh32 \ - : sizeof sh64) -#define xsh_size (clazz == ELFCLASS32 \ + ? sizeof(sh32) \ + : sizeof(sh64)) +#define xsh_size (size_t)(clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_size) \ : elf_getu64(swap, sh64.sh_size)) #define xsh_offset (off_t)(clazz == ELFCLASS32 \ @@ -150,12 +150,15 @@ getu64(int swap, uint64_t value) #define xsh_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_type) \ : elf_getu32(swap, sh64.sh_type)) +#define xsh_name (clazz == ELFCLASS32 \ + ? elf_getu32(swap, sh32.sh_name) \ + : elf_getu32(swap, sh64.sh_name)) #define xph_addr (clazz == ELFCLASS32 \ ? (void *) &ph32 \ : (void *) &ph64) #define xph_sizeof (clazz == ELFCLASS32 \ - ? sizeof ph32 \ - : sizeof ph64) + ? sizeof(ph32) \ + : sizeof(ph64)) #define xph_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_type) \ : elf_getu32(swap, ph64.p_type)) @@ -357,7 +360,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, #endif private size_t -donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, +donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, int clazz, int swap, size_t align, int *flags) { Elf32_Nhdr nh32; @@ -367,6 +370,7 @@ donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, int os_style = -1; #endif uint32_t namesz, descsz; + unsigned char *nbuf = CAST(unsigned char *, vbuf); (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); offset += xnh_sizeof; @@ -415,6 +419,10 @@ donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) goto core; + if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && + xnh_type == NT_GNU_VERSION && descsz == 2) { + file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); + } if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && xnh_type == NT_GNU_VERSION && descsz == 16) { uint32_t desc[4]; @@ -456,13 +464,14 @@ donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { - uint32_t desc[5], i; - if (file_printf(ms, ", BuildID[%s]=0x", descsz == 16 ? "md5/uuid" : + uint8_t desc[20]; + uint32_t i; + if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : "sha1") == -1) return size; (void)memcpy(desc, &nbuf[doff], descsz); - for (i = 0; i < descsz >> 2; i++) - if (file_printf(ms, "%.8x", desc[i]) == -1) + for (i = 0; i < descsz; i++) + if (file_printf(ms, "%02x", desc[i]) == -1) return size; *flags |= FLAGS_DID_BUILD_ID; } @@ -841,15 +850,16 @@ static const cap_desc_t cap_desc_386[] = { private int doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, - size_t size, off_t fsize, int *flags, int mach) + size_t size, off_t fsize, int *flags, int mach, int strtab) { Elf32_Shdr sh32; Elf64_Shdr sh64; int stripped = 1; void *nbuf; - off_t noff, coff; + off_t noff, coff, name_off; uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ + char name[50]; if (size != xsh_sizeof) { if (file_printf(ms, ", corrupted section header size") == -1) diff --git a/ext/fileinfo/libmagic/softmagic.c b/ext/fileinfo/libmagic/softmagic.c index f9c2836dd2..c69fdb5a3e 100644 --- a/ext/fileinfo/libmagic/softmagic.c +++ b/ext/fileinfo/libmagic/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.147 2011/11/05 15:44:22 rrt Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.165 2013/03/07 02:22:24 christos Exp $") #endif /* lint */ #include "magic.h" @@ -48,16 +48,18 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.147 2011/11/05 15:44:22 rrt Exp $") private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, int, int); + const unsigned char *, size_t, size_t, int, int, int, int, int *, int *, + int *); private int mget(struct magic_set *, const unsigned char *, - struct magic *, size_t, unsigned int, int); + struct magic *, size_t, size_t, unsigned int, int, int, int, int, int *, + int *, int *); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); private int32_t moffset(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, size_t); -private int mconvert(struct magic_set *, struct magic *); +private int mconvert(struct magic_set *, struct magic *, int); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); private void cvt_8(union VALUETYPE *, const struct magic *); @@ -75,10 +77,11 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int mode, int text) { struct mlist *ml; - int rv; - for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next) - if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode, - text)) != 0) + int rv, printed_something = 0, need_separator = 0; + for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) + if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, + text, 0, 0, &printed_something, &need_separator, + NULL)) != 0) return rv; return 0; @@ -113,16 +116,19 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, */ private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, - const unsigned char *s, size_t nbytes, int mode, int text) + const unsigned char *s, size_t nbytes, size_t offset, int mode, int text, + int flip, int recursion_level, int *printed_something, int *need_separator, + int *returnval) { uint32_t magindex = 0; unsigned int cont_level = 0; - int need_separator = 0; - int returnval = 0, e; /* if a match is found it is set to 1*/ + int returnvalv = 0, e; /* 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; int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0; + if (returnval == NULL) + returnval = &returnvalv; + if (file_check_mem(ms, cont_level) == -1) return -1; @@ -130,14 +136,17 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, int flush = 0; struct magic *m = &magic[magindex]; + if (m->type != FILE_NAME) if ((IS_LIBMAGIC_STRING(m->type) && - ((text && (m->str_flags & (STRING_BINTEST | STRING_TEXTTEST)) == STRING_BINTEST) || - (!text && (m->str_flags & (STRING_TEXTTEST | STRING_BINTEST)) == STRING_TEXTTEST))) || +#define FLT (STRING_BINTEST | STRING_TEXTTEST) + ((text && (m->str_flags & FLT) == STRING_BINTEST) || + (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || (m->flag & mode) != mode) { /* Skip sub-tests */ - while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) { - magindex++; - } + while (magindex + 1 < nmagic && + magic[magindex + 1].cont_level != 0 && + ++magindex) + continue; continue; /* Skip to next top-level test*/ } @@ -145,7 +154,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->line = m->lineno; /* if main entry matches, print it... */ - switch (mget(ms, s, m, nbytes, cont_level, text)) { + switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, + flip, recursion_level + 1, printed_something, + need_separator, returnval)) { case -1: return -1; case 0: @@ -153,7 +164,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; default: if (m->type == FILE_INDIRECT) - returnval = 1; + *returnval = 1; switch (magiccheck(ms, m)) { case -1: @@ -172,21 +183,23 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * main entry didn't match, * flush its continuations */ - while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) { + while (magindex < nmagic - 1 && + magic[magindex + 1].cont_level != 0) magindex++; - } continue; } - if ((e = handle_annotation(ms, m)) != 0) + if ((e = handle_annotation(ms, m)) != 0) { + *returnval = 1; return e; + } /* * If we are going to print something, we'll need to print * a blank before we print something else. */ if (*m->desc) { - need_separator = 1; - printed_something = 1; + *need_separator = 1; + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; } @@ -201,8 +214,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (file_check_mem(ms, ++cont_level) == -1) return -1; - while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) { - magindex++; + while (magindex + 1 < nmagic && magic[magindex+1].cont_level != 0 && + ++magindex) { m = &magic[magindex]; ms->line = m->lineno; /* for messages */ @@ -217,7 +230,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } ms->offset = m->offset; if (m->flag & OFFADD) { - ms->offset += ms->c.li[cont_level - 1].off; + ms->offset += + ms->c.li[cont_level - 1].off; } #ifdef ENABLE_CONDITIONALS @@ -227,7 +241,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, continue; } #endif - switch (mget(ms, s, m, nbytes, cont_level, text)) { + switch (mget(ms, s, m, nbytes, offset, cont_level, mode, + text, flip, recursion_level + 1, printed_something, + need_separator, returnval)) { case -1: return -1; case 0: @@ -237,7 +253,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; default: if (m->type == FILE_INDIRECT) - returnval = 1; + *returnval = 1; flush = 0; break; } @@ -260,15 +276,17 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->c.li[cont_level].got_match = 0; break; } - if ((e = handle_annotation(ms, m)) != 0) + if ((e = handle_annotation(ms, m)) != 0) { + *returnval = 1; return e; + } /* * If we are going to print something, * make sure that we have a separator first. */ if (*m->desc) { - if (!printed_something) { - printed_something = 1; + if (!*printed_something) { + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; @@ -281,13 +299,13 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * this item isn't empty. */ /* space if previous printed */ - if (need_separator + if (*need_separator && ((m->flag & NOSPACE) == 0) && *m->desc) { if (print && file_printf(ms, " ") == -1) return -1; - need_separator = 0; + *need_separator = 0; } if (print && mprint(ms, m) == -1) return -1; @@ -295,7 +313,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->c.li[cont_level].off = moffset(ms, m); if (*m->desc) - need_separator = 1; + *need_separator = 1; /* * If we see any continuations @@ -307,16 +325,16 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; } } - if (printed_something) { + if (*printed_something) { firstline = 0; if (print) - returnval = 1; + *returnval = 1; } - if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) { - return returnval; /* don't keep searching */ + if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) { + return *returnval; /* don't keep searching */ } } - return returnval; /* This is hit if -k is set or there is no match */ + return *returnval; /* This is hit if -k is set or there is no match */ } private int @@ -345,7 +363,7 @@ mprint(struct magic_set *ms, struct magic *m) float vf; double vd; int64_t t = 0; - char buf[128]; + char buf[128], tbuf[26]; union VALUETYPE *p = &ms->ms_value; switch (m->type) { @@ -430,11 +448,30 @@ mprint(struct magic_set *ms, struct magic *m) t = ms->offset + m->vallen; } else { + char *str = p->s; + + /* compute t before we mangle the string? */ + t = ms->offset + strlen(str); + if (*m->value.s == '\0') - p->s[strcspn(p->s, "\n")] = '\0'; - if (file_printf(ms, m->desc, p->s) == -1) + str[strcspn(str, "\n")] = '\0'; + + if (m->str_flags & STRING_TRIM) { + char *last; + while (isspace((unsigned char)*str)) + str++; + last = str; + while (*last) + last++; + --last; + while (isspace((unsigned char)*last)) + last--; + *++last = '\0'; + } + + if (file_printf(ms, m->desc, str) == -1) return -1; - t = ms->offset + strlen(p->s); + if (m->type == FILE_PSTRING) t += file_pstring_length_size(m); } @@ -444,25 +481,26 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1) + if (file_printf(ms, m->desc, file_fmttime(p->l, FILE_T_LOCAL, + tbuf)) == -1) return -1; - t = ms->offset + sizeof(time_t); + t = ms->offset + sizeof(uint32_t); break; case FILE_LDATE: case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1) + if (file_printf(ms, m->desc, file_fmttime(p->l, 0, tbuf)) == -1) return -1; - t = ms->offset + sizeof(time_t); + t = ms->offset + sizeof(uint32_t); break; case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, - 1)) == -1) + if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_LOCAL, + tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -470,8 +508,16 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, - 0)) == -1) + if (file_printf(ms, m->desc, file_fmttime(p->q, 0, tbuf)) == -1) + return -1; + t = ms->offset + sizeof(uint64_t); + break; + + case FILE_QWDATE: + case FILE_BEQWDATE: + case FILE_LEQWDATE: + if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_WINDOWS, + tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -521,7 +567,10 @@ mprint(struct magic_set *ms, struct magic *m) int rval; cp = estrndup((const char *)ms->search.s, ms->search.rm_len); - + if (cp == NULL) { + file_oomem(ms, ms->search.rm_len); + return -1; + } rval = file_printf(ms, m->desc, cp); efree(cp); @@ -551,6 +600,8 @@ mprint(struct magic_set *ms, struct magic *m) break; case FILE_INDIRECT: + case FILE_USE: + case FILE_NAME: t = ms->offset; break; @@ -598,7 +649,7 @@ moffset(struct magic_set *ms, struct magic *m) p->s[strcspn(p->s, "\n")] = '\0'; t = CAST(uint32_t, (ms->offset + strlen(p->s))); if (m->type == FILE_PSTRING) - t += file_pstring_length_size(m); + t += (uint32_t)file_pstring_length_size(m); return t; } @@ -606,13 +657,13 @@ moffset(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - return CAST(int32_t, (ms->offset + sizeof(time_t))); + return CAST(int32_t, (ms->offset + sizeof(uint32_t))); case FILE_LDATE: case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - return CAST(int32_t, (ms->offset + sizeof(time_t))); + return CAST(int32_t, (ms->offset + sizeof(uint32_t))); case FILE_QDATE: case FILE_BEQDATE: @@ -658,6 +709,56 @@ moffset(struct magic_set *ms, struct magic *m) } } +private int +cvt_flip(int type, int flip) +{ + if (flip == 0) + return type; + switch (type) { + case FILE_BESHORT: + return FILE_LESHORT; + case FILE_BELONG: + return FILE_LELONG; + case FILE_BEDATE: + return FILE_LEDATE; + case FILE_BELDATE: + return FILE_LELDATE; + case FILE_BEQUAD: + return FILE_LEQUAD; + case FILE_BEQDATE: + return FILE_LEQDATE; + case FILE_BEQLDATE: + return FILE_LEQLDATE; + case FILE_BEQWDATE: + return FILE_LEQWDATE; + case FILE_LESHORT: + return FILE_BESHORT; + case FILE_LELONG: + return FILE_BELONG; + case FILE_LEDATE: + return FILE_BEDATE; + case FILE_LELDATE: + return FILE_BELDATE; + case FILE_LEQUAD: + return FILE_BEQUAD; + case FILE_LEQDATE: + return FILE_BEQDATE; + case FILE_LEQLDATE: + return FILE_BEQLDATE; + case FILE_LEQWDATE: + return FILE_BEQWDATE; + case FILE_BEFLOAT: + return FILE_LEFLOAT; + case FILE_LEFLOAT: + return FILE_BEFLOAT; + case FILE_BEDOUBLE: + return FILE_LEDOUBLE; + case FILE_LEDOUBLE: + return FILE_BEDOUBLE; + default: + return type; + } +} #define DO_CVT(fld, cast) \ if (m->num_mask) \ switch (m->mask_op & FILE_OPS_MASK) { \ @@ -748,11 +849,11 @@ cvt_double(union VALUETYPE *p, const struct magic *m) * (unless you have a better idea) */ private int -mconvert(struct magic_set *ms, struct magic *m) +mconvert(struct magic_set *ms, struct magic *m, int flip) { union VALUETYPE *p = &ms->ms_value; - switch (m->type) { + switch (cvt_flip(m->type, flip)) { case FILE_BYTE: cvt_8(p, m); return 1; @@ -767,6 +868,7 @@ mconvert(struct magic_set *ms, struct magic *m) case FILE_QUAD: case FILE_QDATE: case FILE_QLDATE: + case FILE_QWDATE: cvt_64(p, m); return 1; case FILE_STRING: @@ -800,6 +902,7 @@ mconvert(struct magic_set *ms, struct magic *m) case FILE_BEQUAD: case FILE_BEQDATE: case FILE_BEQLDATE: + case FILE_BEQWDATE: p->q = (uint64_t) (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)| ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)| @@ -821,6 +924,7 @@ mconvert(struct magic_set *ms, struct magic *m) case FILE_LEQUAD: case FILE_LEQDATE: case FILE_LEQLDATE: + case FILE_LEQWDATE: p->q = (uint64_t) (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)| ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)| @@ -868,6 +972,8 @@ mconvert(struct magic_set *ms, struct magic *m) case FILE_REGEX: case FILE_SEARCH: case FILE_DEFAULT: + case FILE_NAME: + case FILE_USE: return 1; default: file_magerror(ms, "invalid type %d in mconvert()", m->type); @@ -879,7 +985,7 @@ mconvert(struct magic_set *ms, struct magic *m) private void mdebug(uint32_t offset, const char *str, size_t len) { - (void) fprintf(stderr, "mget @%d: ", offset); + (void) fprintf(stderr, "mget/%zu @%d: ", len, offset); file_showstr(stderr, str, len); (void) fputc('\n', stderr); (void) fputc('\n', stderr); @@ -946,8 +1052,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, if (type == FILE_BESTRING16) src++; - /* check for pointer overflow */ - if (src < s) { + /* check that offset is within range */ + if (offset >= nbytes) { file_magerror(ms, "invalid offset %u in mcopy()", offset); return -1; @@ -996,26 +1102,40 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, } private int -mget(struct magic_set *ms, const unsigned char *s, - struct magic *m, size_t nbytes, unsigned int cont_level, int text) +mget(struct magic_set *ms, const unsigned char *s, struct magic *m, + size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, + int flip, int recursion_level, int *printed_something, + int *need_separator, int *returnval) { - uint32_t offset = ms->offset; + uint32_t soffset, offset = ms->offset; uint32_t count = m->str_range; + int rv, oneed_separator; + char *sbuf, *rbuf; union VALUETYPE *p = &ms->ms_value; + struct mlist ml; + + if (recursion_level >= 20) { + file_error(ms, 0, "recursion nesting exceeded"); + return -1; + } - if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1) + if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), + (uint32_t)nbytes, count) == -1) return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { + fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, " + "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o, + nbytes, count); mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); } if (m->flag & INDIR) { int off = m->in_offset; if (m->in_op & FILE_OPINDIRECT) { - const union VALUETYPE *q = - ((const void *)(s + offset + off)); - switch (m->in_type) { + const union VALUETYPE *q = CAST(const union VALUETYPE *, + ((const void *)(s + offset + off))); + switch (cvt_flip(m->in_type, flip)) { case FILE_BYTE: off = q->b; break; @@ -1046,8 +1166,10 @@ mget(struct magic_set *ms, const unsigned char *s, (q->hl[3]<<8)|(q->hl[2])); break; } + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "indirect offs=%u\n", off); } - switch (m->in_type) { + switch (cvt_flip(m->in_type, flip)) { case FILE_BYTE: if (nbytes < (offset + 1)) return 0; @@ -1472,7 +1594,7 @@ mget(struct magic_set *ms, const unsigned char *s, break; } - switch (m->in_type) { + switch (cvt_flip(m->in_type, flip)) { case FILE_LEID3: case FILE_BEID3: offset = ((((offset >> 0) & 0x7f) << 0) | @@ -1486,6 +1608,14 @@ mget(struct magic_set *ms, const unsigned char *s, if (m->flag & INDIROFFADD) { offset += ms->c.li[cont_level-1].off; + if (offset == 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, + "indirect *zero* offset\n"); + return 0; + } + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "indirect +offs=%u\n", offset); } if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1) return -1; @@ -1550,19 +1680,61 @@ mget(struct magic_set *ms, const unsigned char *s, break; case FILE_INDIRECT: + if (nbytes < offset) + return 0; + sbuf = ms->o.buf; + soffset = ms->offset; + ms->o.buf = NULL; + ms->offset = 0; + rv = file_softmagic(ms, s + offset, nbytes - offset, + BINTEST, text); + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); + rbuf = ms->o.buf; + ms->o.buf = sbuf; + ms->offset = soffset; + if (rv == 1) { if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && - file_printf(ms, "%s", m->desc) == -1) + file_printf(ms, m->desc, offset) == -1) return -1; + if (file_printf(ms, "%s", rbuf) == -1) + return -1; + free(rbuf); + } + return rv; + + case FILE_USE: if (nbytes < offset) return 0; - return file_softmagic(ms, s + offset, nbytes - offset, - BINTEST, text); + sbuf = m->value.s; + if (*sbuf == '^') { + sbuf++; + flip = !flip; + } + if (file_magicfind(ms, sbuf, &ml) == -1) { + file_error(ms, 0, "cannot find entry `%s'", sbuf); + return -1; + } + oneed_separator = *need_separator; + if (m->flag & NOSPACE) + *need_separator = 0; + rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, + mode, text, flip, recursion_level, printed_something, + need_separator, returnval); + if (rv != 1) + *need_separator = oneed_separator; + return rv; + + case FILE_NAME: + if (file_printf(ms, "%s", m->desc) == -1) + return -1; + return 1; case FILE_DEFAULT: /* nothing to check */ default: break; } - if (!mconvert(ms, m)) + if (!mconvert(ms, m, flip)) return 0; return 1; } @@ -1723,6 +1895,9 @@ magiccheck(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: + case FILE_QWDATE: + case FILE_BEQWDATE: + case FILE_LEQWDATE: v = p->q; break; @@ -1851,11 +2026,7 @@ magiccheck(struct magic_set *ms, struct magic *m) convert_libmagic_pattern(pattern, options); l = v = 0; -#if (PHP_MAJOR_VERSION < 6) if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) { -#else - if ((pce = pcre_get_compiled_regex_cache(IS_STRING, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) { -#endif zval_dtor(pattern); FREE_ZVAL(pattern); return -1; @@ -1872,11 +2043,7 @@ magiccheck(struct magic_set *ms, struct magic *m) haystack = estrndup(ms->search.s, ms->search.s_len); /* match v = 0, no match v = 1 */ -#if (PHP_MAJOR_VERSION < 6) php_pcre_match_impl(pce, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC); -#else - php_pcre_match_impl(pce, IS_STRING, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC); -#endif /* Free haystack */ efree(haystack); @@ -1990,6 +2157,8 @@ magiccheck(struct magic_set *ms, struct magic *m) break; } case FILE_INDIRECT: + case FILE_USE: + case FILE_NAME: return 1; default: file_magerror(ms, "invalid type %d in magiccheck()", m->type); |