Skip to content

Commit 0b2e6bc

Browse files
committed
Cache d_type in directory entry
1 parent 00c1e7b commit 0b2e6bc

11 files changed

+41
-0
lines changed

UPGRADING.INTERNALS

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ PHP 8.3 INTERNALS UPGRADE NOTES
6767
- zend_set_user_opcode_handler
6868
- zend_ssa_inference
6969
* Removed unused macros PHP_FNV1_32A_INIT and PHP_FNV1A_64_INIT. See GH-11114.
70+
* _php_stream_dirent now has an extra d_type field that is used to store the
71+
directory entry type. This can be used to avoid additional stat calls for
72+
types when the type is already known.
7073

7174
========================
7275
2. Build system changes

Zend/zend_virtual_cwd.h

+10
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ typedef unsigned short mode_t;
8787
#else
8888
#ifdef HAVE_DIRENT_H
8989
#include <dirent.h>
90+
91+
#ifndef DT_UNKNOWN
92+
# define DT_UNKNOWN 0
93+
#endif
94+
#ifndef DT_DIR
95+
# define DT_DIR 4
96+
#endif
97+
#ifndef DT_REG
98+
# define DT_REG 8
99+
#endif
90100
#endif
91101

92102
#define DEFAULT_SLASH '/'

ext/phar/dirstream.c

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static ssize_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{
108108
memset(buf, 0, sizeof(php_stream_dirent));
109109
memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
110110
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
111+
((php_stream_dirent *) buf)->d_type = DT_UNKNOWN;
111112

112113
return sizeof(php_stream_dirent);
113114
}

ext/spl/spl_directory.c

+5
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,11 @@ PHP_METHOD(RecursiveDirectoryIterator, hasChildren)
14851485
if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
14861486
RETURN_FALSE;
14871487
} else {
1488+
if (intern->u.dir.entry.d_type == DT_DIR) {
1489+
RETURN_TRUE;
1490+
} else if (intern->u.dir.entry.d_type == DT_REG) {
1491+
RETURN_FALSE;
1492+
}
14881493
if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
14891494
RETURN_THROWS();
14901495
}

ext/standard/ftp_fopen_wrapper.c

+1
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ static ssize_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t coun
629629
memcpy(ent->d_name, ZSTR_VAL(basename), tmp_len);
630630
ent->d_name[tmp_len - 1] = '\0';
631631
zend_string_release_ex(basename, 0);
632+
ent->d_type = DT_UNKNOWN;
632633

633634
/* Trim off trailing whitespace characters */
634635
while (tmp_len > 0 &&

main/php_streams.h

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ typedef struct _php_stream_dirent {
112112
#else
113113
char d_name[MAXPATHLEN];
114114
#endif
115+
unsigned char d_type;
115116
} php_stream_dirent;
116117

117118
/* operations on streams that are file-handles */

main/streams/glob_wrapper.c

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count)
150150
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & GLOB_APPEND, &path);
151151
++pglob->index;
152152
PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
153+
ent->d_type = DT_UNKNOWN;
153154
return sizeof(php_stream_dirent);
154155
}
155156
pglob->index = glob_result_count;

main/streams/plain_wrapper.c

+5
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,11 @@ static ssize_t php_plain_files_dirstream_read(php_stream *stream, char *buf, siz
10321032
result = readdir(dir);
10331033
if (result) {
10341034
PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
1035+
#ifdef _DIRENT_HAVE_D_TYPE
1036+
ent->d_type = result->d_type;
1037+
#else
1038+
ent->d_type = DT_UNKNOWN;
1039+
#endif
10351040
return sizeof(php_stream_dirent);
10361041
}
10371042
return 0;

main/streams/userspace.c

+1
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co
13201320
if (call_result == SUCCESS && Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
13211321
convert_to_string(&retval);
13221322
PHP_STRLCPY(ent->d_name, Z_STRVAL(retval), sizeof(ent->d_name), Z_STRLEN(retval));
1323+
ent->d_type = DT_UNKNOWN;
13231324

13241325
didread = sizeof(php_stream_dirent);
13251326
} else if (call_result == FAILURE) {

win32/readdir.c

+7
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ struct dirent *readdir(DIR *dp)
120120

121121
dp->dent.d_ino = 1;
122122
dp->dent.d_off = dp->offset;
123+
if (dp->fileinfo.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DEVICE)) {
124+
dp->dent.d_type = DT_UNKNOWN; /* conservative */
125+
} else if (dp->fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
126+
dp->dent.d_type = DT_DIR;
127+
} else {
128+
dp->dent.d_type = DT_REG;
129+
}
123130

124131
return &(dp->dent);
125132
}/*}}}*/

win32/readdir.h

+6
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ extern "C" {
1515

1616
#include "ioutil.h"
1717

18+
#define _DIRENT_HAVE_D_TYPE
19+
#define DT_UNKNOWN 0
20+
#define DT_DIR 4
21+
#define DT_REG 8
22+
1823
/* struct dirent - same as Unix */
1924
struct dirent {
2025
long d_ino; /* inode (always 1 in WIN32) */
2126
off_t d_off; /* offset to this dirent */
2227
unsigned short d_reclen; /* length of d_name */
28+
unsigned char d_type;
2329
char d_name[1]; /* null terminated filename in the current encoding, glyph number <= 255 wchar_t's + \0 byte */
2430
};
2531

0 commit comments

Comments
 (0)