From: Stanislav Malyshev Date: Wed, 25 May 2011 21:03:55 +0000 (+0000) Subject: implement streams metadata API per RFC X-Git-Tag: php-5.5.0alpha1~2041 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9088156f4983c82b89729257066171229d95f03;p=php implement streams metadata API per RFC --- 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-- + +#if HAVE_UTIME +# ifdef PHP_WIN32 +# include +# else +# include +# 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, };