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;
|
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)
|
static void php_set_default_dir(zend_resource *res)
|
||||||
{
|
{
|
||||||
if (DIRG(default_dir)) {
|
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 */
|
/* {{{ Close directory connection identified by the dir_handle */
|
||||||
PHP_FUNCTION(closedir)
|
PHP_FUNCTION(closedir)
|
||||||
{
|
{
|
||||||
zval *id = NULL, *myself;
|
zval *id = NULL;
|
||||||
php_stream *dirp;
|
|
||||||
zend_resource *res;
|
|
||||||
|
|
||||||
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)) {
|
php_stream *dirp = php_dir_get_directory_stream_from_user_arg(id);
|
||||||
zend_argument_type_error(1, "must be a valid Directory resource");
|
if (UNEXPECTED(dirp == NULL)) {
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
zend_resource *res = dirp->res;
|
||||||
res = dirp->res;
|
zend_list_close(res);
|
||||||
zend_list_close(dirp->res);
|
|
||||||
|
|
||||||
if (res == DIRG(default_dir)) {
|
if (res == DIRG(default_dir)) {
|
||||||
php_set_default_dir(NULL);
|
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)
|
#if defined(HAVE_CHROOT) && !defined(ZTS) && defined(ENABLE_CHROOT_FUNC)
|
||||||
/* {{{ Change root directory */
|
/* {{{ Change root directory */
|
||||||
PHP_FUNCTION(chroot)
|
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
|
#ifdef HAVE_GLOB
|
||||||
/* {{{ Find pathnames matching a pattern */
|
/* {{{ Find pathnames matching a pattern */
|
||||||
PHP_FUNCTION(glob)
|
PHP_FUNCTION(glob)
|
||||||
|
|
|
@ -98,18 +98,9 @@ final class Directory
|
||||||
/** @var resource */
|
/** @var resource */
|
||||||
public readonly mixed $handle;
|
public readonly mixed $handle;
|
||||||
|
|
||||||
/**
|
|
||||||
* @implementation-alias closedir
|
|
||||||
*/
|
|
||||||
public function close(): void {}
|
public function close(): void {}
|
||||||
|
|
||||||
/**
|
|
||||||
* @implementation-alias rewinddir
|
|
||||||
*/
|
|
||||||
public function rewind(): void {}
|
public function rewind(): void {}
|
||||||
|
|
||||||
/**
|
|
||||||
* @implementation-alias readdir
|
|
||||||
*/
|
|
||||||
public function read(): string|false {}
|
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.
|
/* 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_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0)
|
||||||
ZEND_END_ARG_INFO()
|
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_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Directory_read, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
ZEND_FUNCTION(closedir);
|
ZEND_METHOD(Directory, close);
|
||||||
ZEND_FUNCTION(rewinddir);
|
ZEND_METHOD(Directory, rewind);
|
||||||
ZEND_FUNCTION(readdir);
|
ZEND_METHOD(Directory, read);
|
||||||
|
|
||||||
static const zend_function_entry class_Directory_methods[] = {
|
static const zend_function_entry class_Directory_methods[] = {
|
||||||
ZEND_RAW_FENTRY("close", zif_closedir, arginfo_class_Directory_close, ZEND_ACC_PUBLIC, NULL, NULL)
|
ZEND_ME(Directory, close, arginfo_class_Directory_close, ZEND_ACC_PUBLIC)
|
||||||
ZEND_RAW_FENTRY("rewind", zif_rewinddir, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC, NULL, NULL)
|
ZEND_ME(Directory, rewind, arginfo_class_Directory_rewind, ZEND_ACC_PUBLIC)
|
||||||
ZEND_RAW_FENTRY("read", zif_readdir, arginfo_class_Directory_read, ZEND_ACC_PUBLIC, NULL, NULL)
|
ZEND_ME(Directory, read, arginfo_class_Directory_read, ZEND_ACC_PUBLIC)
|
||||||
ZEND_FE_END
|
ZEND_FE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,5 +47,5 @@ NULL
|
||||||
Directory Handle: resource(%d) of type (Unknown)
|
Directory Handle: resource(%d) of type (Unknown)
|
||||||
|
|
||||||
-- Close directory handle second time: --
|
-- 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)
|
Directory Handle: resource(%d) of type (Unknown)
|
||||||
|
|
|
@ -41,5 +41,5 @@ NULL
|
||||||
Directory Handle: resource(%d) of type (Unknown)
|
Directory Handle: resource(%d) of type (Unknown)
|
||||||
|
|
||||||
-- Close directory handle second time: --
|
-- 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)
|
Directory Handle: resource(%d) of type (Unknown)
|
||||||
|
|
|
@ -85,5 +85,5 @@ object(Directory)#%d (2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Test read after closing the dir:
|
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
|
Done
|
||||||
|
|
|
@ -79,5 +79,5 @@ object(Directory)#%d (2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Test read after closing the dir:
|
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
|
Done
|
||||||
|
|
|
@ -42,4 +42,4 @@ resource(%d) of type (stream)
|
||||||
string(%d) "%s"
|
string(%d) "%s"
|
||||||
|
|
||||||
-- Call to rewinddir() --
|
-- 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"
|
string(%d) "%s"
|
||||||
|
|
||||||
-- Call to rewinddir() --
|
-- 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--
|
--EXPECT--
|
||||||
resource(3) of type (stream)
|
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
|
Error: Typed property Directory::$handle must not be accessed before initialization
|
||||||
|
|
|
@ -27,4 +27,4 @@ object(Directory)#2 (0) {
|
||||||
["handle"]=>
|
["handle"]=>
|
||||||
uninitialized(mixed)
|
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