mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
ext/standard/dir.c: Refactor implementation of Directory and dir functions
This commit is contained in:
parent
2c326d8222
commit
4101a8c099
11 changed files with 161 additions and 104 deletions
|
@ -59,39 +59,6 @@ static zend_function *dir_class_get_constructor(zend_object *object)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define FETCH_DIRP() \
|
||||
myself = getThis(); \
|
||||
if (!myself) { \
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1) \
|
||||
Z_PARAM_OPTIONAL \
|
||||
Z_PARAM_RESOURCE_OR_NULL(id) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
if (id) { \
|
||||
if ((dirp = (php_stream *)zend_fetch_resource(Z_RES_P(id), "Directory", php_file_le_stream())) == NULL) { \
|
||||
RETURN_THROWS(); \
|
||||
} \
|
||||
} else { \
|
||||
if (!DIRG(default_dir)) { \
|
||||
zend_type_error("No resource supplied"); \
|
||||
RETURN_THROWS(); \
|
||||
} \
|
||||
if ((dirp = (php_stream *)zend_fetch_resource(DIRG(default_dir), "Directory", php_file_le_stream())) == NULL) { \
|
||||
RETURN_THROWS(); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
ZEND_PARSE_PARAMETERS_NONE(); \
|
||||
zval *handle_zv = Z_DIRECTORY_HANDLE_P(myself); \
|
||||
if (Z_TYPE_P(handle_zv) != IS_RESOURCE) { \
|
||||
zend_throw_error(NULL, "Unable to find my handle property"); \
|
||||
RETURN_THROWS(); \
|
||||
} \
|
||||
if ((dirp = (php_stream *)zend_fetch_resource_ex(handle_zv, "Directory", php_file_le_stream())) == NULL) { \
|
||||
RETURN_THROWS(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
static void php_set_default_dir(zend_resource *res)
|
||||
{
|
||||
if (DIRG(default_dir)) {
|
||||
|
@ -189,22 +156,72 @@ PHP_FUNCTION(dir)
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
static php_stream* php_dir_get_directory_stream_from_user_arg(zval *arg)
|
||||
{
|
||||
zend_resource *res;
|
||||
if (arg == NULL) {
|
||||
if (UNEXPECTED(DIRG(default_dir) == NULL)) {
|
||||
zend_type_error("No resource supplied");
|
||||
return NULL;
|
||||
}
|
||||
res = DIRG(default_dir);
|
||||
} else {
|
||||
ZEND_ASSERT(Z_TYPE_P(arg) == IS_RESOURCE);
|
||||
res = Z_RES_P(arg);
|
||||
}
|
||||
|
||||
if (UNEXPECTED(res->type != php_file_le_stream())) {
|
||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
||||
return NULL;
|
||||
}
|
||||
php_stream *dir_stream = (php_stream*) res->ptr;
|
||||
if (UNEXPECTED((dir_stream->flags & PHP_STREAM_FLAG_IS_DIR)) == 0) {
|
||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
||||
return NULL;
|
||||
}
|
||||
return dir_stream;
|
||||
}
|
||||
|
||||
static php_stream* php_dir_get_directory_stream_from_this(zval *this_z)
|
||||
{
|
||||
zval *handle_zv = Z_DIRECTORY_HANDLE_P(this_z);
|
||||
if (UNEXPECTED(Z_TYPE_P(handle_zv) != IS_RESOURCE)) {
|
||||
zend_throw_error(NULL, "Internal directory stream has been altered");
|
||||
return NULL;
|
||||
}
|
||||
zend_resource *res = Z_RES_P(handle_zv);
|
||||
/* Assume the close() method was called
|
||||
* (instead of the hacky case where a different resource would have been set via the ArrayObject "hack") */
|
||||
if (UNEXPECTED(res->type != php_file_le_stream())) {
|
||||
/* TypeError is used for BC, TODO: Use base Error in PHP 9 */
|
||||
zend_type_error("Directory::%s(): cannot use Directory resource after it has been closed", get_active_function_name());
|
||||
return NULL;
|
||||
}
|
||||
php_stream *dir_stream = (php_stream*) res->ptr;
|
||||
if (UNEXPECTED((dir_stream->flags & PHP_STREAM_FLAG_IS_DIR)) == 0) {
|
||||
zend_throw_error(NULL, "Internal directory stream has been altered");
|
||||
return NULL;
|
||||
}
|
||||
return dir_stream;
|
||||
}
|
||||
|
||||
/* {{{ Close directory connection identified by the dir_handle */
|
||||
PHP_FUNCTION(closedir)
|
||||
{
|
||||
zval *id = NULL, *myself;
|
||||
php_stream *dirp;
|
||||
zend_resource *res;
|
||||
zval *id = NULL;
|
||||
|
||||
FETCH_DIRP();
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_RESOURCE_OR_NULL(id)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
|
||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_user_arg(id);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
res = dirp->res;
|
||||
zend_list_close(dirp->res);
|
||||
zend_resource *res = dirp->res;
|
||||
zend_list_close(res);
|
||||
|
||||
if (res == DIRG(default_dir)) {
|
||||
php_set_default_dir(NULL);
|
||||
|
@ -212,6 +229,93 @@ PHP_FUNCTION(closedir)
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(Directory, close)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_resource *res = dirp->res;
|
||||
zend_list_close(res);
|
||||
|
||||
if (res == DIRG(default_dir)) {
|
||||
php_set_default_dir(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ Rewind dir_handle back to the start */
|
||||
PHP_FUNCTION(rewinddir)
|
||||
{
|
||||
zval *id = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_RESOURCE_OR_NULL(id)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_user_arg(id);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_stream_rewinddir(dirp);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(Directory, rewind)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_stream_rewinddir(dirp);
|
||||
}
|
||||
|
||||
/* {{{ Read directory entry from dir_handle */
|
||||
PHP_FUNCTION(readdir)
|
||||
{
|
||||
zval *id = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_RESOURCE_OR_NULL(id)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_user_arg(id);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_stream_dirent entry;
|
||||
if (php_stream_readdir(dirp, &entry)) {
|
||||
RETURN_STRING(entry.d_name);
|
||||
}
|
||||
RETURN_FALSE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(Directory, read)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
php_stream *dirp = php_dir_get_directory_stream_from_this(ZEND_THIS);
|
||||
if (UNEXPECTED(dirp == NULL)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_stream_dirent entry;
|
||||
if (php_stream_readdir(dirp, &entry)) {
|
||||
RETURN_STRING(entry.d_name);
|
||||
}
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
#if defined(HAVE_CHROOT) && !defined(ZTS) && defined(ENABLE_CHROOT_FUNC)
|
||||
/* {{{ Change root directory */
|
||||
PHP_FUNCTION(chroot)
|
||||
|
@ -300,44 +404,6 @@ PHP_FUNCTION(getcwd)
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Rewind dir_handle back to the start */
|
||||
PHP_FUNCTION(rewinddir)
|
||||
{
|
||||
zval *id = NULL, *myself;
|
||||
php_stream *dirp;
|
||||
|
||||
FETCH_DIRP();
|
||||
|
||||
if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
|
||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_stream_rewinddir(dirp);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Read directory entry from dir_handle */
|
||||
PHP_FUNCTION(readdir)
|
||||
{
|
||||
zval *id = NULL, *myself;
|
||||
php_stream *dirp;
|
||||
php_stream_dirent entry;
|
||||
|
||||
FETCH_DIRP();
|
||||
|
||||
if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
|
||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (php_stream_readdir(dirp, &entry)) {
|
||||
RETURN_STRINGL(entry.d_name, strlen(entry.d_name));
|
||||
}
|
||||
RETURN_FALSE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
/* {{{ Find pathnames matching a pattern */
|
||||
PHP_FUNCTION(glob)
|
||||
|
|
|
@ -98,18 +98,9 @@ final class Directory
|
|||
/** @var resource */
|
||||
public readonly mixed $handle;
|
||||
|
||||
/**
|
||||
* @implementation-alias closedir
|
||||
*/
|
||||
public function close(): void {}
|
||||
|
||||
/**
|
||||
* @implementation-alias rewinddir
|
||||
*/
|
||||
public function rewind(): void {}
|
||||
|
||||
/**
|
||||
* @implementation-alias readdir
|
||||
*/
|
||||
public function read(): string|false {}
|
||||
}
|
||||
|
|
14
ext/standard/dir_arginfo.h
generated
14
ext/standard/dir_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 069117bab1b9502faf516307aa7e80308f7b7f13 */
|
||||
* Stub hash: 543d0d12062ed88dab7a3ac4354499682c5c7166 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
@ -9,14 +9,14 @@ ZEND_END_ARG_INFO()
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Directory_read, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_FUNCTION(closedir);
|
||||
ZEND_FUNCTION(rewinddir);
|
||||
ZEND_FUNCTION(readdir);
|
||||
ZEND_METHOD(Directory, close);
|
||||
ZEND_METHOD(Directory, rewind);
|
||||
ZEND_METHOD(Directory, read);
|
||||
|
||||
static const zend_function_entry class_Directory_methods[] = {
|
||||
ZEND_RAW_FENTRY("close", zif_closedir, arginfo_class_Directory_close, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("rewind", zif_rewinddir, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("read", zif_readdir, arginfo_class_Directory_read, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_ME(Directory, close, arginfo_class_Directory_close, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Directory, rewind, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Directory, read, arginfo_class_Directory_read, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
|
|
@ -47,5 +47,5 @@ NULL
|
|||
Directory Handle: resource(%d) of type (Unknown)
|
||||
|
||||
-- Close directory handle second time: --
|
||||
closedir(): %s is not a valid Directory resource
|
||||
closedir(): Argument #1 ($dir_handle) must be a valid Directory resource
|
||||
Directory Handle: resource(%d) of type (Unknown)
|
||||
|
|
|
@ -41,5 +41,5 @@ NULL
|
|||
Directory Handle: resource(%d) of type (Unknown)
|
||||
|
||||
-- Close directory handle second time: --
|
||||
closedir(): supplied resource is not a valid Directory resource
|
||||
closedir(): Argument #1 ($dir_handle) must be a valid Directory resource
|
||||
Directory Handle: resource(%d) of type (Unknown)
|
||||
|
|
|
@ -85,5 +85,5 @@ object(Directory)#%d (2) {
|
|||
}
|
||||
|
||||
Test read after closing the dir:
|
||||
Directory::read(): %s is not a valid Directory resource
|
||||
Directory::read(): cannot use Directory resource after it has been closed
|
||||
Done
|
||||
|
|
|
@ -79,5 +79,5 @@ object(Directory)#%d (2) {
|
|||
}
|
||||
|
||||
Test read after closing the dir:
|
||||
Directory::read(): supplied resource is not a valid Directory resource
|
||||
Directory::read(): cannot use Directory resource after it has been closed
|
||||
Done
|
||||
|
|
|
@ -42,4 +42,4 @@ resource(%d) of type (stream)
|
|||
string(%d) "%s"
|
||||
|
||||
-- Call to rewinddir() --
|
||||
rewinddir(): %s is not a valid Directory resource
|
||||
rewinddir(): Argument #1 ($dir_handle) must be a valid Directory resource
|
||||
|
|
|
@ -36,4 +36,4 @@ resource(%d) of type (stream)
|
|||
string(%d) "%s"
|
||||
|
||||
-- Call to rewinddir() --
|
||||
rewinddir(): supplied resource is not a valid Directory resource
|
||||
rewinddir(): Argument #1 ($dir_handle) must be a valid Directory resource
|
||||
|
|
|
@ -30,5 +30,5 @@ try {
|
|||
?>
|
||||
--EXPECT--
|
||||
resource(3) of type (stream)
|
||||
TypeError: Directory::read(): Argument #1 must be a valid Directory resource
|
||||
Error: Internal directory stream has been altered
|
||||
Error: Typed property Directory::$handle must not be accessed before initialization
|
||||
|
|
|
@ -27,4 +27,4 @@ object(Directory)#2 (0) {
|
|||
["handle"]=>
|
||||
uninitialized(mixed)
|
||||
}
|
||||
Error: Unable to find my handle property
|
||||
Error: Internal directory stream has been altered
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue