From 5b148b6131f36770f110c24d61adfb1e17fea06a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Nov 2020 14:40:41 -0600 Subject: [PATCH] Add basic emulation of getcwd/chdir (#214) * Add basic emulation of getcwd/chdir This commit adds basic emulation of a current working directory to wasi-libc. The `getcwd` and `chdir` symbols are now implemented and available for use. The `getcwd` implementation is pretty simple in that it just copies out of a new global, `__wasilibc_cwd`, which defaults to `"/"`. The `chdir` implementation is much more involved and has more ramification, however. A new function, `make_absolute`, was added to the preopens object. Paths stored in the preopen table are now always stored as absolute paths instead of relative paths, and initial relative paths are interpreted as being relative to `/`. Looking up a path to preopen now always turns it into an absolute path, relative to the current working directory, and an appropriate path is then returned. The signature of `__wasilibc_find_relpath` has changed as well. It now returns two path components, one for the absolute part and one for the relative part. Additionally the relative part is always dynamically allocated since it may no longer be a substring of the original input path. This has been tested lightly against the Rust standard library so far, but I'm not a regular C developer so there's likely a few things to improve! * Amortize mallocs made in syscalls * Avoid size bloat on programs that don't use `chdir` * Add threading compat * Collect `link`/`renameat` second path lookup * Update comments about chdir.c in makefile * Move definition of `__wasilibc_find_relpath_alloc` to header * Expand comments * Document the format of strings a bit more * Fixup a few issues in path logic * Fix GitHub Actions --- .github/workflows/main.yml | 2 +- Makefile | 8 + expected/wasm32-wasi/defined-symbols.txt | 5 + .../headers/public/wasi/libc-find-relpath.h | 65 +++++++- libc-bottom-half/sources/chdir.c | 151 ++++++++++++++++++ libc-bottom-half/sources/getcwd.c | 30 ++++ libc-bottom-half/sources/posix.c | 102 ++++++++---- libc-bottom-half/sources/preopens.c | 75 ++++++--- libc-top-half/musl/include/unistd.h | 6 +- 9 files changed, 378 insertions(+), 66 deletions(-) create mode 100644 libc-bottom-half/sources/chdir.c create mode 100644 libc-bottom-half/sources/getcwd.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ae42dba..07df901 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: rustup update stable rustup default stable rustup component add llvm-tools-preview - echo "::set-env name=WASM_NM::$(rustc --print sysroot|sed 's|C:|/c|'|sed 's|\\|/|g')/lib/rustlib/x86_64-pc-windows-msvc/bin/llvm-nm.exe" + echo "WASM_NM=$(rustc --print sysroot|sed 's|C:|/c|'|sed 's|\\|/|g')/lib/rustlib/x86_64-pc-windows-msvc/bin/llvm-nm.exe" >> $GITHUB_ENV if: matrix.os == 'windows-latest' - name: Install clang (MacOS) diff --git a/Makefile b/Makefile index a1d0a31..8994695 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,14 @@ LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources LIBC_BOTTOM_HALF_ALL_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \ $(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c) + +# FIXME(https://reviews.llvm.org/D85567) - due to a bug in LLD the weak +# references to a function defined in `chdir.c` only work if `chdir.c` is at the +# end of the archive, but once that LLD review lands and propagates into LLVM +# then we don't have to do this. +LIBC_BOTTOM_HALF_ALL_SOURCES := $(filter-out $(LIBC_BOTTOM_HALF_SOURCES)/chdir.c,$(LIBC_BOTTOM_HALF_ALL_SOURCES)) +LIBC_BOTTOM_HALF_ALL_SOURCES := $(LIBC_BOTTOM_HALF_ALL_SOURCES) $(LIBC_BOTTOM_HALF_SOURCES)/chdir.c + LIBWASI_EMULATED_MMAN_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c) LIBWASI_EMULATED_SIGNAL_SOURCES = \ diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index 84c508d..5208dbb 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -250,11 +250,14 @@ __uflow __unlist_locked_file __uselocale __utc +__wasilibc_cwd __wasilibc_ensure_environ __wasilibc_environ __wasilibc_environ __wasilibc_fd_renumber +__wasilibc_find_abspath __wasilibc_find_relpath +__wasilibc_find_relpath_alloc __wasilibc_initialize_environ __wasilibc_open_nomode __wasilibc_openat_nomode @@ -368,6 +371,7 @@ ceill cexp cexpf cexpl +chdir cimag cimagf cimagl @@ -579,6 +583,7 @@ getc getc_unlocked getchar getchar_unlocked +getcwd getdate getdate_err getdelim diff --git a/libc-bottom-half/headers/public/wasi/libc-find-relpath.h b/libc-bottom-half/headers/public/wasi/libc-find-relpath.h index 7395ad6..445613f 100644 --- a/libc-bottom-half/headers/public/wasi/libc-find-relpath.h +++ b/libc-bottom-half/headers/public/wasi/libc-find-relpath.h @@ -6,15 +6,72 @@ extern "C" { #endif /** - * Look up the given path in the preopened directory map. If a suitable - * entry is found, return its directory file descriptor, and store the - * computed relative path in *relative_path. + * Look up the given `path`, relative to the cwd, in the preopened directory + * map. If a suitable entry is found, then the file descriptor for that entry + * is returned. Additionally the absolute path of the directory's file + * descriptor is returned in `abs_prefix` and the relative portion that needs + * to be opened is stored in `*relative_path`. * - * Returns -1 if no directories were suitable. + * The `relative_path` argument must be a pointer to a buffer valid for + * `relative_path_len` bytes, and this may be used as storage for the relative + * portion of the path being returned through `*relative_path`. + * + * See documentation on `__wasilibc_find_abspath` for more info about what the + * paths look like. + * + * Returns -1 on failure. Errno is set to either: + * + * * ENOMEM - failed to allocate memory for internal routines. + * * ENOENT - the `path` could not be found relative to any preopened dir. + * * ERANGE - the `relative_path` buffer is too small to hold the relative path. */ int __wasilibc_find_relpath(const char *path, + const char **__restrict__ abs_prefix, + char **relative_path, + size_t relative_path_len); + +/** + * Look up the given `path`, which is interpreted as absolute, in the preopened + * directory map. If a suitable entry is found, then the file descriptor for + * that entry is returned. Additionally the relative portion of the path to + * where the fd is opened is returned through `relative_path`, the absolute + * prefix which was matched is stored to `abs_prefix`, and `relative_path` may + * be an interior pointer to the `abspath` string. + * + * The `abs_prefix` returned string will not contain a leading `/`. Note that + * this may be the empty string. Additionally the returned `relative_path` will + * not contain a leading `/`. The `relative_path` return will not return an + * empty string, it will return `"."` instead if it would otherwise do so. + * + * Returns -1 on failure. Errno is set to either: + * + * * ENOMEM - failed to allocate memory for internal routines. + * * ENOENT - the `path` could not be found relative to any preopened dir. + */ +int __wasilibc_find_abspath(const char *abspath, + const char **__restrict__ abs_prefix, const char **__restrict__ relative_path); +/** + * Same as `__wasilibc_find_relpath`, except that this function will interpret + * `relative` as a malloc'd buffer that will be `realloc`'d to the appropriate + * size to contain the relative path. + * + * Note that this is a weak symbol and if it's not defined you can use + * `__wasilibc_find_relpath`. The weak-nature of this symbols means that if it's + * not otherwise included in the compilation then `chdir` wasn't used an there's + * no need for this symbol. + * + * See documentation on `__wasilibc_find_relpath` for more information. + */ +int __wasilibc_find_relpath_alloc( + const char *path, + const char **abs, + char **relative, + size_t *relative_len, + int can_realloc +) __attribute__((weak)); + #ifdef __cplusplus } #endif diff --git a/libc-bottom-half/sources/chdir.c b/libc-bottom-half/sources/chdir.c new file mode 100644 index 0000000..7820448 --- /dev/null +++ b/libc-bottom-half/sources/chdir.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _REENTRANT +#error "chdir doesn't yet support multiple threads" +#endif + +extern char *__wasilibc_cwd; +static int __wasilibc_cwd_mallocd = 0; + +int chdir(const char *path) +{ + static char *relative_buf = NULL; + static size_t relative_buf_len = 0; + + // Find a preopen'd directory as well as a relative path we're anchored + // from which we're changing directories to. + const char *abs; + int parent_fd = __wasilibc_find_relpath_alloc(path, &abs, &relative_buf, &relative_buf_len, 1); + if (parent_fd == -1) + return -1; + + // Make sure that this directory we're accessing is indeed a directory. + struct stat dirinfo; + int ret = fstatat(parent_fd, relative_buf, &dirinfo, 0); + if (ret == -1) + return -1; + if (!S_ISDIR(dirinfo.st_mode)) { + errno = ENOTDIR; + return -1; + } + + // Create a string that looks like: + // + // __wasilibc_cwd = "/" + abs + "/" + relative_buf + // + // If `relative_buf` is equal to "." or `abs` is equal to the empty string, + // however, we skip that part and the middle slash. + size_t len = strlen(abs) + 1; + int copy_relative = strcmp(relative_buf, ".") != 0; + int mid = copy_relative && abs[0] != 0; + char *new_cwd = malloc(len + (copy_relative ? strlen(relative_buf) + mid: 0)); + if (new_cwd == NULL) { + errno = ENOMEM; + return -1; + } + new_cwd[0] = '/'; + strcpy(new_cwd + 1, abs); + if (mid) + new_cwd[strlen(abs) + 1] = '/'; + if (copy_relative) + strcpy(new_cwd + 1 + mid + strlen(abs), relative_buf); + + // And set our new malloc'd buffer into the global cwd, freeing the + // previous one if necessary. + char *prev_cwd = __wasilibc_cwd; + __wasilibc_cwd = new_cwd; + if (__wasilibc_cwd_mallocd) + free(prev_cwd); + __wasilibc_cwd_mallocd = 1; + return 0; +} + +static const char *make_absolute(const char *path) { + static char *make_absolute_buf = NULL; + static size_t make_absolute_len = 0; + + // If this path is absolute, then we return it as-is. + if (path[0] == '/') { + return path; + } + + // If the path is empty, or points to the current directory, then return + // the current directory. + if (path[0] == 0 || !strcmp(path, ".") || !strcmp(path, "./")) { + return __wasilibc_cwd; + } + + // If the path starts with `./` then we won't be appending that to the cwd. + if (path[0] == '.' && path[1] == '/') + path += 2; + + // Otherwise we'll take the current directory, add a `/`, and then add the + // input `path`. Note that this doesn't do any normalization (like removing + // `/./`). + size_t cwd_len = strlen(__wasilibc_cwd); + size_t path_len = strlen(path); + int need_slash = __wasilibc_cwd[cwd_len - 1] == '/' ? 0 : 1; + size_t alloc_len = cwd_len + path_len + 1 + need_slash; + if (alloc_len > make_absolute_len) { + make_absolute_buf = realloc(make_absolute_buf, alloc_len); + if (make_absolute_buf == NULL) + return NULL; + make_absolute_len = alloc_len; + } + strcpy(make_absolute_buf, __wasilibc_cwd); + if (need_slash) + strcpy(make_absolute_buf + cwd_len, "/"); + strcpy(make_absolute_buf + cwd_len + need_slash, path); + return make_absolute_buf; +} + +// Helper function defined only in this object file and weakly referenced from +// `preopens.c` and `posix.c` This function isn't necessary unless `chdir` is +// pulled in because all paths are otherwise absolute or relative to the root. +int __wasilibc_find_relpath_alloc( + const char *path, + const char **abs_prefix, + char **relative_buf, + size_t *relative_buf_len, + int can_realloc +) { + // First, make our path absolute taking the cwd into account. + const char *abspath = make_absolute(path); + if (abspath == NULL) { + errno = ENOMEM; + return -1; + } + + // Next use our absolute path and split it. Find the preopened `fd` parent + // directory and set `abs_prefix`. Next up we'll be trying to fit `rel` + // into `relative_buf`. + const char *rel; + int fd = __wasilibc_find_abspath(abspath, abs_prefix, &rel); + if (fd == -1) + return -1; + + size_t rel_len = strlen(rel); + if (*relative_buf_len < rel_len + 1) { + if (!can_realloc) { + errno = ERANGE; + return -1; + } + char *tmp = realloc(*relative_buf, rel_len + 1); + if (tmp == NULL) { + errno = ENOMEM; + return -1; + } + *relative_buf = tmp; + *relative_buf_len = rel_len + 1; + } + strcpy(*relative_buf, rel); + return fd; +} diff --git a/libc-bottom-half/sources/getcwd.c b/libc-bottom-half/sources/getcwd.c new file mode 100644 index 0000000..6a2080e --- /dev/null +++ b/libc-bottom-half/sources/getcwd.c @@ -0,0 +1,30 @@ +#include +#include +#include + +// For threads this needs to synchronize with chdir +#ifdef _REENTRANT +#error "getcwd doesn't yet support multiple threads" +#endif + +char *__wasilibc_cwd = "/"; + +char *getcwd(char *buf, size_t size) +{ + if (!buf) { + buf = strdup(__wasilibc_cwd); + if (!buf) { + errno = ENOMEM; + return NULL; + } + } else { + size_t len = strlen(__wasilibc_cwd); + if (size < strlen(__wasilibc_cwd) + 1) { + errno = ERANGE; + return NULL; + } + strcpy(buf, __wasilibc_cwd); + } + return buf; +} + diff --git a/libc-bottom-half/sources/posix.c b/libc-bottom-half/sources/posix.c index 64e6bfa..388a57d 100644 --- a/libc-bottom-half/sources/posix.c +++ b/libc-bottom-half/sources/posix.c @@ -4,12 +4,44 @@ #include #include #include +#include +#include #include #include -#include #include #include +static int find_relpath2( + const char *path, + char **relative, + size_t *relative_len +) { + // See comments in `preopens.c` for what this trick is doing. + const char *abs; + if (__wasilibc_find_relpath_alloc) + return __wasilibc_find_relpath_alloc(path, &abs, relative, relative_len, 1); + return __wasilibc_find_relpath(path, &abs, relative, *relative_len); +} + +// Helper to call `__wasilibc_find_relpath` and return an already-managed +// pointer for the `relative` path. This function is not reentrant since the +// `relative` pointer will point to static data that cannot be reused until +// `relative` is no longer used. +static int find_relpath(const char *path, char **relative) { + static __thread char *relative_buf = NULL; + static __thread size_t relative_buf_len = 0; + *relative = relative_buf; + return find_relpath2(path, relative, &relative_buf_len); +} + +// same as `find_relpath`, but uses another set of static variables to cache +static int find_relpath_alt(const char *path, char **relative) { + static __thread char *relative_buf = NULL; + static __thread size_t relative_buf_len = 0; + *relative = relative_buf; + return find_relpath2(path, relative, &relative_buf_len); +} + int open(const char *path, int oflag, ...) { // WASI libc's `openat` ignores the mode argument, so call a special // entrypoint which avoids the varargs calling convention. @@ -18,8 +50,8 @@ int open(const char *path, int oflag, ...) { // See the documentation in libc.h int __wasilibc_open_nomode(const char *path, int oflag) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -31,8 +63,8 @@ int __wasilibc_open_nomode(const char *path, int oflag) { } int access(const char *path, int amode) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -48,8 +80,8 @@ ssize_t readlink( char *restrict buf, size_t bufsize) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -61,8 +93,8 @@ ssize_t readlink( } int stat(const char *restrict path, struct stat *restrict buf) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -74,8 +106,8 @@ int stat(const char *restrict path, struct stat *restrict buf) { } int lstat(const char *restrict path, struct stat *restrict buf) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -87,8 +119,8 @@ int lstat(const char *restrict path, struct stat *restrict buf) { } int utime(const char *path, const struct utimbuf *times) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -106,8 +138,8 @@ int utime(const char *path, const struct utimbuf *times) { } int unlink(const char *path) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -122,8 +154,8 @@ int unlink(const char *path) { } int rmdir(const char *path) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -135,8 +167,8 @@ int rmdir(const char *path) { } int remove(const char *path) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -158,8 +190,8 @@ int remove(const char *path) { } int mkdir(const char *path, mode_t mode) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(path, &relative_path); + char *relative_path; + int dirfd = find_relpath(path, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -171,8 +203,8 @@ int mkdir(const char *path, mode_t mode) { } DIR *opendir(const char *dirname) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(dirname, &relative_path); + char *relative_path; + int dirfd = find_relpath(dirname, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -189,8 +221,8 @@ int scandir( int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **) ) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(dir, &relative_path); + char *relative_path; + int dirfd = find_relpath(dir, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -202,8 +234,8 @@ int scandir( } int symlink(const char *target, const char *linkpath) { - const char *relative_path; - int dirfd = __wasilibc_find_relpath(linkpath, &relative_path); + char *relative_path; + int dirfd = find_relpath(linkpath, &relative_path); // If we can't find a preopen for it, indicate that we lack capabilities. if (dirfd == -1) { @@ -215,12 +247,12 @@ int symlink(const char *target, const char *linkpath) { } int link(const char *old, const char *new) { - const char *old_relative_path; - int old_dirfd = __wasilibc_find_relpath(old, &old_relative_path); + char *old_relative_path; + int old_dirfd = find_relpath_alt(old, &old_relative_path); if (old_dirfd != -1) { - const char *new_relative_path; - int new_dirfd = __wasilibc_find_relpath(new, &new_relative_path); + char *new_relative_path; + int new_dirfd = find_relpath(new, &new_relative_path); if (new_dirfd != -1) return linkat(old_dirfd, old_relative_path, @@ -233,12 +265,12 @@ int link(const char *old, const char *new) { } int rename(const char *old, const char *new) { - const char *old_relative_path; - int old_dirfd = __wasilibc_find_relpath(old, &old_relative_path); + char *old_relative_path; + int old_dirfd = find_relpath_alt(old, &old_relative_path); if (old_dirfd != -1) { - const char *new_relative_path; - int new_dirfd = __wasilibc_find_relpath(new, &new_relative_path); + char *new_relative_path; + int new_dirfd = find_relpath(new, &new_relative_path); if (new_dirfd != -1) return renameat(old_dirfd, old_relative_path, diff --git a/libc-bottom-half/sources/preopens.c b/libc-bottom-half/sources/preopens.c index fa0e12f..8c68826 100644 --- a/libc-bottom-half/sources/preopens.c +++ b/libc-bottom-half/sources/preopens.c @@ -7,14 +7,15 @@ #endif #include +#include #include #include #include #include #include #include -#include #include +#include /// A name and file descriptor pair. typedef struct preopen { @@ -71,15 +72,38 @@ static int resize(void) { return 0; } +// Normalize an absolute path. Removes leading `/` and leading `./`, so the +// first character is the start of a directory name. This works because our +// process always starts with a working directory of `/`. Additionally translate +// `.` to the empty string. +static const char *strip_prefixes(const char *path) { + while (1) { + if (path[0] == '/') { + path++; + } else if (path[0] == '.' && path[1] == '/') { + path += 2; + } else if (path[0] == '.' && path[1] == 0) { + path++; + } else { + break; + } + } + + 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 *prefix) { +static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { assert_invariants(); if (num_preopens == preopen_capacity && resize() != 0) return -1; + char *prefix = strdup(strip_prefixes(relprefix)); + if (prefix == NULL) + return -1; preopens[num_preopens++] = (preopen) { prefix, fd, }; assert_invariants(); @@ -109,16 +133,30 @@ 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) { - prefix = strdup(prefix); - return prefix == NULL ? -1 : - internal_register_preopened_fd((__wasi_fd_t)fd, prefix); + return internal_register_preopened_fd((__wasi_fd_t)fd, prefix); } // See the documentation in libc-find-relpath.h. int __wasilibc_find_relpath(const char *path, - const char **restrict relative_path) { - assert_invariants(); + const char **abs_prefix, + char **relative_path, + size_t relative_path_len) { + // If `chdir` is linked, whose object file defines this symbol, then we + // call that. Otherwise if the program can't `chdir` then `path` is + // absolute (or relative to the root dir), so we delegate to `find_abspath` + if (__wasilibc_find_relpath_alloc) + return __wasilibc_find_relpath_alloc(path, abs_prefix, relative_path, &relative_path_len, 0); + return __wasilibc_find_abspath(path, abs_prefix, (const char**) relative_path); +} +// See the documentation in libc-find-relpath.h. +int __wasilibc_find_abspath(const char *path, + const char **abs_prefix, + const char **relative_path) { + // Strip leading `/` characters, the prefixes we're mataching won't have + // them. + while (*path == '/') + path++; // Search through the preopens table. Iterate in reverse so that more // recently added preopens take precedence over less recently addded ones. size_t match_len = 0; @@ -128,22 +166,6 @@ int __wasilibc_find_relpath(const char *path, const char *prefix = pre->prefix; size_t len = strlen(prefix); - if (path[0] != '/' && - (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) - { - // We're matching a relative path that doesn't start with "./" and - // isn't ".". - if (len >= 2 && prefix[0] == '.' && prefix[1] == '/') { - // The preopen starts with "./", so skip that prefix. - prefix += 2; - len -= 2; - } else if (len == 1 && prefix[0] == '.') { - // The preopen is ".", so match it as an empty string. - prefix += 1; - len -= 1; - } - } - // If we haven't had a match yet, or the candidate path is longer than // our current best match's path, and the candidate path is a prefix of // the requested path, take that as the new best path. @@ -152,9 +174,15 @@ int __wasilibc_find_relpath(const char *path, { fd = pre->fd; match_len = len; + *abs_prefix = prefix; } } + if (fd == -1) { + errno = ENOENT; + return -1; + } + // The relative path is the substring after the portion that was matched. const char *computed = path + match_len; @@ -202,6 +230,7 @@ static void __wasilibc_populate_preopens(void) { if (internal_register_preopened_fd(fd, prefix) != 0) goto software; + free(prefix); break; } diff --git a/libc-top-half/musl/include/unistd.h b/libc-top-half/musl/include/unistd.h index e55f638..0eac1cf 100644 --- a/libc-top-half/musl/include/unistd.h +++ b/libc-top-half/musl/include/unistd.h @@ -118,11 +118,11 @@ int ftruncate(int, off_t); int access(const char *, int); int faccessat(int, const char *, int, int); -#ifdef __wasilibc_unmodified_upstream /* WASI has no cwd */ -int chdir(const char *); +#ifdef __wasilibc_unmodified_upstream /* WASI has no fchdir */ int fchdir(int); -char *getcwd(char *, size_t); #endif +int chdir(const char *); +char *getcwd(char *, size_t); #ifdef __wasilibc_unmodified_upstream /* WASI has no signals */ unsigned alarm(unsigned); -- 2.39.5