diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0270af6c8..07df901b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,8 +18,8 @@ jobs: run: | curl -fsSLO https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe 7z x LLVM-10.0.0-win64.exe -y -o"llvm" - echo "::add-path::$(pwd)/llvm/bin" - echo "::set-env name=WASM_AR::$(pwd)/llvm/bin/llvm-ar.exe" + echo "$(pwd)/llvm/bin" >> $GITHUB_PATH + echo "WASM_AR=$(pwd)/llvm/bin/llvm-ar.exe" >> $GITHUB_ENV if: matrix.os == 'windows-latest' - name: Install llvm-nm (Windows) @@ -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) @@ -36,8 +36,8 @@ jobs: run: | curl -sSfL https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-apple-darwin.tar.xz | tar xJf - export CLANG_DIR=`pwd`/clang+llvm-10.0.0-x86_64-apple-darwin/bin - echo "::add-path::$CLANG_DIR" - echo "::set-env name=WASM_CC::$CLANG_DIR/clang" + echo "$CLANG_DIR" >> $GITHUB_PATH + echo "WASM_CC=$CLANG_DIR/clang" >> $GITHUB_ENV if: matrix.os == 'macos-latest' - name: Install clang (Linux) @@ -45,8 +45,8 @@ jobs: run: | curl -sSfL https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | tar xJf - export CLANG_DIR=`pwd`/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin - echo "::add-path::$CLANG_DIR" - echo "::set-env name=WASM_CC::$CLANG_DIR/clang" + echo "$CLANG_DIR" >> $GITHUB_PATH + echo "WASM_CC=$CLANG_DIR/clang" >> $GITHUB_ENV if: matrix.os == 'ubuntu-latest' - name: Build libc @@ -76,7 +76,7 @@ jobs: - name: Install Rust (macos) run: | curl https://sh.rustup.rs | sh -s -- -y - echo "##[add-path]$HOME/.cargo/bin" + echo "$HOME/.cargo/bin" >> $GITHUB_PATH if: matrix.os == 'macos-latest' - run: cargo fetch working-directory: tools/wasi-headers diff --git a/Makefile b/Makefile index a1d0a315b..899469512 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 7cab06cb8..63296f18b 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 @@ -367,6 +370,7 @@ ceill cexp cexpf cexpl +chdir cimag cimagf cimagl @@ -578,6 +582,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 7395ad6da..445613f5a 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 000000000..7820448ee --- /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 000000000..6a2080ec5 --- /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 64e6bfaa9..388a57d42 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 fa0e12f99..8c6882646 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 e55f638e9..0eac1cfe9 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);