@@ -31,8 +31,11 @@ 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.
35- #ifndef __wasip3__
3639static struct dirent * grow (struct dirent * * buffer , size_t * buffer_size , size_t target_size ) {
3740 if (* buffer_size < target_size ) {
3841 size_t new_size = * buffer_size ;
@@ -48,7 +51,6 @@ static struct dirent* grow(struct dirent **buffer, size_t *buffer_size, size_t t
4851 }
4952 return * buffer ;
5053}
51- #endif
5254
5355#if defined(__wasip1__ )
5456struct dirent * readdir (DIR * dirp ) {
@@ -144,12 +146,13 @@ struct dirent *readdir(DIR *dirp) {
144146 }
145147}
146148
147- #elif defined(__wasip2__ )
149+ #elif defined(__wasip2__ ) || defined( __wasip3__ )
148150
149151static int ensure_has_directory_stream (DIR * dirp , filesystem_borrow_descriptor_t * handle ) {
150152 if (fd_to_file_handle (dirp -> fd , handle ) < 0 )
151153 return -1 ;
152154
155+ #ifdef __wasip2__
153156 if (dirp -> stream .__handle != 0 )
154157 return 0 ;
155158
@@ -161,10 +164,15 @@ static int ensure_has_directory_stream(DIR *dirp, filesystem_borrow_descriptor_t
161164 translate_error (error_code );
162165 return -1 ;
163166 }
167+ #elif defined(__wasip3__ )
168+ if (dirp -> stream .f0 == 0 )
169+ filesystem_method_descriptor_read_directory (* handle , & dirp -> stream );
170+ #endif
164171 return 0 ;
165172}
166173
167174static struct dirent * readdir_next (DIR * dirp ) {
175+ bool ok ;
168176 filesystem_metadata_hash_value_t metadata ;
169177 filesystem_error_code_t error_code ;
170178 filesystem_borrow_descriptor_t dir_handle ;
@@ -178,9 +186,9 @@ static struct dirent *readdir_next(DIR *dirp) {
178186 dirp -> offset += 1 ;
179187 if (grow (& dirp -> dirent , & dirp -> dirent_size , offsetof(struct dirent , d_name ) + 2 ) == NULL )
180188 return NULL ;
181- bool ok = filesystem_method_descriptor_metadata_hash (dir_handle ,
182- & metadata ,
183- & error_code );
189+ ok = filesystem_method_descriptor_metadata_hash (dir_handle ,
190+ & metadata ,
191+ & error_code );
184192 if (!ok ) {
185193 translate_error (error_code );
186194 return NULL ;
@@ -206,11 +214,12 @@ static struct dirent *readdir_next(DIR *dirp) {
206214 return dirp -> dirent ;
207215 }
208216
217+ #if defined(__wasip2__ )
209218 filesystem_borrow_directory_entry_stream_t stream = filesystem_borrow_directory_entry_stream (dirp -> stream );
210219 filesystem_option_directory_entry_t dir_entry_optional ;
211- bool ok = filesystem_method_directory_entry_stream_read_directory_entry (stream ,
212- & dir_entry_optional ,
213- & error_code );
220+ ok = filesystem_method_directory_entry_stream_read_directory_entry (stream ,
221+ & dir_entry_optional ,
222+ & error_code );
214223 if (!ok ) {
215224 translate_error (error_code );
216225 return NULL ;
@@ -222,10 +231,54 @@ static struct dirent *readdir_next(DIR *dirp) {
222231
223232 filesystem_directory_entry_t dir_entry = dir_entry_optional .val ;
224233
234+ #elif defined(__wasip3__ )
235+ filesystem_directory_entry_t dir_entry ;
236+
237+ // Loop until at least one stream entry is read, or until the stream is closed.
238+ bool closed = false;
239+ while (1 ) {
240+ size_t amount =
241+ __wasilibc_stream_block_on (
242+ filesystem_stream_directory_entry_read (dirp -> stream .f0 , & dir_entry , 1 ),
243+ dirp -> stream .f0 ,
244+ & closed );
245+
246+ // If something was read, then break out and process that below.
247+ if (amount > 0 )
248+ break ;
249+
250+ // If nothing was read and the stream isn't finished yet, try again.
251+ if (!closed )
252+ continue ;
253+
254+ // If the stream's result future hasn't been read yet, do so here.
255+ if (dirp -> stream .f1 ) {
256+ filesystem_result_void_error_code_t result ;
257+ __wasilibc_future_block_on (
258+ filesystem_future_result_void_error_code_read (dirp -> stream .f1 , & result ),
259+ dirp -> stream .f1 );
260+ filesystem_future_result_void_error_code_drop_readable (dirp -> stream .f1 );
261+ dirp -> stream .f1 = 0 ;
262+ if (result .is_err )
263+ translate_error (result .val .err );
264+ }
265+
266+ // The stream is closed, so return NULL. This'll set `errno` based on the
267+ // result of the future above.
268+ return NULL ;
269+ }
270+ #else
271+ #error "Unknown WASI version"
272+ #endif
273+
225274 // Ensure that the dirent is large enough to fit the filename
226275 size_t the_size = offsetof(struct dirent , d_name );
227276 if (grow (& dirp -> dirent , & dirp -> dirent_size , the_size + dir_entry .name .len + 1 ) == NULL ) {
277+ #ifdef __wasip2__
228278 wasip2_string_free (& dir_entry .name );
279+ #else
280+ wasip3_string_free (& dir_entry .name );
281+ #endif
229282 return NULL ;
230283 }
231284
@@ -241,7 +294,11 @@ static struct dirent *readdir_next(DIR *dirp) {
241294 & dir_entry .name ,
242295 & metadata ,
243296 & error_code );
297+ #ifdef __wasip2__
244298 wasip2_string_free (& dir_entry .name );
299+ #else
300+ wasip3_string_free (& dir_entry .name );
301+ #endif
245302 if (!ok ) {
246303 translate_error (error_code );
247304 return NULL ;
@@ -260,13 +317,6 @@ struct dirent *readdir(DIR *dirp) {
260317 }
261318 return result ;
262319}
263- #elif defined(__wasip3__ )
264- struct dirent * readdir (DIR * dirp ) {
265- // TODO(wasip3)
266- errno = ENOTSUP ;
267- free (dirp );
268- return NULL ;
269- }
270320#else
271321# error "Unknown WASI version"
272322#endif
0 commit comments