| ... | ... | @@ -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,12 +101,9 @@ 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); |
| ... | ... | @@ -113,22 +111,32 @@ static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) |
| 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 | } |