diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/fileinfo/libmagic.patch | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/fileinfo/libmagic.patch')
-rw-r--r-- | ext/fileinfo/libmagic.patch | 3197 |
1 files changed, 3197 insertions, 0 deletions
diff --git a/ext/fileinfo/libmagic.patch b/ext/fileinfo/libmagic.patch new file mode 100644 index 0000000..ded9490 --- /dev/null +++ b/ext/fileinfo/libmagic.patch @@ -0,0 +1,3197 @@ +diff -u libmagic.orig/apprentice.c libmagic/apprentice.c +--- libmagic.orig/apprentice.c Sat Dec 17 18:17:18 2011 ++++ libmagic/apprentice.c Tue Nov 27 16:35:47 2012 +@@ -29,6 +29,8 @@ + * apprentice - make one pass through /etc/magic, learning its secrets. + */ + ++#include "php.h" ++ + #include "file.h" + + #ifndef lint +@@ -36,18 +38,31 @@ + #endif /* lint */ + + #include "magic.h" ++#include "patchlevel.h" + #include <stdlib.h> +-#ifdef HAVE_UNISTD_H ++ ++#if defined(__hpux) && !defined(HAVE_STRTOULL) ++#if SIZEOF_LONG == 8 ++# define strtoull strtoul ++#else ++# define strtoull __strtoull ++#endif ++#endif ++ ++#ifdef PHP_WIN32 ++#include "win32/unistd.h" ++#if _MSC_VER <= 1300 ++# include "win32/php_strtoi64.h" ++#endif ++#define strtoull _strtoui64 ++#else + #include <unistd.h> + #endif ++ + #include <string.h> + #include <assert.h> + #include <ctype.h> + #include <fcntl.h> +-#ifdef QUICK +-#include <sys/mman.h> +-#endif +-#include <dirent.h> + + #define EATAB {while (isascii((unsigned char) *l) && \ + isspace((unsigned char) *l)) ++l;} +@@ -112,12 +127,10 @@ + 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 magicsize = sizeof(struct magic); + + private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; +- + private struct { + const char *name; + size_t len; +@@ -131,38 +144,7 @@ + { NULL, 0, NULL } + }; + +-#ifdef COMPILE_ONLY +- +-int main(int, char *[]); +- +-int +-main(int argc, char *argv[]) +-{ +- int ret; +- struct magic_set *ms; +- char *progname; +- +- if ((progname = strrchr(argv[0], '/')) != NULL) +- progname++; +- else +- progname = argv[0]; +- +- if (argc != 2) { +- (void)fprintf(stderr, "Usage: %s file\n", progname); +- return 1; +- } +- +- if ((ms = magic_open(MAGIC_CHECK)) == NULL) { +- (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); +- return 1; +- } +- ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; +- if (ret == 1) +- (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); +- magic_close(ms); +- return ret; +-} +-#endif /* COMPILE_ONLY */ ++#include "../data_file.c" + + static const struct type_tbl_s { + const char name[16]; +@@ -218,6 +200,10 @@ + # undef XX_NULL + }; + ++#ifndef S_ISDIR ++#define S_ISDIR(mode) ((mode) & _S_IFDIR) ++#endif ++ + private int + get_type(const char *l, const char **t) + { +@@ -275,15 +261,17 @@ + if (rv != 0) + return -1; + rv = apprentice_compile(ms, &magic, &nmagic, fn); +- free(magic); ++ efree(magic); + return rv; + } + +-#ifndef COMPILE_ONLY + if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { +- if (ms->flags & MAGIC_CHECK) +- file_magwarn(ms, "using regular magic file `%s'", fn); +- rv = apprentice_load(ms, &magic, &nmagic, fn, action); ++ if (fn) { ++ if (ms->flags & MAGIC_CHECK) ++ file_magwarn(ms, "using regular magic file `%s'", fn); ++ rv = apprentice_load(ms, &magic, &nmagic, fn, action); ++ } ++ + if (rv != 0) + return -1; + } +@@ -295,11 +283,7 @@ + return -1; + } + +- if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) { +- file_delmagic(magic, mapped, nmagic); +- file_oomem(ms, sizeof(*ml)); +- return -1; +- } ++ ml = emalloc(sizeof(*ml)); + + ml->magic = magic; + ml->nmagic = nmagic; +@@ -318,7 +302,6 @@ + } + + return 0; +-#endif /* COMPILE_ONLY */ + } + + protected void +@@ -327,22 +310,18 @@ + if (p == NULL) + return; + switch (type) { +- case 2: +-#ifdef QUICK +- p--; +- (void)munmap((void *)p, sizeof(*p) * (entries + 1)); ++ case 3: ++ /* Do nothing, it's part of the code segment */ + break; +-#else +- (void)&entries; +- abort(); +- /*NOTREACHED*/ +-#endif ++ + case 1: + p--; + /*FALLTHROUGH*/ ++ + case 0: +- free(p); ++ efree(p); + break; ++ + default: + abort(); + } +@@ -355,23 +334,27 @@ + char *p, *mfn; + int file_err, errs = -1; + struct mlist *mlist; +- ++/* XXX disabling default magic loading so the compiled in data is used */ ++#if 0 + if ((fn = magic_getpath(fn, action)) == NULL) + return NULL; ++#endif + + init_file_tables(); + +- if ((mfn = strdup(fn)) == NULL) { +- file_oomem(ms, strlen(fn)); +- return NULL; ++ 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; + } ++ ++ mfn = estrdup(fn); + fn = mfn; + +- if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) { +- free(mfn); +- file_oomem(ms, sizeof(*mlist)); +- return NULL; +- } ++ mlist = emalloc(sizeof(*mlist)); + mlist->next = mlist->prev = mlist; + + while (fn) { +@@ -385,13 +368,13 @@ + fn = p; + } + if (errs == -1) { +- free(mfn); +- free(mlist); ++ efree(mfn); ++ efree(mlist); + mlist = NULL; + file_error(ms, 0, "could not find any magic files!"); + return NULL; + } +- free(mfn); ++ efree(mfn); + return mlist; + } + +@@ -524,6 +507,7 @@ + abort(); + } + ++ + /* + * Magic entries with no description get a bonus because they depend + * on subsequent magic entries to print something. +@@ -539,8 +523,8 @@ + private int + apprentice_sort(const void *a, const void *b) + { +- const struct magic_entry *ma = CAST(const struct magic_entry *, a); +- const struct magic_entry *mb = CAST(const struct magic_entry *, b); ++ const struct magic_entry *ma = a; ++ const struct magic_entry *mb = b; + size_t sa = apprentice_magic_strength(ma->mp); + size_t sb = apprentice_magic_strength(mb->mp); + if (sa == sb) +@@ -671,12 +655,22 @@ + load_1(struct magic_set *ms, int action, const char *fn, int *errs, + struct magic_entry **marray, uint32_t *marraycount) + { +- size_t lineno = 0, llen = 0; ++ char buffer[BUFSIZ + 1]; + char *line = NULL; +- ssize_t len; ++ size_t len; ++ size_t lineno = 0; ++ ++ php_stream *stream; ++ ++ TSRMLS_FETCH(); + +- FILE *f = fopen(ms->file = fn, "r"); +- if (f == NULL) { ++#if PHP_API_VERSION < 20100412 ++ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); ++#else ++ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); ++#endif ++ ++ if (stream == NULL) { + if (errno != ENOENT) + file_error(ms, errno, "cannot read magic file `%s'", + fn); +@@ -684,9 +678,12 @@ + return; + } + +- /* read and parse this file */ +- for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; +- ms->line++) { ++ /* read and parse this file */ ++#if (PHP_MAJOR_VERSION < 6) ++ 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') { +@@ -736,8 +733,7 @@ + break; + } + } +- free(line); +- (void)fclose(f); ++ php_stream_close(stream); + } + + /* +@@ -754,23 +750,21 @@ + apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn, int action) + { +- int errs = 0; ++ int errs = 0; + struct magic_entry *marray; + uint32_t marraycount, i, mentrycount = 0, starttest; +- size_t slen, files = 0, maxfiles = 0; +- char **filearr = NULL, *mfn; ++ size_t files = 0, maxfiles = 0; ++ char **filearr = NULL; + struct stat st; +- DIR *dir; +- struct dirent *d; ++ php_stream *dir; ++ php_stream_dirent d; ++ ++ TSRMLS_FETCH(); + + ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ + +- maxmagic = MAXMAGIS; +- if ((marray = CAST(struct magic_entry *, calloc(maxmagic, +- sizeof(*marray)))) == NULL) { +- file_oomem(ms, maxmagic * sizeof(*marray)); +- return -1; +- } ++ maxmagic = MAXMAGIS; ++ marray = ecalloc(maxmagic, sizeof(*marray)); + marraycount = 0; + + /* print silly verbose header for USG compat. */ +@@ -778,22 +772,26 @@ + (void)fprintf(stderr, "%s\n", usg_hdr); + + /* load directory or file */ +- if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { +- dir = opendir(fn); ++ /* FIXME: Read file names and sort them to prevent ++ non-determinism. See Debian bug #488562. */ ++ if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { ++ int mflen; ++ char mfn[MAXPATHLEN]; ++ ++ dir = php_stream_opendir(fn, REPORT_ERRORS, NULL); + if (!dir) { + errs++; + goto out; + } +- while ((d = readdir(dir)) != NULL) { +- if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { ++ while (php_stream_readdir(dir, &d)) { ++ if ((mflen = snprintf(mfn, sizeof(mfn), "%s/%s", fn, d.d_name)) < 0) { + file_oomem(ms, +- strlen(fn) + strlen(d->d_name) + 2); ++ strlen(fn) + strlen(d.d_name) + 2); + errs++; +- closedir(dir); ++ php_stream_closedir(dir); + goto out; + } + if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { +- free(mfn); + continue; + } + if (files >= maxfiles) { +@@ -803,20 +801,19 @@ + if ((filearr = CAST(char **, + realloc(filearr, mlen))) == NULL) { + file_oomem(ms, mlen); +- free(mfn); +- closedir(dir); ++ php_stream_closedir(dir); + errs++; + goto out; + } + } +- filearr[files++] = mfn; ++ filearr[files++] = estrndup(mfn, (mflen > sizeof(mfn) - 1)? sizeof(mfn) - 1: mflen); + } +- closedir(dir); ++ 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); +- free(filearr[i]); ++ efree(filearr[i]); + } + free(filearr); + } else +@@ -882,12 +879,7 @@ + for (i = 0; i < marraycount; i++) + mentrycount += marray[i].cont_count; + +- slen = sizeof(**magicp) * mentrycount; +- if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) { +- file_oomem(ms, slen); +- errs++; +- goto out; +- } ++ *magicp = emalloc(sizeof(**magicp) * mentrycount); + + mentrycount = 0; + for (i = 0; i < marraycount; i++) { +@@ -896,9 +888,14 @@ + mentrycount += marray[i].cont_count; + } + out: +- for (i = 0; i < marraycount; i++) +- free(marray[i].mp); +- free(marray); ++ for (i = 0; i < marraycount; i++) { ++ if (marray[i].mp) { ++ efree(marray[i].mp); ++ } ++ } ++ if (marray) { ++ efree(marray); ++ } + if (errs) { + *magicp = NULL; + *nmagicp = 0; +@@ -1175,14 +1172,13 @@ + return -1; + } + me = &(*mentryp)[*nmentryp - 1]; ++ if (me->mp == NULL) { ++ return -1; ++ } + if (me->cont_count == me->max_count) { + struct magic *nm; + size_t cnt = me->max_count + ALLOC_CHUNK; +- if ((nm = CAST(struct magic *, realloc(me->mp, +- sizeof(*nm) * cnt))) == NULL) { +- file_oomem(ms, sizeof(*nm) * cnt); +- return -1; +- } ++ nm = erealloc(me->mp, sizeof(*nm) * cnt); + me->mp = m = nm; + me->max_count = CAST(uint32_t, cnt); + } +@@ -1194,23 +1190,13 @@ + struct magic_entry *mp; + + maxmagic += ALLOC_INCR; +- if ((mp = CAST(struct magic_entry *, +- realloc(*mentryp, sizeof(*mp) * maxmagic))) == +- NULL) { +- file_oomem(ms, sizeof(*mp) * maxmagic); +- return -1; +- } +- (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * +- ALLOC_INCR); ++ mp = erealloc(*mentryp, sizeof(*mp) * maxmagic); ++ (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * ALLOC_INCR); + *mentryp = mp; + } + me = &(*mentryp)[*nmentryp]; + if (me->mp == NULL) { +- size_t len = sizeof(*m) * ALLOC_CHUNK; +- if ((m = CAST(struct magic *, malloc(len))) == NULL) { +- file_oomem(ms, len); +- return -1; +- } ++ m = safe_emalloc(sizeof(*m), ALLOC_CHUNK, 0); + me->mp = m; + me->max_count = ALLOC_CHUNK; + } else +@@ -1353,6 +1339,10 @@ + if (m->type == FILE_INVALID) { + if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, "type `%s' invalid", l); ++ if (me->mp) { ++ efree(me->mp); ++ me->mp = NULL; ++ } + return -1; + } + +@@ -1361,7 +1351,7 @@ + + m->mask_op = 0; + if (*l == '~') { +- if (!IS_STRING(m->type)) ++ if (!IS_LIBMAGIC_STRING(m->type)) + m->mask_op |= FILE_OPINVERSE; + else if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, "'~' invalid for string types"); +@@ -1370,7 +1360,7 @@ + m->str_range = 0; + m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; + if ((op = get_op(*l)) != -1) { +- if (!IS_STRING(m->type)) { ++ if (!IS_LIBMAGIC_STRING(m->type)) { + uint64_t val; + ++l; + m->mask_op |= op; +@@ -1558,11 +1548,6 @@ + if (check_format(ms, m) == -1) + return -1; + } +-#ifndef COMPILE_ONLY +- if (action == FILE_CHECK) { +- file_mdump(m); +- } +-#endif + m->mimetype[0] = '\0'; /* initialise MIME type to none */ + if (m->cont_level == 0) + ++(*nmentryp); /* make room for next */ +@@ -2195,56 +2180,79 @@ + + /* + * 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) + { +- int fd; +- struct stat st; + uint32_t *ptr; + uint32_t version; + int needsbyteswap; + char *dbname = NULL; + void *mm = NULL; ++ int ret = 0; ++ php_stream *stream = NULL; ++ php_stream_statbuf st; ++ ++ ++ TSRMLS_FETCH(); ++ ++ if (fn == NULL) { ++ mm = (void *)&php_magic_database; ++ ret = 3; ++ goto internal_loaded; ++ } ++ ++#ifdef PHP_WIN32 ++ /* Don't bother on windows with php_stream_open_wrapper, ++ 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; ++ } ++ } ++#endif + + dbname = mkdbname(ms, fn, 0); + if (dbname == NULL) + goto error2; + +- if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) ++#if PHP_API_VERSION < 20100412 ++ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); ++#else ++ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); ++#endif ++ ++ if (!stream) { + goto error2; ++ } + +- if (fstat(fd, &st) == -1) { ++ if (php_stream_stat(stream, &st) < 0) { + file_error(ms, errno, "cannot stat `%s'", dbname); + goto error1; + } +- if (st.st_size < 8) { ++ ++ if (st.sb.st_size < 8) { + file_error(ms, 0, "file `%s' is too small", dbname); + goto error1; + } + +-#ifdef QUICK +- if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, +- MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { +- file_error(ms, errno, "cannot map `%s'", dbname); +- goto error1; +- } +-#define RET 2 +-#else +- if ((mm = CAST(void *, malloc((size_t)st.st_size))) == NULL) { +- file_oomem(ms, (size_t)st.st_size); +- goto error1; +- } +- if (read(fd, mm, (size_t)st.st_size) != (ssize_t)st.st_size) { ++ 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) { + file_badread(ms); ++ ret = 1; + goto error1; + } +-#define RET 1 +-#endif +- *magicp = CAST(struct magic *, mm); +- (void)close(fd); +- fd = -1; ++ ret = 1; ++ ++ php_stream_close(stream); ++ stream = NULL; ++ ++internal_loaded: ++ *magicp = mm; + ptr = (uint32_t *)(void *)*magicp; + if (*ptr != MAGICNO) { + if (swap4(*ptr) != MAGICNO) { +@@ -2259,35 +2267,55 @@ + else + version = ptr[1]; + if (version != VERSIONNO) { +- file_error(ms, 0, "File %s supports only version %d magic " +- "files. `%s' is version %d", VERSION, ++ 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; + } +- *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)); +- if (*nmagicp > 0) ++ ++ /* 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)); ++ } ++ if (*nmagicp > 0) { + (*nmagicp)--; ++ } + (*magicp)++; +- if (needsbyteswap) ++ if (needsbyteswap) { + byteswap(*magicp, *nmagicp); +- free(dbname); +- return RET; ++ } ++ ++ if (dbname) { ++ efree(dbname); ++ } ++ return ret; + + error1: +- if (fd != -1) +- (void)close(fd); +- if (mm) { +-#ifdef QUICK +- (void)munmap((void *)mm, (size_t)st.st_size); +-#else +- free(mm); +-#endif ++ if (stream) { ++ php_stream_close(stream); ++ } ++ ++ if (mm && ret == 1) { ++ efree(mm); + } else { + *magicp = NULL; + *nmagicp = 0; + } + error2: +- free(dbname); ++ if (dbname) { ++ efree(dbname); ++ } + return -1; + } + +@@ -2301,42 +2329,49 @@ + apprentice_compile(struct magic_set *ms, struct magic **magicp, + uint32_t *nmagicp, const char *fn) + { +- int fd = -1; + char *dbname; + int rv = -1; ++ php_stream *stream; ++ ++ TSRMLS_FETCH(); + +- dbname = mkdbname(ms, fn, 1); ++ dbname = mkdbname(ms, fn, 0); + + if (dbname == NULL) + goto out; + +- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) { ++/* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */ ++#if PHP_API_VERSION < 20100412 ++ stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); ++#else ++ stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL); ++#endif ++ ++ if (!stream) { + file_error(ms, errno, "cannot open `%s'", dbname); + goto out; + } + +- if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { ++ if (php_stream_write(stream, (char *)ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { + file_error(ms, errno, "error writing `%s'", dbname); + goto out; + } + +- if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET) +- != sizeof(struct magic)) { ++ 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 (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) +- != (ssize_t)(sizeof(struct magic) * *nmagicp)) { ++ 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; + } + +- if (fd != -1) +- (void)close(fd); ++ php_stream_close(stream); ++ + rv = 0; + out: +- free(dbname); ++ efree(dbname); + return rv; + } + +@@ -2349,6 +2384,7 @@ + { + const char *p, *q; + char *buf; ++ TSRMLS_FETCH(); + + if (strip) { + if ((p = strrchr(fn, '/')) != NULL) +@@ -2370,14 +2406,18 @@ + q++; + /* Compatibility with old code that looked in .mime */ + if (ms->flags & MAGIC_MIME) { +- asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext); +- if (access(buf, R_OK) != -1) { ++ spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", (int)(q - fn), fn, ext); ++#ifdef PHP_WIN32 ++ if (VCWD_ACCESS(buf, R_OK) == 0) { ++#else ++ if (VCWD_ACCESS(buf, R_OK) != -1) { ++#endif + ms->flags &= MAGIC_MIME_TYPE; + return buf; + } +- free(buf); ++ efree(buf); + } +- asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext); ++ spprintf(&buf, MAXPATHLEN, "%.*s%s", (int)(q - fn), fn, ext); + + /* Compatibility with old code that looked in .mime */ + if (strstr(p, ".mime") != NULL) +@@ -2467,7 +2507,7 @@ + m->offset = swap4((uint32_t)m->offset); + m->in_offset = swap4((uint32_t)m->in_offset); + m->lineno = swap4((uint32_t)m->lineno); +- if (IS_STRING(m->type)) { ++ if (IS_LIBMAGIC_STRING(m->type)) { + m->str_range = swap4(m->str_range); + m->str_flags = swap4(m->str_flags); + } +diff -u libmagic.orig/ascmagic.c libmagic/ascmagic.c +--- libmagic.orig/ascmagic.c Sat Dec 17 18:17:18 2011 ++++ libmagic/ascmagic.c Tue Apr 10 09:46:33 2012 +@@ -139,10 +139,8 @@ + /* malloc size is a conservative overestimate; could be + improved, or at least realloced after conversion. */ + mlen = ulen * 6; +- if ((utf8_buf = CAST(unsigned char *, malloc(mlen))) == NULL) { +- file_oomem(ms, mlen); +- goto done; +- } ++ utf8_buf = emalloc(mlen); ++ + if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen)) + == NULL) + goto done; +@@ -296,7 +294,8 @@ + } + rv = 1; + done: +- free(utf8_buf); ++ if (utf8_buf) ++ efree(utf8_buf); + + return rv; + } +diff -u libmagic.orig/cdf.c libmagic/cdf.c +--- libmagic.orig/cdf.c Mon Feb 20 23:35:29 2012 ++++ libmagic/cdf.c Tue Apr 10 09:46:33 2012 +@@ -43,7 +43,17 @@ + #include <err.h> + #endif + #include <stdlib.h> ++ ++#ifdef PHP_WIN32 ++#include "win32/unistd.h" ++#else + #include <unistd.h> ++#endif ++ ++#ifndef UINT32_MAX ++# define UINT32_MAX (0xffffffff) ++#endif ++ + #include <string.h> + #include <time.h> + #include <ctype.h> +@@ -296,10 +306,10 @@ + if (info->i_fd == -1) + return -1; + +- if (lseek(info->i_fd, off, SEEK_SET) == (off_t)-1) ++ if (FINFO_LSEEK_FUNC(info->i_fd, off, SEEK_SET) == (off_t)-1) + return -1; + +- if (read(info->i_fd, buf, len) != (ssize_t)len) ++ if (FINFO_READ_FUNC(info->i_fd, buf, len) != (ssize_t)len) + return -1; + + return (ssize_t)len; +@@ -1135,7 +1145,7 @@ + cdf_directory_t *d; + char name[__arraycount(d->d_name)]; + cdf_stream_t scn; +- struct timespec ts; ++ struct timeval ts; + + static const char *types[] = { "empty", "user storage", + "user stream", "lockbytes", "property", "root storage" }; +@@ -1188,7 +1198,7 @@ + cdf_dump_property_info(const cdf_property_info_t *info, size_t count) + { + cdf_timestamp_t tp; +- struct timespec ts; ++ struct timeval ts; + char buf[64]; + size_t i, j; + +@@ -1232,7 +1242,11 @@ + break; + case CDF_FILETIME: + tp = info[i].pi_tp; ++#if defined(PHP_WIN32) && _MSC_VER <= 1500 ++ if (tp < 1000000000000000i64) { ++#else + if (tp < 1000000000000000LL) { ++#endif + cdf_print_elapsed_time(buf, sizeof(buf), tp); + (void)fprintf(stderr, "timestamp %s\n", buf); + } else { +diff -u libmagic.orig/cdf.h libmagic/cdf.h +--- libmagic.orig/cdf.h Fri Feb 17 06:28:31 2012 ++++ libmagic/cdf.h Tue Apr 10 09:46:34 2012 +@@ -35,7 +35,7 @@ + #ifndef _H_CDF_ + #define _H_CDF_ + +-#ifdef WIN32 ++#ifdef PHP_WIN32 + #include <winsock2.h> + #define timespec timeval + #define tv_nsec tv_usec +@@ -57,7 +57,11 @@ + + typedef struct { + uint64_t h_magic; +-#define CDF_MAGIC 0xE11AB1A1E011CFD0LL ++#if defined(PHP_WIN32) && _MSC_VER <= 1500 ++# define CDF_MAGIC 0xE11AB1A1E011CFD0i64 ++#else ++# define CDF_MAGIC 0xE11AB1A1E011CFD0LL ++#endif + uint64_t h_uuid[2]; + uint16_t h_revision; + uint16_t h_version; +@@ -267,9 +271,9 @@ + size_t i_len; + } cdf_info_t; + +-struct timespec; +-int cdf_timestamp_to_timespec(struct timespec *, cdf_timestamp_t); +-int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timespec *); ++struct timeval; ++int cdf_timestamp_to_timespec(struct timeval *, cdf_timestamp_t); ++int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timeval *); + int cdf_read_header(const cdf_info_t *, cdf_header_t *); + void cdf_swap_header(cdf_header_t *); + void cdf_unpack_header(cdf_header_t *, char *); +diff -u libmagic.orig/cdf_time.c libmagic/cdf_time.c +--- libmagic.orig/cdf_time.c Tue Dec 13 14:48:41 2011 ++++ libmagic/cdf_time.c Tue Apr 10 09:46:34 2012 +@@ -96,7 +96,7 @@ + } + + int +-cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) ++cdf_timestamp_to_timespec(struct timeval *ts, cdf_timestamp_t t) + { + struct tm tm; + #ifdef HAVE_STRUCT_TM_TM_ZONE +@@ -104,8 +104,8 @@ + #endif + int rdays; + +- /* Unit is 100's of nanoseconds */ +- ts->tv_nsec = (t % CDF_TIME_PREC) * 100; ++ /* Time interval, in microseconds */ ++ ts->tv_usec = (t % CDF_TIME_PREC) * CDF_TIME_PREC; + + t /= CDF_TIME_PREC; + tm.tm_sec = (int)(t % 60); +@@ -117,7 +117,7 @@ + tm.tm_hour = (int)(t % 24); + t /= 24; + +- // XXX: Approx ++ /* XXX: Approx */ + tm.tm_year = (int)(CDF_BASE_YEAR + (t / 365)); + + rdays = cdf_getdays(tm.tm_year); +@@ -144,7 +144,7 @@ + + int + /*ARGSUSED*/ +-cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts) ++cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timeval *ts) + { + #ifndef __lint__ + (void)&t; +@@ -156,7 +156,7 @@ + errno = EINVAL; + return -1; + } +- *t = (ts->ts_nsec / 100) * CDF_TIME_PREC; ++ *t = (ts->ts_usec / CDF_TIME_PREC) * CDF_TIME_PREC; + *t = tm.tm_sec; + *t += tm.tm_min * 60; + *t += tm.tm_hour * 60 * 60; +@@ -182,7 +182,7 @@ + int + main(int argc, char *argv[]) + { +- struct timespec ts; ++ struct timeval ts; + static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; + static const char *ref = "Sat Apr 23 01:30:00 1977"; + char *p, *q; +diff -u libmagic.orig/compress.c libmagic/compress.c +--- libmagic.orig/compress.c Sat Dec 17 18:17:18 2011 ++++ libmagic/compress.c Tue Apr 10 09:46:34 2012 +@@ -32,6 +32,7 @@ + * uncompress(method, old, n, newch) - uncompress old into new, + * using method, return sizeof new + */ ++#include "config.h" + #include "file.h" + + #ifndef lint +@@ -45,7 +46,8 @@ + #endif + #include <string.h> + #include <errno.h> +-#ifndef __MINGW32__ ++#include <sys/types.h> ++#ifndef PHP_WIN32 + #include <sys/ioctl.h> + #endif + #ifdef HAVE_SYS_WAIT_H +@@ -59,6 +61,9 @@ + #include <zlib.h> + #endif + ++#undef FIONREAD ++ ++ + private const struct { + const char magic[8]; + size_t maglen; +@@ -85,8 +90,7 @@ + #define NODATA ((size_t)~0) + + private ssize_t swrite(int, const void *, size_t); +-#if HAVE_FORK +-private size_t ncompr = sizeof(compr) / sizeof(compr[0]); ++#ifdef PHP_FILEINFO_UNCOMPRESS + private size_t uncompressbuf(struct magic_set *, int, size_t, + const unsigned char *, unsigned char **, size_t); + #ifdef BUILTIN_DECOMPRESS +@@ -102,10 +106,13 @@ + size_t i, nsz; + int rv = 0; + int mime = ms->flags & MAGIC_MIME; ++ size_t ncompr; + + if ((ms->flags & MAGIC_COMPRESS) == 0) + return 0; + ++ ncompr = sizeof(compr) / sizeof(compr[0]); ++ + for (i = 0; i < ncompr; i++) { + if (nbytes < compr[i].maglen) + continue; +@@ -134,7 +141,8 @@ + } + } + error: +- free(newbuf); ++ if (newbuf) ++ efree(newbuf); + ms->flags |= MAGIC_COMPRESS; + return rv; + } +@@ -168,12 +176,9 @@ + * `safe' read for sockets and pipes. + */ + protected ssize_t +-sread(int fd, void *buf, size_t n, int canbepipe __attribute__ ((unused))) ++sread(int fd, void *buf, size_t n, int canbepipe) + { + ssize_t rv; +-#ifdef FD_ZERO +- ssize_t cnt; +-#endif + #ifdef FIONREAD + int t = 0; + #endif +@@ -185,6 +190,7 @@ + #ifdef FIONREAD + if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) { + #ifdef FD_ZERO ++ int cnt; + for (cnt = 0;; cnt++) { + fd_set check; + struct timeval tout = {0, 100 * 1000}; +@@ -218,7 +224,7 @@ + + nocheck: + do +- switch ((rv = read(fd, buf, n))) { ++ switch ((rv = FINFO_READ_FUNC(fd, buf, n))) { + case -1: + if (errno == EINTR) + continue; +@@ -295,13 +301,14 @@ + return -1; + } + (void)close(tfd); +- if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, (off_t)0, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + return fd; + } +-#if HAVE_FORK ++ ++#ifdef PHP_FILEINFO_UNCOMPRESS + #ifdef BUILTIN_DECOMPRESS + + #define FHCRC (1 << 1) +@@ -338,9 +345,7 @@ + + if (data_start >= n) + return 0; +- if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) { +- return 0; +- } ++ *newch = (unsigned char *)emalloc(HOWMANY + 1)); + + /* XXX: const castaway, via strchr */ + z.next_in = (Bytef *)strchr((const char *)old + data_start, +@@ -400,7 +405,7 @@ + (void) close(0); + if (fd != -1) { + (void) dup(fd); +- (void) lseek(0, (off_t)0, SEEK_SET); ++ (void) FINFO_LSEEK_FUNC(0, (off_t)0, SEEK_SET); + } else { + (void) dup(fdin[0]); + (void) close(fdin[0]); +@@ -465,20 +470,14 @@ + fdin[1] = -1; + } + +- if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) { +-#ifdef DEBUG +- (void)fprintf(stderr, "Malloc failed (%s)\n", +- strerror(errno)); +-#endif +- n = 0; +- goto err; +- } ++ *newch = (unsigned char *) emalloc(HOWMANY + 1); ++ + if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { + #ifdef DEBUG + (void)fprintf(stderr, "Read failed (%s)\n", + strerror(errno)); + #endif +- free(*newch); ++ efree(*newch); + n = 0; + newch[0] = '\0'; + goto err; +@@ -502,4 +501,4 @@ + return n; + } + } +-#endif ++#endif /* if PHP_FILEINFO_UNCOMPRESS */ +diff -u libmagic.orig/file.h libmagic/file.h +--- libmagic.orig/file.h Tue Sep 20 17:30:14 2011 ++++ libmagic/file.h Mon Apr 23 17:58:54 2012 +@@ -33,11 +33,9 @@ + #ifndef __file_h__ + #define __file_h__ + +-#ifdef HAVE_CONFIG_H +-#include <config.h> +-#endif ++#include "config.h" + +-#ifdef WIN32 ++#ifdef PHP_WIN32 + #ifdef _WIN64 + #define SIZE_T_FORMAT "I64" + #else +@@ -61,9 +59,20 @@ + #ifdef HAVE_INTTYPES_H + #include <inttypes.h> + #endif +-#include <regex.h> ++#ifdef PHP_WIN32 ++#include "win32/php_stdint.h" ++#endif ++ ++#include "php.h" ++#include "ext/standard/php_string.h" ++#include "ext/pcre/php_pcre.h" ++ + #include <sys/types.h> ++#ifdef PHP_WIN32 ++#include "win32/param.h" ++#else + #include <sys/param.h> ++#endif + /* Do this here and now, because struct stat gets re-defined on solaris */ + #include <sys/stat.h> + #include <stdarg.h> +@@ -74,7 +83,7 @@ + #define MAGIC "/etc/magic" + #endif + +-#if defined(__EMX__) || defined (WIN32) ++#if defined(__EMX__) || defined(PHP_WIN32) + #define PATHSEP ';' + #else + #define PATHSEP ':' +@@ -100,12 +109,6 @@ + #endif + #endif + +-#ifndef __GNUC__ +-#ifndef __attribute__ +-#define __attribute__(a) +-#endif +-#endif +- + #ifndef MIN + #define MIN(a,b) (((a) < (b)) ? (a) : (b)) + #endif +@@ -209,7 +212,7 @@ + #define FILE_INDIRECT 41 + #define FILE_NAMES_SIZE 42/* size of array to contain all names */ + +-#define IS_STRING(t) \ ++#define IS_LIBMAGIC_STRING(t) \ + ((t) == FILE_STRING || \ + (t) == FILE_PSTRING || \ + (t) == FILE_BESTRING16 || \ +@@ -231,7 +234,7 @@ + #ifdef ENABLE_CONDITIONALS + uint8_t cond; /* conditional type */ + #else +- uint8_t dummy; ++ uint8_t dummy; + #endif + uint8_t factor_op; + #define FILE_FACTOR_OP_PLUS '+' +@@ -387,21 +390,18 @@ + + struct stat; + protected const char *file_fmttime(uint32_t, int); +-protected int file_buffer(struct magic_set *, int, const char *, const void *, ++protected int file_buffer(struct magic_set *, php_stream *, const char *, const void *, + size_t); +-protected int file_fsmagic(struct magic_set *, const char *, struct stat *); ++protected int file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream *stream); + protected int file_pipe2file(struct magic_set *, int, const void *, size_t); +-protected int file_vprintf(struct magic_set *, const char *, va_list); +-protected size_t file_printedlen(const struct magic_set *); + protected int file_replace(struct magic_set *, const char *, const char *); +-protected int file_printf(struct magic_set *, const char *, ...) +- __attribute__((__format__(__printf__, 2, 3))); ++protected int file_printf(struct magic_set *, const char *, ...); + protected int file_reset(struct magic_set *); + protected int file_tryelf(struct magic_set *, int, const unsigned char *, + size_t); + protected int file_trycdf(struct magic_set *, int, const unsigned char *, + size_t); +-#if HAVE_FORK ++#ifdef PHP_FILEINFO_UNCOMPRESS + protected int file_zmagic(struct magic_set *, int, const char *, + const unsigned char *, size_t); + #endif +@@ -422,13 +422,9 @@ + protected void file_badread(struct magic_set *); + protected void file_badseek(struct magic_set *); + protected void file_oomem(struct magic_set *, size_t); +-protected void file_error(struct magic_set *, int, const char *, ...) +- __attribute__((__format__(__printf__, 3, 4))); +-protected void file_magerror(struct magic_set *, const char *, ...) +- __attribute__((__format__(__printf__, 2, 3))); +-protected void file_magwarn(struct magic_set *, const char *, ...) +- __attribute__((__format__(__printf__, 2, 3))); +-protected void file_mdump(struct magic *); ++protected void file_error(struct magic_set *, int, const char *, ...); ++protected void file_magerror(struct magic_set *, const char *, ...); ++protected void file_magwarn(struct magic_set *, const char *, ...); + protected void file_showstr(FILE *, const char *, size_t); + protected size_t file_mbswidth(const char *); + protected const char *file_getbuffer(struct magic_set *); +@@ -438,16 +434,14 @@ + size_t *); + protected size_t file_pstring_length_size(const struct magic *); + protected size_t file_pstring_get_length(const struct magic *, const char *); ++protected size_t file_printedlen(const struct magic_set *ms); + #ifdef __EMX__ + protected int file_os2_apptype(struct magic_set *, const char *, const void *, + size_t); + #endif /* __EMX__ */ + +- +-#ifndef COMPILE_ONLY + extern const char *file_names[]; + extern const size_t file_nnames; +-#endif + + #ifndef HAVE_STRERROR + extern int sys_nerr; +@@ -460,17 +454,10 @@ + #define strtoul(a, b, c) strtol(a, b, c) + #endif + +-#ifndef HAVE_VASPRINTF +-int vasprintf(char **, const char *, va_list); +-#endif +-#ifndef HAVE_ASPRINTF +-int asprintf(char **ptr, const char *format_string, ...); +-#endif +- +-#ifndef HAVE_STRLCPY ++#ifndef strlcpy + size_t strlcpy(char *dst, const char *src, size_t siz); + #endif +-#ifndef HAVE_STRLCAT ++#ifndef strlcat + size_t strlcat(char *dst, const char *src, size_t siz); + #endif + #ifndef HAVE_GETLINE +@@ -498,6 +485,14 @@ + #endif + #else + #define FILE_RCSID(id) ++#endif ++ ++#ifdef PHP_WIN32 ++#define FINFO_LSEEK_FUNC _lseek ++#define FINFO_READ_FUNC _read ++#else ++#define FINFO_LSEEK_FUNC lseek ++#define FINFO_READ_FUNC read + #endif + + #endif /* __file_h__ */ +diff -u libmagic.orig/fsmagic.c libmagic/fsmagic.c +--- libmagic.orig/fsmagic.c Tue Aug 23 10:57:10 2011 ++++ libmagic/fsmagic.c Tue Apr 10 09:46:34 2012 +@@ -59,27 +59,21 @@ + # define minor(dev) ((dev) & 0xff) + #endif + #undef HAVE_MAJOR +-#ifdef S_IFLNK +-private int +-bad_link(struct magic_set *ms, int err, char *buf) +-{ +- int mime = ms->flags & MAGIC_MIME; +- if ((mime & MAGIC_MIME_TYPE) && +- file_printf(ms, "inode/symlink") +- == -1) +- return -1; +- else if (!mime) { +- if (ms->flags & MAGIC_ERROR) { +- file_error(ms, err, +- "broken symbolic link to `%s'", buf); +- return -1; +- } +- if (file_printf(ms, "broken symbolic link to `%s'", buf) == -1) +- return -1; +- } +- return 1; +-} ++ ++#ifdef PHP_WIN32 ++ ++# undef S_IFIFO + #endif ++ ++ ++#ifndef S_ISDIR ++#define S_ISDIR(mode) ((mode) & _S_IFDIR) ++#endif ++ ++#ifndef S_ISREG ++#define S_ISREG(mode) ((mode) & _S_IFREG) ++#endif ++ + private int + handle_mime(struct magic_set *ms, int mime, const char *str) + { +@@ -96,42 +90,36 @@ + } + + protected int +-file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) ++file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream *stream) + { +- int ret = 0; + int mime = ms->flags & MAGIC_MIME; +-#ifdef S_IFLNK +- char buf[BUFSIZ+4]; +- ssize_t nch; +- struct stat tstatbuf; +-#endif ++ TSRMLS_FETCH(); + + if (ms->flags & MAGIC_APPLE) + return 0; +- if (fn == NULL) ++ ++ if (!fn && !stream) { + return 0; ++ } + +- /* +- * Fstat is cheaper but fails for files you don't have read perms on. +- * On 4.2BSD and similar systems, use lstat() to identify symlinks. +- */ +-#ifdef S_IFLNK +- if ((ms->flags & MAGIC_SYMLINK) == 0) +- ret = lstat(fn, sb); +- else +-#endif +- ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ +- +- if (ret) { +- if (ms->flags & MAGIC_ERROR) { +- file_error(ms, errno, "cannot stat `%s'", fn); +- return -1; ++ if (stream) { ++ php_stream_statbuf ssb; ++ if (php_stream_stat(stream, &ssb) < 0) { ++ if (ms->flags & MAGIC_ERROR) { ++ file_error(ms, errno, "cannot stat `%s'", fn); ++ return -1; ++ } ++ return 1; ++ } ++ memcpy(sb, &ssb.sb, sizeof(struct stat)); ++ } else { ++ if (php_sys_stat(fn, sb) != 0) { ++ if (ms->flags & MAGIC_ERROR) { ++ file_error(ms, errno, "cannot stat `%s'", fn); ++ return -1; ++ } ++ return 1; + } +- if (file_printf(ms, "cannot open `%s' (%s)", +- fn, strerror(errno)) == -1) +- return -1; +- ms->event_flags |= EVENT_HAD_ERR; +- return -1; + } + + if (!mime) { +@@ -153,77 +141,42 @@ + } + + switch (sb->st_mode & S_IFMT) { +- case S_IFDIR: +- if (mime) { +- if (handle_mime(ms, mime, "directory") == -1) +- return -1; +- } else if (file_printf(ms, "directory") == -1) +- return -1; +- return 1; +-#ifdef S_IFCHR +- case S_IFCHR: +- /* +- * If -s has been specified, treat character special files +- * like ordinary files. Otherwise, just report that they +- * are block special files and go on to the next file. +- */ +- if ((ms->flags & MAGIC_DEVICES) != 0) +- break; +- if (mime) { +- if (handle_mime(ms, mime, "chardevice") == -1) +- return -1; +- } 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), +- 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) +- return -1; +-# endif +-#else +- if (file_printf(ms, "character special") == -1) +- return -1; +-#endif +- } +- return 1; +-#endif +-#ifdef S_IFBLK +- case S_IFBLK: +- /* +- * If -s has been specified, treat block special files +- * like ordinary files. Otherwise, just report that they +- * are block special files and go on to the next file. +- */ +- if ((ms->flags & MAGIC_DEVICES) != 0) +- break; +- if (mime) { +- if (handle_mime(ms, mime, "blockdevice") == -1) +- return -1; +- } else { +-#ifdef HAVE_STAT_ST_RDEV +-# ifdef dv_unit +- if (file_printf(ms, "block special (%d/%d/%d)", +- major(sb->st_rdev), dv_unit(sb->st_rdev), +- dv_subunit(sb->st_rdev)) == -1) +- return -1; +-# else +- if (file_printf(ms, "block special (%ld/%ld)", +- (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1) +- return -1; ++#ifndef PHP_WIN32 ++# ifdef S_IFCHR ++ case S_IFCHR: ++ /* ++ * If -s has been specified, treat character special files ++ * like ordinary files. Otherwise, just report that they ++ * are block special files and go on to the next file. ++ */ ++ if ((ms->flags & MAGIC_DEVICES) != 0) { ++ break; ++ } ++ if (mime) { ++ if (handle_mime(ms, mime, "x-character-device") == -1) ++ return -1; ++ } 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), ++ 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) ++ return -1; ++# endif ++# else ++ if (file_printf(ms, "character special") == -1) ++ return -1; ++# endif ++ } ++ return 1; + # endif +-#else +- if (file_printf(ms, "block special") == -1) +- return -1; + #endif +- } +- return 1; +-#endif +- /* TODO add code to handle V7 MUX and Blit MUX files */ ++ + #ifdef S_IFIFO + case S_IFIFO: + if((ms->flags & MAGIC_DEVICES) != 0) +@@ -246,77 +199,14 @@ + #endif + #ifdef S_IFLNK + case S_IFLNK: +- if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { ++ /* stat is used, if it made here then the link is broken */ + if (ms->flags & MAGIC_ERROR) { +- file_error(ms, errno, "unreadable symlink `%s'", +- fn); ++ file_error(ms, errno, "unreadable symlink `%s'", fn); + return -1; + } +- if (mime) { +- if (handle_mime(ms, mime, "symlink") == -1) +- return -1; +- } else if (file_printf(ms, +- "unreadable symlink `%s' (%s)", fn, +- strerror(errno)) == -1) +- return -1; +- return 1; +- } +- buf[nch] = '\0'; /* readlink(2) does not do this */ +- +- /* If broken symlink, say so and quit early. */ +- if (*buf == '/') { +- if (stat(buf, &tstatbuf) < 0) +- return bad_link(ms, errno, buf); +- } else { +- char *tmp; +- char buf2[BUFSIZ+BUFSIZ+4]; +- +- if ((tmp = strrchr(fn, '/')) == NULL) { +- tmp = buf; /* in current directory anyway */ +- } else { +- if (tmp - fn + 1 > BUFSIZ) { +- if (ms->flags & MAGIC_ERROR) { +- file_error(ms, 0, +- "path too long: `%s'", buf); +- return -1; +- } +- if (mime) { +- if (handle_mime(ms, mime, +- "x-path-too-long") == -1) +- return -1; +- } else if (file_printf(ms, +- "path too long: `%s'", fn) == -1) +- return -1; +- return 1; +- } +- /* take dir part */ +- (void)strlcpy(buf2, fn, sizeof buf2); +- buf2[tmp - fn + 1] = '\0'; +- /* plus (rel) link */ +- (void)strlcat(buf2, buf, sizeof buf2); +- tmp = buf2; +- } +- if (stat(tmp, &tstatbuf) < 0) +- return bad_link(ms, errno, buf); +- } +- +- /* Otherwise, handle it. */ +- if ((ms->flags & MAGIC_SYMLINK) != 0) { +- const char *p; +- ms->flags &= MAGIC_SYMLINK; +- p = magic_file(ms, buf); +- ms->flags |= MAGIC_SYMLINK; +- return p != NULL ? 1 : -1; +- } else { /* just print what it points to */ +- if (mime) { +- if (handle_mime(ms, mime, "symlink") == -1) +- return -1; +- } else if (file_printf(ms, "symbolic link to `%s'", +- buf) == -1) +- return -1; +- } +- return 1; ++ return 1; + #endif ++ + #ifdef S_IFSOCK + #ifndef __COHERENT__ + case S_IFSOCK: +@@ -328,12 +218,14 @@ + return 1; + #endif + #endif +- case S_IFREG: +- break; +- default: +- file_error(ms, 0, "invalid mode 0%o", sb->st_mode); +- return -1; +- /*NOTREACHED*/ ++ ++ case S_IFREG: ++ break; ++ ++ default: ++ file_error(ms, 0, "invalid mode 0%o", sb->st_mode); ++ return -1; ++ /*NOTREACHED*/ + } + + /* +diff -u libmagic.orig/funcs.c libmagic/funcs.c +--- libmagic.orig/funcs.c Sat Dec 17 18:17:18 2011 ++++ libmagic/funcs.c Mon Apr 23 17:58:54 2012 +@@ -41,52 +41,42 @@ + #if defined(HAVE_WCTYPE_H) + #include <wctype.h> + #endif +-#if defined(HAVE_LIMITS_H) +-#include <limits.h> ++ ++#ifndef SIZE_MAX ++# define SIZE_MAX ((size_t) -1) + #endif + +-#ifndef SIZE_MAX +-#define SIZE_MAX ((size_t)~0) ++#ifndef PREG_OFFSET_CAPTURE ++# define PREG_OFFSET_CAPTURE (1<<8) + #endif + ++extern public void convert_libmagic_pattern(zval *pattern, int options); ++ + /* + * Like printf, only we append to a buffer. + */ + protected int +-file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) ++file_printf(struct magic_set *ms, const char *fmt, ...) + { ++ va_list ap; + int len; +- char *buf, *newstr; ++ char *buf = NULL, *newstr; + +- len = vasprintf(&buf, fmt, ap); +- if (len < 0) +- goto out; ++ va_start(ap, fmt); ++ len = vspprintf(&buf, 0, fmt, ap); ++ va_end(ap); + + if (ms->o.buf != NULL) { +- len = asprintf(&newstr, "%s%s", ms->o.buf, buf); +- free(buf); +- if (len < 0) +- goto out; +- free(ms->o.buf); +- buf = newstr; ++ len = spprintf(&newstr, 0, "%s%s", ms->o.buf, (buf ? buf : "")); ++ if (buf) { ++ efree(buf); ++ } ++ efree(ms->o.buf); ++ ms->o.buf = newstr; ++ } else { ++ ms->o.buf = buf; + } +- ms->o.buf = buf; + return 0; +-out: +- file_error(ms, errno, "vasprintf failed"); +- return -1; +-} +- +-protected int +-file_printf(struct magic_set *ms, const char *fmt, ...) +-{ +- int rv; +- va_list ap; +- +- va_start(ap, fmt); +- rv = file_vprintf(ms, fmt, ap); +- va_end(ap); +- return rv; + } + + /* +@@ -97,17 +87,30 @@ + file_error_core(struct magic_set *ms, int error, const char *f, va_list va, + size_t lineno) + { ++ char *buf = NULL; ++ + /* Only the first error is ok */ + if (ms->event_flags & EVENT_HAD_ERR) + return; + if (lineno != 0) { +- free(ms->o.buf); ++ efree(ms->o.buf); + ms->o.buf = NULL; + file_printf(ms, "line %" SIZE_T_FORMAT "u: ", lineno); + } +- file_vprintf(ms, f, va); +- if (error > 0) +- file_printf(ms, " (%s)", strerror(error)); ++ ++ vspprintf(&buf, 0, f, va); ++ va_end(va); ++ ++ if (error > 0) { ++ file_printf(ms, "%s (%s)", (*buf ? buf : ""), strerror(error)); ++ } else if (*buf) { ++ file_printf(ms, "%s", buf); ++ } ++ ++ if (buf) { ++ efree(buf); ++ } ++ + ms->event_flags |= EVENT_HAD_ERR; + ms->error = error; + } +@@ -154,10 +157,9 @@ + file_error(ms, errno, "error reading"); + } + +-#ifndef COMPILE_ONLY + protected int +-file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unused)), +- const void *buf, size_t nb) ++file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const void *buf, ++ size_t nb) + { + int m = 0, rv = 0, looks_text = 0; + int mime = ms->flags & MAGIC_MIME; +@@ -189,7 +191,7 @@ + &code, &code_mime, &type); + } + +-#ifdef __EMX__ ++#if defined(__EMX__) + if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) { + switch (file_os2_apptype(ms, inname, buf, nb)) { + case -1: +@@ -201,10 +203,10 @@ + } + } + #endif +-#if HAVE_FORK +- /* try compression stuff */ ++ ++#if PHP_FILEINFO_UNCOMPRESS + if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) +- if ((m = file_zmagic(ms, fd, inname, ubuf, nb)) != 0) { ++ if ((m = file_zmagic(ms, stream, inname, ubuf, nb)) != 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + (void)fprintf(stderr, "zmagic %d\n", m); + goto done; +@@ -219,12 +221,17 @@ + } + + /* Check if we have a CDF file */ +- if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) +- if ((m = file_trycdf(ms, fd, ubuf, nb)) != 0) { +- if ((ms->flags & MAGIC_DEBUG) != 0) +- (void)fprintf(stderr, "cdf %d\n", m); +- goto done; ++ if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) { ++ int fd; ++ TSRMLS_FETCH(); ++ if (stream && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, 0)) { ++ if ((m = file_trycdf(ms, fd, ubuf, nb)) != 0) { ++ if ((ms->flags & MAGIC_DEBUG) != 0) ++ (void)fprintf(stderr, "cdf %d\n", m); ++ goto done; ++ } + } ++ } + + /* try soft magic tests */ + if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) +@@ -296,7 +303,6 @@ + + return m; + } +-#endif + + protected int + file_reset(struct magic_set *ms) +@@ -306,11 +312,11 @@ + return -1; + } + if (ms->o.buf) { +- free(ms->o.buf); ++ efree(ms->o.buf); + ms->o.buf = NULL; + } + if (ms->o.pbuf) { +- free(ms->o.pbuf); ++ efree(ms->o.pbuf); + ms->o.pbuf = NULL; + } + ms->event_flags &= ~EVENT_HAD_ERR; +@@ -344,14 +350,10 @@ + /* * 4 is for octal representation, + 1 is for NUL */ + len = strlen(ms->o.buf); + if (len > (SIZE_MAX - 1) / 4) { +- file_oomem(ms, len); + return NULL; + } + psize = len * 4 + 1; +- if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) { +- file_oomem(ms, psize); +- return NULL; +- } ++ pbuf = erealloc(ms->o.pbuf, psize); + ms->o.pbuf = pbuf; + + #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) +@@ -411,13 +413,7 @@ + + if (level >= ms->c.len) { + len = (ms->c.len += 20) * sizeof(*ms->c.li); +- ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? +- malloc(len) : +- realloc(ms->c.li, len)); +- if (ms->c.li == NULL) { +- file_oomem(ms, len); +- return -1; +- } ++ ms->c.li = (ms->c.li == NULL) ? emalloc(len) : erealloc(ms->c.li, len); + } + ms->c.li[level].got_match = 0; + #ifdef ENABLE_CONDITIONALS +@@ -433,29 +429,51 @@ + return ms->o.buf == NULL ? 0 : strlen(ms->o.buf); + } + +-protected int ++ ++protected int + file_replace(struct magic_set *ms, const char *pat, const char *rep) + { +- regex_t rx; +- int rc; ++ zval *patt; ++ int opts = 0; ++ pcre_cache_entry *pce; ++ char *res; ++ zval *repl; ++ int res_len, rep_cnt = 0; ++ TSRMLS_FETCH(); ++ ++ MAKE_STD_ZVAL(patt); ++ 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; ++ } ++ ++ MAKE_STD_ZVAL(repl); ++ ZVAL_STRINGL(repl, rep, strlen(rep), 0); + +- rc = regcomp(&rx, pat, REG_EXTENDED); +- if (rc) { +- char errmsg[512]; +- (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); +- file_magerror(ms, "regex error %d, (%s)", rc, errmsg); ++ res = php_pcre_replace_impl(pce, ms->o.buf, strlen(ms->o.buf), repl, ++ 0, &res_len, -1, &rep_cnt TSRMLS_CC); ++ ++ FREE_ZVAL(repl); ++ zval_dtor(patt); ++ FREE_ZVAL(patt); ++ ++ if (NULL == res) { + return -1; +- } else { +- regmatch_t rm; +- int nm = 0; +- while (regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) { +- ms->o.buf[rm.rm_so] = '\0'; +- if (file_printf(ms, "%s%s", rep, +- rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) +- return -1; +- nm++; +- } +- regfree(&rx); +- return nm; + } ++ ++ strncpy(ms->o.buf, res, res_len); ++ ms->o.buf[res_len] = '\0'; ++ ++ efree(res); ++ ++ return rep_cnt; + } ++ +diff -u libmagic.orig/magic.c libmagic/magic.c +--- libmagic.orig/magic.c Thu May 26 03:27:59 2011 ++++ libmagic/magic.c Tue Apr 10 09:46:34 2012 +@@ -25,11 +25,6 @@ + * SUCH DAMAGE. + */ + +-#ifdef WIN32 +-#include <windows.h> +-#include <shlwapi.h> +-#endif +- + #include "file.h" + + #ifndef lint +@@ -39,15 +34,24 @@ + #include "magic.h" + + #include <stdlib.h> ++#ifdef PHP_WIN32 ++#include "win32/unistd.h" ++#else + #include <unistd.h> ++#endif + #include <string.h> +-#ifdef QUICK +-#include <sys/mman.h> ++#ifdef PHP_WIN32 ++# include "config.w32.h" ++#else ++# include "php_config.h" + #endif +-#ifdef HAVE_LIMITS_H +-#include <limits.h> /* for PIPE_BUF */ ++ ++#ifdef PHP_WIN32 ++#include <shlwapi.h> + #endif + ++#include <limits.h> /* for PIPE_BUF */ ++ + #if defined(HAVE_UTIMES) + # include <sys/time.h> + #elif defined(HAVE_UTIME) +@@ -71,19 +75,24 @@ + #endif + #endif + ++#ifdef PHP_WIN32 ++# undef S_IFLNK ++# undef S_IFIFO ++#endif ++ + private void free_mlist(struct mlist *); + private void close_and_restore(const struct magic_set *, const char *, int, + const struct stat *); + private int unreadable_info(struct magic_set *, mode_t, const char *); + private const char* get_default_magic(void); +-#ifndef COMPILE_ONLY +-private const char *file_or_fd(struct magic_set *, const char *, int); +-#endif ++private const char *file_or_stream(struct magic_set *, const char *, php_stream *); + + #ifndef STDIN_FILENO + #define STDIN_FILENO 0 + #endif + ++/* XXX this functionality is excluded in php, enable it in apprentice.c:340 */ ++#if 0 + private const char * + get_default_magic(void) + { +@@ -91,7 +100,7 @@ + static char *default_magic; + char *home, *hmagicpath; + +-#ifndef WIN32 ++#ifndef PHP_WIN32 + struct stat st; + + if (default_magic) { +@@ -124,6 +133,7 @@ + #else + char *hmagicp = hmagicpath; + char *tmppath = NULL; ++ LPTSTR dllpath; + + #define APPENDPATH() \ + do { \ +@@ -168,7 +178,7 @@ + } + + /* Third, try to get magic file relative to dll location */ +- LPTSTR dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1)); ++ dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1)); + dllpath[MAX_PATH] = 0; /* just in case long path gets truncated and not null terminated */ + if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){ + PathRemoveFileSpecA(dllpath); +@@ -206,16 +216,14 @@ + + return action == FILE_LOAD ? get_default_magic() : MAGIC; + } ++#endif + + public struct magic_set * + magic_open(int flags) + { + struct magic_set *ms; +- size_t len; + +- if ((ms = CAST(struct magic_set *, calloc((size_t)1, +- sizeof(struct magic_set)))) == NULL) +- return NULL; ++ ms = ecalloc((size_t)1, sizeof(struct magic_set)); + + if (magic_setflags(ms, flags) == -1) { + errno = EINVAL; +@@ -223,11 +231,9 @@ + } + + ms->o.buf = ms->o.pbuf = NULL; +- len = (ms->c.len = 10) * sizeof(*ms->c.li); +- +- if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) +- goto free; + ++ ms->c.li = emalloc((ms->c.len = 10) * sizeof(*ms->c.li)); ++ + ms->event_flags = 0; + ms->error = -1; + ms->mlist = NULL; +@@ -235,7 +241,7 @@ + ms->line = 0; + return ms; + free: +- free(ms); ++ efree(ms); + return NULL; + } + +@@ -251,10 +257,10 @@ + struct mlist *next = ml->next; + struct magic *mg = ml->magic; + file_delmagic(mg, ml->mapped, ml->nmagic); +- free(ml); ++ efree(ml); + ml = next; + } +- free(ml); ++ efree(ml); + } + + private int +@@ -278,11 +284,19 @@ + public void + magic_close(struct magic_set *ms) + { +- free_mlist(ms->mlist); +- free(ms->o.pbuf); +- free(ms->o.buf); +- free(ms->c.li); +- free(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); + } + + /* +@@ -308,13 +322,6 @@ + return ml ? 0 : -1; + } + +-public int +-magic_check(struct magic_set *ms, const char *magicfile) +-{ +- struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); +- free_mlist(ml); +- return ml ? 0 : -1; +-} + + public int + magic_list(struct magic_set *ms, const char *magicfile) +@@ -328,9 +335,6 @@ + close_and_restore(const struct magic_set *ms, const char *name, int fd, + const struct stat *sb) + { +- if (fd == STDIN_FILENO) +- return; +- (void) close(fd); + + if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { + /* +@@ -357,7 +361,6 @@ + } + } + +-#ifndef COMPILE_ONLY + + /* + * find type of descriptor +@@ -365,7 +368,7 @@ + public const char * + magic_descriptor(struct magic_set *ms, int fd) + { +- return file_or_fd(ms, NULL, fd); ++ return file_or_stream(ms, NULL, NULL); + } + + /* +@@ -374,30 +377,40 @@ + public const char * + magic_file(struct magic_set *ms, const char *inname) + { +- return file_or_fd(ms, inname, STDIN_FILENO); ++ return file_or_stream(ms, inname, NULL); ++} ++ ++public const char * ++magic_stream(struct magic_set *ms, php_stream *stream) ++{ ++ return file_or_stream(ms, NULL, stream); + } + + private const char * +-file_or_fd(struct magic_set *ms, const char *inname, int fd) ++file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream) + { + int rv = -1; + unsigned char *buf; + struct stat sb; + ssize_t nbytes = 0; /* number of bytes read from a datafile */ +- int ispipe = 0; ++ int no_in_stream = 0; ++ TSRMLS_FETCH(); ++ ++ if (!inname && !stream) { ++ return NULL; ++ } + + /* + * one extra for terminating '\0', and + * some overlapping space for matches near EOF + */ + #define SLOP (1 + sizeof(union VALUETYPE)) +- if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL) +- return NULL; ++ buf = emalloc(HOWMANY + SLOP); + + if (file_reset(ms) == -1) + goto done; + +- switch (file_fsmagic(ms, inname, &sb)) { ++ switch (file_fsmagic(ms, inname, &sb, stream)) { + case -1: /* error */ + goto done; + case 0: /* nothing found */ +@@ -407,68 +420,48 @@ + goto done; + } + +- if (inname == NULL) { +- if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) +- ispipe = 1; +- } else { +- int flags = O_RDONLY|O_BINARY; ++ errno = 0; + +- if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) { +-#ifdef O_NONBLOCK +- flags |= O_NONBLOCK; ++ if (!stream && inname) { ++ no_in_stream = 1; ++#if PHP_API_VERSION < 20100412 ++ stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); ++#else ++ stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL); + #endif +- ispipe = 1; +- } ++ } + +- errno = 0; +- if ((fd = open(inname, flags)) < 0) { +- if (unreadable_info(ms, sb.st_mode, inname) == -1) +- goto done; +- rv = 0; ++ if (!stream) { ++ if (unreadable_info(ms, sb.st_mode, inname) == -1) + goto done; +- } ++ rv = 0; ++ goto done; ++ } ++ + #ifdef O_NONBLOCK +- if ((flags = fcntl(fd, F_GETFL)) != -1) { +- flags &= ~O_NONBLOCK; +- (void)fcntl(fd, F_SETFL, flags); +- } ++/* we should be already be in non blocking mode for network socket */ + #endif +- } + + /* + * try looking at the first HOWMANY bytes + */ +- if (ispipe) { +- ssize_t r = 0; +- +- while ((r = sread(fd, (void *)&buf[nbytes], +- (size_t)(HOWMANY - nbytes), 1)) > 0) { +- nbytes += r; +- if (r < PIPE_BUF) break; +- } +- +- if (nbytes == 0) { +- /* We can not read it, but we were able to stat it. */ +- if (unreadable_info(ms, sb.st_mode, inname) == -1) +- goto done; +- rv = 0; +- goto done; +- } +- +- } else { +- if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { +- file_error(ms, errno, "cannot read `%s'", inname); +- goto done; +- } ++ if ((nbytes = php_stream_read(stream, (char *)buf, HOWMANY)) < 0) { ++ file_error(ms, errno, "cannot read `%s'", inname); ++ goto done; + } + + (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ +- if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1) ++ if (file_buffer(ms, stream, inname, buf, (size_t)nbytes) == -1) + goto done; + rv = 0; + done: +- free(buf); +- close_and_restore(ms, inname, fd, &sb); ++ efree(buf); ++ ++ if (no_in_stream && stream) { ++ php_stream_close(stream); ++ } ++ ++ close_and_restore(ms, inname, 0, &sb); + return rv == 0 ? file_getbuffer(ms) : NULL; + } + +@@ -480,14 +473,13 @@ + return NULL; + /* + * The main work is done here! +- * We have the file name and/or the data buffer to be identified. ++ * We have the file name and/or the data buffer to be identified. + */ +- if (file_buffer(ms, -1, NULL, buf, nb) == -1) { ++ if (file_buffer(ms, NULL, NULL, buf, nb) == -1) { + return NULL; + } + return file_getbuffer(ms); + } +-#endif + + public const char * + magic_error(struct magic_set *ms) +diff -u libmagic.orig/magic.h libmagic/magic.h +--- libmagic.orig/magic.h Sun Dec 18 15:54:43 2011 ++++ libmagic/magic.h Tue Apr 10 09:46:34 2012 +@@ -85,6 +85,7 @@ + + const char *magic_getpath(const char *, int); + const char *magic_file(magic_t, const char *); ++const char *magic_stream(magic_t, php_stream *); + const char *magic_descriptor(magic_t, int); + const char *magic_buffer(magic_t, const void *, size_t); + +@@ -93,7 +94,6 @@ + + int magic_load(magic_t, const char *); + int magic_compile(magic_t, const char *); +-int magic_check(magic_t, const char *); + int magic_list(magic_t, const char *); + int magic_errno(magic_t); + +diff -u libmagic.orig/print.c libmagic/print.c +--- libmagic.orig/print.c Tue Sep 20 17:28:09 2011 ++++ libmagic/print.c Tue Nov 27 16:34:56 2012 +@@ -29,12 +29,16 @@ + * print.c - debugging printout routines + */ + ++#define _GNU_SOURCE ++#include "php.h" ++ + #include "file.h" + + #ifndef lint + FILE_RCSID("@(#)$File: print.c,v 1.71 2011/09/20 15:28:09 christos Exp $") + #endif /* lint */ + ++#include <stdio.h> + #include <string.h> + #include <stdarg.h> + #include <stdlib.h> +@@ -45,174 +49,21 @@ + + #define SZOF(a) (sizeof(a) / sizeof(a[0])) + +-#ifndef COMPILE_ONLY +-protected void +-file_mdump(struct magic *m) +-{ +- private const char optyp[] = { FILE_OPS }; +- +- (void) fprintf(stderr, "%u: %.*s %u", m->lineno, +- (m->cont_level & 7) + 1, ">>>>>>>>", m->offset); +- +- if (m->flag & INDIR) { +- (void) fprintf(stderr, "(%s,", +- /* Note: type is unsigned */ +- (m->in_type < file_nnames) ? +- file_names[m->in_type] : "*bad*"); +- if (m->in_op & FILE_OPINVERSE) +- (void) fputc('~', stderr); +- (void) fprintf(stderr, "%c%u),", +- ((size_t)(m->in_op & FILE_OPS_MASK) < +- SZOF(optyp)) ? +- optyp[m->in_op & FILE_OPS_MASK] : '?', +- m->in_offset); +- } +- (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "", +- /* Note: type is unsigned */ +- (m->type < file_nnames) ? file_names[m->type] : "*bad*"); +- if (m->mask_op & FILE_OPINVERSE) +- (void) fputc('~', stderr); +- +- if (IS_STRING(m->type)) { +- if (m->str_flags) { +- (void) fputc('/', stderr); +- if (m->str_flags & STRING_COMPACT_WHITESPACE) +- (void) fputc(CHAR_COMPACT_WHITESPACE, stderr); +- if (m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) +- (void) fputc(CHAR_COMPACT_OPTIONAL_WHITESPACE, +- stderr); +- if (m->str_flags & STRING_IGNORE_LOWERCASE) +- (void) fputc(CHAR_IGNORE_LOWERCASE, stderr); +- if (m->str_flags & STRING_IGNORE_UPPERCASE) +- (void) fputc(CHAR_IGNORE_UPPERCASE, stderr); +- if (m->str_flags & REGEX_OFFSET_START) +- (void) fputc(CHAR_REGEX_OFFSET_START, stderr); +- if (m->str_flags & STRING_TEXTTEST) +- (void) fputc(CHAR_TEXTTEST, stderr); +- if (m->str_flags & STRING_BINTEST) +- (void) fputc(CHAR_BINTEST, stderr); +- if (m->str_flags & PSTRING_1_BE) +- (void) fputc(CHAR_PSTRING_1_BE, stderr); +- if (m->str_flags & PSTRING_2_BE) +- (void) fputc(CHAR_PSTRING_2_BE, stderr); +- if (m->str_flags & PSTRING_2_LE) +- (void) fputc(CHAR_PSTRING_2_LE, stderr); +- if (m->str_flags & PSTRING_4_BE) +- (void) fputc(CHAR_PSTRING_4_BE, stderr); +- if (m->str_flags & PSTRING_4_LE) +- (void) fputc(CHAR_PSTRING_4_LE, stderr); +- if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) +- (void) fputc( +- CHAR_PSTRING_LENGTH_INCLUDES_ITSELF, +- stderr); +- } +- if (m->str_range) +- (void) fprintf(stderr, "/%u", m->str_range); +- } +- else { +- if ((size_t)(m->mask_op & FILE_OPS_MASK) < SZOF(optyp)) +- (void) fputc(optyp[m->mask_op & FILE_OPS_MASK], stderr); +- else +- (void) fputc('?', stderr); +- +- if (m->num_mask) { +- (void) fprintf(stderr, "%.8llx", +- (unsigned long long)m->num_mask); +- } +- } +- (void) fprintf(stderr, ",%c", m->reln); +- +- if (m->reln != 'x') { +- switch (m->type) { +- case FILE_BYTE: +- case FILE_SHORT: +- case FILE_LONG: +- case FILE_LESHORT: +- case FILE_LELONG: +- case FILE_MELONG: +- case FILE_BESHORT: +- case FILE_BELONG: +- (void) fprintf(stderr, "%d", m->value.l); +- break; +- case FILE_BEQUAD: +- case FILE_LEQUAD: +- case FILE_QUAD: +- (void) fprintf(stderr, "%" INT64_T_FORMAT "d", +- (unsigned long long)m->value.q); +- break; +- case FILE_PSTRING: +- case FILE_STRING: +- case FILE_REGEX: +- case FILE_BESTRING16: +- case FILE_LESTRING16: +- case FILE_SEARCH: +- file_showstr(stderr, m->value.s, (size_t)m->vallen); +- break; +- case FILE_DATE: +- case FILE_LEDATE: +- case FILE_BEDATE: +- case FILE_MEDATE: +- (void)fprintf(stderr, "%s,", +- file_fmttime(m->value.l, 1)); +- break; +- case FILE_LDATE: +- case FILE_LELDATE: +- case FILE_BELDATE: +- case FILE_MELDATE: +- (void)fprintf(stderr, "%s,", +- file_fmttime(m->value.l, 0)); +- break; +- case FILE_QDATE: +- case FILE_LEQDATE: +- case FILE_BEQDATE: +- (void)fprintf(stderr, "%s,", +- file_fmttime((uint32_t)m->value.q, 1)); +- break; +- case FILE_QLDATE: +- case FILE_LEQLDATE: +- case FILE_BEQLDATE: +- (void)fprintf(stderr, "%s,", +- file_fmttime((uint32_t)m->value.q, 0)); +- break; +- case FILE_FLOAT: +- case FILE_BEFLOAT: +- case FILE_LEFLOAT: +- (void) fprintf(stderr, "%G", m->value.f); +- break; +- case FILE_DOUBLE: +- case FILE_BEDOUBLE: +- case FILE_LEDOUBLE: +- (void) fprintf(stderr, "%G", m->value.d); +- break; +- case FILE_DEFAULT: +- /* XXX - do anything here? */ +- break; +- default: +- (void) fputs("*bad*", stderr); +- break; +- } +- } +- (void) fprintf(stderr, ",\"%s\"]\n", m->desc); +-} +-#endif +- + /*VARARGS*/ + protected void + file_magwarn(struct magic_set *ms, const char *f, ...) + { + va_list va; ++ char *expanded_format; ++ TSRMLS_FETCH(); + +- /* cuz we use stdout for most, stderr here */ +- (void) fflush(stdout); +- +- if (ms->file) +- (void) fprintf(stderr, "%s, %lu: ", ms->file, +- (unsigned long)ms->line); +- (void) fprintf(stderr, "Warning: "); + va_start(va, f); +- (void) vfprintf(stderr, f, va); ++ vasprintf(&expanded_format, f, va); + va_end(va); +- (void) fputc('\n', stderr); ++ ++ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Warning: %s", expanded_format); ++ ++ free(expanded_format); + } + + protected const char * +diff -u libmagic.orig/readcdf.c libmagic/readcdf.c +--- libmagic.orig/readcdf.c Mon Feb 20 21:04:58 2012 ++++ libmagic/readcdf.c Tue Apr 10 09:46:34 2012 +@@ -30,7 +30,11 @@ + #endif + + #include <stdlib.h> ++#ifdef PHP_WIN32 ++#include "win32/unistd.h" ++#else + #include <unistd.h> ++#endif + #include <string.h> + #include <time.h> + #include <ctype.h> +@@ -46,7 +50,7 @@ + { + size_t i; + cdf_timestamp_t tp; +- struct timespec ts; ++ struct timeval ts; + char buf[64]; + const char *str = NULL; + const char *s; +@@ -125,7 +129,11 @@ + case CDF_FILETIME: + tp = info[i].pi_tp; + if (tp != 0) { +- if (tp < 1000000000000000LL) { ++#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); +@@ -134,7 +142,9 @@ + return -1; + } else { + char *c, *ec; +- cdf_timestamp_to_timespec(&ts, tp); ++ if (cdf_timestamp_to_timespec(&ts, tp) == -1) { ++ return -1; ++ } + c = cdf_ctime(&ts.tv_sec); + if ((ec = strchr(c, '\n')) != NULL) + *ec = '\0'; +diff -u libmagic.orig/readelf.c libmagic/readelf.c +--- libmagic.orig/readelf.c Tue Aug 23 10:57:10 2011 ++++ libmagic/readelf.c Tue Apr 10 09:46:34 2012 +@@ -49,7 +49,7 @@ + off_t, int *, int); + private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, + off_t, int *, int); +-private size_t donote(struct magic_set *, void *, size_t, size_t, int, ++private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, + int, size_t, int *); + + #define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) +@@ -309,11 +309,11 @@ + * Loop through all the program headers. + */ + for ( ; num; num--) { +- if (lseek(fd, off, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } +- if (read(fd, xph_addr, xph_sizeof) == -1) { ++ if (FINFO_READ_FUNC(fd, xph_addr, xph_sizeof) == -1) { + file_badread(ms); + return -1; + } +@@ -331,11 +331,11 @@ + * This is a PT_NOTE section; loop through all the notes + * in the section. + */ +- if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, xph_offset, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } +- bufsize = read(fd, nbuf, ++ bufsize = FINFO_READ_FUNC(fd, nbuf, + ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); + if (bufsize == -1) { + file_badread(ms); +@@ -357,7 +357,7 @@ + #endif + + private size_t +-donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, ++donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, + int clazz, int swap, size_t align, int *flags) + { + Elf32_Nhdr nh32; +@@ -367,7 +367,6 @@ + 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; +@@ -859,11 +858,11 @@ + } + + for ( ; num; num--) { +- if (lseek(fd, off, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } +- if (read(fd, xsh_addr, xsh_sizeof) == -1) { ++ if (FINFO_READ_FUNC(fd, xsh_addr, xsh_sizeof) == -1) { + file_badread(ms); + return -1; + } +@@ -888,20 +887,16 @@ + /* Things we can determine when we seek */ + switch (xsh_type) { + case SHT_NOTE: +- if ((nbuf = malloc((size_t)xsh_size)) == NULL) { +- file_error(ms, errno, "Cannot allocate memory" +- " for note"); +- return -1; +- } +- if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == ++ nbuf = emalloc((size_t)xsh_size); ++ if ((noff = FINFO_LSEEK_FUNC(fd, (off_t)xsh_offset, SEEK_SET)) == + (off_t)-1) { + file_badread(ms); +- free(nbuf); ++ efree(nbuf); + return -1; + } +- if (read(fd, nbuf, (size_t)xsh_size) != ++ if (FINFO_READ_FUNC(fd, nbuf, (size_t)xsh_size) != + (ssize_t)xsh_size) { +- free(nbuf); ++ efree(nbuf); + file_badread(ms); + return -1; + } +@@ -916,10 +911,10 @@ + if (noff == 0) + break; + } +- free(nbuf); ++ efree(nbuf); + break; + case SHT_SUNW_cap: +- if (lseek(fd, (off_t)xsh_offset, SEEK_SET) == ++ if (FINFO_LSEEK_FUNC(fd, (off_t)xsh_offset, SEEK_SET) == + (off_t)-1) { + file_badseek(ms); + return -1; +@@ -932,7 +927,7 @@ + MAX(sizeof cap32, sizeof cap64)]; + if ((coff += xcap_sizeof) > (off_t)xsh_size) + break; +- if (read(fd, cbuf, (size_t)xcap_sizeof) != ++ if (FINFO_READ_FUNC(fd, cbuf, (size_t)xcap_sizeof) != + (ssize_t)xcap_sizeof) { + file_badread(ms); + return -1; +@@ -1051,12 +1046,12 @@ + } + + for ( ; num; num--) { +- if (lseek(fd, off, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + +- if (read(fd, xph_addr, xph_sizeof) == -1) { ++ if (FINFO_READ_FUNC(fd, xph_addr, xph_sizeof) == -1) { + file_badread(ms); + return -1; + } +@@ -1095,11 +1090,11 @@ + * This is a PT_NOTE section; loop through all the notes + * in the section. + */ +- if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { ++ if (FINFO_LSEEK_FUNC(fd, xph_offset, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } +- bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? ++ bufsize = FINFO_READ_FUNC(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? + xph_filesz : sizeof(nbuf))); + if (bufsize == -1) { + file_badread(ms); +@@ -1161,7 +1156,7 @@ + /* + * If we cannot seek, it must be a pipe, socket or fifo. + */ +- if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) ++ if((FINFO_LSEEK_FUNC(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) + fd = file_pipe2file(ms, fd, buf, nbytes); + + if (fstat(fd, &st) == -1) { +diff -u libmagic.orig/softmagic.c libmagic/softmagic.c +--- libmagic.orig/softmagic.c Sat Dec 17 18:17:18 2011 ++++ libmagic/softmagic.c Fri May 25 09:59:25 2012 +@@ -41,6 +41,11 @@ + #include <stdlib.h> + #include <time.h> + ++#ifndef PREG_OFFSET_CAPTURE ++# define PREG_OFFSET_CAPTURE (1<<8) ++#endif ++ ++ + + private int match(struct magic_set *, struct magic *, uint32_t, + const unsigned char *, size_t, int, int); +@@ -125,14 +130,14 @@ + int flush = 0; + struct magic *m = &magic[magindex]; + +- if ((IS_STRING(m->type) && ++ 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))) || + (m->flag & mode) != mode) { + /* Skip sub-tests */ +- while (magic[magindex + 1].cont_level != 0 && +- ++magindex < nmagic) +- continue; ++ while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) { ++ magindex++; ++ } + continue; /* Skip to next top-level test*/ + } + +@@ -167,9 +172,9 @@ + * 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; + } + +@@ -196,8 +201,8 @@ + if (file_check_mem(ms, ++cont_level) == -1) + return -1; + +- while (magic[magindex+1].cont_level != 0 && +- ++magindex < nmagic) { ++ while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) { ++ magindex++; + m = &magic[magindex]; + ms->line = m->lineno; /* for messages */ + +@@ -212,8 +217,7 @@ + } + 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 +@@ -318,44 +322,22 @@ + private int + check_fmt(struct magic_set *ms, struct magic *m) + { +- regex_t rx; +- int rc; +- +- if (strchr(m->desc, '%') == NULL) ++ pcre *pce; ++ int re_options; ++ pcre_extra *re_extra; ++ TSRMLS_FETCH(); ++ ++ if (strchr(m->desc, '%') == NULL) { + return 0; +- +- rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); +- if (rc) { +- char errmsg[512]; +- (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); +- file_magerror(ms, "regex error %d, (%s)", rc, errmsg); ++ } ++ ++ if ((pce = pcre_get_compiled_regex("~%[-0-9.]*s~", &re_extra, &re_options TSRMLS_CC)) == NULL) { + return -1; + } else { +- rc = regexec(&rx, m->desc, 0, 0, 0); +- regfree(&rx); +- return !rc; ++ return !pcre_exec(pce, re_extra, m->desc, strlen(m->desc), 0, re_options, NULL, 0); + } + } + +-#ifndef HAVE_STRNDUP +-char * strndup(const char *, size_t); +- +-char * +-strndup(const char *str, size_t n) +-{ +- size_t len; +- char *copy; +- +- for (len = 0; len < n && str[len]; len++) +- continue; +- if ((copy = malloc(len + 1)) == NULL) +- return NULL; +- (void)memcpy(copy, str, len); +- copy[len] = '\0'; +- return copy; +-} +-#endif /* HAVE_STRNDUP */ +- + private int32_t + mprint(struct magic_set *ms, struct magic *m) + { +@@ -538,13 +520,10 @@ + char *cp; + int rval; + +- cp = strndup((const char *)ms->search.s, ms->search.rm_len); +- if (cp == NULL) { +- file_oomem(ms, ms->search.rm_len); +- return -1; +- } ++ cp = estrndup((const char *)ms->search.s, ms->search.rm_len); ++ + rval = file_printf(ms, m->desc, cp); +- free(cp); ++ efree(cp); + + if (rval == -1) + return -1; +@@ -738,16 +717,16 @@ + if (m->num_mask) \ + switch (m->mask_op & FILE_OPS_MASK) { \ + case FILE_OPADD: \ +- p->fld += cast m->num_mask; \ ++ p->fld += cast (int64_t)m->num_mask; \ + break; \ + case FILE_OPMINUS: \ +- p->fld -= cast m->num_mask; \ ++ p->fld -= cast (int64_t)m->num_mask; \ + break; \ + case FILE_OPMULTIPLY: \ +- p->fld *= cast m->num_mask; \ ++ p->fld *= cast (int64_t)m->num_mask; \ + break; \ + case FILE_OPDIVIDE: \ +- p->fld /= cast m->num_mask; \ ++ p->fld /= cast (int64_t)m->num_mask; \ + break; \ + } \ + +@@ -1029,16 +1008,13 @@ + + if ((ms->flags & MAGIC_DEBUG) != 0) { + mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); +-#ifndef COMPILE_ONLY +- file_mdump(m); +-#endif + } + + if (m->flag & INDIR) { + int off = m->in_offset; + if (m->in_op & FILE_OPINDIRECT) { +- const union VALUETYPE *q = CAST(const union VALUETYPE *, +- ((const void *)(s + offset + off))); ++ const union VALUETYPE *q = ++ ((const void *)(s + offset + off)); + switch (m->in_type) { + case FILE_BYTE: + off = q->b; +@@ -1518,9 +1494,6 @@ + if ((ms->flags & MAGIC_DEBUG) != 0) { + mdebug(offset, (char *)(void *)p, + sizeof(union VALUETYPE)); +-#ifndef COMPILE_ONLY +- file_mdump(m); +-#endif + } + } + +@@ -1669,6 +1642,42 @@ + return file_strncmp(a, b, len, flags); + } + ++public void ++convert_libmagic_pattern(zval *pattern, int options) ++{ ++ int i, j=0; ++ char *t; ++ ++ t = (char *) safe_emalloc(Z_STRLEN_P(pattern), 2, 5); ++ ++ t[j++] = '~'; ++ ++ for (i=0; i<Z_STRLEN_P(pattern); i++, j++) { ++ switch (Z_STRVAL_P(pattern)[i]) { ++ case '~': ++ t[j++] = '\\'; ++ t[j] = '~'; ++ break; ++ default: ++ t[j] = Z_STRVAL_P(pattern)[i]; ++ break; ++ } ++ } ++ t[j++] = '~'; ++ ++ if (options & PCRE_CASELESS) ++ t[j++] = 'i'; ++ ++ if (options & PCRE_MULTILINE) ++ t[j++] = 'm'; ++ ++ t[j]='\0'; ++ ++ Z_STRVAL_P(pattern) = t; ++ Z_STRLEN_P(pattern) = j; ++ ++} ++ + private int + magiccheck(struct magic_set *ms, struct magic *m) + { +@@ -1825,67 +1834,163 @@ + break; + } + case FILE_REGEX: { +- int rc; +- regex_t rx; +- char errmsg[512]; +- +- if (ms->search.s == NULL) +- return 0; +- +- l = 0; +- rc = regcomp(&rx, m->value.s, +- REG_EXTENDED|REG_NEWLINE| +- ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); +- if (rc) { +- (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); +- file_magerror(ms, "regex error %d, (%s)", +- rc, errmsg); +- v = (uint64_t)-1; +- } +- else { +- regmatch_t pmatch[1]; +-#ifndef REG_STARTEND +-#define REG_STARTEND 0 +- size_t l = ms->search.s_len - 1; +- char c = ms->search.s[l]; +- ((char *)(intptr_t)ms->search.s)[l] = '\0'; ++ zval *pattern; ++ int options = 0; ++ pcre_cache_entry *pce; ++ TSRMLS_FETCH(); ++ ++ MAKE_STD_ZVAL(pattern); ++ ZVAL_STRINGL(pattern, (char *)m->value.s, m->vallen, 0); ++ ++ options |= PCRE_MULTILINE; ++ ++ if (m->str_flags & STRING_IGNORE_CASE) { ++ options |= PCRE_CASELESS; ++ } ++ ++ 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 +- pmatch[0].rm_so = 0; +- pmatch[0].rm_eo = ms->search.s_len; ++ if ((pce = pcre_get_compiled_regex_cache(IS_STRING, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) { + #endif +- rc = regexec(&rx, (const char *)ms->search.s, +- 1, pmatch, REG_STARTEND); +-#if REG_STARTEND == 0 +- ((char *)(intptr_t)ms->search.s)[l] = c; ++ zval_dtor(pattern); ++ FREE_ZVAL(pattern); ++ return -1; ++ } else { ++ /* pce now contains the compiled regex */ ++ zval *retval; ++ zval *subpats; ++ char *haystack; ++ ++ MAKE_STD_ZVAL(retval); ++ ALLOC_INIT_ZVAL(subpats); ++ ++ /* Cut the search len from haystack, equals to REG_STARTEND */ ++ 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 +- switch (rc) { +- case 0: +- ms->search.s += (int)pmatch[0].rm_so; +- ms->search.offset += (size_t)pmatch[0].rm_so; +- ms->search.rm_len = +- (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so); +- v = 0; +- break; ++ /* Free haystack */ ++ efree(haystack); ++ ++ if (Z_LVAL_P(retval) < 0) { ++ zval_ptr_dtor(&subpats); ++ FREE_ZVAL(retval); ++ zval_dtor(pattern); ++ FREE_ZVAL(pattern); ++ return -1; ++ } else if ((Z_LVAL_P(retval) > 0) && (Z_TYPE_P(subpats) == IS_ARRAY)) { ++ ++ /* Need to fetch global match which equals pmatch[0] */ ++ HashTable *ht = Z_ARRVAL_P(subpats); ++ HashPosition outer_pos; ++ zval *pattern_match = NULL, *pattern_offset = NULL; ++ ++ zend_hash_internal_pointer_reset_ex(ht, &outer_pos); ++ ++ if (zend_hash_has_more_elements_ex(ht, &outer_pos) == SUCCESS && ++ zend_hash_move_forward_ex(ht, &outer_pos)) { ++ ++ zval **ppzval; ++ ++ /* The first element (should be) is the global match ++ Need to move to the inner array to get the global match */ ++ ++ if (zend_hash_get_current_data_ex(ht, (void**)&ppzval, &outer_pos) != FAILURE) { ++ ++ HashTable *inner_ht; ++ HashPosition inner_pos; ++ zval **match, **offset; ++ zval tmpcopy = **ppzval, matchcopy, offsetcopy; ++ ++ zval_copy_ctor(&tmpcopy); ++ INIT_PZVAL(&tmpcopy); ++ ++ inner_ht = Z_ARRVAL(tmpcopy); ++ ++ /* If everything goes according to the master plan ++ tmpcopy now contains two elements: ++ 0 = the match ++ 1 = starting position of the match */ ++ zend_hash_internal_pointer_reset_ex(inner_ht, &inner_pos); ++ ++ if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS && ++ zend_hash_move_forward_ex(inner_ht, &inner_pos)) { ++ ++ if (zend_hash_get_current_data_ex(inner_ht, (void**)&match, &inner_pos) != FAILURE) { ++ ++ matchcopy = **match; ++ zval_copy_ctor(&matchcopy); ++ INIT_PZVAL(&matchcopy); ++ convert_to_string(&matchcopy); ++ ++ MAKE_STD_ZVAL(pattern_match); ++ Z_STRVAL_P(pattern_match) = (char *)Z_STRVAL(matchcopy); ++ Z_STRLEN_P(pattern_match) = Z_STRLEN(matchcopy); ++ Z_TYPE_P(pattern_match) = IS_STRING; ++ ++ zval_dtor(&matchcopy); ++ } ++ } ++ ++ if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS && ++ zend_hash_move_forward_ex(inner_ht, &inner_pos)) { ++ ++ if (zend_hash_get_current_data_ex(inner_ht, (void**)&offset, &inner_pos) != FAILURE) { ++ ++ offsetcopy = **offset; ++ zval_copy_ctor(&offsetcopy); ++ INIT_PZVAL(&offsetcopy); ++ convert_to_long(&offsetcopy); ++ ++ MAKE_STD_ZVAL(pattern_offset); ++ Z_LVAL_P(pattern_offset) = Z_LVAL(offsetcopy); ++ Z_TYPE_P(pattern_offset) = IS_LONG; ++ ++ zval_dtor(&offsetcopy); ++ } ++ } ++ zval_dtor(&tmpcopy); ++ } ++ ++ if ((pattern_match != NULL) && (pattern_offset != NULL)) { ++ ms->search.s += (int)Z_LVAL_P(pattern_offset); /* this is where the match starts */ ++ ms->search.offset += (size_t)Z_LVAL_P(pattern_offset); /* this is where the match starts as size_t */ ++ ms->search.rm_len = Z_STRLEN_P(pattern_match) /* This is the length of the matched pattern */; ++ v = 0; ++ ++ efree(pattern_match); ++ efree(pattern_offset); ++ ++ } else { ++ zval_ptr_dtor(&subpats); ++ FREE_ZVAL(retval); ++ zval_dtor(pattern); ++ FREE_ZVAL(pattern); ++ return -1; ++ } ++ } + +- case REG_NOMATCH: ++ ++ } else { + v = 1; +- break; +- +- default: +- (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); +- file_magerror(ms, "regexec error %d, (%s)", +- rc, errmsg); +- v = (uint64_t)-1; +- break; + } +- regfree(&rx); ++ zval_ptr_dtor(&subpats); ++ FREE_ZVAL(retval); + } +- if (v == (uint64_t)-1) +- return -1; +- break; ++ zval_dtor(pattern); ++ FREE_ZVAL(pattern); ++ break; + } + case FILE_INDIRECT: +- return 1; ++ return 1; + default: + file_magerror(ms, "invalid type %d in magiccheck()", m->type); + return -1; |