- use php's stream in libmagic

- remove duplicate code (like mime_content_type() compatibility function
  now use the same base as finfo_file())
- make it portable (works now on windows too, belongs other OSes)

- ([20:28]  <lsmith> Pierre: ok please commit)
This commit is contained in:
Pierre Joye 2008-09-01 18:56:06 +00:00
parent 0f701b8d31
commit 99041160df
10 changed files with 409 additions and 437 deletions

View File

@ -38,6 +38,10 @@
#include "php_fileinfo.h"
#include "fopen_wrappers.h" /* needed for is_url */
#ifndef _S_IFDIR
# define _S_IFDIR S_IFDIR
#endif
/* {{{ macros and type definitions */
struct php_fileinfo {
long options;
@ -405,83 +409,148 @@ PHP_FUNCTION(finfo_set_flags)
}
/* }}} */
static void _php_finfo_get_type(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
#define FILEINFO_MODE_BUFFER 0
#define FILEINFO_MODE_STREAM 1
#define FILEINFO_MODE_FILE 2
static void _php_finfo_get_type(INTERNAL_FUNCTION_PARAMETERS, int mode, int mimetype_emu) /* {{{ */
{
long options = 0;
char *tmp, *ret_val, *buffer = NULL;
char *ret_val = NULL, *buffer = NULL;
int buffer_len;
struct php_fileinfo *finfo;
zval *zfinfo, *zcontext = NULL;
zval *what;
char mime_directory[] = "directory";
struct magic_set *magic = NULL;
FILEINFO_DECLARE_INIT_OBJECT(object)
if (object) {
if (mimetype_emu) {
/* mime_content_type(..) emulation */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &what) == FAILURE) {
return;
}
switch (Z_TYPE_P(what)) {
case IS_STRING:
buffer = Z_STRVAL_P(what);
buffer_len = Z_STRLEN_P(what);
break;
case IS_RESOURCE:
mode = FILEINFO_MODE_STREAM;
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only process string or stream arguments");
RETURN_FALSE;
}
magic = magic_open(MAGIC_MIME);
if (magic_load(magic, NULL) == -1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to load magic database.");
magic_close(magic);
RETURN_FALSE;
}
} else if (object) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr", &buffer, &buffer_len, &options, &zcontext) == FAILURE) {
RETURN_FALSE;
}
FILEINFO_FROM_OBJECT(finfo, object);
magic = finfo->magic;
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lr", &zfinfo, &buffer, &buffer_len, &options, &zcontext) == FAILURE) {
RETURN_FALSE;
}
ZEND_FETCH_RESOURCE(finfo, struct php_fileinfo *, &zfinfo, -1, "file_info", le_fileinfo);
magic = finfo->magic;
}
/* Set options for the current file/buffer. */
if (options) {
FINFO_SET_OPTION(finfo->magic, options)
FINFO_SET_OPTION(magic, options)
}
if (mode) { /* file */
/* determine if the file is a local file or remote URL */
char *tmp2;
php_stream_wrapper *wrap = php_stream_locate_url_wrapper(buffer, &tmp2, 0 TSRMLS_CC);
if (wrap && wrap->is_url) {
#ifdef ZEND_ENGINE_2
php_stream_context *context = php_stream_context_from_zval(zcontext, 0);
#else
php_stream_context *context = NULL;
#endif
php_stream *stream = php_stream_open_wrapper_ex(buffer, "rb",
ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
if (!stream) {
switch (mode) {
case FILEINFO_MODE_BUFFER:
{
ret_val = (char *) magic_buffer(magic, buffer, buffer_len);
break;
}
case FILEINFO_MODE_STREAM:
{
php_stream *stream;
off_t streampos;
php_stream_from_zval_no_verify(stream, &what);
if (!stream) {
goto common;
}
streampos = php_stream_tell(stream); /* remember stream position for restoration */
php_stream_seek(stream, 0, SEEK_SET);
ret_val = (char *) magic_stream(magic, stream);
break;
}
case FILEINFO_MODE_FILE:
{
/* determine if the file is a local file or remote URL */
char *tmp2;
php_stream_wrapper *wrap;
struct stat sb;
if (buffer_len < 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty filename or path");
RETURN_FALSE;
}
buffer_len = php_stream_copy_to_mem(stream, &tmp, HOWMANY, 0);
php_stream_close(stream);
if (buffer_len == 0) {
RETURN_FALSE;
if (php_sys_stat(buffer, &sb) == 0 && (sb.st_mode & _S_IFDIR)) {
ret_val = mime_directory;
goto common;
}
} else { /* local file */
char resolved_path[MAXPATHLEN];
if (*buffer && VCWD_REALPATH(buffer, resolved_path)) {
if ((PG(safe_mode) && (!php_checkuid(resolved_path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(resolved_path TSRMLS_CC)) {
wrap = php_stream_locate_url_wrapper(buffer, &tmp2, 0 TSRMLS_CC);
if (wrap) {
php_stream_context *context = php_stream_context_from_zval(zcontext, 0);
php_stream *stream = php_stream_open_wrapper_ex(buffer, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
if (!stream) {
RETURN_FALSE;
}
ret_val = (char *) magic_file(finfo->magic, resolved_path);
} else {
RETURN_FALSE;
ret_val = magic_stream(magic, stream);
php_stream_close(stream);
}
goto common;
break;
}
} else { /* buffer */
tmp = buffer;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only process string or stream arguments");
RETURN_FALSE;
}
ret_val = (char *) magic_buffer(finfo->magic, tmp, buffer_len);
if (mode) {
efree(tmp);
}
common:
if (mimetype_emu) {
if (magic) {
magic_close(magic);
}
}
/* Restore options */
if (options) {
FINFO_SET_OPTION(finfo->magic, finfo->options)
FINFO_SET_OPTION(magic, finfo->options)
}
if (!ret_val) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed identify data %d:%s",
magic_errno(finfo->magic), magic_error(finfo->magic));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic));
RETURN_FALSE;
} else {
RETURN_STRING(ret_val, 1);
@ -493,7 +562,7 @@ common:
Return information about a file. */
PHP_FUNCTION(finfo_file)
{
_php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
_php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, FILEINFO_MODE_FILE, 0);
}
/* }}} */
@ -501,7 +570,7 @@ PHP_FUNCTION(finfo_file)
Return infromation about a string buffer. */
PHP_FUNCTION(finfo_buffer)
{
_php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
_php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, FILEINFO_MODE_BUFFER, 0);
}
/* }}} */
@ -509,90 +578,7 @@ PHP_FUNCTION(finfo_buffer)
Return content-type for file */
PHP_FUNCTION(mime_content_type)
{
zval *what;
magic_t magic;
char *tmp, *ret_val;
int buffer_len;
char *tmp2;
php_stream_wrapper *wrap;
zval *zcontext = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &what) == FAILURE) {
return;
}
RETVAL_FALSE;
magic = magic_open(MAGIC_MIME);
if (magic_load(magic, NULL) == -1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to load magic database.");
goto cleanup;
}
switch (Z_TYPE_P(what)) {
case IS_STRING:
wrap = php_stream_locate_url_wrapper(Z_STRVAL_P(what), &tmp2, 0 TSRMLS_CC);
/* determine if the file is a local file or remote URL */
if (wrap && wrap->is_url) {
php_stream_context *context = php_stream_context_from_zval(zcontext, 0);
php_stream *stream = php_stream_open_wrapper_ex(Z_STRVAL_P(what), "rb",
ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
if (!stream) {
goto cleanup;
}
buffer_len = php_stream_copy_to_mem(stream, &tmp, 4096, 0);
php_stream_close(stream);
if (buffer_len == 0) {
goto cleanup;
}
ret_val = (char *) magic_buffer(magic, tmp, buffer_len);
} else { /* local file */
char resolved_path[MAXPATHLEN];
if (*Z_STRVAL_P(what) && VCWD_REALPATH(Z_STRVAL_P(what), resolved_path)) {
if ((PG(safe_mode) && (!php_checkuid(resolved_path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(resolved_path TSRMLS_CC)) {
goto cleanup;
}
ret_val = (char *) magic_file(magic, resolved_path);
} else {
goto cleanup;
}
}
break;
case IS_RESOURCE:
{
php_stream *stream;
off_t streampos;
php_stream_from_zval_no_verify(stream, &what);
if (!stream) {
goto cleanup;
}
streampos = php_stream_tell(stream); /* remember stream position for restoration */
php_stream_seek(stream, 0, SEEK_SET);
buffer_len = php_stream_copy_to_mem(stream, &tmp, 4096, 0);
php_stream_seek(stream, streampos, SEEK_SET);
if (buffer_len == 0) {
goto cleanup;
}
ret_val = (char *) magic_buffer(magic, tmp, buffer_len);
}
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only process string or stream arguments");
goto cleanup;
}
if (!ret_val) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed identify data %d:%s",
magic_errno(magic), magic_error(magic));
} else {
RETVAL_STRING(ret_val, 1);
}
cleanup:
magic_close(magic);
_php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1, 1);
}
/* }}} */

View File

@ -29,21 +29,32 @@
* apprentice - make one pass through /etc/magic, learning its secrets.
*/
#include "php.h"
#include "file.h"
#include "magic.h"
#include "patchlevel.h"
#include <stdlib.h>
//#ifdef HAVE_UNISTD_H
#ifdef PHP_WIN32
#include "win32/unistd.h"
#define strtoull _strtoui64
#else
#include <unistd.h>
//#endif
#endif
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef PHP_WIN32
#include <sys/param.h>
#endif
#include <sys/types.h>
#ifndef PHP_WIN32
#include <dirent.h>
#endif
#ifndef lint
FILE_RCSID("@(#)$File: apprentice.c,v 1.132 2008/03/28 18:19:30 christos Exp $")
@ -174,6 +185,10 @@ static const struct type_tbl_s {
# undef XX_NULL
};
#ifndef S_ISDIR
#define S_ISDIR(mode) ((mode) & _S_IFDIR)
#endif
private int
get_type(const char *l, const char **t)
{
@ -528,30 +543,43 @@ private void
load_1(struct magic_set *ms, int action, const char *fn, int *errs,
struct magic_entry **marray, uint32_t *marraycount)
{
char line[BUFSIZ];
char buffer[BUFSIZ + 1];
char *line;
size_t line_len;
size_t lineno = 0;
FILE *f = fopen(ms->file = fn, "r");
if (f == NULL) {
php_stream *stream;
TSRMLS_FETCH();
#if (PHP_MAJOR_VERSION < 6)
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);
(*errs)++;
} else {
/* read and parse this file */
for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
size_t len;
len = strlen(line);
if (len == 0) /* null line, garbage, etc */
for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &line_len)) != NULL; ms->line++) {
if (line_len == 0 || /* null line, garbage, etc */
line[0] == '\0' || /* empty*/
line[0] == '#' || /* comment */
line[0] == '\n' || line[0] == '\r') { /* New Line */
continue;
if (line[len - 1] == '\n') {
lineno++;
line[len - 1] = '\0'; /* delete newline */
}
if (line[0] == '\0') /* empty, do not parse */
continue;
if (line[0] == '#') /* comment, do not parse */
continue;
if (len > mime_marker_len &&
if (line[line_len - 1] == '\n') {
lineno++;
line[line_len - 1] = '\0'; /* delete newline */
}
if (line_len > mime_marker_len &&
memcmp(line, mime_marker, mime_marker_len) == 0) {
/* MIME type */
if (parse_mime(ms, marray, marraycount,
@ -563,7 +591,7 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs,
(*errs)++;
}
(void)fclose(f);
php_stream_close(stream);
}
}
@ -585,7 +613,7 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
maxmagic = MAXMAGIS;
maxmagic = MAXMAGIS;
marray = ecalloc(maxmagic, sizeof(*marray));
marraycount = 0;
@ -594,7 +622,7 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
(void)fprintf(stderr, "%s\n", usg_hdr);
/* load directory or file */
if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
dir = opendir(fn);
if (dir) {
while ((d = readdir(dir))) {
@ -1816,17 +1844,20 @@ 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;
php_stream_statbuf st;
TSRMLS_FETCH();
if (fn == NULL) {
mm = &php_magic_database;
mm = (void *)&php_magic_database;
ret = 3;
goto internal_loaded;
}
@ -1835,27 +1866,34 @@ apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
if (dbname == NULL)
goto error2;
if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
goto error2;
#if (PHP_MAJOR_VERSION < 6)
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 (fstat(fd, &st) == -1) {
if (!stream) {
goto error2;
}
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;
}
mm = emalloc((size_t)st.st_size);
if (read(fd, mm, (size_t)st.st_size) != (size_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);
goto error1;
}
ret = 1;
(void)close(fd);
fd = -1;
php_stream_close(stream);
internal_loaded:
*magicp = mm;
@ -1882,7 +1920,7 @@ internal_loaded:
if (fn == NULL) {
*nmagicp = (sizeof(php_magic_database) / sizeof(struct magic));
} else {
*nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
*nmagicp = (uint32_t)(st.sb.st_size / sizeof(struct magic));
}
if (*nmagicp > 0) {
(*nmagicp)--;
@ -1898,8 +1936,9 @@ internal_loaded:
return ret;
error1:
if (fd != -1)
(void)close(fd);
if (stream) {
php_stream_close(stream);
}
if (mm) {
efree(mm);
} else {
@ -1921,38 +1960,47 @@ private int
apprentice_compile(struct magic_set *ms, struct magic **magicp,
uint32_t *nmagicp, const char *fn)
{
int fd;
char *dbname;
int rv = -1;
php_stream *stream;
TSRMLS_FETCH();
mkdbname(fn, &dbname, 1);
if (dbname == NULL)
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_MAJOR_VERSION < 6)
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;
}
(void)close(fd);
php_stream_close(stream);
rv = 0;
out:
efree(dbname);

View File

@ -32,6 +32,7 @@
* uncompress(method, old, n, newch) - uncompress old into new,
* using method, return sizeof new
*/
#include "config.h"
#include "file.h"
#include "magic.h"
@ -43,7 +44,9 @@
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#ifndef PHP_WIN32
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
@ -55,6 +58,7 @@
#include <zlib.h>
#endif
#undef FIONREAD
#ifndef lint
FILE_RCSID("@(#)$File: compress.c,v 1.56 2008/02/07 00:58:52 christos Exp $")
@ -86,6 +90,7 @@ private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
private ssize_t swrite(int, const void *, size_t);
#ifdef PHP_FILEINFO_UNCOMPRESS
private size_t uncompressbuf(struct magic_set *, int, size_t,
const unsigned char *, unsigned char **, size_t);
#ifdef BUILTIN_DECOMPRESS
@ -138,6 +143,7 @@ error:
ms->flags |= MAGIC_COMPRESS;
return rv;
}
#endif
/*
* `safe' write for sockets and pipes.
@ -295,6 +301,7 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
return fd;
}
#ifdef PHP_FILEINFO_UNCOMPRESS
#ifdef BUILTIN_DECOMPRESS
#define FHCRC (1 << 1)
@ -365,6 +372,7 @@ uncompressgzipped(struct magic_set *ms, const unsigned char *old,
}
#endif
private size_t
uncompressbuf(struct magic_set *ms, int fd, size_t method,
const unsigned char *old, unsigned char **newch, size_t n)
@ -483,3 +491,4 @@ err:
return n;
}
}
#endif /* if PHP_FILEINFO_UNCOMPRESS */

View File

@ -33,9 +33,7 @@
#ifndef __file_h__
#define __file_h__
//#ifdef HAVE_CONFIG_H
#include "config.h"
//#endif */
#include <stdio.h> /* Include that here, to make sure __P gets defined */
#include <errno.h>
@ -46,6 +44,9 @@
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef PHP_WIN32
#include "win32/php_stdint.h"
#endif
#include "php.h"
#include "ext/standard/php_string.h"
@ -62,7 +63,7 @@
#define MAGIC "/etc/magic"
#endif
#ifdef __EMX__
#if defined(__EMX__) || defined(PHP_WIN32)
#define PATHSEP ';'
#else
#define PATHSEP ':'
@ -323,16 +324,18 @@ typedef unsigned long unichar;
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_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);
#ifdef PHP_FILEINFO_UNCOMPRESS
protected int file_zmagic(struct magic_set *, int, const char *,
const unsigned char *, size_t);
#endif
protected int file_ascmagic(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);

View File

@ -60,69 +60,64 @@
FILE_RCSID("@(#)$File: fsmagic.c,v 1.50 2008/02/12 17:22:54 rrt Exp $")
#endif /* lint */
private int
bad_link(struct magic_set *ms, int err, char *buf)
{
char *errfmt;
if (err == ELOOP)
errfmt = "symbolic link in a loop";
else
errfmt = "broken symbolic link to `%s'";
if (ms->flags & MAGIC_ERROR) {
file_error(ms, err, errfmt, buf);
return -1;
}
if (file_printf(ms, errfmt, 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
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];
int nch;
struct stat tstatbuf;
#endif
TSRMLS_FETCH();
if (fn == NULL)
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 (file_printf(ms, "cannot open `%s' (%s)",
fn, strerror(errno)) == -1)
return -1;
return 1;
if (!fn && !stream) {
return -1;
}
if (mime) {
if ((sb->st_mode & S_IFMT) != S_IFREG) {
if ((mime & MAGIC_MIME_TYPE) &&
file_printf(ms, "application/x-not-regular-file")
== -1)
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;
}
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;
}
}
else {
if (mime) {
if (!S_ISREG(sb->st_mode)) {
if ((mime & MAGIC_MIME_TYPE) &&
file_printf(ms, "application/x-not-regular-file") == -1) {
return -1;
}
return 1;
}
if (S_ISDIR(sb->st_mode)) {
if (file_printf(ms, "directory") == -1) {
return -1;
}
return 1;
}
} else {
#ifdef S_ISUID
if (sb->st_mode & S_ISUID)
if (file_printf(ms, "setuid ") == -1)
@ -139,65 +134,41 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
return -1;
#endif
}
switch (sb->st_mode & S_IFMT) {
case S_IFDIR:
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;
#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;
#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;
}
# 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, "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;
#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;
# 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)
@ -212,67 +183,17 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
return -1;
return 1;
#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 (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 (file_printf(ms,
"path too long: `%s'", fn) == -1)
return -1;
return 1;
}
(void)strcpy(buf2, fn); /* take dir part */
buf2[tmp - fn + 1] = '\0';
(void)strcat(buf2, buf); /* plus (rel) link */
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 (file_printf(ms, "symbolic link to `%s'",
buf) == -1)
return -1;
}
return 1;
#endif
#ifdef S_IFSOCK
#ifndef __COHERENT__
case S_IFSOCK:
@ -281,12 +202,14 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
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*/
}
/*

View File

@ -146,7 +146,7 @@ file_badread(struct magic_set *ms)
}
protected int
file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const void *buf,
size_t nb)
{
int m;
@ -166,7 +166,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
return 1;
}
#ifdef __EMX__
#if defined(__EMX__)
if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
switch (file_os2_apptype(ms, inname, buf, nb)) {
case -1:
@ -179,31 +179,30 @@ file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
}
#endif
#if PHP_FILEINFO_UNCOMPRESS
/* try compression stuff */
if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) != 0 ||
(m = file_zmagic(ms, fd, inname, buf, nb)) == 0) {
/* Check if we have a tar file */
if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 ||
(m = file_is_tar(ms, buf, nb)) == 0) {
/* try tests in /etc/magic (or surrogate magic file) */
if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 ||
(m = file_softmagic(ms, buf, nb, BINTEST)) == 0) {
/* try known keywords, check whether it is ASCII */
if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 ||
(m = file_ascmagic(ms, buf, nb)) == 0) {
/* abandon hope, all ye who remain here */
if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
file_printf(ms, mime ? "application/octet-stream" :
"data") == -1)
return -1;
m = 1;
}
(m = file_zmagic(ms, stream, inname, buf, nb)) == 0)
#endif
{
/* Check if we have a tar file */
if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 || (m = file_is_tar(ms, buf, nb)) == 0) {
/* try tests in /etc/magic (or surrogate magic file) */
if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 || (m = file_softmagic(ms, buf, nb, BINTEST)) == 0) {
/* try known keywords, check whether it is ASCII */
if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 || (m = file_ascmagic(ms, buf, nb)) == 0) {
/* abandon hope, all ye who remain here */
if ((!mime || (mime & MAGIC_MIME_TYPE)) && file_printf(ms, mime ? "application/octet-stream" : "data") == -1) {
return -1;
}
m = 1;
}
}
}
}
}
#ifdef BUILTIN_ELF
if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
nb > 5 && fd != -1) {
if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 && nb > 5 && fd != -1) {
/*
* We matched something in the file, so this *might*
* be an ELF file, and the file is at least 5 bytes
@ -212,7 +211,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
* information from the ELF headers that cannot easily
* be extracted with rules in the magic file.
*/
(void)file_tryelf(ms, fd, buf, nb);
(void)file_tryelf(ms, stream, buf, nb);
}
#endif
return m;

