@@ -25,6 +25,7 @@ typedef struct preopen {
25
25
} preopen ;
26
26
27
27
/// A simple growable array of `preopen`.
28
+ static _Atomic _Bool preopens_populated = false;
28
29
static preopen * preopens ;
29
30
static size_t num_preopens ;
30
31
static size_t preopen_capacity ;
@@ -100,35 +101,42 @@ static const char *strip_prefixes(const char *path) {
100
101
return path ;
101
102
}
102
103
103
- /// Register the given preopened file descriptor under the given path.
104
- ///
105
- /// This function takes ownership of `prefix`.
106
- static int internal_register_preopened_fd (__wasi_fd_t fd , const char * relprefix ) {
107
- LOCK (lock );
108
-
104
+ /// Similar to `internal_register_preopened_fd_unlocked` but does not
105
+ /// take a lock.
106
+ static int internal_register_preopened_fd_unlocked (__wasi_fd_t fd , const char * relprefix ) {
109
107
// Check preconditions.
110
108
assert_invariants ();
111
109
assert (fd != AT_FDCWD );
112
110
assert (fd != -1 );
113
111
assert (relprefix != NULL );
114
112
115
113
if (num_preopens == preopen_capacity && resize () != 0 ) {
116
- UNLOCK (lock );
117
114
return -1 ;
118
115
}
119
116
120
117
char * prefix = strdup (strip_prefixes (relprefix ));
121
118
if (prefix == NULL ) {
122
- UNLOCK (lock );
123
119
return -1 ;
124
120
}
125
121
preopens [num_preopens ++ ] = (preopen ) { prefix , fd , };
126
122
127
123
assert_invariants ();
128
- UNLOCK (lock );
129
124
return 0 ;
130
125
}
131
126
127
+ /// Register the given preopened file descriptor under the given path.
128
+ ///
129
+ /// This function takes ownership of `prefix`.
130
+ static int internal_register_preopened_fd (__wasi_fd_t fd , const char * relprefix ) {
131
+ LOCK (lock );
132
+
133
+ int r = internal_register_preopened_fd_unlocked (fd , relprefix );
134
+
135
+ UNLOCK (lock );
136
+
137
+ return r ;
138
+ }
139
+
132
140
/// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`?
133
141
static bool prefix_matches (const char * prefix , size_t prefix_len , const char * path ) {
134
142
// Allow an empty string as a prefix of any relative path.
@@ -152,6 +160,8 @@ static bool prefix_matches(const char *prefix, size_t prefix_len, const char *pa
152
160
153
161
// See the documentation in libc.h
154
162
int __wasilibc_register_preopened_fd (int fd , const char * prefix ) {
163
+ __wasilibc_populate_preopens ();
164
+
155
165
return internal_register_preopened_fd ((__wasi_fd_t )fd , prefix );
156
166
}
157
167
@@ -172,6 +182,8 @@ int __wasilibc_find_relpath(const char *path,
172
182
int __wasilibc_find_abspath (const char * path ,
173
183
const char * * abs_prefix ,
174
184
const char * * relative_path ) {
185
+ __wasilibc_populate_preopens ();
186
+
175
187
// Strip leading `/` characters, the prefixes we're mataching won't have
176
188
// them.
177
189
while (* path == '/' )
@@ -218,3 +230,84 @@ int __wasilibc_find_abspath(const char *path,
218
230
* relative_path = computed ;
219
231
return fd ;
220
232
}
233
+
234
+ __attribute__((constructor (51 )))
235
+ void __wasilibc_populate_preopens (void ) {
236
+ // Fast path: If the preopens are already initialized, do nothing.
237
+ if (preopens_populated ) {
238
+ return ;
239
+ }
240
+
241
+ LOCK (lock );
242
+
243
+ // Check whether another thread initialized the preopens already.
244
+ if (preopens_populated ) {
245
+ UNLOCK (lock );
246
+ return ;
247
+ }
248
+
249
+ // Skip stdin, stdout, and stderr, and count up until we reach an invalid
250
+ // file descriptor.
251
+ for (__wasi_fd_t fd = 3 ; fd != 0 ; ++ fd ) {
252
+ __wasi_prestat_t prestat ;
253
+ __wasi_errno_t ret = __wasi_fd_prestat_get (fd , & prestat );
254
+ if (ret == __WASI_ERRNO_BADF )
255
+ break ;
256
+ if (ret != __WASI_ERRNO_SUCCESS )
257
+ goto oserr ;
258
+ switch (prestat .tag ) {
259
+ case __WASI_PREOPENTYPE_DIR : {
260
+ char * prefix = malloc (prestat .u .dir .pr_name_len + 1 );
261
+ if (prefix == NULL )
262
+ goto software ;
263
+
264
+ // TODO: Remove the cast on `prefix` once the witx is updated with
265
+ // char8 support.
266
+ ret = __wasi_fd_prestat_dir_name (fd , (uint8_t * )prefix ,
267
+ prestat .u .dir .pr_name_len );
268
+ if (ret != __WASI_ERRNO_SUCCESS )
269
+ goto oserr ;
270
+ prefix [prestat .u .dir .pr_name_len ] = '\0' ;
271
+
272
+ if (internal_register_preopened_fd_unlocked (fd , prefix ) != 0 )
273
+ goto software ;
274
+ free (prefix );
275
+
276
+ break ;
277
+ }
278
+ default :
279
+ break ;
280
+ }
281
+ }
282
+
283
+ // Preopens are now initialized.
284
+ preopens_populated = true;
285
+
286
+ UNLOCK (lock );
287
+
288
+ return ;
289
+ oserr :
290
+ _Exit (EX_OSERR );
291
+ software :
292
+ _Exit (EX_SOFTWARE );
293
+ }
294
+
295
+ void __wasilibc_reset_preopens (void ) {
296
+ LOCK (lock );
297
+
298
+ if (num_preopens ) {
299
+ for (int i = 0 ; i < num_preopens ; ++ i ) {
300
+ free ((void * ) preopens [i ].prefix );
301
+ }
302
+ free (preopens );
303
+ }
304
+
305
+ preopens_populated = false;
306
+ preopens = NULL ;
307
+ num_preopens = 0 ;
308
+ preopen_capacity = 0 ;
309
+
310
+ assert_invariants ();
311
+
312
+ UNLOCK (lock );
313
+ }
0 commit comments