@@ -31,6 +31,10 @@ static_assert(DT_REG == __WASI_FILETYPE_REGULAR_FILE, "Value mismatch");
3131static_assert (DT_UNKNOWN == __WASI_FILETYPE_UNKNOWN , "Value mismatch" );
3232#endif
3333
34+ #ifdef __wasip3__
35+ #include <wasi/wasip3_block.h>
36+ #endif
37+
3438// Grows a buffer to be large enough to hold a certain amount of data.
3539#define GROW (buffer , buffer_size , target_size ) \
3640 do { \
@@ -140,12 +144,13 @@ struct dirent *readdir(DIR *dirp) {
140144 }
141145}
142146
143- #elif defined(__wasip2__ )
147+ #elif defined(__wasip2__ ) || defined( __wasip3__ )
144148
145149static int ensure_has_directory_stream (DIR * dirp , filesystem_borrow_descriptor_t * handle ) {
146150 if (fd_to_file_handle (dirp -> fd , handle ) < 0 )
147151 return -1 ;
148152
153+ #ifdef __wasip2__
149154 if (dirp -> stream .__handle != 0 )
150155 return 0 ;
151156
@@ -157,10 +162,15 @@ static int ensure_has_directory_stream(DIR *dirp, filesystem_borrow_descriptor_t
157162 translate_error (error_code );
158163 return -1 ;
159164 }
165+ #elif defined(__wasip3__ )
166+ if (dirp -> stream .f0 == 0 )
167+ filesystem_method_descriptor_read_directory (* handle , & dirp -> stream );
168+ #endif
160169 return 0 ;
161170}
162171
163172static struct dirent * readdir_next (DIR * dirp ) {
173+ bool ok ;
164174 filesystem_metadata_hash_value_t metadata ;
165175 filesystem_error_code_t error_code ;
166176 filesystem_borrow_descriptor_t dir_handle ;
@@ -173,7 +183,7 @@ static struct dirent *readdir_next(DIR *dirp) {
173183 if (dirp -> offset == 0 ) {
174184 dirp -> offset += 1 ;
175185 GROW (dirp -> dirent , dirp -> dirent_size , offsetof(struct dirent , d_name ) + 2 );
176- bool ok = filesystem_method_descriptor_metadata_hash (dir_handle ,
186+ ok = filesystem_method_descriptor_metadata_hash (dir_handle ,
177187 & metadata ,
178188 & error_code );
179189 if (!ok ) {
@@ -200,11 +210,12 @@ static struct dirent *readdir_next(DIR *dirp) {
200210 return dirp -> dirent ;
201211 }
202212
213+ #if defined(__wasip2__ )
203214 filesystem_borrow_directory_entry_stream_t stream = filesystem_borrow_directory_entry_stream (dirp -> stream );
204215 filesystem_option_directory_entry_t dir_entry_optional ;
205- bool ok = filesystem_method_directory_entry_stream_read_directory_entry (stream ,
206- & dir_entry_optional ,
207- & error_code );
216+ ok = filesystem_method_directory_entry_stream_read_directory_entry (stream ,
217+ & dir_entry_optional ,
218+ & error_code );
208219 if (!ok ) {
209220 translate_error (error_code );
210221 return NULL ;
@@ -216,6 +227,46 @@ static struct dirent *readdir_next(DIR *dirp) {
216227
217228 filesystem_directory_entry_t dir_entry = dir_entry_optional .val ;
218229
230+ #elif defined(__wasip3__ )
231+ filesystem_directory_entry_t dir_entry ;
232+
233+ // Loop until at least one stream entry is read, or until the stream is closed.
234+ bool closed = false;
235+ while (1 ) {
236+ size_t amount =
237+ wasip3_stream_block_on (
238+ filesystem_stream_directory_entry_read (dirp -> stream .f0 , & dir_entry , 1 ),
239+ dirp -> stream .f0 ,
240+ & closed );
241+
242+ // If something was read, then break out and process that below.
243+ if (amount > 0 )
244+ break ;
245+
246+ // If nothing was read and the stream isn't finished yet, try again.
247+ if (!closed )
248+ continue ;
249+
250+ // If the stream's result future hasn't been read yet, do so here.
251+ if (dirp -> stream .f1 ) {
252+ filesystem_result_void_error_code_t result ;
253+ wasip3_future_block_on (
254+ filesystem_future_result_void_error_code_read (dirp -> stream .f1 , & result ),
255+ dirp -> stream .f1 );
256+ filesystem_future_result_void_error_code_drop_readable (dirp -> stream .f1 );
257+ dirp -> stream .f1 = 0 ;
258+ if (result .is_err )
259+ translate_error (result .val .err );
260+ }
261+
262+ // The stream is closed, so return NULL. This'll set `errno` based on the
263+ // result of the future above.
264+ return NULL ;
265+ }
266+ #else
267+ #error "Unknown WASI version"
268+ #endif
269+
219270 // Ensure that the dirent is large enough to fit the filename
220271 size_t the_size = offsetof(struct dirent , d_name );
221272 GROW (dirp -> dirent , dirp -> dirent_size , the_size + dir_entry .name .len + 1 );
@@ -232,7 +283,11 @@ static struct dirent *readdir_next(DIR *dirp) {
232283 & dir_entry .name ,
233284 & metadata ,
234285 & error_code );
286+ #ifdef __wasip2__
235287 wasip2_string_free (& dir_entry .name );
288+ #else
289+ wasip3_string_free (& dir_entry .name );
290+ #endif
236291 if (!ok ) {
237292 translate_error (error_code );
238293 return NULL ;
@@ -251,13 +306,6 @@ struct dirent *readdir(DIR *dirp) {
251306 }
252307 return result ;
253308}
254- #elif defined(__wasip3__ )
255- struct dirent * readdir (DIR * dirp ) {
256- // TODO(wasip3)
257- errno = ENOTSUP ;
258- free (dirp );
259- return NULL ;
260- }
261309#else
262310# error "Unknown WASI version"
263311#endif
0 commit comments