Cache d_type in directory entry

This commit is contained in:
Niels Dossche 2023-07-02 14:35:43 +02:00
parent 00c1e7bf0f
commit 0b2e6bc2b0
11 changed files with 41 additions and 0 deletions

View File

@ -67,6 +67,9 @@ PHP 8.3 INTERNALS UPGRADE NOTES
- zend_set_user_opcode_handler
- zend_ssa_inference
* Removed unused macros PHP_FNV1_32A_INIT and PHP_FNV1A_64_INIT. See GH-11114.
* _php_stream_dirent now has an extra d_type field that is used to store the
directory entry type. This can be used to avoid additional stat calls for
types when the type is already known.
========================
2. Build system changes

View File

@ -87,6 +87,16 @@ typedef unsigned short mode_t;
#else
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#ifndef DT_UNKNOWN
# define DT_UNKNOWN 0
#endif
#ifndef DT_DIR
# define DT_DIR 4
#endif
#ifndef DT_REG
# define DT_REG 8
#endif
#endif
#define DEFAULT_SLASH '/'

View File

@ -108,6 +108,7 @@ static ssize_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{
memset(buf, 0, sizeof(php_stream_dirent));
memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
((php_stream_dirent *) buf)->d_type = DT_UNKNOWN;
return sizeof(php_stream_dirent);
}

View File

@ -1485,6 +1485,11 @@ PHP_METHOD(RecursiveDirectoryIterator, hasChildren)
if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
RETURN_FALSE;
} else {
if (intern->u.dir.entry.d_type == DT_DIR) {
RETURN_TRUE;
} else if (intern->u.dir.entry.d_type == DT_REG) {
RETURN_FALSE;
}
if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
RETURN_THROWS();
}

View File

@ -629,6 +629,7 @@ static ssize_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t coun
memcpy(ent->d_name, ZSTR_VAL(basename), tmp_len);
ent->d_name[tmp_len - 1] = '\0';
zend_string_release_ex(basename, 0);
ent->d_type = DT_UNKNOWN;
/* Trim off trailing whitespace characters */
while (tmp_len > 0 &&

View File

@ -112,6 +112,7 @@ typedef struct _php_stream_dirent {
#else
char d_name[MAXPATHLEN];
#endif
unsigned char d_type;
} php_stream_dirent;
/* operations on streams that are file-handles */

View File

@ -150,6 +150,7 @@ static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count)
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & GLOB_APPEND, &path);
++pglob->index;
PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
ent->d_type = DT_UNKNOWN;
return sizeof(php_stream_dirent);
}
pglob->index = glob_result_count;

View File

@ -1032,6 +1032,11 @@ static ssize_t php_plain_files_dirstream_read(php_stream *stream, char *buf, siz
result = readdir(dir);
if (result) {
PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
#ifdef _DIRENT_HAVE_D_TYPE
ent->d_type = result->d_type;
#else
ent->d_type = DT_UNKNOWN;
#endif
return sizeof(php_stream_dirent);
}
return 0;

View File

@ -1320,6 +1320,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co
if (call_result == SUCCESS && Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
convert_to_string(&retval);
PHP_STRLCPY(ent->d_name, Z_STRVAL(retval), sizeof(ent->d_name), Z_STRLEN(retval));
ent->d_type = DT_UNKNOWN;
didread = sizeof(php_stream_dirent);
} else if (call_result == FAILURE) {

View File

@ -120,6 +120,13 @@ struct dirent *readdir(DIR *dp)
dp->dent.d_ino = 1;
dp->dent.d_off = dp->offset;
if (dp->fileinfo.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DEVICE)) {
dp->dent.d_type = DT_UNKNOWN; /* conservative */
} else if (dp->fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
dp->dent.d_type = DT_DIR;
} else {
dp->dent.d_type = DT_REG;
}
return &(dp->dent);
}/*}}}*/

View File

@ -15,11 +15,17 @@ extern "C" {
#include "ioutil.h"
#define _DIRENT_HAVE_D_TYPE
#define DT_UNKNOWN 0
#define DT_DIR 4
#define DT_REG 8
/* struct dirent - same as Unix */
struct dirent {
long d_ino; /* inode (always 1 in WIN32) */
off_t d_off; /* offset to this dirent */
unsigned short d_reclen; /* length of d_name */
unsigned char d_type;
char d_name[1]; /* null terminated filename in the current encoding, glyph number <= 255 wchar_t's + \0 byte */
};