2008-05-13 05:03:49 +08:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| phar php single-file executable PHP extension |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Copyright (c) 2005-2008 The PHP Group |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
|
|
| available through the world-wide-web at the following url: |
|
|
|
|
| http://www.php.net/license/3_01.txt. |
|
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Authors: Gregory Beaver <cellog@php.net> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include "phar_internal.h"
|
|
|
|
|
|
|
|
#define PHAR_FUNC(name) \
|
|
|
|
static PHP_NAMED_FUNCTION(name)
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_opendir) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int filename_len;
|
|
|
|
zval *zcontext = NULL;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
/* we are checking for existence of a file within the relative path. Chances are good that this is
|
|
|
|
retrieving something from within the phar archive */
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
php_stream_context *context = NULL;
|
|
|
|
php_stream *stream;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = estrndup(filename, filename_len);
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
/* retrieving a file within the current directory, so use this if possible */
|
|
|
|
entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
|
|
|
|
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
spprintf(&name, 4096, "phar://%s%s", arch, entry);
|
|
|
|
} else {
|
|
|
|
spprintf(&name, 4096, "phar://%s/%s", arch, entry);
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
if (zcontext) {
|
|
|
|
context = php_stream_context_from_zval(zcontext, 0);
|
|
|
|
}
|
|
|
|
stream = php_stream_opendir(name, REPORT_ERRORS, context);
|
|
|
|
efree(name);
|
|
|
|
if (!stream) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
php_stream_to_zval(stream, return_value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_opendir)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_file_get_contents) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int filename_len;
|
|
|
|
char *contents;
|
|
|
|
zend_bool use_include_path = 0;
|
|
|
|
php_stream *stream;
|
|
|
|
int len, newlen;
|
|
|
|
long offset = -1;
|
|
|
|
long maxlen = PHP_STREAM_COPY_ALL;
|
|
|
|
zval *zcontext = NULL;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
/* Parse arguments */
|
|
|
|
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
php_stream_context *context = NULL;
|
|
|
|
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
char *name;
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = filename;
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() == 5 && maxlen < 0) {
|
|
|
|
efree(arch);
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* retrieving a file defaults to within the current directory, so use this if possible */
|
|
|
|
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (use_include_path) {
|
|
|
|
if ((entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
|
|
|
|
name = entry;
|
|
|
|
goto phar_it;
|
|
|
|
} else {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
notfound:
|
|
|
|
efree(arch);
|
|
|
|
efree(entry);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
|
|
|
|
goto notfound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* auto-convert to phar:// */
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
spprintf(&name, 4096, "phar://%s%s", arch, entry);
|
|
|
|
} else {
|
|
|
|
spprintf(&name, 4096, "phar://%s/%s", arch, entry);
|
|
|
|
}
|
|
|
|
if (entry != filename) {
|
|
|
|
efree(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
phar_it:
|
|
|
|
efree(arch);
|
|
|
|
if (zcontext) {
|
|
|
|
context = php_stream_context_from_zval(zcontext, 0);
|
|
|
|
}
|
|
|
|
stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
|
|
|
|
efree(name);
|
|
|
|
|
|
|
|
if (!stream) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
|
|
|
|
php_stream_close(stream);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* uses mmap if possible */
|
|
|
|
if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
|
|
|
|
#if PHP_MAJOR_VERSION < 6
|
|
|
|
if (PG(magic_quotes_runtime)) {
|
|
|
|
contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
|
|
|
|
len = newlen;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
RETVAL_STRINGL(contents, len, 0);
|
|
|
|
} else if (len == 0) {
|
|
|
|
RETVAL_EMPTY_STRING();
|
|
|
|
} else {
|
|
|
|
RETVAL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
php_stream_close(stream);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_readfile) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int filename_len;
|
|
|
|
int size = 0;
|
|
|
|
zend_bool use_include_path = 0;
|
|
|
|
zval *zcontext = NULL;
|
|
|
|
php_stream *stream;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
php_stream_context *context = NULL;
|
|
|
|
char *name;
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = filename;
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
/* retrieving a file defaults to within the current directory, so use this if possible */
|
|
|
|
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (use_include_path) {
|
|
|
|
if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
} else {
|
|
|
|
name = entry;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
notfound:
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
|
|
|
|
goto notfound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* auto-convert to phar:// */
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
spprintf(&name, 4096, "phar://%s%s", arch, entry);
|
|
|
|
} else {
|
|
|
|
spprintf(&name, 4096, "phar://%s/%s", arch, entry);
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(arch);
|
|
|
|
context = php_stream_context_from_zval(zcontext, 0);
|
|
|
|
stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
|
|
|
|
efree(name);
|
|
|
|
if (stream == NULL) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
size = php_stream_passthru(stream);
|
|
|
|
php_stream_close(stream);
|
|
|
|
RETURN_LONG(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_readfile)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_fopen) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename, *mode;
|
|
|
|
int filename_len, mode_len;
|
|
|
|
zend_bool use_include_path = 0;
|
|
|
|
zval *zcontext = NULL;
|
|
|
|
php_stream *stream;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
/* no need to check, include_path not even specified in fopen/ no active phars */
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
php_stream_context *context = NULL;
|
|
|
|
char *name;
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = filename;
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
/* retrieving a file defaults to within the current directory, so use this if possible */
|
|
|
|
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (use_include_path) {
|
|
|
|
if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
} else {
|
|
|
|
name = entry;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
notfound:
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
|
|
|
|
/* this file is not in the phar, use the original path */
|
|
|
|
goto notfound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* auto-convert to phar:// */
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
spprintf(&name, 4096, "phar://%s%s", arch, entry);
|
|
|
|
} else {
|
|
|
|
spprintf(&name, 4096, "phar://%s/%s", arch, entry);
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(arch);
|
|
|
|
context = php_stream_context_from_zval(zcontext, 0);
|
|
|
|
stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context);
|
|
|
|
efree(name);
|
|
|
|
if (stream == NULL) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
php_stream_to_zval(stream, return_value);
|
|
|
|
if (zcontext) {
|
|
|
|
zend_list_addref(Z_RESVAL_P(zcontext));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#ifndef S_ISDIR
|
|
|
|
#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
|
|
|
|
#endif
|
|
|
|
#ifndef S_ISREG
|
|
|
|
#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
|
|
|
|
#endif
|
|
|
|
#ifndef S_ISLNK
|
|
|
|
#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define S_IXROOT ( S_IXUSR | S_IXGRP | S_IXOTH )
|
|
|
|
|
|
|
|
#define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT)
|
|
|
|
#define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK)
|
|
|
|
#define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X)
|
|
|
|
#define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS)
|
|
|
|
|
|
|
|
/* {{{ php_stat
|
|
|
|
*/
|
|
|
|
void phar_fancy_stat(struct stat *stat_sb, int type, zval *return_value TSRMLS_DC)
|
|
|
|
{
|
|
|
|
zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev,
|
|
|
|
*stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks;
|
|
|
|
int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */
|
|
|
|
char *stat_sb_names[13] = {
|
|
|
|
"dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
|
|
|
|
"size", "atime", "mtime", "ctime", "blksize", "blocks"
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef NETWARE
|
|
|
|
if (type >= FS_IS_W && type <= FS_IS_X) {
|
|
|
|
if(stat_sb->st_uid==getuid()) {
|
|
|
|
rmask=S_IRUSR;
|
|
|
|
wmask=S_IWUSR;
|
|
|
|
xmask=S_IXUSR;
|
|
|
|
} else if(stat_sb->st_gid==getgid()) {
|
|
|
|
rmask=S_IRGRP;
|
|
|
|
wmask=S_IWGRP;
|
|
|
|
xmask=S_IXGRP;
|
|
|
|
} else {
|
|
|
|
int groups, n, i;
|
|
|
|
gid_t *gids;
|
|
|
|
|
|
|
|
groups = getgroups(0, NULL);
|
|
|
|
if(groups > 0) {
|
|
|
|
gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0);
|
|
|
|
n=getgroups(groups, gids);
|
|
|
|
for(i=0;i<n;++i){
|
|
|
|
if(stat_sb->st_gid==gids[i]) {
|
|
|
|
rmask=S_IRGRP;
|
|
|
|
wmask=S_IWGRP;
|
|
|
|
xmask=S_IXGRP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(gids);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case FS_PERMS:
|
|
|
|
RETURN_LONG((long)stat_sb->st_mode);
|
|
|
|
case FS_INODE:
|
|
|
|
RETURN_LONG((long)stat_sb->st_ino);
|
|
|
|
case FS_SIZE:
|
|
|
|
RETURN_LONG((long)stat_sb->st_size);
|
|
|
|
case FS_OWNER:
|
|
|
|
RETURN_LONG((long)stat_sb->st_uid);
|
|
|
|
case FS_GROUP:
|
|
|
|
RETURN_LONG((long)stat_sb->st_gid);
|
|
|
|
case FS_ATIME:
|
|
|
|
#ifdef NETWARE
|
|
|
|
RETURN_LONG((long)stat_sb->st_atime.tv_sec);
|
|
|
|
#else
|
|
|
|
RETURN_LONG((long)stat_sb->st_atime);
|
|
|
|
#endif
|
|
|
|
case FS_MTIME:
|
|
|
|
#ifdef NETWARE
|
|
|
|
RETURN_LONG((long)stat_sb->st_mtime.tv_sec);
|
|
|
|
#else
|
|
|
|
RETURN_LONG((long)stat_sb->st_mtime);
|
|
|
|
#endif
|
|
|
|
case FS_CTIME:
|
|
|
|
#ifdef NETWARE
|
|
|
|
RETURN_LONG((long)stat_sb->st_ctime.tv_sec);
|
|
|
|
#else
|
|
|
|
RETURN_LONG((long)stat_sb->st_ctime);
|
|
|
|
#endif
|
|
|
|
case FS_TYPE:
|
|
|
|
if (S_ISLNK(stat_sb->st_mode)) {
|
|
|
|
RETURN_STRING("link", 1);
|
|
|
|
}
|
|
|
|
switch(stat_sb->st_mode & S_IFMT) {
|
|
|
|
case S_IFDIR: RETURN_STRING("dir", 1);
|
|
|
|
case S_IFREG: RETURN_STRING("file", 1);
|
|
|
|
}
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%d)", stat_sb->st_mode&S_IFMT);
|
|
|
|
RETURN_STRING("unknown", 1);
|
|
|
|
case FS_IS_W:
|
|
|
|
RETURN_BOOL((stat_sb->st_mode & wmask) != 0);
|
|
|
|
case FS_IS_R:
|
|
|
|
RETURN_BOOL((stat_sb->st_mode&rmask)!=0);
|
|
|
|
case FS_IS_X:
|
|
|
|
RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode));
|
|
|
|
case FS_IS_FILE:
|
|
|
|
RETURN_BOOL(S_ISREG(stat_sb->st_mode));
|
|
|
|
case FS_IS_DIR:
|
|
|
|
RETURN_BOOL(S_ISDIR(stat_sb->st_mode));
|
|
|
|
case FS_IS_LINK:
|
|
|
|
RETURN_BOOL(S_ISLNK(stat_sb->st_mode));
|
|
|
|
case FS_EXISTS:
|
|
|
|
RETURN_TRUE; /* the false case was done earlier */
|
|
|
|
case FS_LSTAT:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case FS_STAT:
|
|
|
|
array_init(return_value);
|
|
|
|
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid);
|
|
|
|
#ifdef HAVE_ST_RDEV
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev);
|
|
|
|
#else
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
|
|
|
|
#endif
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size);
|
|
|
|
#ifdef NETWARE
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_atime, (stat_sb->st_atime).tv_sec);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_mtime, (stat_sb->st_mtime).tv_sec);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_ctime, (stat_sb->st_ctime).tv_sec);
|
|
|
|
#else
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime);
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime);
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ST_BLKSIZE
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize);
|
|
|
|
#else
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_blksize,-1);
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ST_BLOCKS
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks);
|
|
|
|
#else
|
|
|
|
MAKE_LONG_ZVAL_INCREF(stat_blocks,-1);
|
|
|
|
#endif
|
|
|
|
/* Store numeric indexes in propper order */
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL);
|
|
|
|
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL);
|
|
|
|
zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL);
|
|
|
|
|
|
|
|
/* Store string indexes referencing the same zval*/
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL);
|
|
|
|
zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
|
|
|
{
|
|
|
|
if (!filename_length) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
struct stat sb = {0};
|
|
|
|
phar_entry_info *data = NULL;
|
|
|
|
char *tmp;
|
|
|
|
int tmp_len;
|
|
|
|
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
/* we are checking for existence of a file within the relative path. Chances are good that this is
|
|
|
|
retrieving something from within the phar archive */
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = estrndup(filename, filename_length);
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = (int) filename_length;
|
|
|
|
if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
efree(arch);
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
|
|
|
|
efree(entry);
|
|
|
|
goto stat_entry;
|
|
|
|
}
|
|
|
|
goto notfound;
|
|
|
|
}
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
|
|
|
|
efree(entry);
|
|
|
|
goto stat_entry;
|
|
|
|
} else {
|
|
|
|
char *save, *save2, *actual;
|
|
|
|
int save_len, save2_len, actual_len;
|
|
|
|
|
|
|
|
notfound:
|
|
|
|
save = PHAR_G(cwd);
|
|
|
|
save2 = entry;
|
|
|
|
actual = entry[0] == '/' ? (entry + 1) : entry;
|
|
|
|
save_len = PHAR_G(cwd_len);
|
|
|
|
save2_len = entry_len;
|
|
|
|
actual_len = entry[0] == '/' ? (entry_len - 1) : entry_len;
|
|
|
|
/* this file is not in the current directory, use the original path */
|
|
|
|
entry = estrndup(filename, filename_length);
|
|
|
|
entry_len = filename_length;
|
|
|
|
PHAR_G(cwd) = "/";
|
|
|
|
PHAR_G(cwd_len) = 0;
|
|
|
|
/* clean path without cwd */
|
|
|
|
entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
|
|
|
|
PHAR_G(cwd) = save;
|
|
|
|
PHAR_G(cwd_len) = save_len;
|
|
|
|
efree(entry);
|
|
|
|
efree(save2);
|
|
|
|
goto stat_entry;
|
|
|
|
} else {
|
|
|
|
phar_archive_data *phar = *pphar;
|
2008-05-15 05:29:51 +08:00
|
|
|
phar_zstr key;
|
|
|
|
char *str_key;
|
2008-05-13 05:03:49 +08:00
|
|
|
uint keylen;
|
|
|
|
ulong unused;
|
|
|
|
|
|
|
|
PHAR_G(cwd) = save;
|
|
|
|
PHAR_G(cwd_len) = save_len;
|
|
|
|
/* original not found either, this is possibly a directory relative to cwd */
|
|
|
|
zend_hash_internal_pointer_reset(&phar->manifest);
|
|
|
|
while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
|
|
|
|
if (HASH_KEY_NON_EXISTANT !=
|
|
|
|
zend_hash_get_current_key_ex(
|
|
|
|
&phar->manifest, &key, &keylen, &unused, 0, NULL)) {
|
2008-05-15 05:29:51 +08:00
|
|
|
PHAR_STR(key, str_key);
|
|
|
|
if (!memcmp(actual, str_key, actual_len)) {
|
2008-05-13 05:03:49 +08:00
|
|
|
efree(save2);
|
|
|
|
efree(entry);
|
|
|
|
/* directory found, all dirs have the same stat */
|
2008-05-15 05:29:51 +08:00
|
|
|
if (str_key[actual_len] == '/') {
|
2008-05-13 05:03:49 +08:00
|
|
|
sb.st_size = 0;
|
|
|
|
sb.st_mode = 0777;
|
|
|
|
sb.st_mode |= S_IFDIR; /* regular directory */
|
|
|
|
#ifdef NETWARE
|
|
|
|
sb.st_mtime.tv_sec = phar->max_timestamp;
|
|
|
|
sb.st_atime.tv_sec = phar->max_timestamp;
|
|
|
|
sb.st_ctime.tv_sec = phar->max_timestamp;
|
|
|
|
#else
|
|
|
|
sb.st_mtime = phar->max_timestamp;
|
|
|
|
sb.st_atime = phar->max_timestamp;
|
|
|
|
sb.st_ctime = phar->max_timestamp;
|
|
|
|
#endif
|
|
|
|
goto statme_baby;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
efree(save2);
|
|
|
|
efree(arch);
|
|
|
|
/* Error Occured */
|
|
|
|
if (!IS_EXISTS_CHECK(type)) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename);
|
|
|
|
}
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
stat_entry:
|
|
|
|
if (!data->is_dir) {
|
|
|
|
sb.st_size = data->uncompressed_filesize;
|
|
|
|
sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
|
|
|
|
if (data->link) {
|
|
|
|
sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */
|
|
|
|
} else {
|
|
|
|
sb.st_mode |= S_IFREG; /* regular file */
|
|
|
|
}
|
|
|
|
/* timestamp is just the timestamp when this was added to the phar */
|
|
|
|
#ifdef NETWARE
|
|
|
|
sb.st_mtime.tv_sec = data->timestamp;
|
|
|
|
sb.st_atime.tv_sec = data->timestamp;
|
|
|
|
sb.st_ctime.tv_sec = data->timestamp;
|
|
|
|
#else
|
|
|
|
sb.st_mtime = data->timestamp;
|
|
|
|
sb.st_atime = data->timestamp;
|
|
|
|
sb.st_ctime = data->timestamp;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
sb.st_size = 0;
|
|
|
|
sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
|
|
|
|
sb.st_mode |= S_IFDIR; /* regular directory */
|
|
|
|
if (data->link) {
|
|
|
|
sb.st_mode |= S_IFLNK;
|
|
|
|
}
|
|
|
|
/* timestamp is just the timestamp when this was added to the phar */
|
|
|
|
#ifdef NETWARE
|
|
|
|
sb.st_mtime.tv_sec = data->timestamp;
|
|
|
|
sb.st_atime.tv_sec = data->timestamp;
|
|
|
|
sb.st_ctime.tv_sec = data->timestamp;
|
|
|
|
#else
|
|
|
|
sb.st_mtime = data->timestamp;
|
|
|
|
sb.st_atime = data->timestamp;
|
|
|
|
sb.st_ctime = data->timestamp;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
statme_baby:
|
|
|
|
efree(arch);
|
|
|
|
if (!(*pphar)->is_writeable) {
|
|
|
|
sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
|
|
|
|
}
|
|
|
|
|
|
|
|
sb.st_nlink = 1;
|
|
|
|
sb.st_rdev = -1;
|
|
|
|
if (data) {
|
|
|
|
tmp_len = data->filename_len + (*pphar)->alias_len;
|
|
|
|
} else {
|
|
|
|
tmp_len = (*pphar)->alias_len + 1;
|
|
|
|
}
|
|
|
|
tmp = (char *) emalloc(tmp_len);
|
|
|
|
memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len);
|
|
|
|
if (data) {
|
|
|
|
memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len);
|
|
|
|
} else {
|
|
|
|
*(tmp + (*pphar)->alias_len) = '/';
|
|
|
|
}
|
|
|
|
/* this is only for APC, so use /dev/null device - no chance of conflict there! */
|
|
|
|
sb.st_dev = 0xc;
|
|
|
|
/* generate unique inode number for alias/filename, so no phars will conflict */
|
|
|
|
sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
|
|
|
|
efree(tmp);
|
|
|
|
#ifndef PHP_WIN32
|
|
|
|
sb.st_blksize = -1;
|
|
|
|
sb.st_blocks = -1;
|
|
|
|
#endif
|
|
|
|
phar_fancy_stat(&sb, type, return_value TSRMLS_CC);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#define PharFileFunction(fname, funcnum, orig) \
|
|
|
|
void fname(INTERNAL_FUNCTION_PARAMETERS) { \
|
|
|
|
char *filename; \
|
|
|
|
int filename_len; \
|
|
|
|
\
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int fileperms(string filename)
|
|
|
|
Get file permissions */
|
|
|
|
PharFileFunction(phar_fileperms, FS_PERMS, orig_fileperms)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int fileinode(string filename)
|
|
|
|
Get file inode */
|
|
|
|
PharFileFunction(phar_fileinode, FS_INODE, orig_fileinode)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int filesize(string filename)
|
|
|
|
Get file size */
|
|
|
|
PharFileFunction(phar_filesize, FS_SIZE, orig_filesize)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int fileowner(string filename)
|
|
|
|
Get file owner */
|
|
|
|
PharFileFunction(phar_fileowner, FS_OWNER, orig_fileowner)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int filegroup(string filename)
|
|
|
|
Get file group */
|
|
|
|
PharFileFunction(phar_filegroup, FS_GROUP, orig_filegroup)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int fileatime(string filename)
|
|
|
|
Get last access time of file */
|
|
|
|
PharFileFunction(phar_fileatime, FS_ATIME, orig_fileatime)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int filemtime(string filename)
|
|
|
|
Get last modification time of file */
|
|
|
|
PharFileFunction(phar_filemtime, FS_MTIME, orig_filemtime)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int filectime(string filename)
|
|
|
|
Get inode modification time of file */
|
|
|
|
PharFileFunction(phar_filectime, FS_CTIME, orig_filectime)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto string filetype(string filename)
|
|
|
|
Get file type */
|
|
|
|
PharFileFunction(phar_filetype, FS_TYPE, orig_filetype)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool is_writable(string filename)
|
|
|
|
Returns true if file can be written */
|
|
|
|
PharFileFunction(phar_is_writable, FS_IS_W, orig_is_writable)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool is_readable(string filename)
|
|
|
|
Returns true if file can be read */
|
|
|
|
PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool is_executable(string filename)
|
|
|
|
Returns true if file is executable */
|
|
|
|
PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool is_executable(string filename)
|
|
|
|
Returns true if file is executable */
|
|
|
|
PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool is_executable(string filename)
|
|
|
|
Returns true if file is executable */
|
|
|
|
PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_is_file) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int filename_len;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
/* we are checking for existence of a file within the relative path. Chances are good that this is
|
|
|
|
retrieving something from within the phar archive */
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = filename;
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
/* retrieving a file within the current directory, so use this if possible */
|
|
|
|
if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
phar_entry_info *etemp;
|
|
|
|
|
|
|
|
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
|
|
|
|
/* this file is not in the current directory, use the original path */
|
|
|
|
found_it:
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
RETURN_BOOL(!etemp->is_dir);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
|
|
|
|
goto found_it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_is_file)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
PHAR_FUNC(phar_is_link) /* {{{ */
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int filename_len;
|
|
|
|
|
|
|
|
if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
|
|
|
|
char *arch, *entry, *fname;
|
|
|
|
int arch_len, entry_len, fname_len;
|
|
|
|
fname = zend_get_executed_filename(TSRMLS_C);
|
|
|
|
|
|
|
|
/* we are checking for existence of a file within the relative path. Chances are good that this is
|
|
|
|
retrieving something from within the phar archive */
|
|
|
|
|
|
|
|
if (strncasecmp(fname, "phar://", 7)) {
|
|
|
|
goto skip_phar;
|
|
|
|
}
|
|
|
|
fname_len = strlen(fname);
|
|
|
|
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
|
|
|
|
phar_archive_data **pphar;
|
|
|
|
|
|
|
|
efree(entry);
|
|
|
|
entry = filename;
|
|
|
|
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
|
|
|
|
entry_len = filename_len;
|
|
|
|
/* retrieving a file within the current directory, so use this if possible */
|
|
|
|
if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
|
|
|
|
phar_entry_info *etemp;
|
|
|
|
|
|
|
|
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
|
|
|
|
if (entry[0] == '/') {
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
|
|
|
|
/* this file is not in the current directory, use the original path */
|
|
|
|
found_it:
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
RETURN_BOOL(etemp->link);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
|
|
|
|
goto found_it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(entry);
|
|
|
|
efree(arch);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_phar:
|
|
|
|
PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto array lstat(string filename)
|
|
|
|
Give information about a file or symbolic link */
|
|
|
|
PharFileFunction(phar_lstat, FS_LSTAT, orig_lstat)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto array stat(string filename)
|
|
|
|
Give information about a file */
|
|
|
|
PharFileFunction(phar_stat, FS_STAT, orig_stat)
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ void phar_intercept_functions(TSRMLS_D) */
|
|
|
|
#define PHAR_INTERCEPT(func) \
|
|
|
|
PHAR_G(orig_##func) = NULL; \
|
|
|
|
if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
|
|
|
|
PHAR_G(orig_##func) = orig->internal_function.handler; \
|
|
|
|
orig->internal_function.handler = phar_##func; \
|
|
|
|
}
|
|
|
|
|
|
|
|
void phar_intercept_functions(TSRMLS_D)
|
|
|
|
{
|
|
|
|
zend_function *orig;
|
|
|
|
|
|
|
|
if (!PHAR_G(request_init)) {
|
|
|
|
PHAR_G(cwd) = NULL;
|
|
|
|
PHAR_G(cwd_len) = 0;
|
|
|
|
} else if (PHAR_G(orig_fopen)) {
|
|
|
|
/* don't double-intercept */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PHAR_INTERCEPT(fopen);
|
|
|
|
PHAR_INTERCEPT(file_get_contents);
|
|
|
|
PHAR_INTERCEPT(is_file);
|
|
|
|
PHAR_INTERCEPT(is_link);
|
|
|
|
PHAR_INTERCEPT(is_dir);
|
|
|
|
PHAR_INTERCEPT(opendir);
|
|
|
|
PHAR_INTERCEPT(file_exists);
|
|
|
|
PHAR_INTERCEPT(fileperms);
|
|
|
|
PHAR_INTERCEPT(fileinode);
|
|
|
|
PHAR_INTERCEPT(filesize);
|
|
|
|
PHAR_INTERCEPT(fileowner);
|
|
|
|
PHAR_INTERCEPT(filegroup);
|
|
|
|
PHAR_INTERCEPT(fileatime);
|
|
|
|
PHAR_INTERCEPT(filemtime);
|
|
|
|
PHAR_INTERCEPT(filectime);
|
|
|
|
PHAR_INTERCEPT(filetype);
|
|
|
|
PHAR_INTERCEPT(is_writable);
|
|
|
|
PHAR_INTERCEPT(is_readable);
|
|
|
|
PHAR_INTERCEPT(is_executable);
|
|
|
|
PHAR_INTERCEPT(lstat);
|
|
|
|
PHAR_INTERCEPT(stat);
|
|
|
|
PHAR_INTERCEPT(readfile);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ void phar_release_functions(TSRMLS_D) */
|
|
|
|
#define PHAR_RELEASE(func) \
|
|
|
|
if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
|
|
|
|
orig->internal_function.handler = PHAR_G(orig_##func); \
|
|
|
|
} \
|
|
|
|
PHAR_G(orig_##func) = NULL;
|
|
|
|
|
|
|
|
void phar_release_functions(TSRMLS_D)
|
|
|
|
{
|
|
|
|
zend_function *orig;
|
|
|
|
|
|
|
|
PHAR_RELEASE(fopen);
|
|
|
|
PHAR_RELEASE(file_get_contents);
|
|
|
|
PHAR_RELEASE(is_file);
|
|
|
|
PHAR_RELEASE(is_dir);
|
|
|
|
PHAR_RELEASE(opendir);
|
|
|
|
PHAR_RELEASE(file_exists);
|
|
|
|
PHAR_RELEASE(fileperms);
|
|
|
|
PHAR_RELEASE(fileinode);
|
|
|
|
PHAR_RELEASE(filesize);
|
|
|
|
PHAR_RELEASE(fileowner);
|
|
|
|
PHAR_RELEASE(filegroup);
|
|
|
|
PHAR_RELEASE(fileatime);
|
|
|
|
PHAR_RELEASE(filemtime);
|
|
|
|
PHAR_RELEASE(filectime);
|
|
|
|
PHAR_RELEASE(filetype);
|
|
|
|
PHAR_RELEASE(is_writable);
|
|
|
|
PHAR_RELEASE(is_readable);
|
|
|
|
PHAR_RELEASE(is_executable);
|
|
|
|
PHAR_RELEASE(lstat);
|
|
|
|
PHAR_RELEASE(stat);
|
|
|
|
PHAR_RELEASE(readfile);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
|
|
* vim<600: noet sw=4 ts=4
|
|
|
|
*/
|