From f2e779e5f1ba4a539937cedeeaa762c1e0c162df Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 4 Feb 2021 09:29:21 -0800 Subject: [PATCH] AT_FDCWD support. AT_FDCWD is a special constant in POSIX that can be passed to *at functions to indicate the current working directory. Since the current working directory is emulated in wasi libc, add emulated AT_FDCWD support as well. Fixes #42. --- expected/wasm32-wasi/defined-symbols.txt | 22 ++- expected/wasm32-wasi/include-all.c | 1 + expected/wasm32-wasi/predefined-macros.txt | 2 + .../cloudlibc/src/libc/dirent/opendirat.c | 5 +- .../cloudlibc/src/libc/dirent/scandirat.c | 9 +- .../cloudlibc/src/libc/fcntl/openat.c | 9 +- .../cloudlibc/src/libc/stdio/renameat.c | 2 +- .../cloudlibc/src/libc/sys/stat/fstatat.c | 4 +- .../cloudlibc/src/libc/sys/stat/mkdirat.c | 2 +- .../cloudlibc/src/libc/sys/stat/utimensat.c | 4 +- .../cloudlibc/src/libc/unistd/faccessat.c | 2 +- .../cloudlibc/src/libc/unistd/linkat.c | 2 +- .../cloudlibc/src/libc/unistd/readlinkat.c | 4 +- .../cloudlibc/src/libc/unistd/symlinkat.c | 2 +- libc-bottom-half/headers/private/stdio.h | 1 + .../headers/public/__header_fcntl.h | 2 + .../headers/public/wasi/libc-nocwd.h | 58 ++++++ libc-bottom-half/headers/public/wasi/libc.h | 34 +++- libc-bottom-half/sources/__wasilibc_rmdirat.c | 2 +- .../sources/__wasilibc_unlinkat.c | 2 +- libc-bottom-half/sources/at_fdcwd.c | 141 ++++++++++++++ libc-bottom-half/sources/posix.c | 176 ++++++++++++++++-- libc-bottom-half/sources/preopens.c | 5 + 23 files changed, 442 insertions(+), 49 deletions(-) create mode 100644 libc-bottom-half/headers/public/wasi/libc-nocwd.h create mode 100644 libc-bottom-half/sources/at_fdcwd.c diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index c3efc08..8c0776c 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -249,6 +249,7 @@ __uflow __unlist_locked_file __uselocale __utc +__wasilibc_access __wasilibc_cwd __wasilibc_ensure_environ __wasilibc_environ @@ -258,12 +259,31 @@ __wasilibc_find_abspath __wasilibc_find_relpath __wasilibc_find_relpath_alloc __wasilibc_initialize_environ +__wasilibc_link +__wasilibc_link_newat +__wasilibc_link_oldat +__wasilibc_nocwd___wasilibc_rmdirat +__wasilibc_nocwd___wasilibc_unlinkat +__wasilibc_nocwd_faccessat +__wasilibc_nocwd_fstatat +__wasilibc_nocwd_linkat +__wasilibc_nocwd_mkdirat_nomode +__wasilibc_nocwd_openat_nomode +__wasilibc_nocwd_opendirat +__wasilibc_nocwd_readlinkat +__wasilibc_nocwd_renameat +__wasilibc_nocwd_scandirat +__wasilibc_nocwd_symlinkat +__wasilibc_nocwd_utimensat __wasilibc_open_nomode -__wasilibc_openat_nomode __wasilibc_register_preopened_fd +__wasilibc_rename_newat +__wasilibc_rename_oldat __wasilibc_rmdirat +__wasilibc_stat __wasilibc_tell __wasilibc_unlinkat +__wasilibc_utimens __wasm_call_dtors __wcscoll_l __wcsftime_l diff --git a/expected/wasm32-wasi/include-all.c b/expected/wasm32-wasi/include-all.c index f6ecbce..6e8a59a 100644 --- a/expected/wasm32-wasi/include-all.c +++ b/expected/wasm32-wasi/include-all.c @@ -166,6 +166,7 @@ #include #include #include +#include #include #include #include diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt index 48386ac..015b4ea 100644 --- a/expected/wasm32-wasi/predefined-macros.txt +++ b/expected/wasm32-wasi/predefined-macros.txt @@ -46,6 +46,7 @@ #define ARG_MAX 131072 #define ARMAG "!\n" #define AT_EACCESS (0x0) +#define AT_FDCWD (-2) #define AT_REMOVEDIR (0x4) #define AT_SYMLINK_FOLLOW (0x2) #define AT_SYMLINK_NOFOLLOW (0x1) @@ -3021,6 +3022,7 @@ #define __wasi_libc_environ_h #define __wasi_libc_find_relpath_h #define __wasi_libc_h +#define __wasi_libc_nocwd_h #define __wasilibc___errno_h #define __wasilibc___errno_values_h #define __wasilibc___fd_set_h diff --git a/libc-bottom-half/cloudlibc/src/libc/dirent/opendirat.c b/libc-bottom-half/cloudlibc/src/libc/dirent/opendirat.c index 1465004..e6d1c2a 100644 --- a/libc-bottom-half/cloudlibc/src/libc/dirent/opendirat.c +++ b/libc-bottom-half/cloudlibc/src/libc/dirent/opendirat.c @@ -3,14 +3,15 @@ // SPDX-License-Identifier: BSD-2-Clause #include +#include #include #include #include #include -DIR *opendirat(int dir, const char *dirname) { +DIR *__wasilibc_nocwd_opendirat(int dir, const char *dirname) { // Open directory. - int fd = __wasilibc_openat_nomode(dir, dirname, O_RDONLY | O_NONBLOCK | O_DIRECTORY); + int fd = __wasilibc_nocwd_openat_nomode(dir, dirname, O_RDONLY | O_NONBLOCK | O_DIRECTORY); if (fd == -1) return NULL; diff --git a/libc-bottom-half/cloudlibc/src/libc/dirent/scandirat.c b/libc-bottom-half/cloudlibc/src/libc/dirent/scandirat.c index a77a1d3..06feae9 100644 --- a/libc-bottom-half/cloudlibc/src/libc/dirent/scandirat.c +++ b/libc-bottom-half/cloudlibc/src/libc/dirent/scandirat.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -17,15 +18,15 @@ static int sel_true(const struct dirent *de) { return 1; } -int scandirat(int dirfd, const char *dir, struct dirent ***namelist, - int (*sel)(const struct dirent *), - int (*compar)(const struct dirent **, const struct dirent **)) { +int __wasilibc_nocwd_scandirat(int dirfd, const char *dir, struct dirent ***namelist, + int (*sel)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) { // Match all files if no select function is provided. if (sel == NULL) sel = sel_true; // Open the directory. - int fd = __wasilibc_openat_nomode(dirfd, dir, O_RDONLY | O_NONBLOCK | O_DIRECTORY); + int fd = __wasilibc_nocwd_openat_nomode(dirfd, dir, O_RDONLY | O_NONBLOCK | O_DIRECTORY); if (fd == -1) return -1; diff --git a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c index da54a72..f5a4cbd 100644 --- a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c +++ b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c @@ -22,19 +22,14 @@ static_assert(O_DIRECTORY >> 12 == __WASI_OFLAGS_DIRECTORY, "Value mismatch"); static_assert(O_EXCL >> 12 == __WASI_OFLAGS_EXCL, "Value mismatch"); static_assert(O_TRUNC >> 12 == __WASI_OFLAGS_TRUNC, "Value mismatch"); -int openat(int fd, const char *path, int oflag, ...) { - return __wasilibc_openat_nomode(fd, path, oflag); -} - -int __wasilibc_openat_nomode(int fd, const char *path, int oflag) { +int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) { // Compute rights corresponding with the access modes provided. // Attempt to obtain all rights, except the ones that contradict the // access mode provided to openat(). __wasi_rights_t max = ~(__WASI_RIGHTS_FD_DATASYNC | __WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_WRITE | __WASI_RIGHTS_FD_ALLOCATE | - __WASI_RIGHTS_FD_READDIR | __WASI_RIGHTS_FD_FILESTAT_SET_SIZE | - 0); + __WASI_RIGHTS_FD_READDIR | __WASI_RIGHTS_FD_FILESTAT_SET_SIZE); switch (oflag & O_ACCMODE) { case O_RDONLY: case O_RDWR: diff --git a/libc-bottom-half/cloudlibc/src/libc/stdio/renameat.c b/libc-bottom-half/cloudlibc/src/libc/stdio/renameat.c index da9b5c5..031a71f 100644 --- a/libc-bottom-half/cloudlibc/src/libc/stdio/renameat.c +++ b/libc-bottom-half/cloudlibc/src/libc/stdio/renameat.c @@ -9,7 +9,7 @@ #include #include -int renameat(int oldfd, const char *old, int newfd, const char *new) { +int __wasilibc_nocwd_renameat(int oldfd, const char *old, int newfd, const char *new) { __wasi_errno_t error = __wasi_path_rename(oldfd, old, strlen(old), newfd, new, strlen(new)); if (error != 0) { diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c index 6f31ddb..db5bf1f 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c @@ -13,8 +13,8 @@ #include "stat_impl.h" -int fstatat(int fd, const char *restrict path, struct stat *restrict buf, - int flag) { +int __wasilibc_nocwd_fstatat(int fd, const char *restrict path, struct stat *restrict buf, + int flag) { // Create lookup properties. __wasi_lookupflags_t lookup_flags = 0; if ((flag & AT_SYMLINK_NOFOLLOW) == 0) diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c index df79f76..f956dd5 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c @@ -10,7 +10,7 @@ #include #include -int mkdirat(int fd, const char *path, mode_t mode) { +int __wasilibc_nocwd_mkdirat_nomode(int fd, const char *path) { __wasi_errno_t error = __wasi_path_create_directory( fd, path, strlen(path)); if (error != 0) { diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c index 0a8e61b..67f3adf 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c @@ -13,8 +13,8 @@ #include "stat_impl.h" -int utimensat(int fd, const char *path, const struct timespec times[2], - int flag) { +int __wasilibc_nocwd_utimensat(int fd, const char *path, const struct timespec times[2], + int flag) { // Convert timestamps and extract NOW/OMIT flags. __wasi_timestamp_t st_atim; __wasi_timestamp_t st_mtim; diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c b/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c index 2ccecb8..a60faf8 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/faccessat.c @@ -10,7 +10,7 @@ #include #include -int faccessat(int fd, const char *path, int amode, int flag) { +int __wasilibc_nocwd_faccessat(int fd, const char *path, int amode, int flag) { // Validate function parameters. if ((amode & ~(F_OK | R_OK | W_OK | X_OK)) != 0 || (flag & ~AT_EACCESS) != 0) { diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/linkat.c b/libc-bottom-half/cloudlibc/src/libc/unistd/linkat.c index eaaf274..d861d7b 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/linkat.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/linkat.c @@ -10,7 +10,7 @@ #include #include -int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag) { +int __wasilibc_nocwd_linkat(int fd1, const char *path1, int fd2, const char *path2, int flag) { // Create lookup properties. __wasi_lookupflags_t lookup1_flags = 0; if ((flag & AT_SYMLINK_FOLLOW) != 0) diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/readlinkat.c b/libc-bottom-half/cloudlibc/src/libc/unistd/readlinkat.c index 82a9939..3732620 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/readlinkat.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/readlinkat.c @@ -9,8 +9,8 @@ #include #include -ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf, - size_t bufsize) { +ssize_t __wasilibc_nocwd_readlinkat(int fd, const char *restrict path, char *restrict buf, + size_t bufsize) { size_t bufused; // TODO: Remove the cast on `buf` once the witx is updated with char8 support. __wasi_errno_t error = __wasi_path_readlink(fd, path, strlen(path), diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/symlinkat.c b/libc-bottom-half/cloudlibc/src/libc/unistd/symlinkat.c index ec7cc94..2ffbcf3 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/symlinkat.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/symlinkat.c @@ -9,7 +9,7 @@ #include #include -int symlinkat(const char *path1, int fd, const char *path2) { +int __wasilibc_nocwd_symlinkat(const char *path1, int fd, const char *path2) { __wasi_errno_t error = __wasi_path_symlink(path1, strlen(path1), fd, path2, strlen(path2)); if (error != 0) { diff --git a/libc-bottom-half/headers/private/stdio.h b/libc-bottom-half/headers/private/stdio.h index dfbefa1..b135b6a 100644 --- a/libc-bottom-half/headers/private/stdio.h +++ b/libc-bottom-half/headers/private/stdio.h @@ -1,2 +1,3 @@ #include <_/cdefs.h> int snprintf(char *str, size_t size, const char *format, ...); +int rename(const char *oldpath, const char *newpath); diff --git a/libc-bottom-half/headers/public/__header_fcntl.h b/libc-bottom-half/headers/public/__header_fcntl.h index 9826439..04252ac 100644 --- a/libc-bottom-half/headers/public/__header_fcntl.h +++ b/libc-bottom-half/headers/public/__header_fcntl.h @@ -56,4 +56,6 @@ #define AT_SYMLINK_FOLLOW (0x2) #define AT_REMOVEDIR (0x4) +#define AT_FDCWD (-2) + #endif diff --git a/libc-bottom-half/headers/public/wasi/libc-nocwd.h b/libc-bottom-half/headers/public/wasi/libc-nocwd.h new file mode 100644 index 0000000..a988503 --- /dev/null +++ b/libc-bottom-half/headers/public/wasi/libc-nocwd.h @@ -0,0 +1,58 @@ +#ifndef __wasi_libc_nocwd_h +#define __wasi_libc_nocwd_h + +/* + * In order to support AT_FDCWD, we need to wrap the *at functions to handle + * it by calling back into the non-at versions which perform libpreopen + * queries. These __wasilibc_nocwd_* forms are the underlying calls which + * assume AT_FDCWD has already been resolved. + */ + +#define __need_size_t +#include +#include <__typedef_ssize_t.h> +#include <__typedef_mode_t.h> +#include <__typedef_DIR.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct timespec; +struct stat; +struct dirent; + +int __wasilibc_nocwd___wasilibc_unlinkat(int, const char *) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd___wasilibc_rmdirat(int, const char *) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_linkat(int, const char *, int, const char *, int) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_symlinkat(const char *, int, const char *) + __attribute__((__warn_unused_result__)); +ssize_t __wasilibc_nocwd_readlinkat(int, const char *__restrict, char *__restrict, size_t) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_faccessat(int, const char *, int, int) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_renameat(int, const char *, int, const char *) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_openat_nomode(int, const char *, int) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_fstatat(int, const char *__restrict, struct stat *__restrict, int) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_mkdirat_nomode(int, const char *) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_utimensat(int, const char *, const struct timespec [2], int) + __attribute__((__warn_unused_result__)); +DIR *__wasilibc_nocwd_opendirat(int, const char *) + __attribute__((__warn_unused_result__)); +int __wasilibc_nocwd_scandirat(int, const char *, struct dirent ***, + int (*)(const struct dirent *), + int (*)(const struct dirent **, const struct dirent **)) + __attribute__((__warn_unused_result__)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc-bottom-half/headers/public/wasi/libc.h b/libc-bottom-half/headers/public/wasi/libc.h index 5997c47..b50518b 100644 --- a/libc-bottom-half/headers/public/wasi/libc.h +++ b/libc-bottom-half/headers/public/wasi/libc.h @@ -2,11 +2,15 @@ #define __wasi_libc_h #include <__typedef_off_t.h> +#include <__struct_timespec.h> #ifdef __cplusplus extern "C" { #endif +struct stat; +struct timespec; + /// Register the given pre-opened file descriptor under the given path. /// /// This function does not take ownership of `prefix` (it makes its own copy). @@ -14,13 +18,16 @@ int __wasilibc_register_preopened_fd(int fd, const char *prefix); /// Renumber `fd` to `newfd`; similar to `dup2` but does a move rather than a /// copy. -int __wasilibc_fd_renumber(int fd, int newfd); +int __wasilibc_fd_renumber(int fd, int newfd) + __attribute__((__warn_unused_result__)); /// Like `unlinkat`, but without depending on `__wasi_path_remove_directory`. -int __wasilibc_unlinkat(int fd, const char *path); +int __wasilibc_unlinkat(int fd, const char *path) + __attribute__((__warn_unused_result__)); /// An `*at` version of rmdir. -int __wasilibc_rmdirat(int fd, const char *path); +int __wasilibc_rmdirat(int fd, const char *path) + __attribute__((__warn_unused_result__)); /// Like `open`, but without the varargs in the signature. int __wasilibc_open_nomode(const char *path, int oflag); @@ -30,7 +37,26 @@ int __wasilibc_openat_nomode(int fd, const char *path, int oflag); /// Return the current file offset. Like `lseek(fd, 0, SEEK_CUR)`, but without /// depending on `lseek`. -off_t __wasilibc_tell(int fd); +off_t __wasilibc_tell(int fd) + __attribute__((__warn_unused_result__)); + +/* Non-`at` forms of various `*at` functions. */ +int __wasilibc_access(const char *pathname, int mode, int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_stat(const char *__restrict pathname, struct stat *__restrict statbuf, int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_utimens(const char *pathname, const struct timespec times[2], int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_link(const char *oldpath, const char *newpath, int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_link_oldat(int olddirfd, const char *oldpath, const char *newpath, int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_link_newat(const char *oldpath, int newdirfd, const char *newpath, int flags) + __attribute__((__warn_unused_result__)); +int __wasilibc_rename_oldat(int olddirfd, const char *oldpath, const char *newpath) + __attribute__((__warn_unused_result__)); +int __wasilibc_rename_newat(const char *oldpath, int newdirfd, const char *newpath) + __attribute__((__warn_unused_result__)); #ifdef __cplusplus } diff --git a/libc-bottom-half/sources/__wasilibc_rmdirat.c b/libc-bottom-half/sources/__wasilibc_rmdirat.c index acb9528..3ba3663 100644 --- a/libc-bottom-half/sources/__wasilibc_rmdirat.c +++ b/libc-bottom-half/sources/__wasilibc_rmdirat.c @@ -4,7 +4,7 @@ #include #include -int __wasilibc_rmdirat(int fd, const char *path) { +int __wasilibc_nocwd___wasilibc_rmdirat(int fd, const char *path) { size_t path_len = strlen(path); __wasi_errno_t error = __wasi_path_remove_directory(fd, path, path_len); if (error != 0) { diff --git a/libc-bottom-half/sources/__wasilibc_unlinkat.c b/libc-bottom-half/sources/__wasilibc_unlinkat.c index a266348..a29ce2c 100644 --- a/libc-bottom-half/sources/__wasilibc_unlinkat.c +++ b/libc-bottom-half/sources/__wasilibc_unlinkat.c @@ -4,7 +4,7 @@ #include #include -int __wasilibc_unlinkat(int fd, const char *path) { +int __wasilibc_nocwd___wasilibc_unlinkat(int fd, const char *path) { size_t path_len = strlen(path); __wasi_errno_t error = __wasi_path_unlink_file(fd, path, path_len); if (error != 0) { diff --git a/libc-bottom-half/sources/at_fdcwd.c b/libc-bottom-half/sources/at_fdcwd.c new file mode 100644 index 0000000..c83797d --- /dev/null +++ b/libc-bottom-half/sources/at_fdcwd.c @@ -0,0 +1,141 @@ +// Handle AT_FDCWD and absolute paths for the *at functions. +// +// In the case of an AT_FDCWD file descriptor or an absolute path, call the +// corresponding non-`at` function. This will send it through the libpreopen +// wrappers to convert the path into a directory file descriptor and relative +// path before translating it into the corresponding `__wasilibc_nocwd_*at` +// function, which then calls the appropriate WASI function. + +#include +#include +#include +#include +#include +#include +#include +#include + +// If the platform doesn't define O_TMPFILE, we don't need to worry about it. +#ifndef O_TMPFILE +#define O_TMPFILE 0 +#endif + +int openat(int dirfd, const char *pathname, int flags, ...) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return open(pathname, flags); + } + + return __wasilibc_nocwd_openat_nomode(dirfd, pathname, flags); +} + +int symlinkat(const char *target, int dirfd, const char *linkpath) { + if (dirfd == AT_FDCWD || linkpath[0] == '/') { + return symlink(target, linkpath); + } + + return __wasilibc_nocwd_symlinkat(target, dirfd, linkpath); +} + +ssize_t readlinkat(int dirfd, const char *__restrict pathname, char *__restrict buf, size_t bufsiz) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return readlink(pathname, buf, bufsiz); + } + + return __wasilibc_nocwd_readlinkat(dirfd, pathname, buf, bufsiz); +} + +int mkdirat(int dirfd, const char *pathname, mode_t mode) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return mkdir(pathname, mode); + } + + return __wasilibc_nocwd_mkdirat_nomode(dirfd, pathname); +} + +DIR *opendirat(int dirfd, const char *path) { + if (dirfd == AT_FDCWD || path[0] == '/') { + return opendir(path); + } + + return __wasilibc_nocwd_opendirat(dirfd, path); +} + +int scandirat(int dirfd, const char *dirp, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) { + if (dirfd == AT_FDCWD || dirp[0] == '/') { + return scandir(dirp, namelist, filter, compar); + } + + return __wasilibc_nocwd_scandirat(dirfd, dirp, namelist, filter, compar); +} + +int faccessat(int dirfd, const char *pathname, int mode, int flags) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return __wasilibc_access(pathname, mode, flags); + } + + return __wasilibc_nocwd_faccessat(dirfd, pathname, mode, flags); +} + +int fstatat(int dirfd, const char *__restrict pathname, struct stat *__restrict statbuf, int flags) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return __wasilibc_stat(pathname, statbuf, flags); + } + + return __wasilibc_nocwd_fstatat(dirfd, pathname, statbuf, flags); +} + +int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + if (dirfd == AT_FDCWD || pathname[0] == '/') { + return __wasilibc_utimens(pathname, times, flags); + } + + return __wasilibc_nocwd_utimensat(dirfd, pathname, times, flags); +} + +int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) { + if ((olddirfd == AT_FDCWD || oldpath[0] == '/') && + (newdirfd == AT_FDCWD || newpath[0] == '/')) { + return __wasilibc_link(oldpath, newpath, flags); + } + if (olddirfd == AT_FDCWD || oldpath[0] == '/') { + return __wasilibc_link_newat(oldpath, newdirfd, newpath, flags); + } + if (newdirfd == AT_FDCWD || newpath[0] == '/') { + return __wasilibc_link_oldat(olddirfd, oldpath, newpath, flags); + } + + return __wasilibc_nocwd_linkat(olddirfd, oldpath, newdirfd, newpath, flags); +} + +int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + if ((olddirfd == AT_FDCWD || oldpath[0] == '/') && + (newdirfd == AT_FDCWD || newpath[0] == '/')) { + return rename(oldpath, newpath); + } + if (olddirfd == AT_FDCWD || oldpath[0] == '/') { + return __wasilibc_rename_newat(oldpath, newdirfd, newpath); + } + if (newdirfd == AT_FDCWD || newpath[0] == '/') { + return __wasilibc_rename_oldat(olddirfd, oldpath, newpath); + } + + return __wasilibc_nocwd_renameat(olddirfd, oldpath, newdirfd, newpath); +} + +int __wasilibc_unlinkat(int dirfd, const char *path) { + if (dirfd == AT_FDCWD || path[0] == '/') { + return unlink(path); + } + + return __wasilibc_nocwd___wasilibc_unlinkat(dirfd, path); +} + +int __wasilibc_rmdirat(int dirfd, const char *path) { + if (dirfd == AT_FDCWD || path[0] == '/') { + return rmdir(path); + } + + return __wasilibc_nocwd___wasilibc_rmdirat(dirfd, path); +} diff --git a/libc-bottom-half/sources/posix.c b/libc-bottom-half/sources/posix.c index 388a57d..153280f 100644 --- a/libc-bottom-half/sources/posix.c +++ b/libc-bottom-half/sources/posix.c @@ -10,6 +10,7 @@ #include #include #include +#include static int find_relpath2( const char *path, @@ -59,7 +60,7 @@ int __wasilibc_open_nomode(const char *path, int oflag) { return -1; } - return __wasilibc_openat_nomode(dirfd, relative_path, oflag); + return __wasilibc_nocwd_openat_nomode(dirfd, relative_path, oflag); } int access(const char *path, int amode) { @@ -72,7 +73,7 @@ int access(const char *path, int amode) { return -1; } - return faccessat(dirfd, relative_path, amode, 0); + return __wasilibc_nocwd_faccessat(dirfd, relative_path, amode, 0); } ssize_t readlink( @@ -89,7 +90,7 @@ ssize_t readlink( return -1; } - return readlinkat(dirfd, relative_path, buf, bufsize); + return __wasilibc_nocwd_readlinkat(dirfd, relative_path, buf, bufsize); } int stat(const char *restrict path, struct stat *restrict buf) { @@ -102,7 +103,7 @@ int stat(const char *restrict path, struct stat *restrict buf) { return -1; } - return fstatat(dirfd, relative_path, buf, 0); + return __wasilibc_nocwd_fstatat(dirfd, relative_path, buf, 0); } int lstat(const char *restrict path, struct stat *restrict buf) { @@ -115,7 +116,7 @@ int lstat(const char *restrict path, struct stat *restrict buf) { return -1; } - return fstatat(dirfd, relative_path, buf, AT_SYMLINK_NOFOLLOW); + return __wasilibc_nocwd_fstatat(dirfd, relative_path, buf, AT_SYMLINK_NOFOLLOW); } int utime(const char *path, const struct utimbuf *times) { @@ -128,7 +129,8 @@ int utime(const char *path, const struct utimbuf *times) { return -1; } - return utimensat(dirfd, relative_path, + return __wasilibc_nocwd_utimensat( + dirfd, relative_path, times ? ((struct timespec [2]) { { .tv_sec = times->actime }, { .tv_sec = times->modtime } @@ -150,7 +152,7 @@ int unlink(const char *path) { // `unlinkat` imports `__wasi_path_remove_directory` even when // `AT_REMOVEDIR` isn't passed. Instead, use a specialized function which // just imports `__wasi_path_unlink_file`. - return __wasilibc_unlinkat(dirfd, relative_path); + return __wasilibc_nocwd___wasilibc_unlinkat(dirfd, relative_path); } int rmdir(const char *path) { @@ -163,7 +165,7 @@ int rmdir(const char *path) { return -1; } - return __wasilibc_rmdirat(dirfd, relative_path); + return __wasilibc_nocwd___wasilibc_rmdirat(dirfd, relative_path); } int remove(const char *path) { @@ -177,10 +179,10 @@ int remove(const char *path) { } // First try to remove it as a file. - int r = __wasilibc_unlinkat(dirfd, relative_path); + int r = __wasilibc_nocwd___wasilibc_unlinkat(dirfd, relative_path); if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE)) { // That failed, but it might be a directory. - r = __wasilibc_rmdirat(dirfd, relative_path); + r = __wasilibc_nocwd___wasilibc_rmdirat(dirfd, relative_path); // If it isn't a directory, we lack capabilities to remove it as a file. if (errno == ENOTDIR) @@ -199,7 +201,7 @@ int mkdir(const char *path, mode_t mode) { return -1; } - return mkdirat(dirfd, relative_path, mode); + return __wasilibc_nocwd_mkdirat_nomode(dirfd, relative_path); } DIR *opendir(const char *dirname) { @@ -212,7 +214,7 @@ DIR *opendir(const char *dirname) { return NULL; } - return opendirat(dirfd, relative_path); + return __wasilibc_nocwd_opendirat(dirfd, relative_path); } int scandir( @@ -230,7 +232,7 @@ int scandir( return -1; } - return scandirat(dirfd, relative_path, namelist, filter, compar); + return __wasilibc_nocwd_scandirat(dirfd, relative_path, namelist, filter, compar); } int symlink(const char *target, const char *linkpath) { @@ -243,7 +245,7 @@ int symlink(const char *target, const char *linkpath) { return -1; } - return symlinkat(target, dirfd, relative_path); + return __wasilibc_nocwd_symlinkat(target, dirfd, relative_path); } int link(const char *old, const char *new) { @@ -255,8 +257,8 @@ int link(const char *old, const char *new) { int new_dirfd = find_relpath(new, &new_relative_path); if (new_dirfd != -1) - return linkat(old_dirfd, old_relative_path, - new_dirfd, new_relative_path, 0); + return __wasilibc_nocwd_linkat(old_dirfd, old_relative_path, + new_dirfd, new_relative_path, 0); } // We couldn't find a preopen for it; indicate that we lack capabilities. @@ -273,11 +275,149 @@ int rename(const char *old, const char *new) { int new_dirfd = find_relpath(new, &new_relative_path); if (new_dirfd != -1) - return renameat(old_dirfd, old_relative_path, - new_dirfd, new_relative_path); + return __wasilibc_nocwd_renameat(old_dirfd, old_relative_path, + new_dirfd, new_relative_path); } // We couldn't find a preopen for it; indicate that we lack capabilities. errno = ENOTCAPABLE; return -1; } + +// Like `access`, but with `faccessat`'s flags argument. +int +__wasilibc_access(const char *path, int mode, int flags) +{ + 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) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_faccessat(dirfd, relative_path, + mode, flags); +} + +// Like `utimensat`, but without the `at` part. +int +__wasilibc_utimens(const char *path, const struct timespec times[2], int flags) +{ + 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) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_utimensat(dirfd, relative_path, + times, flags); +} + +// Like `stat`, but with `fstatat`'s flags argument. +int +__wasilibc_stat(const char *__restrict path, struct stat *__restrict st, int flags) +{ + 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) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_fstatat(dirfd, relative_path, st, flags); +} + +// Like `link`, but with `linkat`'s flags argument. +int +__wasilibc_link(const char *oldpath, const char *newpath, int flags) +{ + char *old_relative_path; + char *new_relative_path; + int old_dirfd = find_relpath(oldpath, &old_relative_path); + int new_dirfd = find_relpath(newpath, &new_relative_path); + + // If we can't find a preopen for it, indicate that we lack capabilities. + if (old_dirfd == -1 || new_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_linkat(old_dirfd, old_relative_path, + new_dirfd, new_relative_path, + flags); +} + +// Like `__wasilibc_link`, but oldpath is relative to olddirfd. +int +__wasilibc_link_oldat(int olddirfd, const char *oldpath, const char *newpath, int flags) +{ + char *new_relative_path; + int new_dirfd = find_relpath(newpath, &new_relative_path); + + // If we can't find a preopen for it, indicate that we lack capabilities. + if (new_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_linkat(olddirfd, oldpath, + new_dirfd, new_relative_path, + flags); +} + +// Like `__wasilibc_link`, but newpath is relative to newdirfd. +int +__wasilibc_link_newat(const char *oldpath, int newdirfd, const char *newpath, int flags) +{ + char *old_relative_path; + int old_dirfd = find_relpath(oldpath, &old_relative_path); + + // If we can't find a preopen for it, indicate that we lack capabilities. + if (old_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_linkat(old_dirfd, old_relative_path, + newdirfd, newpath, + flags); +} + +// Like `rename`, but from is relative to fromdirfd. +int +__wasilibc_rename_oldat(int fromdirfd, const char *from, const char *to) +{ + char *to_relative_path; + int to_dirfd = find_relpath(to, &to_relative_path); + + // If we can't find a preopen for it, indicate that we lack capabilities. + if (to_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_renameat(fromdirfd, from, to_dirfd, to_relative_path); +} + +// Like `rename`, but to is relative to todirfd. +int +__wasilibc_rename_newat(const char *from, int todirfd, const char *to) +{ + char *from_relative_path; + int from_dirfd = find_relpath(from, &from_relative_path); + + // If we can't find a preopen for it, indicate that we lack capabilities. + if (from_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_nocwd_renameat(from_dirfd, from_relative_path, todirfd, to); +} diff --git a/libc-bottom-half/sources/preopens.c b/libc-bottom-half/sources/preopens.c index 8c68826..b6fb9f7 100644 --- a/libc-bottom-half/sources/preopens.c +++ b/libc-bottom-half/sources/preopens.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -96,7 +97,11 @@ static const char *strip_prefixes(const char *path) { /// /// This function takes ownership of `prefix`. static int internal_register_preopened_fd(__wasi_fd_t fd, const char *relprefix) { + // Check preconditions. assert_invariants(); + assert(fd != AT_FDCWD); + assert(fd != -1); + assert(relprefix != NULL); if (num_preopens == preopen_capacity && resize() != 0) return -1;