Commit 8a8da49b52
Changed files (5)
lib
libc
include
wasm-wasi-musl
wasi
wasi
libc-bottom-half
cloudlibc
src
libc
unistd
lib/libc/include/wasm-wasi-musl/wasi/libc.h
@@ -17,6 +17,10 @@ struct timespec;
/// afterward, you should call this before doing so.
void __wasilibc_populate_preopens(void);
+/// Reset the preopens table to an uninitialized state, forcing it to be
+/// reinitialized next time it is needed.
+void __wasilibc_reset_preopens(void);
+
/// Register the given pre-opened file descriptor under the given path.
///
/// This function does not take ownership of `prefix` (it makes its own copy).
lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c
@@ -4,6 +4,9 @@
#include <unistd.h>
int __wasilibc_fd_renumber(int fd, int newfd) {
+ // Scan the preopen fds before making any changes.
+ __wasilibc_populate_preopens();
+
__wasi_errno_t error = __wasi_fd_renumber(fd, newfd);
if (error != 0) {
errno = error;
lib/libc/wasi/libc-bottom-half/sources/preopens.c
@@ -25,6 +25,7 @@ typedef struct preopen {
} preopen;
/// A simple growable array of `preopen`.
+static _Atomic _Bool preopens_populated = false;
static preopen *preopens;
static size_t num_preopens;
static size_t preopen_capacity;
@@ -100,12 +101,9 @@ static const char *strip_prefixes(const char *path) {
return path;
}
-/// Register the given preopened file descriptor under the given path.
-///
-/// This function takes ownership of `prefix`.
-static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) {
- LOCK(lock);
-
+/// Similar to `internal_register_preopened_fd_unlocked` but does not
+/// take a lock.
+static int internal_register_preopened_fd_unlocked(__wasi_fd_t fd, const char *relprefix) {
// Check preconditions.
assert_invariants();
assert(fd != AT_FDCWD);
@@ -113,22 +111,32 @@ static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix)
assert(relprefix != NULL);
if (num_preopens == preopen_capacity && resize() != 0) {
- UNLOCK(lock);
return -1;
}
char *prefix = strdup(strip_prefixes(relprefix));
if (prefix == NULL) {
- UNLOCK(lock);
return -1;
}
preopens[num_preopens++] = (preopen) { prefix, fd, };
assert_invariants();
- UNLOCK(lock);
return 0;
}
+/// Register the given preopened file descriptor under the given path.
+///
+/// This function takes ownership of `prefix`.
+static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) {
+ LOCK(lock);
+
+ int r = internal_register_preopened_fd_unlocked(fd, relprefix);
+
+ UNLOCK(lock);
+
+ return r;
+}
+
/// Are the `prefix_len` bytes pointed to by `prefix` a prefix of `path`?
static bool prefix_matches(const char *prefix, size_t prefix_len, const char *path) {
// 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
// See the documentation in libc.h
int __wasilibc_register_preopened_fd(int fd, const char *prefix) {
+ __wasilibc_populate_preopens();
+
return internal_register_preopened_fd((__wasi_fd_t)fd, prefix);
}
@@ -172,6 +182,8 @@ int __wasilibc_find_relpath(const char *path,
int __wasilibc_find_abspath(const char *path,
const char **abs_prefix,
const char **relative_path) {
+ __wasilibc_populate_preopens();
+
// Strip leading `/` characters, the prefixes we're mataching won't have
// them.
while (*path == '/')
@@ -218,3 +230,84 @@ int __wasilibc_find_abspath(const char *path,
*relative_path = computed;
return fd;
}
+
+__attribute__((constructor(51)))
+void __wasilibc_populate_preopens(void) {
+ // Fast path: If the preopens are already initialized, do nothing.
+ if (preopens_populated) {
+ return;
+ }
+
+ LOCK(lock);
+
+ // Check whether another thread initialized the preopens already.
+ if (preopens_populated) {
+ UNLOCK(lock);
+ return;
+ }
+
+ // Skip stdin, stdout, and stderr, and count up until we reach an invalid
+ // file descriptor.
+ for (__wasi_fd_t fd = 3; fd != 0; ++fd) {
+ __wasi_prestat_t prestat;
+ __wasi_errno_t ret = __wasi_fd_prestat_get(fd, &prestat);
+ if (ret == __WASI_ERRNO_BADF)
+ break;
+ if (ret != __WASI_ERRNO_SUCCESS)
+ goto oserr;
+ switch (prestat.tag) {
+ case __WASI_PREOPENTYPE_DIR: {
+ char *prefix = malloc(prestat.u.dir.pr_name_len + 1);
+ if (prefix == NULL)
+ goto software;
+
+ // TODO: Remove the cast on `prefix` once the witx is updated with
+ // char8 support.
+ ret = __wasi_fd_prestat_dir_name(fd, (uint8_t *)prefix,
+ prestat.u.dir.pr_name_len);
+ if (ret != __WASI_ERRNO_SUCCESS)
+ goto oserr;
+ prefix[prestat.u.dir.pr_name_len] = '\0';
+
+ if (internal_register_preopened_fd_unlocked(fd, prefix) != 0)
+ goto software;
+ free(prefix);
+
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Preopens are now initialized.
+ preopens_populated = true;
+
+ UNLOCK(lock);
+
+ return;
+oserr:
+ _Exit(EX_OSERR);
+software:
+ _Exit(EX_SOFTWARE);
+}
+
+void __wasilibc_reset_preopens(void) {
+ LOCK(lock);
+
+ if (num_preopens) {
+ for (int i = 0; i < num_preopens; ++i) {
+ free((void*) preopens[i].prefix);
+ }
+ free(preopens);
+ }
+
+ preopens_populated = false;
+ preopens = NULL;
+ num_preopens = 0;
+ preopen_capacity = 0;
+
+ assert_invariants();
+
+ UNLOCK(lock);
+}
src/wasi_libc.zig
@@ -463,7 +463,6 @@ const libc_bottom_half_src_files = [_][]const u8{
"wasi/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/time/nanosleep.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/time/time.c",
- "wasi/libc-bottom-half/cloudlibc/src/libc/unistd/close.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fdatasync.c",
"wasi/libc-bottom-half/cloudlibc/src/libc/unistd/fsync.c",