summaryrefslogtreecommitdiffstats
path: root/libc-bottom-half/cloudlibc/src/libc/sys
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
commit8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch)
treedf55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-bottom-half/cloudlibc/src/libc/sys
parentInitial commit. (diff)
downloadwasi-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')
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c88
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c125
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/select/select.c25
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/socket/getsockopt.c48
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/socket/recv.c40
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/socket/send.c32
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/socket/shutdown.c27
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/socket/socket_impl.h57
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/fstat.c21
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/fstatat.c31
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/futimens.c29
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/mkdirat.c18
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/stat_impl.h116
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/stat/utimensat.c38
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/time/gettimeofday.c18
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/uio/preadv.c24
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/uio/pwritev.c24
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/uio/readv.c40
-rw-r--r--libc-bottom-half/cloudlibc/src/libc/sys/uio/writev.c40
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 = &empty;
+ if (writefds == NULL)
+ writefds = &empty;
+
+ // 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(&times[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(&times[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;
+}