View File

@ -30,10 +30,19 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef PHP_WIN32
#include "win32/unistd.h"
#else
#include <unistd.h>
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/param.h> /* for MAXPATHLEN */
#ifdef PHP_WIN32
# include "config.w32.h"
#else
# include "php_config.h"
#endif
#include <sys/stat.h>
#include <limits.h> /* for PIPE_BUF */
@ -54,9 +63,9 @@
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <netinet/in.h> /* for byte swapping */
#ifndef PHP_WIN32
# include <netinet/in.h> /* for byte swapping */
#endif
#include "patchlevel.h"
#ifndef lint
@ -72,6 +81,11 @@ FILE_RCSID("@(#)$File: magic.c,v 1.50 2008/02/19 00:58:59 rrt Exp $")
#endif
#endif
#ifdef PHP_WIN32
# undef S_IFLNK
# undef S_IFIFO
#endif
#ifdef __EMX__
private char *apptypeName = NULL;
protected int file_os2_apptype(struct magic_set *ms, const char *fn,
@ -82,7 +96,7 @@ private void free_mlist(struct mlist *);
private void close_and_restore(const struct magic_set *, const char *, int,
const struct stat *);
private int info_from_stat(struct magic_set *, mode_t);
private const char *file_or_fd(struct magic_set *, const char *, int);
private const char *file_or_stream(struct magic_set *, const char *, php_stream *);
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
@ -204,10 +218,6 @@ private void
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) {
/*
* Try to restore access, modification times if read it.
@ -240,7 +250,7 @@ close_and_restore(const struct magic_set *ms, const char *name, int fd,
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);
}
/*
@ -249,17 +259,28 @@ magic_descriptor(struct magic_set *ms, int fd)
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;
TSRMLS_FETCH();
if (!inname && !stream) {
return NULL;
}
/*
* one extra for terminating '\0', and
@ -268,89 +289,65 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
#define SLOP (1 + sizeof(union VALUETYPE))
buf = emalloc(HOWMANY + SLOP);
if (file_reset(ms) == -1)
goto done;
switch (file_fsmagic(ms, inname, &sb)) {
case -1: /* error */
goto done;
case 0: /* nothing found */
break;
default: /* matched it and printed type */
rv = 0;
if (file_reset(ms) == -1) {
goto done;
}
if (inname == NULL) {
if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
ispipe = 1;
} else {
int flags = O_RDONLY|O_BINARY;
if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
flags |= O_NONBLOCK;
ispipe = 1;
}
switch (file_fsmagic(ms, inname, &sb, stream)) {
case -1: /* error */
goto done;
case 0: /* nothing found */
break;
default: /* matched it and printed type */
rv = 0;
goto done;
}
errno = 0;
if ((fd = open(inname, flags)) < 0) {
#ifdef __CYGWIN__
/* FIXME: Do this with EXEEXT from autotools */
char *tmp = alloca(strlen(inname) + 5);
(void)strcat(strcpy(tmp, inname), ".exe");
if ((fd = open(tmp, flags)) < 0) {
if (!stream && inname) {
#if (PHP_MAJOR_VERSION < 6)
stream = php_stream_open_wrapper(inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
#else
stream = php_stream_open_wrapper(inname, "rb", REPORT_ERRORS, NULL);
#endif
}
if (!stream) {
fprintf(stderr, "couldn't open file\n");
if (info_from_stat(ms, sb.st_mode) == -1)
goto done;
rv = 0;
goto done;
#ifdef __CYGWIN__
}
#endif
}
#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
* leaving the comment/#ifdef as documentation
*/
#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 (info_from_stat(ms, sb.st_mode) == -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:
efree(buf);
close_and_restore(ms, inname, fd, &sb);
if (stream) {
php_stream_close(stream);
}
close_and_restore(ms, inname, 0, &sb);
return rv == 0 ? file_getbuffer(ms) : NULL;
}
@ -364,7 +361,7 @@ magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
* The main work is done here!
* 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);

View File

@ -64,6 +64,7 @@ magic_t magic_open(int);
void magic_close(magic_t);
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);

View File

@ -943,7 +943,6 @@ dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off,
return 0;
}
protected int
file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
size_t nbytes)
@ -963,6 +962,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
if (ms->flags & MAGIC_MIME)
return 0;
/*
* ELF executables have multiple section headers in arbitrary
* file locations and thus file(1) cannot determine it from easily.

View File

@ -11,9 +11,15 @@ var_dump(finfo_file($fp, '.'));
var_dump(finfo_file($fp, '&'));
?>
--EXPECT--
--EXPECTF--
bool(false)
Warning: finfo_file(): Empty filename or path in %s on line %d
bool(false)
Warning: finfo_file(): Empty filename or path in %s on line %d
bool(false)
string(9) "directory"
Warning: finfo_file(&): failed to open stream: No such file or directory in %s on line %d
bool(false)