mirror of
https://github.com/php/php-src.git
synced 2026-04-05 15:12:39 +02:00
MFH: Fix filesystemiterator with ./.. + add cloning tests
This commit is contained in:
@@ -200,10 +200,18 @@ static int spl_filesystem_dir_read(spl_filesystem_object *intern TSRMLS_DC) /* {
|
||||
|
||||
#define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
|
||||
|
||||
static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
|
||||
{
|
||||
return !strcmp(d_name, ".") || !strcmp(d_name, "..");
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_filesystem_dir_open */
|
||||
/* open a directory resource */
|
||||
static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path TSRMLS_DC)
|
||||
{
|
||||
int skip_dots = intern->flags & SPL_FILE_DIR_SKIPDOTS;
|
||||
|
||||
intern->type = SPL_FS_DIR;
|
||||
intern->_path_len = strlen(path);
|
||||
intern->u.dir.dirp = php_stream_opendir(path, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
|
||||
@@ -219,7 +227,9 @@ static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path TS
|
||||
/* throw exception: should've been already happened */
|
||||
intern->u.dir.entry.d_name[0] = '\0';
|
||||
} else {
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
do {
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
@@ -277,6 +287,7 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
|
||||
zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
|
||||
spl_filesystem_object *intern;
|
||||
spl_filesystem_object *source;
|
||||
int index, skip_dots;
|
||||
|
||||
old_object = zend_objects_get_address(zobject TSRMLS_CC);
|
||||
source = (spl_filesystem_object*)old_object;
|
||||
@@ -284,6 +295,8 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
|
||||
new_obj_val = spl_filesystem_object_new_ex(old_object->ce, &intern TSRMLS_CC);
|
||||
new_object = &intern->std;
|
||||
|
||||
intern->flags = source->flags;
|
||||
|
||||
switch (source->type) {
|
||||
case SPL_FS_INFO:
|
||||
intern->_path_len = source->_path_len;
|
||||
@@ -293,6 +306,14 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
|
||||
break;
|
||||
case SPL_FS_DIR:
|
||||
spl_filesystem_dir_open(intern, source->_path TSRMLS_CC);
|
||||
/* read until we hit the position in which we were before */
|
||||
skip_dots = source->flags & SPL_FILE_DIR_SKIPDOTS;
|
||||
for(index = 0; index < source->u.dir.index; ++index) {
|
||||
do {
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
|
||||
}
|
||||
intern->u.dir.index = index;
|
||||
break;
|
||||
case SPL_FS_FILE:
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "An object of class %s cannot be cloned", old_object->ce->name);
|
||||
@@ -301,7 +322,6 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
|
||||
|
||||
intern->file_class = source->file_class;
|
||||
intern->info_class = source->info_class;
|
||||
intern->flags = source->flags;
|
||||
intern->oth = source->oth;
|
||||
intern->oth_handler = source->oth_handler;
|
||||
|
||||
@@ -468,12 +488,6 @@ static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_fil
|
||||
return NULL;
|
||||
} /* }}} */
|
||||
|
||||
static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
|
||||
{
|
||||
return !strcmp(d_name, ".") || !strcmp(d_name, "..");
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
|
||||
{
|
||||
return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
|
||||
@@ -562,6 +576,9 @@ void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, int ctor_flag
|
||||
flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
|
||||
parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len);
|
||||
}
|
||||
if (ctor_flags & SPL_FILE_DIR_SKIPDOTS) {
|
||||
flags |= SPL_FILE_DIR_SKIPDOTS;
|
||||
}
|
||||
if (parsed == FAILURE) {
|
||||
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
|
||||
return;
|
||||
@@ -573,6 +590,7 @@ void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, int ctor_flag
|
||||
}
|
||||
|
||||
intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
intern->flags = flags;
|
||||
if ((ctor_flags & DIT_CTOR_GLOB) && strstr(path, "glob://") != path) {
|
||||
spprintf(&path, 0, "glob://%s", path);
|
||||
spl_filesystem_dir_open(intern, path TSRMLS_CC);
|
||||
@@ -582,7 +600,6 @@ void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, int ctor_flag
|
||||
}
|
||||
|
||||
intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator TSRMLS_CC) ? 1 : 0;
|
||||
intern->flags = flags;
|
||||
|
||||
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
|
||||
}
|
||||
@@ -637,9 +654,12 @@ SPL_METHOD(DirectoryIterator, current)
|
||||
SPL_METHOD(DirectoryIterator, next)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
int skip_dots = intern->flags & SPL_FILE_DIR_SKIPDOTS;
|
||||
|
||||
intern->u.dir.index++;
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
do {
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
|
||||
if (intern->file_name) {
|
||||
efree(intern->file_name);
|
||||
intern->file_name = NULL;
|
||||
@@ -1071,7 +1091,7 @@ SPL_METHOD(SplFileInfo, getPathInfo)
|
||||
Cronstructs a new dir iterator from a path. */
|
||||
SPL_METHOD(FilesystemIterator, __construct)
|
||||
{
|
||||
spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
|
||||
spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1091,30 +1111,13 @@ SPL_METHOD(FilesystemIterator, rewind)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void FilesystemIterator::next()
|
||||
Move to next entry */
|
||||
SPL_METHOD(FilesystemIterator, next)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
intern->u.dir.index++;
|
||||
do {
|
||||
spl_filesystem_dir_read(intern TSRMLS_CC);
|
||||
} while (spl_filesystem_is_dot(intern->u.dir.entry.d_name));
|
||||
if (intern->file_name) {
|
||||
efree(intern->file_name);
|
||||
intern->file_name = NULL;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int FilesystemIterator::getFlags()
|
||||
Get handling flags */
|
||||
SPL_METHOD(FilesystemIterator, getFlags)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
RETURN_LONG(intern->flags);
|
||||
RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK));
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ proto void FilesystemIterator::setFlags(long $flags)
|
||||
@@ -1609,7 +1612,7 @@ ZEND_END_ARG_INFO()
|
||||
static const zend_function_entry spl_FilesystemIterator_functions[] = {
|
||||
SPL_ME(FilesystemIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(FilesystemIterator, rewind, NULL, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(FilesystemIterator, next, NULL, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(DirectoryIterator, next, NULL, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(FilesystemIterator, key, NULL, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(FilesystemIterator, current, NULL, ZEND_ACC_PUBLIC)
|
||||
SPL_ME(FilesystemIterator, getFlags, NULL, ZEND_ACC_PUBLIC)
|
||||
@@ -2033,7 +2036,7 @@ SPL_METHOD(SplFileObject, getFlags)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
RETURN_LONG(intern->flags);
|
||||
RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ proto void SplFileObject::setMaxLineLen(int max_len)
|
||||
|
||||
@@ -115,6 +115,7 @@ static inline spl_filesystem_object* spl_filesystem_iterator_to_object(spl_files
|
||||
#define SPL_FILE_OBJECT_READ_AHEAD 0x00000002 /* read on rewind/next */
|
||||
#define SPL_FILE_OBJECT_SKIP_EMPTY 0x00000006 /* skip empty lines */
|
||||
#define SPL_FILE_OBJECT_READ_CSV 0x00000008 /* read via fgetcsv */
|
||||
#define SPL_FILE_OBJECT_MASK 0x0000000F /* read via fgetcsv */
|
||||
|
||||
#define SPL_FILE_DIR_CURRENT_AS_FILEINFO 0x00000000 /* make RecursiveDirectoryTree::current() return SplFileInfo */
|
||||
#define SPL_FILE_DIR_CURRENT_AS_SELF 0x00000010 /* make RecursiveDirectoryTree::current() return getSelf() */
|
||||
@@ -127,6 +128,8 @@ static inline spl_filesystem_object* spl_filesystem_iterator_to_object(spl_files
|
||||
#define SPL_FILE_DIR_KEY_MODE_MASK 0x00000F00 /* mask RecursiveDirectoryTree::key() */
|
||||
#define SPL_FILE_DIR_KEY(intern,mode) ((intern->flags&SPL_FILE_DIR_KEY_MODE_MASK)==mode)
|
||||
|
||||
#define SPL_FILE_DIR_SKIPDOTS 0x00001000 /* Tells whether it should skip dots or not */
|
||||
|
||||
#endif /* SPL_DIRECTORY_H */
|
||||
|
||||
/*
|
||||
|
||||
26
ext/spl/tests/dit_004.phpt
Normal file
26
ext/spl/tests/dit_004.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
SPL: DirectoryIterator and clone
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("spl")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$a = new DirectoryIterator(__DIR__);
|
||||
$b = clone $a;
|
||||
var_dump((string)$b == (string)$a);
|
||||
var_dump($a->key(), $b->key());
|
||||
$a->next();
|
||||
$a->next();
|
||||
$a->next();
|
||||
$c = clone $a;
|
||||
var_dump((string)$c == (string)$a);
|
||||
var_dump($a->key(), $c->key());
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
||||
bool(true)
|
||||
int(3)
|
||||
int(3)
|
||||
===DONE===
|
||||
24
ext/spl/tests/dit_005.phpt
Normal file
24
ext/spl/tests/dit_005.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
SPL: FilesystemIterator and clone
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("spl")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$a = new FileSystemIterator(__DIR__);
|
||||
$b = clone $a;
|
||||
var_dump((string)$b == (string)$a);
|
||||
var_dump($a->key() == $b->key());
|
||||
$a->next();
|
||||
$a->next();
|
||||
$a->next();
|
||||
$c = clone $a;
|
||||
var_dump((string)$c == (string)$a);
|
||||
var_dump($a->key() == $c->key());
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
===DONE===
|
||||
Reference in New Issue
Block a user