diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
commit | 8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch) | |
tree | df55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-bottom-half/cloudlibc/src/libc/sys | |
parent | Initial commit. (diff) | |
download | wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.tar.xz wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.zip |
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libc-bottom-half/cloudlibc/src/libc/sys')
19 files changed, 841 insertions, 0 deletions
diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c b/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c new file mode 100644 index 0000000..7d03cc6 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c @@ -0,0 +1,88 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/ioctl.h> + +#include <wasi/api.h> +#include <errno.h> +#include <stdarg.h> + +int ioctl(int fildes, int request, ...) { + switch (request) { + case FIONREAD: { + // Poll the file descriptor to determine how many bytes can be read. + __wasi_subscription_t subscriptions[2] = { + { + .u.tag = __WASI_EVENTTYPE_FD_READ, + .u.u.fd_read.file_descriptor = fildes, + }, + { + .u.tag = __WASI_EVENTTYPE_CLOCK, + .u.u.clock.id = __WASI_CLOCKID_MONOTONIC, + }, + }; + __wasi_event_t events[__arraycount(subscriptions)]; + size_t nevents; + __wasi_errno_t error = __wasi_poll_oneoff( + subscriptions, events, __arraycount(subscriptions), &nevents); + if (error != 0) { + errno = error; + return -1; + } + + // Location where result should be written. + va_list ap; + va_start(ap, request); + int *result = va_arg(ap, int *); + va_end(ap); + + // Extract number of bytes for reading from poll results. + for (size_t i = 0; i < nevents; ++i) { + __wasi_event_t *event = &events[i]; + if (event->error != 0) { + errno = event->error; + return -1; + } + if (event->type == __WASI_EVENTTYPE_FD_READ) { + *result = event->fd_readwrite.nbytes; + return 0; + } + } + + // No data available for reading. + *result = 0; + return 0; + } + case FIONBIO: { + // Obtain the current file descriptor flags. + __wasi_fdstat_t fds; + __wasi_errno_t error = __wasi_fd_fdstat_get(fildes, &fds); + if (error != 0) { + errno = error; + return -1; + } + + // Toggle the non-blocking flag based on the argument. + va_list ap; + va_start(ap, request); + if (*va_arg(ap, const int *) != 0) + fds.fs_flags |= __WASI_FDFLAGS_NONBLOCK; + else + fds.fs_flags &= ~__WASI_FDFLAGS_NONBLOCK; + va_end(ap); + + // Update the file descriptor flags. + error = __wasi_fd_fdstat_set_flags(fildes, fds.fs_flags); + if (error != 0) { + errno = error; + return -1; + } + return 0; + } + default: + // Invalid request. + errno = EINVAL; + return -1; + } +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c b/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c new file mode 100644 index 0000000..fdc470e --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c @@ -0,0 +1,125 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <common/time.h> + +#include <sys/select.h> + +#include <wasi/api.h> +#include <errno.h> + +int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, + fd_set *restrict errorfds, const struct timespec *restrict timeout, + const sigset_t *sigmask) { + // Negative file descriptor upperbound. + if (nfds < 0) { + errno = EINVAL; + return -1; + } + + // This implementation does not support polling for exceptional + // conditions, such as out-of-band data on TCP sockets. + if (errorfds != NULL && errorfds->__nfds > 0) { + errno = ENOSYS; + return -1; + } + + // Replace NULL pointers by the empty set. + fd_set empty; + FD_ZERO(&empty); + if (readfds == NULL) + readfds = ∅ + if (writefds == NULL) + writefds = ∅ + + // Determine the maximum number of events. + size_t maxevents = readfds->__nfds + writefds->__nfds + 1; + __wasi_subscription_t subscriptions[maxevents]; + size_t nsubscriptions = 0; + + // Convert the readfds set. + for (size_t i = 0; i < readfds->__nfds; ++i) { + int fd = readfds->__fds[i]; + if (fd < nfds) { + __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++]; + *subscription = (__wasi_subscription_t){ + .userdata = fd, + .u.tag = __WASI_EVENTTYPE_FD_READ, + .u.u.fd_read.file_descriptor = fd, + }; + } + } + + // Convert the writefds set. + for (size_t i = 0; i < writefds->__nfds; ++i) { + int fd = writefds->__fds[i]; + if (fd < nfds) { + __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++]; + *subscription = (__wasi_subscription_t){ + .userdata = fd, + .u.tag = __WASI_EVENTTYPE_FD_WRITE, + .u.u.fd_write.file_descriptor = fd, + }; + } + } + + // Create extra event for the timeout. + if (timeout != NULL) { + __wasi_subscription_t *subscription = &subscriptions[nsubscriptions++]; + *subscription = (__wasi_subscription_t){ + .u.tag = __WASI_EVENTTYPE_CLOCK, + .u.u.clock.id = __WASI_CLOCKID_REALTIME, + }; + if (!timespec_to_timestamp_clamp(timeout, &subscription->u.u.clock.timeout)) { + errno = EINVAL; + return -1; + } + } + + // Execute poll(). + size_t nevents; + __wasi_event_t events[nsubscriptions]; + __wasi_errno_t error = + __wasi_poll_oneoff(subscriptions, events, nsubscriptions, &nevents); + if (error != 0) { + // WASI's poll requires at least one subscription, or else it returns + // `EINVAL`. Since a `pselect` with nothing to wait for is valid in POSIX, + // return `ENOTSUP` to indicate that we don't support that case. + // + // Wasm has no signal handling, so if none of the user-provided `pollfd` + // elements, nor the timeout, led us to producing even one subscription + // to wait for, there would be no way for the poll to wake up. WASI + // returns `EINVAL` in this case, but for users of `poll`, `ENOTSUP` is + // more likely to be understood. + if (nsubscriptions == 0) + errno = ENOTSUP; + else + errno = error; + return -1; + } + + // Test for EBADF. + for (size_t i = 0; i < nevents; ++i) { + const __wasi_event_t *event = &events[i]; + if ((event->type == __WASI_EVENTTYPE_FD_READ || + event->type == __WASI_EVENTTYPE_FD_WRITE) && + event->error == __WASI_ERRNO_BADF) { + errno = EBADF; + return -1; + } + } + + // Clear and set entries in the result sets. + FD_ZERO(readfds); + FD_ZERO(writefds); + for (size_t i = 0; i < nevents; ++i) { + const __wasi_event_t *event = &events[i]; + if (event->type == __WASI_EVENTTYPE_FD_READ) { + readfds->__fds[readfds->__nfds++] = event->userdata; + } else if (event->type == __WASI_EVENTTYPE_FD_WRITE) { + writefds->__fds[writefds->__nfds++] = event->userdata; + } + } + return readfds->__nfds + writefds->__nfds; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c b/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c new file mode 100644 index 0000000..ebe5e8c --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/select/select.c @@ -0,0 +1,25 @@ +// Copyright (c) 2015 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/select.h> + +#include <errno.h> +#include <stddef.h> + +int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, + fd_set *restrict errorfds, struct timeval *restrict timeout) { + if (timeout != NULL) { + // Timeout specified. + if (timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) { + errno = EINVAL; + return -1; + } + struct timespec ts = {.tv_sec = timeout->tv_sec, + .tv_nsec = (long)timeout->tv_usec * 1000}; + return pselect(nfds, readfds, writefds, errorfds, &ts, NULL); + } else { + // No timeout specified. + return pselect(nfds, readfds, writefds, errorfds, NULL, NULL); + } +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/getsockopt.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/getsockopt.c new file mode 100644 index 0000000..1fe41c4 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/getsockopt.c @@ -0,0 +1,48 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/socket.h> + +#include <wasi/api.h> +#include <errno.h> +#include <string.h> + +int getsockopt(int socket, int level, int option_name, + void *restrict option_value, socklen_t *restrict option_len) { + // Only support SOL_SOCKET options for now. + if (level != SOL_SOCKET) { + errno = ENOPROTOOPT; + return -1; + } + + int value; + switch (option_name) { + case SO_TYPE: { + // Return the type of the socket. This information can simply be + // obtained by looking at the file descriptor type. + __wasi_fdstat_t fsb; + if (__wasi_fd_fdstat_get(socket, &fsb) != 0) { + errno = EBADF; + return -1; + } + if (fsb.fs_filetype != __WASI_FILETYPE_SOCKET_DGRAM && + fsb.fs_filetype != __WASI_FILETYPE_SOCKET_STREAM) { + errno = ENOTSOCK; + return -1; + } + value = fsb.fs_filetype; + break; + } + default: { + errno = ENOPROTOOPT; + return -1; + } + } + + // Copy out integer value. + memcpy(option_value, &value, + *option_len < sizeof(int) ? *option_len : sizeof(int)); + *option_len = sizeof(int); + return 0; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/recv.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/recv.c new file mode 100644 index 0000000..d35f889 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/recv.c @@ -0,0 +1,40 @@ +// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/socket.h> + +#include <assert.h> +#include <wasi/api.h> +#include <errno.h> +#include <stdint.h> + +static_assert(MSG_PEEK == __WASI_RIFLAGS_RECV_PEEK, "Value mismatch"); +static_assert(MSG_WAITALL == __WASI_RIFLAGS_RECV_WAITALL, "Value mismatch"); + +ssize_t recv(int socket, void *restrict buffer, size_t length, int flags) { + // Validate flags. + if ((flags & ~(MSG_PEEK | MSG_WAITALL)) != 0) { + errno = EOPNOTSUPP; + return -1; + } + + // Prepare input parameters. + __wasi_iovec_t iov = {.buf = buffer, .buf_len = length}; + __wasi_iovec_t *ri_data = &iov; + size_t ri_data_len = 1; + __wasi_riflags_t ri_flags = flags; + + // Perform system call. + size_t ro_datalen; + __wasi_roflags_t ro_flags; + __wasi_errno_t error = __wasi_sock_recv(socket, + ri_data, ri_data_len, ri_flags, + &ro_datalen, + &ro_flags); + if (error != 0) { + errno = error; + return -1; + } + return ro_datalen; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/send.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/send.c new file mode 100644 index 0000000..85a298a --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/send.c @@ -0,0 +1,32 @@ +// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/socket.h> + +#include <assert.h> +#include <wasi/api.h> +#include <errno.h> + +ssize_t send(int socket, const void *buffer, size_t length, int flags) { + // This implementation does not support any flags. + if (flags != 0) { + errno = EOPNOTSUPP; + return -1; + } + + // Prepare input parameters. + __wasi_ciovec_t iov = {.buf = buffer, .buf_len = length}; + __wasi_ciovec_t *si_data = &iov; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // Perform system call. + size_t so_datalen; + __wasi_errno_t error = __wasi_sock_send(socket, si_data, si_data_len, si_flags, &so_datalen); + if (error != 0) { + errno = error; + return -1; + } + return so_datalen; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/shutdown.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/shutdown.c new file mode 100644 index 0000000..261fcb8 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/shutdown.c @@ -0,0 +1,27 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/socket.h> + +#include <assert.h> +#include <wasi/api.h> +#include <errno.h> + +static_assert(SHUT_RD == __WASI_SDFLAGS_RD, "Value mismatch"); +static_assert(SHUT_WR == __WASI_SDFLAGS_WR, "Value mismatch"); + +int shutdown(int socket, int how) { + // Validate shutdown flags. + if (how != SHUT_RD && how != SHUT_WR && how != SHUT_RDWR) { + errno = EINVAL; + return -1; + } + + __wasi_errno_t error = __wasi_sock_shutdown(socket, how); + if (error != 0) { + errno = error; + return -1; + } + return error; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/socket_impl.h b/libc-bottom-half/cloudlibc/src/libc/sys/socket/socket_impl.h new file mode 100644 index 0000000..7b1a366 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/socket_impl.h @@ -0,0 +1,57 @@ +// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#ifndef SYS_SOCKET_SOCKET_IMPL_H +#define SYS_SOCKET_SOCKET_IMPL_H + +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> + +#include <assert.h> +#include <stdalign.h> +#include <stddef.h> +#include <stdint.h> + +static_assert(sizeof(struct sockaddr_storage) >= sizeof(struct sockaddr), + "struct sockaddr_storage too small"); +static_assert(alignof(struct sockaddr_storage) == alignof(struct sockaddr), + "struct sockaddr alignment incorrect"); +static_assert(sizeof(struct sockaddr_storage) >= sizeof(struct sockaddr_in), + "struct sockaddr_storage too small"); +static_assert(alignof(struct sockaddr_storage) == alignof(struct sockaddr_in), + "struct sockaddr_in alignment incorrect"); +static_assert(sizeof(struct sockaddr_storage) >= sizeof(struct sockaddr_in6), + "struct sockaddr_storage too small"); +static_assert(alignof(struct sockaddr_storage) == alignof(struct sockaddr_in6), + "struct sockaddr_in6 alignment incorrect"); +static_assert(sizeof(struct sockaddr_storage) >= sizeof(struct sockaddr_un), + "struct sockaddr_storage too small"); +static_assert(alignof(struct sockaddr_storage) == alignof(struct sockaddr_un), + "struct sockaddr_un alignment incorrect"); + +// Returns the control message header stored at a provided memory +// address, ensuring that it is stored within the ancillary data buffer +// of a message header. +static inline struct cmsghdr *CMSG_GET(const struct msghdr *mhdr, void *cmsg) { + // Safety belt: require that the returned object is properly aligned. + assert((uintptr_t)cmsg % alignof(struct cmsghdr) == 0 && + "Attempted to access unaligned control message header"); + + // Safety belt: the computed starting address of the control message + // header may only lie inside the ancillary data buffer, or right + // after it in case we've reached the end of the buffer. + const unsigned char *begin = mhdr->msg_control; + const unsigned char *end = begin + mhdr->msg_controllen; + assert((unsigned char *)cmsg >= begin && + (unsigned char *)cmsg < end + alignof(struct cmsghdr) && + "Computed object outside of buffer boundaries"); + + // Only return the control message header in case all of its fields + // lie within the ancillary data buffer. + return CMSG_DATA((struct cmsghdr *)cmsg) <= end ? cmsg : NULL; +} + +#endif diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c new file mode 100644 index 0000000..b8ffdb5 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c @@ -0,0 +1,21 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/stat.h> + +#include <wasi/api.h> +#include <errno.h> + +#include "stat_impl.h" + +int fstat(int fildes, struct stat *buf) { + __wasi_filestat_t internal_stat; + __wasi_errno_t error = __wasi_fd_filestat_get(fildes, &internal_stat); + if (error != 0) { + errno = error; + return -1; + } + to_public_stat(&internal_stat, buf); + return 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 new file mode 100644 index 0000000..25b29ac --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c @@ -0,0 +1,31 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/stat.h> + +#include <wasi/api.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> + +#include "stat_impl.h" + +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) + lookup_flags |= __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW; + + // Perform system call. + __wasi_filestat_t internal_stat; + __wasi_errno_t error = + __wasi_path_filestat_get(fd, lookup_flags, path, &internal_stat); + if (error != 0) { + errno = error; + return -1; + } + to_public_stat(&internal_stat, buf); + return 0; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/futimens.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/futimens.c new file mode 100644 index 0000000..13357fc --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/futimens.c @@ -0,0 +1,29 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/stat.h> + +#include <wasi/api.h> +#include <errno.h> + +#include "stat_impl.h" + +int futimens(int fd, const struct timespec *times) { + // Convert timestamps and extract NOW/OMIT flags. + __wasi_timestamp_t st_atim; + __wasi_timestamp_t st_mtim; + __wasi_fstflags_t flags; + if (!utimens_get_timestamps(times, &st_atim, &st_mtim, &flags)) { + errno = EINVAL; + return -1; + } + + // Perform system call. + __wasi_errno_t error = __wasi_fd_filestat_set_times(fd, st_atim, st_mtim, flags); + if (error != 0) { + errno = error; + return -1; + } + return 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 new file mode 100644 index 0000000..fd27d5e --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c @@ -0,0 +1,18 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/stat.h> + +#include <wasi/api.h> +#include <errno.h> +#include <string.h> + +int __wasilibc_nocwd_mkdirat_nomode(int fd, const char *path) { + __wasi_errno_t error = __wasi_path_create_directory(fd, path); + if (error != 0) { + errno = error; + return -1; + } + return 0; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/stat_impl.h b/libc-bottom-half/cloudlibc/src/libc/sys/stat/stat_impl.h new file mode 100644 index 0000000..9726b51 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/stat_impl.h @@ -0,0 +1,116 @@ +// Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#ifndef SYS_STAT_STAT_IMPL_H +#define SYS_STAT_STAT_IMPL_H + +#include <common/time.h> + +#include <sys/stat.h> + +#include <assert.h> +#include <wasi/api.h> +#include <stdbool.h> + +static_assert(S_ISBLK(S_IFBLK), "Value mismatch"); +static_assert(S_ISCHR(S_IFCHR), "Value mismatch"); +static_assert(S_ISDIR(S_IFDIR), "Value mismatch"); +static_assert(S_ISFIFO(S_IFIFO), "Value mismatch"); +static_assert(S_ISLNK(S_IFLNK), "Value mismatch"); +static_assert(S_ISREG(S_IFREG), "Value mismatch"); +static_assert(S_ISSOCK(S_IFSOCK), "Value mismatch"); + +static inline void to_public_stat(const __wasi_filestat_t *in, + struct stat *out) { + // Ensure that we don't truncate any values. + static_assert(sizeof(in->dev) == sizeof(out->st_dev), "Size mismatch"); + static_assert(sizeof(in->ino) == sizeof(out->st_ino), "Size mismatch"); + /* + * The non-standard __st_filetype field appears to only be used for shared + * memory, which we don't currently support. + */ + /* nlink_t is 64-bit on wasm32, following the x32 ABI. */ + static_assert(sizeof(in->nlink) <= sizeof(out->st_nlink), "Size shortfall"); + static_assert(sizeof(in->size) == sizeof(out->st_size), "Size mismatch"); + + *out = (struct stat){ + .st_dev = in->dev, + .st_ino = in->ino, + .st_nlink = in->nlink, + .st_size = in->size, + .st_atim = timestamp_to_timespec(in->atim), + .st_mtim = timestamp_to_timespec(in->mtim), + .st_ctim = timestamp_to_timespec(in->ctim), + }; + + // Convert file type to legacy types encoded in st_mode. + switch (in->filetype) { + case __WASI_FILETYPE_BLOCK_DEVICE: + out->st_mode |= S_IFBLK; + break; + case __WASI_FILETYPE_CHARACTER_DEVICE: + out->st_mode |= S_IFCHR; + break; + case __WASI_FILETYPE_DIRECTORY: + out->st_mode |= S_IFDIR; + break; + case __WASI_FILETYPE_REGULAR_FILE: + out->st_mode |= S_IFREG; + break; + case __WASI_FILETYPE_SOCKET_DGRAM: + case __WASI_FILETYPE_SOCKET_STREAM: + out->st_mode |= S_IFSOCK; + break; + case __WASI_FILETYPE_SYMBOLIC_LINK: + out->st_mode |= S_IFLNK; + break; + } +} + +static inline bool utimens_get_timestamps(const struct timespec *times, + __wasi_timestamp_t *st_atim, + __wasi_timestamp_t *st_mtim, + __wasi_fstflags_t *flags) { + if (times == NULL) { + // Update both timestamps. + *flags = __WASI_FSTFLAGS_ATIM_NOW | __WASI_FSTFLAGS_MTIM_NOW; + *st_atim = (__wasi_timestamp_t) { 0 }; + *st_mtim = (__wasi_timestamp_t) { 0 }; + } else { + // Set individual timestamps. + *flags = 0; + switch (times[0].tv_nsec) { + case UTIME_NOW: + *flags |= __WASI_FSTFLAGS_ATIM_NOW; + *st_atim = (__wasi_timestamp_t) { 0 }; + break; + case UTIME_OMIT: + *st_atim = (__wasi_timestamp_t) { 0 }; + break; + default: + *flags |= __WASI_FSTFLAGS_ATIM; + if (!timespec_to_timestamp_exact(×[0], st_atim)) + return false; + break; + } + + switch (times[1].tv_nsec) { + case UTIME_NOW: + *flags |= __WASI_FSTFLAGS_MTIM_NOW; + *st_mtim = (__wasi_timestamp_t) { 0 }; + break; + case UTIME_OMIT: + *st_mtim = (__wasi_timestamp_t) { 0 }; + break; + default: + *flags |= __WASI_FSTFLAGS_MTIM; + if (!timespec_to_timestamp_exact(×[1], st_mtim)) + return false; + break; + } + } + return true; +} + +#endif diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c b/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c new file mode 100644 index 0000000..19508a1 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c @@ -0,0 +1,38 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/stat.h> + +#include <wasi/api.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> + +#include "stat_impl.h" + +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; + __wasi_fstflags_t flags; + if (!utimens_get_timestamps(times, &st_atim, &st_mtim, &flags)) { + errno = EINVAL; + return -1; + } + + // Create lookup properties. + __wasi_lookupflags_t lookup_flags = 0; + if ((flag & AT_SYMLINK_NOFOLLOW) == 0) + lookup_flags |= __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW; + + // Perform system call. + __wasi_errno_t error = + __wasi_path_filestat_set_times(fd, lookup_flags, path, st_atim, st_mtim, flags); + if (error != 0) { + errno = error; + return -1; + } + return 0; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/time/gettimeofday.c b/libc-bottom-half/cloudlibc/src/libc/sys/time/gettimeofday.c new file mode 100644 index 0000000..596bdff --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/time/gettimeofday.c @@ -0,0 +1,18 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <common/time.h> + +#include <sys/time.h> + +#include <wasi/api.h> + +int gettimeofday(struct timeval *restrict tp, void *tz) { + if (tp != NULL) { + __wasi_timestamp_t ts = 0; + (void)__wasi_clock_time_get(__WASI_CLOCKID_REALTIME, 1000, &ts); + *tp = timestamp_to_timeval(ts); + } + return 0; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/uio/preadv.c b/libc-bottom-half/cloudlibc/src/libc/sys/uio/preadv.c new file mode 100644 index 0000000..36f882d --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/uio/preadv.c @@ -0,0 +1,24 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/types.h> +#include <sys/uio.h> + +#include <wasi/api.h> +#include <errno.h> + +ssize_t preadv(int fildes, const struct iovec *iov, int iovcnt, off_t offset) { + if (iovcnt < 0 || offset < 0) { + errno = EINVAL; + return -1; + } + size_t bytes_read; + __wasi_errno_t error = __wasi_fd_pread( + fildes, (const __wasi_iovec_t *)iov, iovcnt, offset, &bytes_read); + if (error != 0) { + errno = error; + return -1; + } + return bytes_read; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/uio/pwritev.c b/libc-bottom-half/cloudlibc/src/libc/sys/uio/pwritev.c new file mode 100644 index 0000000..d6f8851 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/uio/pwritev.c @@ -0,0 +1,24 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/types.h> +#include <sys/uio.h> + +#include <wasi/api.h> +#include <errno.h> + +ssize_t pwritev(int fildes, const struct iovec *iov, int iovcnt, off_t offset) { + if (iovcnt < 0 || offset < 0) { + errno = EINVAL; + return -1; + } + size_t bytes_written; + __wasi_errno_t error = __wasi_fd_pwrite( + fildes, (const __wasi_ciovec_t *)iov, iovcnt, offset, &bytes_written); + if (error != 0) { + errno = error; + return -1; + } + return bytes_written; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/uio/readv.c b/libc-bottom-half/cloudlibc/src/libc/sys/uio/readv.c new file mode 100644 index 0000000..e3eaebe --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/uio/readv.c @@ -0,0 +1,40 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/uio.h> + +#include <assert.h> +#include <wasi/api.h> +#include <errno.h> +#include <stddef.h> + +static_assert(offsetof(struct iovec, iov_base) == + offsetof(__wasi_iovec_t, buf), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_base) == + sizeof(((__wasi_iovec_t *)0)->buf), + "Size mismatch"); +static_assert(offsetof(struct iovec, iov_len) == + offsetof(__wasi_iovec_t, buf_len), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_len) == + sizeof(((__wasi_iovec_t *)0)->buf_len), + "Size mismatch"); +static_assert(sizeof(struct iovec) == sizeof(__wasi_iovec_t), + "Size mismatch"); + +ssize_t readv(int fildes, const struct iovec *iov, int iovcnt) { + if (iovcnt < 0) { + errno = EINVAL; + return -1; + } + size_t bytes_read; + __wasi_errno_t error = __wasi_fd_read( + fildes, (const __wasi_iovec_t *)iov, iovcnt, &bytes_read); + if (error != 0) { + errno = error; + return -1; + } + return bytes_read; +} diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/uio/writev.c b/libc-bottom-half/cloudlibc/src/libc/sys/uio/writev.c new file mode 100644 index 0000000..459b152 --- /dev/null +++ b/libc-bottom-half/cloudlibc/src/libc/sys/uio/writev.c @@ -0,0 +1,40 @@ +// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ +// +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/uio.h> + +#include <assert.h> +#include <wasi/api.h> +#include <errno.h> +#include <stddef.h> + +static_assert(offsetof(struct iovec, iov_base) == + offsetof(__wasi_ciovec_t, buf), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_base) == + sizeof(((__wasi_ciovec_t *)0)->buf), + "Size mismatch"); +static_assert(offsetof(struct iovec, iov_len) == + offsetof(__wasi_ciovec_t, buf_len), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_len) == + sizeof(((__wasi_ciovec_t *)0)->buf_len), + "Size mismatch"); +static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), + "Size mismatch"); + +ssize_t writev(int fildes, const struct iovec *iov, int iovcnt) { + if (iovcnt < 0) { + errno = EINVAL; + return -1; + } + size_t bytes_written; + __wasi_errno_t error = __wasi_fd_write( + fildes, (const __wasi_ciovec_t *)iov, iovcnt, &bytes_written); + if (error != 0) { + errno = error; + return -1; + } + return bytes_written; +} |