diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | ext/standard/filestat.c | 200 | ||||
-rw-r--r-- | ext/standard/tests/file/userstreams_007.phpt | 49 | ||||
-rwxr-xr-x | main/php_streams.h | 11 | ||||
-rw-r--r-- | main/streams/plain_wrapper.c | 94 | ||||
-rw-r--r-- | main/streams/userspace.c | 270 |
6 files changed, 500 insertions, 126 deletions
@@ -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, }; |