summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--ext/standard/filestat.c200
-rw-r--r--ext/standard/tests/file/userstreams_007.phpt49
-rwxr-xr-xmain/php_streams.h11
-rw-r--r--main/streams/plain_wrapper.c94
-rw-r--r--main/streams/userspace.c270
6 files changed, 500 insertions, 126 deletions
diff --git a/NEWS b/NEWS
index f20af98488..007aa6b4a5 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,8 @@ PHP NEWS
one SAPI module the same time. FR #53271, FR #52410. (Jani)
. Added optional argument to debug_backtrace() and debug_print_backtrace()
to limit the amount of stack frames returned. (Sebastian, Patrick)
+ . Added stream metadata API support and stream_metadata() stream class
+ handler. (Stas)
- Improved Zend Engine memory usage: (Dmitry)
. Replaced zend_function.pass_rest_by_reference by
diff --git a/ext/standard/filestat.c b/ext/standard/filestat.c
index 85a6d16eca..6ae7cdad3b 100644
--- a/ext/standard/filestat.c
+++ b/ext/standard/filestat.c
@@ -386,21 +386,8 @@ PHP_FUNCTION(disk_free_space)
/* }}} */
#if !defined(WINDOWS) && !defined(NETWARE)
-static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */
+PHPAPI int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC)
{
- char *filename;
- int filename_len;
- zval *group;
- gid_t gid;
- int ret;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/", &filename, &filename_len, &group) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (Z_TYPE_P(group) == IS_LONG) {
- gid = (gid_t)Z_LVAL_P(group);
- } else if (Z_TYPE_P(group) == IS_STRING) {
#if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
struct group gr;
struct group *retgrptr;
@@ -408,26 +395,73 @@ static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */
char *grbuf;
if (grbuflen < 1) {
- RETURN_FALSE;
+ return FAILURE;
}
grbuf = emalloc(grbuflen);
- if (getgrnam_r(Z_STRVAL_P(group), &gr, grbuf, grbuflen, &retgrptr) != 0 || retgrptr == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find gid for %s", Z_STRVAL_P(group));
+ if (getgrnam_r(name, &gr, grbuf, grbuflen, &retgrptr) != 0 || retgrptr == NULL) {
efree(grbuf);
- RETURN_FALSE;
+ return FAILURE;
}
efree(grbuf);
- gid = gr.gr_gid;
+ *gid = gr.gr_gid;
#else
- struct group *gr = getgrnam(Z_STRVAL_P(group));
+ struct group *gr = getgrnam(name);
if (!gr) {
+ return FAILURE;
+ }
+ *gid = gr->gr_gid;
+#endif
+ return SUCCESS;
+}
+
+static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+ zval *group;
+ gid_t gid;
+ int ret;
+ php_stream_wrapper *wrapper;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/", &filename, &filename_len, &group) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC);
+ if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
+ if(wrapper && wrapper->wops->stream_metadata) {
+ int option;
+ void *value;
+ if (Z_TYPE_P(group) == IS_LONG) {
+ option = PHP_STREAM_META_GROUP;
+ value = &Z_LVAL_P(group);
+ } else if (Z_TYPE_P(group) == IS_STRING) {
+ option = PHP_STREAM_META_GROUP_NAME;
+ value = Z_STRVAL_P(group);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given", zend_zval_type_name(group));
+ RETURN_FALSE;
+ }
+ if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL TSRMLS_CC)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chgrp() for a non-standard stream");
+ RETURN_FALSE;
+ }
+ }
+
+ if (Z_TYPE_P(group) == IS_LONG) {
+ gid = (gid_t)Z_LVAL_P(group);
+ } else if (Z_TYPE_P(group) == IS_STRING) {
+ if(php_get_gid_by_name(Z_STRVAL_P(group), &gid TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find gid for %s", Z_STRVAL_P(group));
RETURN_FALSE;
}
- gid = gr->gr_gid;
-#endif
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given", zend_zval_type_name(group));
RETURN_FALSE;
@@ -483,21 +517,8 @@ PHP_FUNCTION(lchgrp)
#endif /* !NETWARE */
#if !defined(WINDOWS) && !defined(NETWARE)
-static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */
+PHPAPI uid_t php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC)
{
- char *filename;
- int filename_len;
- zval *user;
- uid_t uid;
- int ret;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/", &filename, &filename_len, &user) == FAILURE) {
- return;
- }
-
- if (Z_TYPE_P(user) == IS_LONG) {
- uid = (uid_t)Z_LVAL_P(user);
- } else if (Z_TYPE_P(user) == IS_STRING) {
#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
struct passwd pw;
struct passwd *retpwptr = NULL;
@@ -509,22 +530,69 @@ static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */
}
pwbuf = emalloc(pwbuflen);
- if (getpwnam_r(Z_STRVAL_P(user), &pw, pwbuf, pwbuflen, &retpwptr) != 0 || retpwptr == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find uid for %s", Z_STRVAL_P(user));
+ if (getpwnam_r(name, &pw, pwbuf, pwbuflen, &retpwptr) != 0 || retpwptr == NULL) {
efree(pwbuf);
- RETURN_FALSE;
+ return FAILURE;
}
efree(pwbuf);
- uid = pw.pw_uid;
+ *uid = pw.pw_uid;
#else
- struct passwd *pw = getpwnam(Z_STRVAL_P(user));
+ struct passwd *pw = getpwnam(name);
if (!pw) {
+ return FAILURE;
+ }
+ *uid = pw->pw_uid;
+#endif
+ return SUCCESS;
+}
+
+static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+ zval *user;
+ uid_t uid;
+ int ret;
+ php_stream_wrapper *wrapper;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/", &filename, &filename_len, &user) == FAILURE) {
+ return;
+ }
+
+ wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC);
+ if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
+ if(wrapper && wrapper->wops->stream_metadata) {
+ int option;
+ void *value;
+ if (Z_TYPE_P(user) == IS_LONG) {
+ option = PHP_STREAM_META_OWNER;
+ value = &Z_LVAL_P(user);
+ } else if (Z_TYPE_P(user) == IS_STRING) {
+ option = PHP_STREAM_META_OWNER_NAME;
+ value = Z_STRVAL_P(user);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given", zend_zval_type_name(user));
+ RETURN_FALSE;
+ }
+ if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL TSRMLS_CC)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chown() for a non-standard stream");
+ RETURN_FALSE;
+ }
+ }
+
+ if (Z_TYPE_P(user) == IS_LONG) {
+ uid = (uid_t)Z_LVAL_P(user);
+ } else if (Z_TYPE_P(user) == IS_STRING) {
+ if(php_get_uid_by_name(Z_STRVAL_P(user), &uid TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find uid for %s", Z_STRVAL_P(user));
RETURN_FALSE;
}
- uid = pw->pw_uid;
-#endif
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given", zend_zval_type_name(user));
RETURN_FALSE;
@@ -589,11 +657,28 @@ PHP_FUNCTION(chmod)
long mode;
int ret;
mode_t imode;
+ php_stream_wrapper *wrapper;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &filename, &filename_len, &mode) == FAILURE) {
return;
}
+ wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC);
+ if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
+ if(wrapper && wrapper->wops->stream_metadata) {
+ int option;
+ void *value;
+ if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_ACCESS, &mode, NULL TSRMLS_CC)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chmod() for a non-standard stream");
+ RETURN_FALSE;
+ }
+ }
+
/* Check the basedir */
if (php_check_open_basedir(filename TSRMLS_CC)) {
RETURN_FALSE;
@@ -622,11 +707,16 @@ PHP_FUNCTION(touch)
FILE *file;
struct utimbuf newtimebuf;
struct utimbuf *newtime = &newtimebuf;
+ php_stream_wrapper *wrapper;
if (zend_parse_parameters(argc TSRMLS_CC, "s|ll", &filename, &filename_len, &filetime, &fileatime) == FAILURE) {
return;
}
+ if (!filename_len) {
+ RETURN_FALSE;
+ }
+
switch (argc) {
case 1:
#ifdef HAVE_UTIME_NULL
@@ -647,6 +737,30 @@ PHP_FUNCTION(touch)
WRONG_PARAM_COUNT;
}
+ wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC);
+ if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
+ if(wrapper && wrapper->wops->stream_metadata) {
+ if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_TOUCH, newtime, NULL TSRMLS_CC)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ } else {
+ php_stream *stream;
+ if(argc > 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call touch() for a non-standard stream");
+ RETURN_FALSE;
+ }
+ stream = php_stream_open_wrapper_ex(filename, "c", REPORT_ERRORS, NULL, NULL);
+ if(stream != NULL) {
+ php_stream_pclose(stream);
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ }
+ }
+
/* Check the basedir */
if (php_check_open_basedir(filename TSRMLS_CC)) {
RETURN_FALSE;
diff --git a/ext/standard/tests/file/userstreams_007.phpt b/ext/standard/tests/file/userstreams_007.phpt
new file mode 100644
index 0000000000..3f66f1802b
--- /dev/null
+++ b/ext/standard/tests/file/userstreams_007.phpt
@@ -0,0 +1,49 @@
+--TEST--
+User-space streams: test metadata option
+--FILE--
+<?php
+class test_wrapper {
+ function stream_open($path, $mode, $openedpath) {
+ return true;
+ }
+ public function stream_metadata($path, $option, $var) {
+ echo "metadata: $path, $option\n";
+ if(is_array($var)) {
+ echo join(",", $var);
+ } else {
+ echo $var;
+ }
+ echo "\n";
+ return false;
+ }
+}
+
+var_dump(stream_wrapper_register('test', 'test_wrapper'));
+
+$fd = fopen("test://foo","r");
+touch("test://testdir/touch");
+touch("test://testdir/touch", 1);
+touch("test://testdir/touch", 1, 2);
+chown("test://testdir/chown", "test");
+chown("test://testdir/chown", 42);
+chgrp("test://testdir/chgrp", "test");
+chgrp("test://testdir/chgrp", 42);
+chmod("test://testdir/chmod", 0755);
+--EXPECT--
+bool(true)
+metadata: test://testdir/touch, 1
+
+metadata: test://testdir/touch, 1
+1,1
+metadata: test://testdir/touch, 1
+1,2
+metadata: test://testdir/chown, 2
+test
+metadata: test://testdir/chown, 3
+42
+metadata: test://testdir/chgrp, 4
+test
+metadata: test://testdir/chgrp, 5
+42
+metadata: test://testdir/chmod, 6
+493 \ No newline at end of file
diff --git a/main/php_streams.h b/main/php_streams.h
index 444c2a038e..b87cf1b86e 100755
--- a/main/php_streams.h
+++ b/main/php_streams.h
@@ -154,6 +154,8 @@ typedef struct _php_stream_wrapper_ops {
/* Create/Remove directory */
int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+ /* Metadata handling */
+ int (*stream_metadata)(php_stream_wrapper *wrapper, char *url, int options, void *value, php_stream_context *context TSRMLS_DC);
} php_stream_wrapper_ops;
struct _php_stream_wrapper {
@@ -590,6 +592,15 @@ END_EXTERN_C()
/* Definitions for user streams */
#define PHP_STREAM_IS_URL 1
+
+/* Stream metadata definitions */
+/* Create if referred resource does not exist */
+#define PHP_STREAM_META_TOUCH 1
+#define PHP_STREAM_META_OWNER_NAME 2
+#define PHP_STREAM_META_OWNER 3
+#define PHP_STREAM_META_GROUP_NAME 4
+#define PHP_STREAM_META_GROUP 5
+#define PHP_STREAM_META_ACCESS 6
/*
* Local variables:
* tab-width: 4
diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c
index 62ae48e4dd..041a0e34e2 100644
--- a/main/streams/plain_wrapper.c
+++ b/main/streams/plain_wrapper.c
@@ -48,6 +48,11 @@
#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC)
#define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+#if !defined(WINDOWS) && !defined(NETWARE)
+extern int php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC);
+extern int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC);
+#endif
+
/* parse standard "fopen" modes into open() flags */
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
@@ -1249,6 +1254,92 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int opt
return 1;
}
+static int php_plain_files_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct utimbuf *newtime;
+ char *p;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ uid_t uid;
+ gid_t gid;
+#endif
+ mode_t mode;
+ int ret = 0;
+#if PHP_WIN32
+ int url_len = strlen(url);
+#endif
+
+#if PHP_WIN32
+ if (!php_win32_check_trailing_space(url, url_len)) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT));
+ return 0;
+ }
+#endif
+
+ if ((p = strstr(url, "://")) != NULL) {
+ url = p + 3;
+ }
+
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
+ }
+
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ newtime = (struct utimbuf *)value;
+ if (VCWD_ACCESS(url, F_OK) != 0) {
+ FILE *file = VCWD_FOPEN(url, "w");
+ if (file == NULL) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno));
+ return 0;
+ }
+ fclose(file);
+ }
+
+ ret = VCWD_UTIME(url, newtime);
+ break;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ case PHP_STREAM_META_OWNER_NAME:
+ case PHP_STREAM_META_OWNER:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_uid_by_name((char *)value, &uid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find uid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ uid = (uid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, uid, -1);
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_GROUP_NAME:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_gid_by_name((char *)value, &gid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find gid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ gid = (gid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, -1, gid);
+ break;
+#endif
+ case PHP_STREAM_META_ACCESS:
+ mode = (mode_t)*(long *)value;
+ ret = VCWD_CHMOD(url, mode);
+ break;
+ default:
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unknown option %d for stream_metadata", option);
+ return 0;
+ }
+ if (ret == -1) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Operation failed: %s", strerror(errno));
+ return 0;
+ }
+ php_clear_stat_cache(0, NULL, 0 TSRMLS_CC);
+ return 1;
+}
+
+
static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_stream_opener,
NULL,
@@ -1259,7 +1350,8 @@ static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_unlink,
php_plain_files_rename,
php_plain_files_mkdir,
- php_plain_files_rmdir
+ php_plain_files_rmdir,
+ php_plain_files_metadata
};
php_stream_wrapper php_plain_files_wrapper = {
diff --git a/main/streams/userspace.c b/main/streams/userspace.c
index 44ee715264..e10c63ce54 100644
--- a/main/streams/userspace.c
+++ b/main/streams/userspace.c
@@ -28,6 +28,14 @@
#endif
#include <stddef.h>
+#if HAVE_UTIME
+# ifdef PHP_WIN32
+# include <sys/utime.h>
+# else
+# include <utime.h>
+# endif
+#endif
+
static int le_protocols;
struct php_user_stream_wrapper {
@@ -43,6 +51,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC);
static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
@@ -56,7 +65,8 @@ static php_stream_wrapper_ops user_stream_wops = {
user_wrapper_unlink,
user_wrapper_rename,
user_wrapper_mkdir,
- user_wrapper_rmdir
+ user_wrapper_rmdir,
+ user_wrapper_metadata
};
@@ -99,6 +109,12 @@ PHP_MINIT_FUNCTION(user_streams)
REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM", PHP_STREAM_AS_STDIO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT", PHP_STREAM_AS_FD_FOR_SELECT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_TOUCH", PHP_STREAM_META_TOUCH, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER", PHP_STREAM_META_OWNER, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER_NAME", PHP_STREAM_META_OWNER_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP", PHP_STREAM_META_GROUP, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP_NAME", PHP_STREAM_META_GROUP_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_ACCESS", PHP_STREAM_META_ACCESS, CONST_CS|CONST_PERSISTENT);
return SUCCESS;
}
@@ -131,35 +147,36 @@ typedef struct _php_userstream_data php_userstream_data_t;
#define USERSTREAM_CAST "stream_cast"
#define USERSTREAM_SET_OPTION "stream_set_option"
#define USERSTREAM_TRUNCATE "stream_truncate"
+#define USERSTREAM_METADATA "stream_metadata"
/* {{{ class should have methods like these:
-
+
function stream_open($path, $mode, $options, &$opened_path)
{
return true/false;
}
-
+
function stream_read($count)
{
return false on error;
else return string;
}
-
+
function stream_write($data)
{
return false on error;
else return count written;
}
-
+
function stream_close()
{
}
-
+
function stream_flush()
{
return true/false;
}
-
+
function stream_seek($offset, $whence)
{
return true/false;
@@ -261,7 +278,7 @@ typedef struct _php_userstream_data php_userstream_data_t;
{
return true / false;
}
-
+
}}} **/
static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
@@ -269,7 +286,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
php_userstream_data_t *us;
zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
- zval **args[4];
+ zval **args[4];
int call_result;
php_stream *stream = NULL;
zend_bool old_in_user_include;
@@ -280,32 +297,32 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
return NULL;
}
FG(user_stream_current_filename) = filename;
-
+
/* if the user stream was registered as local and we are in include context,
we add allow_url_include restrictions to allow_url_fopen ones */
/* we need only is_url == 0 here since if is_url == 1 and remote wrappers
were restricted we wouldn't get here */
old_in_user_include = PG(in_user_include);
- if(uwrap->wrapper.is_url == 0 &&
+ if(uwrap->wrapper.is_url == 0 &&
(options & STREAM_OPEN_FOR_INCLUDE) &&
!PG(allow_url_include)) {
PG(in_user_include) = 1;
}
us = emalloc(sizeof(*us));
- us->wrapper = uwrap;
+ us->wrapper = uwrap;
/* create an instance of our class */
ALLOC_ZVAL(us->object);
object_init_ex(us->object, uwrap->ce);
Z_SET_REFCOUNT_P(us->object, 1);
Z_SET_ISREF_P(us->object);
-
+
if (uwrap->ce->constructor) {
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zval *retval_ptr;
-
+
fci.size = sizeof(fci);
fci.function_table = &uwrap->ce->function_table;
fci.function_name = NULL;
@@ -315,7 +332,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
fci.param_count = 0;
fci.params = NULL;
fci.no_separation = 1;
-
+
fcc.initialized = 1;
fcc.function_handler = uwrap->ce->constructor;
fcc.calling_scope = EG(scope);
@@ -343,7 +360,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
} else {
add_property_null(us->object, "context");
}
-
+
/* call it's stream_open method - set up params first */
MAKE_STD_ZVAL(zfilename);
ZVAL_STRING(zfilename, filename, 1);
@@ -365,14 +382,14 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_OPEN, 1);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
zfuncname,
&zretval,
4, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
/* the stream is now open! */
stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
@@ -389,7 +406,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_OPEN "\" call failed",
us->wrapper->classname);
}
-
+
/* destroy everything else */
if (stream == NULL) {
zval_ptr_dtor(&us->object);
@@ -397,7 +414,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
}
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zopened);
zval_ptr_dtor(&zoptions);
@@ -405,7 +422,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
zval_ptr_dtor(&zfilename);
FG(user_stream_current_filename) = NULL;
-
+
PG(in_user_include) = old_in_user_include;
return stream;
}
@@ -416,7 +433,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
php_userstream_data_t *us;
zval *zfilename, *zoptions, *zretval = NULL, *zfuncname;
- zval **args[2];
+ zval **args[2];
int call_result;
php_stream *stream = NULL;
@@ -426,9 +443,9 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
return NULL;
}
FG(user_stream_current_filename) = filename;
-
+
us = emalloc(sizeof(*us));
- us->wrapper = uwrap;
+ us->wrapper = uwrap;
/* create an instance of our class */
ALLOC_ZVAL(us->object);
@@ -442,7 +459,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
} else {
add_property_null(us->object, "context");
}
-
+
/* call it's dir_open method - set up params first */
MAKE_STD_ZVAL(zfilename);
ZVAL_STRING(zfilename, filename, 1);
@@ -454,14 +471,14 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_DIR_OPEN, 1);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
zfuncname,
&zretval,
2, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
/* the stream is now open! */
stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode);
@@ -473,7 +490,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
us->wrapper->classname);
}
-
+
/* destroy everything else */
if (stream == NULL) {
zval_ptr_dtor(&us->object);
@@ -481,13 +498,13 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
}
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zoptions);
zval_ptr_dtor(&zfilename);
FG(user_stream_current_filename) = NULL;
-
+
return stream;
}
@@ -501,11 +518,11 @@ PHP_FUNCTION(stream_wrapper_register)
struct php_user_stream_wrapper * uwrap;
int rsrc_id;
long flags = 0;
-
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &protocol, &protocol_len, &classname, &classname_len, &flags) == FAILURE) {
RETURN_FALSE;
}
-
+
uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
uwrap->protoname = estrndup(protocol, protocol_len);
uwrap->classname = estrndup(classname, classname_len);
@@ -591,7 +608,7 @@ PHP_FUNCTION(stream_wrapper_restore)
if (php_register_url_stream_wrapper_volatile(protocol, wrapper TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to restore original %s:// wrapper", protocol);
RETURN_FALSE;
- }
+ }
RETURN_TRUE;
}
@@ -639,10 +656,10 @@ static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t
(long)(didwrite - count), (long)didwrite, (long)count);
didwrite = count;
}
-
+
if (retval)
zval_ptr_dtor(&retval);
-
+
return didwrite;
}
@@ -727,9 +744,9 @@ static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
assert(us != NULL);
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -738,11 +755,11 @@ static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC
if (retval)
zval_ptr_dtor(&retval);
-
+
zval_ptr_dtor(&us->object);
efree(us);
-
+
return 0;
}
@@ -756,7 +773,7 @@ static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
assert(us != NULL);
ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1, 0);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -767,10 +784,10 @@ static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
call_result = 0;
else
call_result = -1;
-
+
if (retval)
zval_ptr_dtor(&retval);
-
+
return call_result;
}
@@ -809,10 +826,10 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o
/* stream_seek is not implemented, so disable seeks for this stream */
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
/* there should be no retval to clean up */
-
- if (retval)
+
+ if (retval)
zval_ptr_dtor(&retval);
-
+
return -1;
} else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
ret = 0;
@@ -895,8 +912,8 @@ static int statbuf_from_array(zval *array, php_stream_statbuf *ssb TSRMLS_DC)
STAT_PROP_ENTRY(blocks);
#endif
-#undef STAT_PROP_ENTRY
-#undef STAT_PROP_ENTRY_EX
+#undef STAT_PROP_ENTRY
+#undef STAT_PROP_ENTRY_EX
return SUCCESS;
}
@@ -926,9 +943,9 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb TSR
}
}
- if (retval)
+ if (retval)
zval_ptr_dtor(&retval);
-
+
return ret;
}
@@ -976,34 +993,34 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
}
args[0] = &zvalue;
-
+
/* TODO wouldblock */
ZVAL_STRINGL(&func_name, USERSTREAM_LOCK, sizeof(USERSTREAM_LOCK)-1, 0);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
&func_name,
&retval,
1, args, 0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
ret = !Z_LVAL_P(retval);
} else if (call_result == FAILURE) {
- if (value == 0) {
+ if (value == 0) {
/* lock support test (TODO: more check) */
ret = PHP_STREAM_OPTION_RETURN_OK;
} else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
us->wrapper->classname);
ret = PHP_STREAM_OPTION_RETURN_ERR;
}
}
break;
-
+
case PHP_STREAM_OPTION_TRUNCATE_API:
ZVAL_STRINGL(&func_name, USERSTREAM_TRUNCATE, sizeof(USERSTREAM_TRUNCATE)-1, 0);
-
+
switch (value) {
case PHP_STREAM_TRUNCATE_SUPPORTED:
if (zend_is_callable_ex(&func_name, us->object, IS_CALLABLE_CHECK_SILENT,
@@ -1012,7 +1029,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
else
ret = PHP_STREAM_OPTION_RETURN_ERR;
break;
-
+
case PHP_STREAM_TRUNCATE_SET_SIZE: {
ptrdiff_t new_size = *(ptrdiff_t*) ptrparam;
if (new_size >= 0 && new_size <= (ptrdiff_t)LONG_MAX) {
@@ -1045,14 +1062,14 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
}
}
break;
-
+
case PHP_STREAM_OPTION_READ_BUFFER:
case PHP_STREAM_OPTION_WRITE_BUFFER:
case PHP_STREAM_OPTION_READ_TIMEOUT:
case PHP_STREAM_OPTION_BLOCKING: {
zval *zoption = NULL;
zval *zptrparam = NULL;
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, sizeof(USERSTREAM_SET_OPTION)-1, 0);
ALLOC_INIT_ZVAL(zoption);
@@ -1093,7 +1110,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
&func_name,
&retval,
3, args, 0, NULL TSRMLS_CC);
-
+
if (call_result == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
us->wrapper->classname);
@@ -1119,7 +1136,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
if (retval) {
zval_ptr_dtor(&retval);
}
-
+
if (zvalue) {
zval_ptr_dtor(&zvalue);
@@ -1158,7 +1175,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_UNLINK, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1176,7 +1193,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
@@ -1216,7 +1233,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_RENAME, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1234,7 +1251,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zold_name);
zval_ptr_dtor(&znew_name);
@@ -1279,7 +1296,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode,
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_MKDIR, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1298,7 +1315,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode,
if (zretval) {
zval_ptr_dtor(&zretval);
}
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zmode);
@@ -1340,7 +1357,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_RMDIR, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1359,7 +1376,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
if (zretval) {
zval_ptr_dtor(&zretval);
}
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zoptions);
@@ -1367,11 +1384,100 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
return ret;
}
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zoption, *zvalue, *zfuncname, *zretval;
+ zval **args[3];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ MAKE_STD_ZVAL(zvalue);
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ array_init(zvalue);
+ if(value) {
+ struct utimbuf *newtime = (struct utimbuf *)value;
+ add_index_long(zvalue, 0, newtime->modtime);
+ add_index_long(zvalue, 1, newtime->actime);
+ }
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_OWNER:
+ case PHP_STREAM_META_ACCESS:
+ ZVAL_LONG(zvalue, *(long *)value);
+ break;
+ case PHP_STREAM_META_GROUP_NAME:
+ case PHP_STREAM_META_OWNER_NAME:
+ ZVAL_STRING(zvalue, value, 1);
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option %d for " USERSTREAM_METADATA, option);
+ zval_ptr_dtor(&zvalue);
+ return ret;
+ }
+
+ /* create an instance of our class */
+ ALLOC_ZVAL(object);
+ object_init_ex(object, uwrap->ce);
+ Z_SET_REFCOUNT_P(object, 1);
+ Z_SET_ISREF_P(object);
+
+ if (context) {
+ add_property_resource(object, "context", context->rsrc_id);
+ zend_list_addref(context->rsrc_id);
+ } else {
+ add_property_null(object, "context");
+ }
+
+ /* call the mkdir method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zoption);
+ ZVAL_LONG(zoption, option);
+ args[1] = &zoption;
+
+ args[2] = &zvalue;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_METADATA, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 3, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zoption);
+ zval_ptr_dtor(&zvalue);
+
+ return ret;
+}
+
+
static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
{
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
zval *zfilename, *zfuncname, *zretval, *zflags;
- zval **args[2];
+ zval **args[2];
int call_result;
zval *object;
int ret = -1;
@@ -1400,14 +1506,14 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int fla
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_STATURL, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
&zretval,
2, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && Z_TYPE_P(zretval) == IS_ARRAY) {
/* We got the info we needed */
if (SUCCESS == statbuf_from_array(zretval, ssb TSRMLS_CC))
@@ -1418,16 +1524,16 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int fla
uwrap->classname);
}
}
-
+
/* clean up */
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zflags);
-
+
return ret;
}
@@ -1477,9 +1583,9 @@ static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
assert(us != NULL);
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_DIR_CLOSE, sizeof(USERSTREAM_DIR_CLOSE)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -1488,11 +1594,11 @@ static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS
if (retval)
zval_ptr_dtor(&retval);
-
+
zval_ptr_dtor(&us->object);
efree(us);
-
+
return 0;
}
@@ -1503,7 +1609,7 @@ static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int when
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
ZVAL_STRINGL(&func_name, USERSTREAM_DIR_REWIND, sizeof(USERSTREAM_DIR_REWIND)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -1512,7 +1618,7 @@ static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int when
if (retval)
zval_ptr_dtor(&retval);
-
+
return 0;
}
@@ -1587,7 +1693,7 @@ php_stream_ops php_stream_userspace_ops = {
"user-space",
php_userstreamop_seek,
php_userstreamop_cast,
- php_userstreamop_stat,
+ php_userstreamop_stat,
php_userstreamop_set_option,
};