Преглед изворни кода

Abstract POSIX filesystem functions (#2585)

To allow non-POSIX platforms such as Windows to support WASI libc
filesystem functionality, create a set of wrapper functions which provide a
platform-agnostic interface to interact with the host filesystem. For now,
the Windows implementation is stubbed but this will be implemented
properly in a future PR. There are no functional changes in this change,
just a reorganization of code to move any direct POSIX references out of
posix.c in the libc implementation into posix_file.c under the shared
POSIX sources.

See https://github.com/bytecodealliance/wasm-micro-runtime/issues/2495 for a
more detailed overview of the plan to port the WASI libc filesystem to Windows.
zoraaver пре 2 година
родитељ
комит
fa5e9d72b0
40 измењених фајлова са 3602 додато и 2076 уклоњено
  1. 47 36
      core/iwasm/common/wasm_runtime_common.c
  2. 4 4
      core/iwasm/common/wasm_runtime_common.h
  3. 15 10
      core/iwasm/include/wasm_export.h
  4. 1 1
      core/iwasm/interpreter/wasm.h
  5. 1 0
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
  6. 0 1
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h
  7. 548 1305
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
  8. 41 95
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c
  9. 23 27
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h
  10. 162 527
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  11. 2 1
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h
  12. 0 64
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h
  13. 4 0
      core/shared/platform/alios/platform_internal.h
  14. 4 0
      core/shared/platform/android/platform_internal.h
  15. 256 0
      core/shared/platform/common/libc-util/libc_errno.c
  16. 15 0
      core/shared/platform/common/libc-util/libc_errno.h
  17. 8 0
      core/shared/platform/common/libc-util/platform_common_libc_util.cmake
  18. 7 0
      core/shared/platform/common/posix/platform_api_posix.cmake
  19. 1013 0
      core/shared/platform/common/posix/posix_file.c
  20. 4 0
      core/shared/platform/cosmopolitan/platform_internal.h
  21. 4 0
      core/shared/platform/darwin/platform_internal.h
  22. 4 0
      core/shared/platform/esp-idf/platform_internal.h
  23. 4 0
      core/shared/platform/freebsd/platform_internal.h
  24. 1 0
      core/shared/platform/include/platform_api_extension.h
  25. 1100 0
      core/shared/platform/include/platform_wasi.h
  26. 4 0
      core/shared/platform/linux-sgx/platform_internal.h
  27. 0 1
      core/shared/platform/linux-sgx/sgx_ipfs.h
  28. 8 4
      core/shared/platform/linux-sgx/shared_platform.cmake
  29. 4 0
      core/shared/platform/linux/platform_internal.h
  30. 4 0
      core/shared/platform/nuttx/platform_internal.h
  31. 6 0
      core/shared/platform/nuttx/shared_platform.cmake
  32. 4 0
      core/shared/platform/riot/platform_internal.h
  33. 4 0
      core/shared/platform/rt-thread/platform_internal.h
  34. 4 0
      core/shared/platform/vxworks/platform_internal.h
  35. 8 0
      core/shared/platform/windows/platform_internal.h
  36. 7 0
      core/shared/platform/windows/shared_platform.cmake
  37. 267 0
      core/shared/platform/windows/win_file.c
  38. 4 0
      core/shared/platform/zephyr/platform_internal.h
  39. 4 0
      product-mini/platforms/nuttx/wamr.mk
  40. 6 0
      wamr-compiler/CMakeLists.txt

+ 47 - 36
core/iwasm/common/wasm_runtime_common.c

@@ -2778,7 +2778,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
                               uint32 dir_count, const char *map_dir_list[],
                               uint32 map_dir_count, const char *env_list[],
                               uint32 env_count, char *argv[], int argc,
-                              int stdinfd, int stdoutfd, int stderrfd)
+                              int64 stdinfd, int64 stdoutfd, int64 stderrfd)
 {
     WASIArguments *wasi_args = get_wasi_args_from_module(module);
 
@@ -2792,9 +2792,9 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
     wasi_args->env_count = env_count;
     wasi_args->argv = argv;
     wasi_args->argc = (uint32)argc;
-    wasi_args->stdio[0] = stdinfd;
-    wasi_args->stdio[1] = stdoutfd;
-    wasi_args->stdio[2] = stderrfd;
+    wasi_args->stdio[0] = (os_raw_file_handle)stdinfd;
+    wasi_args->stdio[1] = (os_raw_file_handle)stdoutfd;
+    wasi_args->stdio[2] = (os_raw_file_handle)stderrfd;
 
 #if WASM_ENABLE_MULTI_MODULE != 0
 #if WASM_ENABLE_INTERP != 0
@@ -2889,8 +2889,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size)
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size)
 {
     WASIContext *wasi_ctx;
     char *argv_buf = NULL;
@@ -2908,7 +2909,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     bool argv_environ_inited = false;
     bool addr_pool_inited = false;
     __wasi_fd_t wasm_fd = 3;
-    int32 raw_fd;
+    os_file_handle file_handle;
     char *path, resolved_path[PATH_MAX];
     uint32 i;
 
@@ -2978,15 +2979,19 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     }
     addr_pool_inited = true;
 
-    /* Prepopulate curfds with stdin, stdout, and stderr file descriptors.
-     *
-     * If -1 is given, use STDIN_FILENO (0), STDOUT_FILENO (1),
-     * STDERR_FILENO (2) respectively.
-     */
-    if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0)
-        || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1)
-        || !fd_table_insert_existing(curfds, 2,
-                                     (stderrfd != -1) ? stderrfd : 2)) {
+    os_file_handle stdin_file_handle = os_convert_stdin_handle(stdinfd);
+    os_file_handle stdout_file_handle = os_convert_stdout_handle(stdoutfd);
+    os_file_handle stderr_file_handle = os_convert_stderr_handle(stderrfd);
+
+    if (!os_is_handle_valid(&stdin_file_handle)
+        || !os_is_handle_valid(&stdout_file_handle)
+        || !os_is_handle_valid(&stderr_file_handle))
+        goto fail;
+
+    /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */
+    if (!fd_table_insert_existing(curfds, 0, stdin_file_handle, true)
+        || !fd_table_insert_existing(curfds, 1, stdout_file_handle, true)
+        || !fd_table_insert_existing(curfds, 2, stderr_file_handle, true)) {
         set_error_buf(error_buf, error_buf_size,
                       "Init wasi environment failed: init fd table failed");
         goto fail;
@@ -2994,11 +2999,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
 
     wasm_fd = 3;
     for (i = 0; i < dir_count; i++, wasm_fd++) {
-#ifdef BH_PLATFORM_WINDOWS
-        path = _fullpath(resolved_path, dir_list[i], PATH_MAX);
-#else
-        path = realpath(dir_list[i], resolved_path);
-#endif
+        path = os_realpath(dir_list[i], resolved_path);
         if (!path) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
@@ -3006,25 +3007,34 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                          dir_list[i], errno);
             goto fail;
         }
-#ifdef BH_PLATFORM_WINDOWS
-        if (error_buf)
-            snprintf(
-                error_buf, error_buf_size,
-                "pre-opening directory is not supported on windows platforms");
-        goto fail;
-#else
-        raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0);
-#endif
-        if (raw_fd == -1) {
+
+        __wasi_errno_t error = os_open_preopendir(path, &file_handle);
+
+        if (error != __WASI_ESUCCESS) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
                          "error while pre-opening directory %s: %d\n",
-                         dir_list[i], errno);
+                         dir_list[i], error);
+            goto fail;
+        }
+
+        if (!fd_table_insert_existing(curfds, wasm_fd, file_handle, false)) {
+            if (error_buf)
+                snprintf(error_buf, error_buf_size,
+                         "error inserting preopen fd %u (directory %s) into fd "
+                         "table",
+                         (unsigned int)wasm_fd, dir_list[i]);
             goto fail;
         }
 
-        fd_table_insert_existing(curfds, wasm_fd, raw_fd);
-        fd_prestats_insert(prestats, dir_list[i], wasm_fd);
+        if (!fd_prestats_insert(prestats, dir_list[i], wasm_fd)) {
+            if (error_buf)
+                snprintf(error_buf, error_buf_size,
+                         "error inserting preopen fd %u (directory %s) into "
+                         "prestats table",
+                         (unsigned int)wasm_fd, dir_list[i]);
+            goto fail;
+        }
     }
 
     /* addr_pool(textual) -> apool */
@@ -3152,8 +3162,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size)
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size)
 {
     WASIContext *ctx;
     uvwasi_t *uvwasi;

+ 4 - 4
core/iwasm/common/wasm_runtime_common.h

@@ -14,7 +14,6 @@
 #include "../interpreter/wasm.h"
 #if WASM_ENABLE_LIBC_WASI != 0
 #if WASM_ENABLE_UVWASI == 0
-#include "wasmtime_ssp.h"
 #include "posix.h"
 #else
 #include "uvwasi.h"
@@ -853,7 +852,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
                               uint32 dir_count, const char *map_dir_list[],
                               uint32 map_dir_count, const char *env_list[],
                               uint32 env_count, char *argv[], int argc,
-                              int stdinfd, int stdoutfd, int stderrfd);
+                              int64 stdinfd, int64 stdoutfd, int64 stderrfd);
 
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
@@ -881,8 +880,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size);
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size);
 
 void
 wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst);

+ 15 - 10
core/iwasm/include/wasm_export.h

@@ -431,26 +431,31 @@ wasm_runtime_get_module_hash(wasm_module_t module);
  * @param env_count     The number of elements in env.
  * @param argv          The list of command line arguments.
  * @param argc          The number of elements in argv.
- * @param stdinfd       The host file descriptor to back WASI STDIN_FILENO.
- *                      If -1 is specified, STDIN_FILENO is used.
- * @param stdoutfd      The host file descriptor to back WASI STDOUT_FILENO.
- *                      If -1 is specified, STDOUT_FILENO is used.
- * @param stderrfd      The host file descriptor to back WASI STDERR_FILENO.
- *                      If -1 is specified, STDERR_FILENO is used.
+ * @param stdin_handle  The raw host handle to back WASI STDIN_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDIN is used.
+ * @param stdoutfd      The raw host handle to back WASI STDOUT_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDOUT is used.
+ * @param stderrfd      The raw host handle to back WASI STDERR_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDERR is used.
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_wasi_args_ex(wasm_module_t module,
                            const char *dir_list[], uint32_t dir_count,
                            const char *map_dir_list[], uint32_t map_dir_count,
                            const char *env[], uint32_t env_count,
-                           char *argv[], int argc,
-                           int stdinfd, int stdoutfd, int stderrfd);
+                           char *argv[], int argc, int64_t stdinfd,
+                           int64_t stdoutfd, int64_t stderrfd);
 
 /**
  * Set WASI parameters.
  *
- * Same as wasm_runtime_set_wasi_args_ex with stdinfd = -1, stdoutfd = -1,
- * stderrfd = -1.
+ * Same as wasm_runtime_set_wasi_args_ex but with default stdio handles
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_wasi_args(wasm_module_t module,

+ 1 - 1
core/iwasm/interpreter/wasm.h

@@ -350,7 +350,7 @@ typedef struct WASIArguments {
     uint32 ns_lookup_count;
     char **argv;
     uint32 argc;
-    int stdio[3];
+    os_raw_file_handle stdio[3];
 } WASIArguments;
 #endif
 

+ 1 - 0
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -7,6 +7,7 @@
 #include "bh_platform.h"
 #include "wasm_export.h"
 #include "wasm_runtime_common.h"
+#include "wasmtime_ssp.h"
 
 #if WASM_ENABLE_THREAD_MGR != 0
 #include "../../../thread-mgr/thread_manager.h"

+ 0 - 1
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h

@@ -6,7 +6,6 @@
 #ifndef _LIBC_WASI_WRAPPER_H
 #define _LIBC_WASI_WRAPPER_H
 
-#include "wasmtime_ssp.h"
 #include "posix.h"
 
 #ifdef __cplusplus

Разлика између датотеке није приказан због своје велике величине
+ 548 - 1305
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h


+ 41 - 95
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c

@@ -8,119 +8,68 @@
 #include "ssp_config.h"
 #include "blocking_op.h"
 
-int
-blocking_op_close(wasm_exec_env_t exec_env, int fd)
+__wasi_errno_t
+blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle,
+                  bool is_stdio)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    int ret = close(fd);
+    __wasi_errno_t error = os_close(handle, is_stdio);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
 
-ssize_t
-blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                  int iovcnt)
+__wasi_errno_t
+blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle,
+                  const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    errno = ENOTSUP;
-    return -1;
-#else
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = readv(fd, iov, iovcnt);
+    __wasi_errno_t error = os_readv(handle, iov, iovcnt, nread);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-#endif
+    return error;
 }
 
-#if CONFIG_HAS_PREADV
-ssize_t
-blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt, off_t offset)
-{
-    if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
-    }
-    ssize_t ret = preadv(fd, iov, iovcnt, offset);
-    wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-}
-#else /* CONFIG_HAS_PREADV */
-ssize_t
-blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb,
-                  off_t offset)
+__wasi_errno_t
+blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_iovec_t *iov, int iovcnt,
+                   __wasi_filesize_t offset, size_t *nread)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    errno = ENOTSUP;
-    return -1;
-#else
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = pread(fd, p, nb, offset);
+    __wasi_errno_t ret = os_preadv(handle, iov, iovcnt, offset, nread);
     wasm_runtime_end_blocking_op(exec_env);
     return ret;
-#endif
 }
-#endif /* CONFIG_HAS_PREADV */
 
-ssize_t
-blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt)
+__wasi_errno_t
+blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_ciovec_t *iov, int iovcnt,
+                   size_t *nwritten)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    errno = ENOTSUP;
-    return -1;
-#else
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = writev(fd, iov, iovcnt);
+    __wasi_errno_t error = os_writev(handle, iov, iovcnt, nwritten);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-#endif
+    return error;
 }
 
-#if CONFIG_HAS_PWRITEV
-ssize_t
-blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                    int iovcnt, off_t offset)
+__wasi_errno_t
+blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle,
+                    const struct __wasi_ciovec_t *iov, int iovcnt,
+                    __wasi_filesize_t offset, size_t *nwritten)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = pwritev(fd, iov, iovcnt, offset);
+    __wasi_errno_t error = os_pwritev(handle, iov, iovcnt, offset, nwritten);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
-#else /* CONFIG_HAS_PWRITEV */
-ssize_t
-blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb,
-                   off_t offset)
-{
-#ifdef BH_PLATFORM_WINDOWS
-    errno = ENOTSUP;
-    return -1;
-#else
-    if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
-    }
-    ssize_t ret = pwrite(fd, p, nb, offset);
-    wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-#endif
-}
-#endif /* CONFIG_HAS_PWRITEV */
 
 int
 blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock,
@@ -207,20 +156,17 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host,
     return ret;
 }
 
-int
-blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path,
-                   int oflags, mode_t mode)
+__wasi_errno_t
+blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const char *path, __wasi_oflags_t oflags,
+                   __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+                   wasi_libc_file_access_mode access_mode, os_file_handle *out)
 {
-#ifdef BH_PLATFORM_WINDOWS
-    errno = ENOTSUP;
-    return -1;
-#else
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    int ret = openat(fd, path, oflags, mode);
+    __wasi_errno_t error = os_openat(handle, path, oflags, fd_flags,
+                                     lookup_flags, access_mode, out);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-#endif
+    return error;
 }

+ 23 - 27
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h

@@ -6,26 +6,24 @@
 #include "bh_platform.h"
 #include "wasm_export.h"
 
-int
-blocking_op_close(wasm_exec_env_t exec_env, int fd);
-ssize_t
-blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                  int iovcnt);
-ssize_t
-blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt, off_t offset);
-ssize_t
-blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb,
-                  off_t offset);
-ssize_t
-blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt);
-ssize_t
-blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                    int iovcnt, off_t offset);
-ssize_t
-blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb,
-                   off_t offset);
+__wasi_errno_t
+blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle,
+                  bool is_stdio);
+__wasi_errno_t
+blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle,
+                  const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread);
+__wasi_errno_t
+blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_iovec_t *iov, int iovcnt,
+                   __wasi_filesize_t offset, size_t *nread);
+__wasi_errno_t
+blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_ciovec_t *iov, int iovcnt,
+                   size_t *nwritten);
+__wasi_errno_t
+blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle,
+                    const struct __wasi_ciovec_t *iov, int iovcnt,
+                    __wasi_filesize_t offset, size_t *nwritten);
 int
 blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock,
                           bh_socket_t *sockp, void *addr,
@@ -48,10 +46,8 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host,
                                 bh_addr_info_t *addr_info,
                                 size_t addr_info_size, size_t *max_info_size);
 
-#ifdef BH_PLATFORM_WINDOWS
-/* TODO to be (re)moved as part of WASI on windows work */
-typedef unsigned mode_t;
-#endif
-int
-blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path,
-                   int oflags, mode_t mode);
+__wasi_errno_t
+blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const char *path, __wasi_oflags_t oflags,
+                   __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+                   wasi_libc_file_access_mode access_mode, os_file_handle *out);

Разлика између датотеке није приказан због своје велике величине
+ 162 - 527
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c


+ 2 - 1
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h

@@ -60,7 +60,8 @@ struct addr_pool {
 bool
 fd_table_init(struct fd_table *);
 bool
-fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int);
+fd_table_insert_existing(struct fd_table *, __wasi_fd_t, os_file_handle,
+                         bool is_stdio);
 bool
 fd_prestats_init(struct fd_prestats *);
 bool

+ 0 - 64
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h

@@ -47,38 +47,6 @@
 #define CONFIG_HAS_CLOCK_NANOSLEEP 0
 #endif
 
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM) \
-    && !defined(_WIN32)
-#define CONFIG_HAS_FDATASYNC 1
-#else
-#define CONFIG_HAS_FDATASYNC 0
-#endif
-
-/*
- * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header.
- * (platform_internal.h)
- */
-#ifndef __NuttX__
-#ifndef __CloudABI__
-#define CONFIG_HAS_ISATTY 1
-#else
-#define CONFIG_HAS_ISATTY 0
-#endif
-#endif
-
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(_WIN32) \
-    && !defined(__COSMOPOLITAN__)
-#define CONFIG_HAS_POSIX_FALLOCATE 1
-#else
-#define CONFIG_HAS_POSIX_FALLOCATE 0
-#endif
-
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(_WIN32)
-#define CONFIG_HAS_PREADV 1
-#else
-#define CONFIG_HAS_PREADV 0
-#endif
-
 #if defined(__APPLE__) || defined(__CloudABI__)
 #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
 #else
@@ -92,32 +60,6 @@
 #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
 #endif
 
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(_WIN32)
-#define CONFIG_HAS_PWRITEV 1
-#else
-#define CONFIG_HAS_PWRITEV 0
-#endif
-
-#ifdef __APPLE__
-#define st_atim st_atimespec
-#define st_ctim st_ctimespec
-#define st_mtim st_mtimespec
-#endif
-
-#if defined(O_DSYNC)
-#define CONFIG_HAS_O_DSYNC
-#endif
-
-// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support
-// it.
-#if defined(O_RSYNC) && !defined(__linux__)
-#define CONFIG_HAS_O_RSYNC
-#endif
-
-#if defined(O_SYNC)
-#define CONFIG_HAS_O_SYNC
-#endif
-
 #if !defined(BH_PLATFORM_LINUX_SGX)
 /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one,
 so we have to handle this case specially */
@@ -145,10 +87,4 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */
 #define CONFIG_HAS_STD_ATOMIC 0
 #endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */
 
-#if !defined(__NuttX__)
-#define CONFIG_HAS_D_INO 1
-#else
-#define CONFIG_HAS_D_INO 0
-#endif
-
 #endif

+ 4 - 0
core/shared/platform/alios/platform_internal.h

@@ -64,4 +64,8 @@ int signbit(double x);
 int isnan(double x);
 /* clang-format on */
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #endif /* end of _BH_PLATFORM_H */

+ 4 - 0
core/shared/platform/android/platform_internal.h

@@ -146,6 +146,10 @@ preadv(int __fd, const struct iovec *__iov, int __count, off_t __offset);
 ssize_t
 pwritev(int __fd, const struct iovec *__iov, int __count, off_t __offset);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 256 - 0
core/shared/platform/common/libc-util/libc_errno.c

@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "errno.h"
+#include "libc_errno.h"
+
+__wasi_errno_t
+convert_errno(int error)
+{
+    // The C standard library only requires EDOM, EILSEQ and ERANGE to be
+    // defined. Other error codes are POSIX-specific and hence may or may
+    // not be available on non-POSIX platforms.
+    __wasi_errno_t code = __WASI_ENOSYS;
+#define X(v)               \
+    case v:                \
+        code = __WASI_##v; \
+        break;
+    switch (error) {
+        X(EDOM)
+        X(EILSEQ)
+        X(ERANGE)
+#ifdef E2BIG
+        X(E2BIG)
+#endif
+#ifdef EACCES
+        X(EACCES)
+#endif
+#ifdef EADDRINUSE
+        X(EADDRINUSE)
+#endif
+#ifdef EADDRNOTAVAIL
+        X(EADDRNOTAVAIL)
+#endif
+#ifdef EAFNOSUPPORT
+        X(EAFNOSUPPORT)
+#endif
+#ifdef EAGAIN
+        X(EAGAIN)
+#endif
+#ifdef EALREADY
+        X(EALREADY)
+#endif
+#ifdef EBADF
+        X(EBADF)
+#endif
+#ifdef EBADMSG
+        X(EBADMSG)
+#endif
+#ifdef EBUSY
+        X(EBUSY)
+#endif
+#ifdef ECANCELED
+        X(ECANCELED)
+#endif
+#ifdef ECHILD
+        X(ECHILD)
+#endif
+#ifdef ECONNABORTED
+        X(ECONNABORTED)
+#endif
+#ifdef ECONNREFUSED
+        X(ECONNREFUSED)
+#endif
+#ifdef ECONNRESET
+        X(ECONNRESET)
+#endif
+#ifdef EDEADLK
+        X(EDEADLK)
+#endif
+#ifdef EDESTADDRREQ
+        X(EDESTADDRREQ)
+#endif
+#ifdef EDQUOT
+        X(EDQUOT)
+#endif
+#ifdef EEXIST
+        X(EEXIST)
+#endif
+#ifdef EFAULT
+        X(EFAULT)
+#endif
+#ifdef EFBIG
+        X(EFBIG)
+#endif
+#ifdef EHOSTUNREACH
+        X(EHOSTUNREACH)
+#endif
+#ifdef EIDRM
+        X(EIDRM)
+#endif
+#ifdef EINPROGRESS
+        X(EINPROGRESS)
+#endif
+#ifdef EINTR
+        X(EINTR)
+#endif
+#ifdef EINVAL
+        X(EINVAL)
+#endif
+#ifdef EIO
+        X(EIO)
+#endif
+#ifdef EISCONN
+        X(EISCONN)
+#endif
+#ifdef EISDIR
+        X(EISDIR)
+#endif
+#ifdef ELOOP
+        X(ELOOP)
+#endif
+#ifdef EMFILE
+        X(EMFILE)
+#endif
+#ifdef EMLINK
+        X(EMLINK)
+#endif
+#ifdef EMSGSIZE
+        X(EMSGSIZE)
+#endif
+#ifdef EMULTIHOP
+        X(EMULTIHOP)
+#endif
+#ifdef ENAMETOOLONG
+        X(ENAMETOOLONG)
+#endif
+#ifdef ENETDOWN
+        X(ENETDOWN)
+#endif
+#ifdef ENETRESET
+        X(ENETRESET)
+#endif
+#ifdef ENETUNREACH
+        X(ENETUNREACH)
+#endif
+#ifdef ENFILE
+        X(ENFILE)
+#endif
+#ifdef ENOBUFS
+        X(ENOBUFS)
+#endif
+#ifdef ENODEV
+        X(ENODEV)
+#endif
+#ifdef ENOENT
+        X(ENOENT)
+#endif
+#ifdef ENOEXEC
+        X(ENOEXEC)
+#endif
+#ifdef ENOLCK
+        X(ENOLCK)
+#endif
+#ifdef ENOLINK
+        X(ENOLINK)
+#endif
+#ifdef ENOMEM
+        X(ENOMEM)
+#endif
+#ifdef ENOMSG
+        X(ENOMSG)
+#endif
+#ifdef ENOPROTOOPT
+        X(ENOPROTOOPT)
+#endif
+#ifdef ENOSPC
+        X(ENOSPC)
+#endif
+#ifdef ENOSYS
+        X(ENOSYS)
+#endif
+#ifdef ENOTCAPABLE
+        X(ENOTCAPABLE)
+#endif
+#ifdef ENOTCONN
+        X(ENOTCONN)
+#endif
+#ifdef ENOTDIR
+        X(ENOTDIR)
+#endif
+#ifdef ENOTEMPTY
+        X(ENOTEMPTY)
+#endif
+#ifdef ENOTRECOVERABLE
+        X(ENOTRECOVERABLE)
+#endif
+#ifdef ENOTSOCK
+        X(ENOTSOCK)
+#endif
+#ifdef ENOTSUP
+        X(ENOTSUP)
+#endif
+#ifdef ENOTTY
+        X(ENOTTY)
+#endif
+#ifdef ENXIO
+        X(ENXIO)
+#endif
+#ifdef EOVERFLOW
+        X(EOVERFLOW)
+#endif
+#ifdef EOWNERDEAD
+        X(EOWNERDEAD)
+#endif
+#ifdef EPERM
+        X(EPERM)
+#endif
+#ifdef EPIPE
+        X(EPIPE)
+#endif
+#ifdef EPROTO
+        X(EPROTO)
+#endif
+#ifdef EPROTONOSUPPORT
+        X(EPROTONOSUPPORT)
+#endif
+#ifdef EPROTOTYPE
+        X(EPROTOTYPE)
+#endif
+#ifdef EROFS
+        X(EROFS)
+#endif
+#ifdef ESPIPE
+        X(ESPIPE)
+#endif
+#ifdef ESRCH
+        X(ESRCH)
+#endif
+#ifdef ESTALE
+        X(ESTALE)
+#endif
+#ifdef ETIMEDOUT
+        X(ETIMEDOUT)
+#endif
+#ifdef ETXTBSY
+        X(ETXTBSY)
+#endif
+#ifdef EXDEV
+        X(EXDEV)
+#endif
+        default:
+#ifdef EOPNOTSUPP
+            if (error == EOPNOTSUPP)
+                code = __WASI_ENOTSUP;
+#endif
+#ifdef EWOULDBLOCK
+            if (error == EWOULDBLOCK)
+                code = __WASI_EAGAIN;
+#endif
+            break;
+    }
+#undef X
+    return code;
+}

+ 15 - 0
core/shared/platform/common/libc-util/libc_errno.h

@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef WASI_ERRNO_H
+#define WASI_ERRNO_H
+
+#include "platform_wasi.h"
+
+// Converts an errno error code to a WASI error code.
+__wasi_errno_t
+convert_errno(int error);
+
+#endif /* end of WASI_ERRNO_H */

+ 8 - 0
core/shared/platform/common/libc-util/platform_common_libc_util.cmake

@@ -0,0 +1,8 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ 
+set (PLATFORM_COMMON_LIBC_UTIL_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+include_directories(${PLATFORM_COMMON_LIBC_UTIL_DIR})
+
+file (GLOB_RECURSE PLATFORM_COMMON_LIBC_UTIL_SOURCE ${PLATFORM_COMMON_LIBC_UTIL_DIR}/*.c)

+ 7 - 0
core/shared/platform/common/posix/platform_api_posix.cmake

@@ -5,4 +5,11 @@ set (PLATFORM_COMMON_POSIX_DIR ${CMAKE_CURRENT_LIST_DIR})
 
 file (GLOB_RECURSE source_all ${PLATFORM_COMMON_POSIX_DIR}/*.c)
 
+if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
+    list(REMOVE_ITEM source_all ${PLATFORM_COMMON_POSIX_DIR}/posix_file.c)
+else()
+    include (${CMAKE_CURRENT_LIST_DIR}/../libc-util/platform_common_libc_util.cmake)
+    set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif()
+
 set (PLATFORM_COMMON_POSIX_SOURCE ${source_all} )

+ 1013 - 0
core/shared/platform/common/posix/posix_file.c

@@ -0,0 +1,1013 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_extension.h"
+#include "libc_errno.h"
+#include <unistd.h>
+
+#if !defined(__APPLE__) && !defined(ESP_PLATFORM)
+#define CONFIG_HAS_PWRITEV 1
+#define CONFIG_HAS_PREADV 1
+#else
+#define CONFIG_HAS_PWRITEV 0
+#define CONFIG_HAS_PREADV 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM)
+#define CONFIG_HAS_FDATASYNC 1
+#else
+#define CONFIG_HAS_FDATASYNC 0
+#endif
+
+/*
+ * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header.
+ * (platform_internal.h)
+ */
+#if !defined(__NuttX__)
+#define CONFIG_HAS_D_INO 1
+#define CONFIG_HAS_ISATTY 1
+#else
+#define CONFIG_HAS_D_INO 0
+#endif
+
+#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__)
+#define CONFIG_HAS_POSIX_FALLOCATE 1
+#else
+#define CONFIG_HAS_POSIX_FALLOCATE 0
+#endif
+
+#if defined(O_DSYNC)
+#define CONFIG_HAS_O_DSYNC
+#endif
+
+// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support
+// it.
+#if defined(O_RSYNC) && !defined(__linux__)
+#define CONFIG_HAS_O_RSYNC
+#endif
+
+#if defined(O_SYNC)
+#define CONFIG_HAS_O_SYNC
+#endif
+
+// Converts a POSIX timespec to a WASI timestamp.
+static __wasi_timestamp_t
+convert_timespec(const struct timespec *ts)
+{
+    if (ts->tv_sec < 0)
+        return 0;
+    if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000)
+        return UINT64_MAX;
+    return (__wasi_timestamp_t)ts->tv_sec * 1000000000
+           + (__wasi_timestamp_t)ts->tv_nsec;
+}
+
+// Converts a POSIX stat structure to a WASI filestat structure
+static void
+convert_stat(os_file_handle handle, const struct stat *in,
+             __wasi_filestat_t *out)
+{
+    out->st_dev = in->st_dev;
+    out->st_ino = in->st_ino;
+    out->st_nlink = (__wasi_linkcount_t)in->st_nlink;
+    out->st_size = (__wasi_filesize_t)in->st_size;
+#ifdef __APPLE__
+    out->st_atim = convert_timespec(&in->st_atimespec);
+    out->st_mtim = convert_timespec(&in->st_mtimespec);
+    out->st_ctim = convert_timespec(&in->st_ctimespec);
+#else
+    out->st_atim = convert_timespec(&in->st_atim);
+    out->st_mtim = convert_timespec(&in->st_mtim);
+    out->st_ctim = convert_timespec(&in->st_ctim);
+#endif
+
+    // Convert the file type. In the case of sockets there is no way we
+    // can easily determine the exact socket type.
+    if (S_ISBLK(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE;
+    }
+    else if (S_ISCHR(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE;
+    }
+    else if (S_ISDIR(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_DIRECTORY;
+    }
+    else if (S_ISFIFO(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
+    }
+    else if (S_ISLNK(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK;
+    }
+    else if (S_ISREG(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_REGULAR_FILE;
+    }
+    else if (S_ISSOCK(in->st_mode)) {
+        int socktype;
+        socklen_t socktypelen = sizeof(socktype);
+
+        if (getsockopt(handle, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen)
+            < 0) {
+            out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+            return;
+        }
+
+        switch (socktype) {
+            case SOCK_DGRAM:
+                out->st_filetype = __WASI_FILETYPE_SOCKET_DGRAM;
+                break;
+            case SOCK_STREAM:
+                out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
+                break;
+            default:
+                out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+                return;
+        }
+    }
+    else {
+        out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+    }
+}
+
+static void
+convert_timestamp(__wasi_timestamp_t in, struct timespec *out)
+{
+    // Store sub-second remainder.
+#if defined(__SYSCALL_SLONG_TYPE)
+    out->tv_nsec = (__SYSCALL_SLONG_TYPE)(in % 1000000000);
+#else
+    out->tv_nsec = (long)(in % 1000000000);
+#endif
+    in /= 1000000000;
+
+    // Clamp to the maximum in case it would overflow our system's time_t.
+    out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX;
+}
+
+// Converts the provided timestamps and flags to a set of arguments for
+// futimens() and utimensat().
+static void
+convert_utimens_arguments(__wasi_timestamp_t st_atim,
+                          __wasi_timestamp_t st_mtim,
+                          __wasi_fstflags_t fstflags, struct timespec *ts)
+{
+    if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) {
+        ts[0].tv_nsec = UTIME_NOW;
+    }
+    else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) {
+        convert_timestamp(st_atim, &ts[0]);
+    }
+    else {
+        ts[0].tv_nsec = UTIME_OMIT;
+    }
+
+    if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) {
+        ts[1].tv_nsec = UTIME_NOW;
+    }
+    else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) {
+        convert_timestamp(st_mtim, &ts[1]);
+    }
+    else {
+        ts[1].tv_nsec = UTIME_OMIT;
+    }
+}
+
+__wasi_errno_t
+os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf)
+{
+    struct stat stat_buf;
+    int ret = fstat(handle, &stat_buf);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    convert_stat(handle, &stat_buf, buf);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fstatat(os_file_handle handle, const char *path,
+           struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags)
+{
+    struct stat stat_buf;
+    int ret = fstatat(handle, path, &stat_buf,
+                      (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                          ? AT_SYMLINK_FOLLOW
+                          : AT_SYMLINK_NOFOLLOW);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    convert_stat(handle, &stat_buf, buf);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
+{
+    int ret = fcntl(handle, F_GETFL);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    *flags = 0;
+
+    if ((ret & O_APPEND) != 0)
+        *flags |= __WASI_FDFLAG_APPEND;
+#ifdef CONFIG_HAS_O_DSYNC
+    if ((ret & O_DSYNC) != 0)
+        *flags |= __WASI_FDFLAG_DSYNC;
+#endif
+    if ((ret & O_NONBLOCK) != 0)
+        *flags |= __WASI_FDFLAG_NONBLOCK;
+#ifdef CONFIG_HAS_O_RSYNC
+    if ((ret & O_RSYNC) != 0)
+        *flags |= __WASI_FDFLAG_RSYNC;
+#endif
+#ifdef CONFIG_HAS_O_SYNC
+    if ((ret & O_SYNC) != 0)
+        *flags |= __WASI_FDFLAG_SYNC;
+#endif
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
+{
+    int fcntl_flags = 0;
+
+    if ((flags & __WASI_FDFLAG_APPEND) != 0)
+        fcntl_flags |= O_APPEND;
+    if ((flags & __WASI_FDFLAG_DSYNC) != 0)
+#ifdef CONFIG_HAS_O_DSYNC
+        fcntl_flags |= O_DSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    if ((flags & __WASI_FDFLAG_NONBLOCK) != 0)
+        fcntl_flags |= O_NONBLOCK;
+    if ((flags & __WASI_FDFLAG_RSYNC) != 0)
+#ifdef CONFIG_HAS_O_RSYNC
+        fcntl_flags |= O_RSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    if ((flags & __WASI_FDFLAG_SYNC) != 0)
+#ifdef CONFIG_HAS_O_SYNC
+        fcntl_flags |= O_SYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+
+    int ret = fcntl(handle, F_SETFL, fcntl_flags);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fdatasync(os_file_handle handle)
+{
+#if CONFIG_HAS_FDATASYNC
+    int ret = fdatasync(handle);
+#else
+    int ret = fsync(handle);
+#endif
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fsync(os_file_handle handle)
+{
+    int ret = fsync(handle);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_open_preopendir(const char *path, os_file_handle *out)
+{
+
+    int fd = open(path, O_RDONLY | O_DIRECTORY, 0);
+
+    if (fd < 0)
+        return convert_errno(errno);
+
+    *out = fd;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
+          __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags,
+          wasi_libc_file_access_mode read_write_mode, os_file_handle *out)
+{
+    int open_flags = 0;
+
+    // Convert open flags.
+    if ((oflags & __WASI_O_CREAT) != 0) {
+        open_flags |= O_CREAT;
+    }
+    if ((oflags & __WASI_O_DIRECTORY) != 0)
+        open_flags |= O_DIRECTORY;
+    if ((oflags & __WASI_O_EXCL) != 0)
+        open_flags |= O_EXCL;
+    if ((oflags & __WASI_O_TRUNC) != 0) {
+        open_flags |= O_TRUNC;
+    }
+
+    // Convert file descriptor flags.
+    if ((fs_flags & __WASI_FDFLAG_APPEND) != 0)
+        open_flags |= O_APPEND;
+    if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) {
+#ifdef CONFIG_HAS_O_DSYNC
+        open_flags |= O_DSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+    if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0)
+        open_flags |= O_NONBLOCK;
+    if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) {
+#ifdef CONFIG_HAS_O_RSYNC
+        open_flags |= O_RSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+    if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) {
+#ifdef CONFIG_HAS_O_SYNC
+        open_flags |= O_SYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+
+    if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) {
+        open_flags |= O_NOFOLLOW;
+    }
+
+    switch (read_write_mode) {
+        case WASI_LIBC_ACCESS_MODE_READ_WRITE:
+            open_flags |= O_RDWR;
+            break;
+        case WASI_LIBC_ACCESS_MODE_READ_ONLY:
+            open_flags |= O_RDONLY;
+            break;
+        case WASI_LIBC_ACCESS_MODE_WRITE_ONLY:
+            open_flags |= O_WRONLY;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    int fd = openat(handle, path, open_flags, 0666);
+
+    if (fd < 0) {
+        int openat_errno = errno;
+        // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket.
+        if (openat_errno == ENXIO) {
+            struct stat sb;
+            int ret = fstatat(fd, path, &sb,
+                              (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                                  ? 0
+                                  : AT_SYMLINK_NOFOLLOW);
+            return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP
+                                                    : __WASI_ENXIO;
+        }
+        // Linux returns ENOTDIR instead of ELOOP when using
+        // O_NOFOLLOW|O_DIRECTORY on a symlink.
+        if (openat_errno == ENOTDIR
+            && (open_flags & (O_NOFOLLOW | O_DIRECTORY)) != 0) {
+            struct stat sb;
+            int ret = fstatat(fd, path, &sb, AT_SYMLINK_NOFOLLOW);
+            if (S_ISLNK(sb.st_mode)) {
+                return __WASI_ELOOP;
+            }
+            (void)ret;
+        }
+        // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
+        // a symlink.
+        if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0
+            && openat_errno == EMLINK)
+            return __WASI_ELOOP;
+
+        return convert_errno(openat_errno);
+    }
+
+    *out = fd;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_get_access_mode(os_file_handle handle,
+                        wasi_libc_file_access_mode *access_mode)
+{
+    int ret = fcntl(handle, F_GETFL, 0);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    switch (ret & O_ACCMODE) {
+        case O_RDONLY:
+            *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY;
+            break;
+        case O_WRONLY:
+            *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY;
+            break;
+        case O_RDWR:
+            *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_close(os_file_handle handle, bool is_stdio)
+{
+    if (is_stdio)
+        return __WASI_ESUCCESS;
+
+    int ret = close(handle);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+          __wasi_filesize_t offset, size_t *nread)
+{
+#if CONFIG_HAS_PREADV
+    ssize_t len =
+        preadv(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len;
+    return __WASI_ESUCCESS;
+#else
+    if (iovcnt == 1) {
+        ssize_t len = pread(handle, iov->buf, iov->buf_len, offset);
+
+        if (len < 0)
+            return convert_errno(errno);
+
+        *nread = len;
+        return __WASI_ESUCCESS;
+    }
+
+    // Allocate a single buffer to fit all data.
+    size_t totalsize = 0;
+    for (size_t i = 0; i < iovcnt; ++i)
+        totalsize += iov[i].buf_len;
+
+    char *buf = BH_MALLOC(totalsize);
+
+    if (buf == NULL) {
+        return __WASI_ENOMEM;
+    }
+
+    // Perform a single read operation.
+    ssize_t len = pread(handle, buf, totalsize, offset);
+
+    if (len < 0) {
+        BH_FREE(buf);
+        return convert_errno(errno);
+    }
+
+    // Copy data back to vectors.
+    size_t bufoff = 0;
+    for (size_t i = 0; i < iovcnt; ++i) {
+        if (bufoff + iov[i].buf_len < (size_t)len) {
+            memcpy(iov[i].buf, buf + bufoff, iov[i].buf_len);
+            bufoff += iov[i].buf_len;
+        }
+        else {
+            memcpy(iov[i].buf, buf + bufoff, len - bufoff);
+            break;
+        }
+    }
+    BH_FREE(buf);
+    *nread = len;
+
+    return __WASI_ESUCCESS;
+#endif
+}
+
+__wasi_errno_t
+os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+           __wasi_filesize_t offset, size_t *nwritten)
+{
+    if (iovcnt == 0)
+        return __WASI_EINVAL;
+
+    ssize_t len = 0;
+#if CONFIG_HAS_PWRITEV
+    len =
+        pwritev(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
+#else
+    if (iovcnt == 1) {
+        len = pwrite(handle, iov->buf, iov->buf_len, offset);
+    }
+    else {
+        // Allocate a single buffer to fit all data.
+        size_t totalsize = 0;
+        for (size_t i = 0; i < iovcnt; ++i)
+            totalsize += iov[i].buf_len;
+        char *buf = BH_MALLOC(totalsize);
+        if (buf == NULL) {
+            return __WASI_ENOMEM;
+        }
+        size_t bufoff = 0;
+        for (size_t i = 0; i < iovcnt; ++i) {
+            memcpy(buf + bufoff, iov[i].buf, iov[i].buf_len);
+            bufoff += iov[i].buf_len;
+        }
+
+        // Perform a single write operation.
+        len = pwrite(handle, buf, totalsize, offset);
+        BH_FREE(buf);
+    }
+#endif
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nwritten = (size_t)len;
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+         size_t *nread)
+{
+    ssize_t len = readv(handle, (const struct iovec *)iov, (int)iovcnt);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+          size_t *nwritten)
+{
+    ssize_t len = writev(handle, (const struct iovec *)iov, (int)iovcnt);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nwritten = (size_t)len;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
+             __wasi_filesize_t length)
+{
+#if CONFIG_HAS_POSIX_FALLOCATE
+    int ret = posix_fallocate(handle, (off_t)offset, (off_t)length);
+#else
+    // At least ensure that the file is grown to the right size.
+    // TODO(ed): See if this can somehow be implemented without any race
+    // conditions. We may end up shrinking the file right now.
+    struct stat sb;
+    int ret = fstat(handle, &sb);
+    off_t newsize = (off_t)(offset + length);
+
+    if (ret == 0 && sb.st_size < newsize)
+        ret = ftruncate(handle, newsize);
+#endif
+
+    if (ret != 0)
+        return convert_errno(ret);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
+{
+    int ret = ftruncate(handle, (off_t)size);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
+            __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags)
+{
+    struct timespec ts[2];
+    convert_utimens_arguments(access_time, modification_time, fstflags, ts);
+
+    int ret = futimens(handle, ts);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_utimensat(os_file_handle handle, const char *path,
+             __wasi_timestamp_t access_time,
+             __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
+             __wasi_lookupflags_t lookup_flags)
+{
+    struct timespec ts[2];
+    convert_utimens_arguments(access_time, modification_time, fstflags, ts);
+
+    int ret = utimensat(handle, path, ts,
+                        (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                            ? 0
+                            : AT_SYMLINK_NOFOLLOW);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readlinkat(os_file_handle handle, const char *path, char *buf,
+              size_t bufsize, size_t *nread)
+{
+    // Linux requires that the buffer size is positive. whereas POSIX does
+    // not. Use a fake buffer to store the results if the size is zero.
+    char fakebuf[1];
+    ssize_t len = readlinkat(handle, path, bufsize == 0 ? fakebuf : buf,
+                             bufsize == 0 ? sizeof(fakebuf) : bufsize);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len < bufsize ? (size_t)len : bufsize;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_linkat(os_file_handle from_handle, const char *from_path,
+          os_file_handle to_handle, const char *to_path,
+          __wasi_lookupflags_t lookup_flags)
+{
+    int ret = linkat(
+        from_handle, from_path, to_handle, to_path,
+        (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) ? AT_SYMLINK_FOLLOW : 0);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
+{
+    int ret = symlinkat(old_path, handle, new_path);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_mkdirat(os_file_handle handle, const char *path)
+{
+    int ret = mkdirat(handle, path, 0777);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_renameat(os_file_handle old_handle, const char *old_path,
+            os_file_handle new_handle, const char *new_path)
+{
+
+    int ret = renameat(old_handle, old_path, new_handle, new_path);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
+{
+    int ret = unlinkat(handle, path, is_dir ? AT_REMOVEDIR : 0);
+
+#ifndef __linux__
+    if (ret < 0) {
+        // Non-Linux implementations may return EPERM when attempting to remove
+        // a directory without REMOVEDIR. While that's what POSIX specifies,
+        // it's less useful. Adjust this to EISDIR. It doesn't matter that this
+        // is not atomic with the unlinkat, because if the file is removed and a
+        // directory is created before fstatat sees it, we're racing with that
+        // change anyway and unlinkat could have legitimately seen the directory
+        // if the race had turned out differently.
+        if (errno == EPERM) {
+            struct stat statbuf;
+            if (fstatat(handle, path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0
+                && S_ISDIR(statbuf.st_mode)) {
+                errno = EISDIR;
+            }
+        }
+        // POSIX permits either EEXIST or ENOTEMPTY when the directory is not
+        // empty. Map it to ENOTEMPTY.
+        else if (errno == EEXIST) {
+            errno = ENOTEMPTY;
+        }
+
+        return convert_errno(errno);
+    }
+#endif
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
+         __wasi_whence_t whence, __wasi_filesize_t *new_offset)
+{
+    int nwhence;
+
+    switch (whence) {
+        case __WASI_WHENCE_CUR:
+            nwhence = SEEK_CUR;
+            break;
+        case __WASI_WHENCE_END:
+            nwhence = SEEK_END;
+            break;
+        case __WASI_WHENCE_SET:
+            nwhence = SEEK_SET;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    off_t ret = lseek(handle, offset, nwhence);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    *new_offset = (__wasi_filesize_t)ret;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
+           __wasi_filesize_t length, __wasi_advice_t advice)
+{
+#ifdef POSIX_FADV_NORMAL
+    int nadvice;
+    switch (advice) {
+        case __WASI_ADVICE_DONTNEED:
+            nadvice = POSIX_FADV_DONTNEED;
+            break;
+        case __WASI_ADVICE_NOREUSE:
+            nadvice = POSIX_FADV_NOREUSE;
+            break;
+        case __WASI_ADVICE_NORMAL:
+            nadvice = POSIX_FADV_NORMAL;
+            break;
+        case __WASI_ADVICE_RANDOM:
+            nadvice = POSIX_FADV_RANDOM;
+            break;
+        case __WASI_ADVICE_SEQUENTIAL:
+            nadvice = POSIX_FADV_SEQUENTIAL;
+            break;
+        case __WASI_ADVICE_WILLNEED:
+            nadvice = POSIX_FADV_WILLNEED;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    int ret = posix_fadvise(handle, (off_t)offset, (off_t)length, nadvice);
+
+    if (ret < 0)
+        return convert_errno(ret);
+
+    return __WASI_ESUCCESS;
+#else
+    // Advisory information can be safely ignored if not supported
+    switch (advice) {
+        case __WASI_ADVICE_DONTNEED:
+        case __WASI_ADVICE_NOREUSE:
+        case __WASI_ADVICE_NORMAL:
+        case __WASI_ADVICE_RANDOM:
+        case __WASI_ADVICE_SEQUENTIAL:
+        case __WASI_ADVICE_WILLNEED:
+            return __WASI_ESUCCESS;
+        default:
+            return __WASI_EINVAL;
+    }
+#endif
+}
+
+__wasi_errno_t
+os_isatty(os_file_handle handle)
+{
+#if CONFIG_HAS_ISATTY
+    int ret = isatty(handle);
+
+    if (ret == 1)
+        return __WASI_ESUCCESS;
+
+    return __WASI_ENOTTY;
+#else
+    return __WASI_ENOTSUP;
+#endif
+}
+
+os_file_handle
+os_convert_stdin_handle(os_raw_file_handle raw_stdin)
+{
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+    return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO;
+}
+
+os_file_handle
+os_convert_stdout_handle(os_raw_file_handle raw_stdout)
+{
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+    return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO;
+}
+
+os_file_handle
+os_convert_stderr_handle(os_raw_file_handle raw_stderr)
+{
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+    return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO;
+}
+
+__wasi_errno_t
+os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
+{
+    *dir_stream = fdopendir(handle);
+
+    if (*dir_stream == NULL)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_rewinddir(os_dir_stream dir_stream)
+{
+    rewinddir(dir_stream);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position)
+{
+    seekdir(dir_stream, (long)position);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
+           const char **d_name)
+{
+    errno = 0;
+
+    struct dirent *dent = readdir(dir_stream);
+
+    if (dent == NULL) {
+        *d_name = NULL;
+        return convert_errno(errno);
+    }
+
+    long offset = (__wasi_dircookie_t)telldir(dir_stream);
+
+    size_t namlen = strlen(dent->d_name);
+
+    *d_name = dent->d_name;
+    entry->d_next = offset;
+    entry->d_namlen = (__wasi_dirnamlen_t)namlen;
+#if CONFIG_HAS_D_INO
+    entry->d_ino = dent->d_ino;
+#else
+    entry->d_ino = 0;
+#endif
+
+    switch (dent->d_type) {
+        case DT_BLK:
+            entry->d_type = __WASI_FILETYPE_BLOCK_DEVICE;
+            break;
+        case DT_CHR:
+            entry->d_type = __WASI_FILETYPE_CHARACTER_DEVICE;
+            break;
+        case DT_DIR:
+            entry->d_type = __WASI_FILETYPE_DIRECTORY;
+            break;
+        case DT_FIFO:
+            entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
+            break;
+        case DT_LNK:
+            entry->d_type = __WASI_FILETYPE_SYMBOLIC_LINK;
+            break;
+        case DT_REG:
+            entry->d_type = __WASI_FILETYPE_REGULAR_FILE;
+            break;
+#ifdef DT_SOCK
+        case DT_SOCK:
+            // Technically not correct, but good enough.
+            entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
+            break;
+#endif
+        default:
+            entry->d_type = __WASI_FILETYPE_UNKNOWN;
+            break;
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_closedir(os_dir_stream dir_stream)
+{
+    int ret = closedir(dir_stream);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
+os_dir_stream
+os_get_invalid_dir_stream()
+{
+    return NULL;
+}
+
+bool
+os_is_dir_stream_valid(os_dir_stream *dir_stream)
+{
+    assert(dir_stream != NULL);
+
+    return *dir_stream != NULL;
+}
+
+bool
+os_is_handle_valid(os_file_handle *handle)
+{
+    assert(handle != NULL);
+
+    return *handle > -1;
+}
+
+char *
+os_realpath(const char *path, char *resolved_path)
+{
+    return realpath(path, resolved_path);
+}

+ 4 - 0
core/shared/platform/cosmopolitan/platform_internal.h

@@ -63,6 +63,10 @@ typedef sem_t korp_sem;
 
 #define bh_socket_t int
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WASM_DISABLE_WRITE_GS_BASE == 0
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
 #define os_writegsbase(base_addr)                                 \

+ 4 - 0
core/shared/platform/darwin/platform_internal.h

@@ -109,6 +109,10 @@ os_sigreturn();
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 0
core/shared/platform/esp-idf/platform_internal.h

@@ -109,6 +109,10 @@ typedef unsigned int korp_sem;
 #define DT_LNK DTYPE_LINK
 #define DT_SOCK DTYPE_SOCK
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 0
core/shared/platform/freebsd/platform_internal.h

@@ -66,6 +66,10 @@ typedef sem_t korp_sem;
 
 #define bh_socket_t int
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WASM_DISABLE_HW_BOUND_CHECK == 0
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)            \
     || defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \

+ 1 - 0
core/shared/platform/include/platform_api_extension.h

@@ -7,6 +7,7 @@
 #define PLATFORM_API_EXTENSION_H
 
 #include "platform_common.h"
+#include "platform_wasi.h"
 /**
  * The related data structures should be defined
  * in platform_internal.h

+ 1100 - 0
core/shared/platform/include/platform_wasi.h

@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2023 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+/*
+ * This file declares the WASI interface as well as optional filesystem
+ * functions which platforms would need to implement to support WASI libc
+ * filesystem operations. The definitions of types, macros and structures in
+ * this file should be consistent with those in wasi-libc:
+ * https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/wasi/api.h
+ */
+
+#ifndef _PLATFORM_WASI_H
+#define _PLATFORM_WASI_H
+
+#include "platform_common.h"
+#include "platform_internal.h"
+
+/* clang-format off */
+
+#ifdef __cplusplus
+#ifndef _Static_assert
+#define _Static_assert static_assert
+#endif /* _Static_assert */
+
+#ifndef _Alignof
+#define _Alignof alignof
+#endif /* _Alignof */
+
+extern "C" {
+#endif
+
+/* There is no need to check the WASI layout if we're using uvwasi or libc-wasi
+ * is not enabled at all. */
+#if WASM_ENABLE_UVWASI != 0 || WASM_ENABLE_LIBC_WASI == 0
+#define assert_wasi_layout(expr, message) /* nothing */
+#else
+#define assert_wasi_layout(expr, message) _Static_assert(expr, message)
+#endif
+
+assert_wasi_layout(_Alignof(int8_t) == 1, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint8_t) == 1, "non-wasi data layout");
+assert_wasi_layout(_Alignof(int16_t) == 2, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint16_t) == 2, "non-wasi data layout");
+assert_wasi_layout(_Alignof(int32_t) == 4, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint32_t) == 4, "non-wasi data layout");
+#if 0
+assert_wasi_layout(_Alignof(int64_t) == 8, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint64_t) == 8, "non-wasi data layout");
+#endif
+
+typedef uint32_t __wasi_size_t;
+assert_wasi_layout(_Alignof(__wasi_size_t) == 4, "non-wasi data layout");
+
+typedef uint8_t __wasi_advice_t;
+#define __WASI_ADVICE_NORMAL     (0)
+#define __WASI_ADVICE_SEQUENTIAL (1)
+#define __WASI_ADVICE_RANDOM     (2)
+#define __WASI_ADVICE_WILLNEED   (3)
+#define __WASI_ADVICE_DONTNEED   (4)
+#define __WASI_ADVICE_NOREUSE    (5)
+
+typedef uint32_t __wasi_clockid_t;
+#define __WASI_CLOCK_REALTIME           (0)
+#define __WASI_CLOCK_MONOTONIC          (1)
+#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2)
+#define __WASI_CLOCK_THREAD_CPUTIME_ID  (3)
+
+typedef uint64_t __wasi_device_t;
+
+typedef uint64_t __wasi_dircookie_t;
+#define __WASI_DIRCOOKIE_START (0)
+
+typedef uint32_t __wasi_dirnamlen_t;
+
+typedef uint16_t __wasi_errno_t;
+#define __WASI_ESUCCESS        (0)
+#define __WASI_E2BIG           (1)
+#define __WASI_EACCES          (2)
+#define __WASI_EADDRINUSE      (3)
+#define __WASI_EADDRNOTAVAIL   (4)
+#define __WASI_EAFNOSUPPORT    (5)
+#define __WASI_EAGAIN          (6)
+#define __WASI_EALREADY        (7)
+#define __WASI_EBADF           (8)
+#define __WASI_EBADMSG         (9)
+#define __WASI_EBUSY           (10)
+#define __WASI_ECANCELED       (11)
+#define __WASI_ECHILD          (12)
+#define __WASI_ECONNABORTED    (13)
+#define __WASI_ECONNREFUSED    (14)
+#define __WASI_ECONNRESET      (15)
+#define __WASI_EDEADLK         (16)
+#define __WASI_EDESTADDRREQ    (17)
+#define __WASI_EDOM            (18)
+#define __WASI_EDQUOT          (19)
+#define __WASI_EEXIST          (20)
+#define __WASI_EFAULT          (21)
+#define __WASI_EFBIG           (22)
+#define __WASI_EHOSTUNREACH    (23)
+#define __WASI_EIDRM           (24)
+#define __WASI_EILSEQ          (25)
+#define __WASI_EINPROGRESS     (26)
+#define __WASI_EINTR           (27)
+#define __WASI_EINVAL          (28)
+#define __WASI_EIO             (29)
+#define __WASI_EISCONN         (30)
+#define __WASI_EISDIR          (31)
+#define __WASI_ELOOP           (32)
+#define __WASI_EMFILE          (33)
+#define __WASI_EMLINK          (34)
+#define __WASI_EMSGSIZE        (35)
+#define __WASI_EMULTIHOP       (36)
+#define __WASI_ENAMETOOLONG    (37)
+#define __WASI_ENETDOWN        (38)
+#define __WASI_ENETRESET       (39)
+#define __WASI_ENETUNREACH     (40)
+#define __WASI_ENFILE          (41)
+#define __WASI_ENOBUFS         (42)
+#define __WASI_ENODEV          (43)
+#define __WASI_ENOENT          (44)
+#define __WASI_ENOEXEC         (45)
+#define __WASI_ENOLCK          (46)
+#define __WASI_ENOLINK         (47)
+#define __WASI_ENOMEM          (48)
+#define __WASI_ENOMSG          (49)
+#define __WASI_ENOPROTOOPT     (50)
+#define __WASI_ENOSPC          (51)
+#define __WASI_ENOSYS          (52)
+#define __WASI_ENOTCONN        (53)
+#define __WASI_ENOTDIR         (54)
+#define __WASI_ENOTEMPTY       (55)
+#define __WASI_ENOTRECOVERABLE (56)
+#define __WASI_ENOTSOCK        (57)
+#define __WASI_ENOTSUP         (58)
+#define __WASI_ENOTTY          (59)
+#define __WASI_ENXIO           (60)
+#define __WASI_EOVERFLOW       (61)
+#define __WASI_EOWNERDEAD      (62)
+#define __WASI_EPERM           (63)
+#define __WASI_EPIPE           (64)
+#define __WASI_EPROTO          (65)
+#define __WASI_EPROTONOSUPPORT (66)
+#define __WASI_EPROTOTYPE      (67)
+#define __WASI_ERANGE          (68)
+#define __WASI_EROFS           (69)
+#define __WASI_ESPIPE          (70)
+#define __WASI_ESRCH           (71)
+#define __WASI_ESTALE          (72)
+#define __WASI_ETIMEDOUT       (73)
+#define __WASI_ETXTBSY         (74)
+#define __WASI_EXDEV           (75)
+#define __WASI_ENOTCAPABLE     (76)
+
+#if defined(_MSC_VER)
+#define ALIGNED_(x) __declspec(align(x))
+#define WARN_UNUSED _Check_return_
+#elif defined(__GNUC__)
+#define ALIGNED_(x) __attribute__ ((aligned(x)))
+#define WARN_UNUSED __attribute__((__warn_unused_result__))
+#endif
+
+#define ALIGNED_TYPE(t,x) typedef t ALIGNED_(x)
+
+typedef uint16_t __wasi_eventrwflags_t;
+#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001)
+
+typedef uint8_t __wasi_eventtype_t;
+#define __WASI_EVENTTYPE_CLOCK          (0)
+#define __WASI_EVENTTYPE_FD_READ        (1)
+#define __WASI_EVENTTYPE_FD_WRITE       (2)
+
+typedef uint32_t __wasi_exitcode_t;
+
+typedef uint32_t __wasi_fd_t;
+
+typedef uint16_t __wasi_fdflags_t;
+#define __WASI_FDFLAG_APPEND   (0x0001)
+#define __WASI_FDFLAG_DSYNC    (0x0002)
+#define __WASI_FDFLAG_NONBLOCK (0x0004)
+#define __WASI_FDFLAG_RSYNC    (0x0008)
+#define __WASI_FDFLAG_SYNC     (0x0010)
+
+typedef int64_t __wasi_filedelta_t;
+
+typedef uint64_t __wasi_filesize_t;
+
+typedef uint8_t __wasi_filetype_t;
+#define __WASI_FILETYPE_UNKNOWN          (0)
+#define __WASI_FILETYPE_BLOCK_DEVICE     (1)
+#define __WASI_FILETYPE_CHARACTER_DEVICE (2)
+#define __WASI_FILETYPE_DIRECTORY        (3)
+#define __WASI_FILETYPE_REGULAR_FILE     (4)
+#define __WASI_FILETYPE_SOCKET_DGRAM     (5)
+#define __WASI_FILETYPE_SOCKET_STREAM    (6)
+#define __WASI_FILETYPE_SYMBOLIC_LINK    (7)
+
+typedef uint16_t __wasi_fstflags_t;
+#define __WASI_FILESTAT_SET_ATIM     (0x0001)
+#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002)
+#define __WASI_FILESTAT_SET_MTIM     (0x0004)
+#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008)
+
+typedef uint64_t __wasi_inode_t;
+
+ALIGNED_TYPE(uint64_t, 8) __wasi_linkcount_t;
+
+typedef uint32_t __wasi_lookupflags_t;
+#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001)
+
+typedef uint16_t __wasi_oflags_t;
+#define __WASI_O_CREAT     (0x0001)
+#define __WASI_O_DIRECTORY (0x0002)
+#define __WASI_O_EXCL      (0x0004)
+#define __WASI_O_TRUNC     (0x0008)
+
+typedef uint16_t __wasi_riflags_t;
+#define __WASI_SOCK_RECV_PEEK    (0x0001)
+#define __WASI_SOCK_RECV_WAITALL (0x0002)
+
+typedef uint64_t __wasi_rights_t;
+
+/**
+ * Observe that WASI defines rights in the plural form
+ * TODO: refactor to use RIGHTS instead of RIGHT
+ */
+#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0))
+#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1))
+#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2))
+#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3))
+#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4))
+#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5))
+#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6))
+#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7))
+#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8))
+#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9))
+#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10))
+#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11))
+#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12))
+#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13))
+#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14))
+#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15))
+#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16))
+#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17))
+#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20))
+#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21))
+#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22))
+#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23))
+#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24))
+#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25))
+#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26))
+#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27))
+#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28))
+#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29))
+#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30))
+#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31))
+#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32))
+#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33))
+#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34))
+#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35))
+#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36))
+#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37))
+
+typedef uint16_t __wasi_roflags_t;
+#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001)
+
+typedef uint8_t __wasi_sdflags_t;
+#define __WASI_SHUT_RD (0x01)
+#define __WASI_SHUT_WR (0x02)
+
+typedef uint16_t __wasi_siflags_t;
+
+typedef uint8_t __wasi_signal_t;
+
+typedef uint16_t __wasi_subclockflags_t;
+#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001)
+
+typedef uint64_t __wasi_timestamp_t;
+
+typedef uint64_t __wasi_userdata_t;
+
+typedef uint8_t __wasi_whence_t;
+#define __WASI_WHENCE_SET (0)
+#define __WASI_WHENCE_CUR (1)
+#define __WASI_WHENCE_END (2)
+
+typedef uint8_t __wasi_preopentype_t;
+#define __WASI_PREOPENTYPE_DIR              (0)
+
+struct fd_table;
+struct fd_prestats;
+struct argv_environ_values;
+struct addr_pool;
+
+typedef struct ALIGNED_(8) __wasi_dirent_t {
+    __wasi_dircookie_t d_next;
+    __wasi_inode_t d_ino;
+    __wasi_dirnamlen_t d_namlen;
+    __wasi_filetype_t d_type;
+} __wasi_dirent_t;
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_event_t {
+    __wasi_userdata_t userdata;
+    __wasi_errno_t error;
+    __wasi_eventtype_t type;
+    uint8_t __paddings[5];
+    union __wasi_event_u {
+        struct __wasi_event_u_fd_readwrite_t {
+            __wasi_filesize_t nbytes;
+            __wasi_eventrwflags_t flags;
+            uint8_t __paddings[6];
+        } fd_readwrite;
+    } u;
+} __wasi_event_t;
+assert_wasi_layout(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_event_t) == 32, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_event_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_prestat_t {
+    __wasi_preopentype_t pr_type;
+    union __wasi_prestat_u {
+        struct __wasi_prestat_u_dir_t {
+            size_t pr_name_len;
+        } dir;
+    } u;
+} __wasi_prestat_t;
+assert_wasi_layout(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_prestat_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_prestat_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_fdstat_t {
+    __wasi_filetype_t fs_filetype;
+    __wasi_fdflags_t fs_flags;
+    uint8_t __paddings[4];
+    __wasi_rights_t fs_rights_base;
+    __wasi_rights_t fs_rights_inheriting;
+} __wasi_fdstat_t;
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16,
+    "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_filestat_t {
+    __wasi_device_t st_dev;
+    __wasi_inode_t st_ino;
+    __wasi_filetype_t st_filetype;
+    __wasi_linkcount_t st_nlink;
+    __wasi_filesize_t st_size;
+    __wasi_timestamp_t st_atim;
+    __wasi_timestamp_t st_mtim;
+    __wasi_timestamp_t st_ctim;
+} __wasi_filestat_t;
+assert_wasi_layout(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_ciovec_t {
+    const void *buf;
+    size_t buf_len;
+} __wasi_ciovec_t;
+assert_wasi_layout(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_iovec_t {
+    void *buf;
+    size_t buf_len;
+} __wasi_iovec_t;
+assert_wasi_layout(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_iovec_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_iovec_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout");
+
+/**
+ * The contents of a `subscription` when type is `eventtype::clock`.
+ */
+typedef struct ALIGNED_(8) __wasi_subscription_clock_t {
+    /**
+     * The clock against which to compare the timestamp.
+     */
+    __wasi_clockid_t clock_id;
+
+    uint8_t __paddings1[4];
+
+    /**
+     * The absolute or relative timestamp.
+     */
+    __wasi_timestamp_t timeout;
+
+    /**
+     * The amount of time that the implementation may wait additionally
+     * to coalesce with other events.
+     */
+    __wasi_timestamp_t precision;
+
+    /**
+     * Flags specifying whether the timeout is absolute or relative
+     */
+    __wasi_subclockflags_t flags;
+
+    uint8_t __paddings2[4];
+
+} __wasi_subscription_clock_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset");
+
+/**
+ * The contents of a `subscription` when type is type is
+ * `eventtype::fd_read` or `eventtype::fd_write`.
+ */
+typedef struct __wasi_subscription_fd_readwrite_t {
+    /**
+     * The file descriptor on which to wait for it to become ready for reading or writing.
+     */
+    __wasi_fd_t fd;
+
+} __wasi_subscription_fd_readwrite_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset");
+
+/**
+ * The contents of a `subscription`.
+ */
+typedef union __wasi_subscription_u_u_t {
+    __wasi_subscription_clock_t clock;
+    __wasi_subscription_fd_readwrite_t fd_readwrite;
+} __wasi_subscription_u_u_t ;
+
+typedef struct ALIGNED_(8) __wasi_subscription_u_t {
+    __wasi_eventtype_t type;
+    __wasi_subscription_u_u_t u;
+} __wasi_subscription_u_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset");
+assert_wasi_layout(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size");
+assert_wasi_layout(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align");
+
+/**
+ * Subscription to an event.
+ */
+typedef struct __wasi_subscription_t {
+    /**
+     * User-provided value that is attached to the subscription in the
+     * implementation and returned through `event::userdata`.
+     */
+    __wasi_userdata_t userdata;
+
+    /**
+     * The type of the event to which to subscribe, and its contents
+     */
+    __wasi_subscription_u_t u;
+
+} __wasi_subscription_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_t) == 48, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset");
+
+/* keep syncing with wasi_socket_ext.h */
+typedef enum {
+    /* Used only for sock_addr_resolve hints */
+    SOCKET_ANY = -1,
+    SOCKET_DGRAM = 0,
+    SOCKET_STREAM,
+} __wasi_sock_type_t;
+
+typedef uint16_t __wasi_ip_port_t;
+
+typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
+
+/* n0.n1.n2.n3 */
+typedef struct __wasi_addr_ip4_t {
+    uint8_t n0;
+    uint8_t n1;
+    uint8_t n2;
+    uint8_t n3;
+} __wasi_addr_ip4_t;
+
+typedef struct __wasi_addr_ip4_port_t {
+    __wasi_addr_ip4_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip4_port_t;
+
+typedef struct __wasi_addr_ip6_t {
+    uint16_t n0;
+    uint16_t n1;
+    uint16_t n2;
+    uint16_t n3;
+    uint16_t h0;
+    uint16_t h1;
+    uint16_t h2;
+    uint16_t h3;
+} __wasi_addr_ip6_t;
+
+typedef struct __wasi_addr_ip6_port_t {
+    __wasi_addr_ip6_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip6_port_t;
+
+typedef struct __wasi_addr_ip_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_t ip4;
+        __wasi_addr_ip6_t ip6;
+    } addr;
+} __wasi_addr_ip_t;
+
+typedef struct __wasi_addr_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_port_t ip4;
+        __wasi_addr_ip6_port_t ip6;
+    } addr;
+} __wasi_addr_t;
+
+typedef enum { INET4 = 0, INET6, INET_UNSPEC } __wasi_address_family_t;
+
+typedef struct __wasi_addr_info_t {
+    __wasi_addr_t addr;
+    __wasi_sock_type_t type;
+} __wasi_addr_info_t;
+
+typedef struct __wasi_addr_info_hints_t {
+   __wasi_sock_type_t type;
+   __wasi_address_family_t family;
+   // this is to workaround lack of optional parameters
+   uint8_t hints_enabled;
+} __wasi_addr_info_hints_t;
+
+#undef assert_wasi_layout
+
+/* clang-format on */
+
+/****************************************************
+ *                                                  *
+ *                Filesystem interface              *
+ *                                                  *
+ ****************************************************/
+
+/**
+ * NOTES:
+ * Fileystem APIs are required for WASI libc support. If you don't need to
+ * support WASI libc, there is no need to implement these APIs. With a
+ * few exceptions, each filesystem function has been named after the equivalent
+ * POSIX filesystem function with an os_ prefix.
+ *
+ * Filesystem types
+ *
+ * os_raw_file_handle: the underlying OS file handle type e.g. int on POSIX
+ * systems and HANDLE on Windows. This type exists to allow embedders to provide
+ * custom file handles for stdout/stdin/stderr.
+ *
+ * os_file_handle: the file handle type used in the WASI libc fd
+ * table. Filesystem implementations can use it as a means to store any
+ * necessary platform-specific information which may not be directly available
+ * through the raw OS file handle. Similiar to POSIX file descriptors, file
+ * handles may also refer to sockets, directories, symbolic links or character
+ * devices and any of the filesystem operations which make sense for these
+ * resource types should be supported as far as possible.
+ *
+ * os_dir_stream: a directory stream type in which fileystem implementations
+ * can store any necessary state to iterate over the entries in a directory.
+ */
+
+/**
+ * Obtain information about an open file associated with the given handle.
+ *
+ * @param handle the handle for which to obtain file information
+ * @param buf a buffer in which to store the information
+ */
+__wasi_errno_t
+os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf);
+
+/**
+ * Obtain information about an open file or directory.
+ * @param handle the directory handle from which to resolve the file/directory
+ * path
+ * @param path the relative path of the file or directory for which to obtain
+ * information
+ * @param buf a buffer in which to store the information
+ * @param follow_symlink whether to follow symlinks when resolving the path
+ */
+__wasi_errno_t
+os_fstatat(os_file_handle handle, const char *path,
+           struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Obtain the file status flags for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_GETFL command.
+ *
+ * @param handle the handle for which to obtain the file status flags
+ * @param flags a pointer in which to store the output
+ */
+__wasi_errno_t
+os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags);
+
+/**
+ * Set the file status flags for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_SETFL command.
+ *
+ * @param handle the handle for which to set the file status flags
+ * @param flags the flags to set
+ */
+__wasi_errno_t
+os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags);
+
+/**
+ * Synchronize the data of a file to disk.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_fdatasync(os_file_handle handle);
+
+/**
+ * Synchronize the data and metadata of a file to disk.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_fsync(os_file_handle handle);
+
+/**
+ * Open a preopen directory. The path provided must refer to a directory and the
+ * returned handle will allow only readonly operations.
+ *
+ * @param path the path of the preopen directory to open
+ * @param out a pointer in which to store the newly opened handle
+ */
+__wasi_errno_t
+os_open_preopendir(const char *path, os_file_handle *out);
+
+typedef uint8 wasi_libc_file_access_mode;
+#define WASI_LIBC_ACCESS_MODE_READ_ONLY 0
+#define WASI_LIBC_ACCESS_MODE_WRITE_ONLY 1
+#define WASI_LIBC_ACCESS_MODE_READ_WRITE 2
+
+/**
+ * Open a file or directory at the given path.
+ *
+ * @param handle a handle to the directory in which to open the new file or
+ * directory
+ * @param path the relative path of the file or directory to open
+ * @param oflags the flags to determine how the file or directory is opened
+ * @param fd_flags the flags to set on the returned handle
+ * @param lookup_flags whether to follow symlinks when resolving the path
+ * @param access_mode whether the file is opened as read only, write only or
+ * both
+ * @param out a pointer in which to store the newly opened handle
+ */
+__wasi_errno_t
+os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
+          __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+          wasi_libc_file_access_mode access_mode, os_file_handle *out);
+
+/**
+ * Obtain the file access mode for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_GETFL command combined with the
+ * O_ACCMODE mask.
+ *
+ * @param handle the handle for which to obtain the access mode
+ * @param access_mode a pointer in which to store the access mode
+ */
+__wasi_errno_t
+os_file_get_access_mode(os_file_handle handle,
+                        wasi_libc_file_access_mode *access_mode);
+
+/**
+ * Close the provided handle. If is_stdio is true, the raw file handle
+ * associated with the given file handle will not be closed.
+ *
+ * @param handle the handle to close
+ * @param is_stdio whether the provided handle refers to a stdio device
+ */
+__wasi_errno_t
+os_close(os_file_handle handle, bool is_stdio);
+
+/**
+ * Read data from the provided handle at the given offset into multiple buffers.
+ *
+ * @param handle the handle to read from
+ * @param iov the buffers to read into
+ * @param iovcnt the number of buffers to read into
+ * @param offset the offset to read from
+ * @param nread a pointer in which to store the number of bytes read
+ */
+__wasi_errno_t
+os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+          __wasi_filesize_t offset, size_t *nread);
+
+/**
+ * Write data from multiple buffers at the given offset to the provided handle.
+ *
+ * @param handle the handle to write to
+ * @param iov the buffers to write from
+ * @param iovcnt the number of buffers to write from
+ * @param offset the offset to write from
+ * @param nwritten a pointer in which to store the number of bytes written
+ */
+__wasi_errno_t
+os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+           __wasi_filesize_t offset, size_t *nwritten);
+
+/**
+ * Read data from the provided handle into multiple buffers.
+ *
+ * @param handle the handle to read from
+ * @param iov the buffers to read into
+ * @param iovcnt the number of buffers to read into
+ * @param nread a pointer in which to store the number of bytes read
+ */
+__wasi_errno_t
+os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+         size_t *nread);
+
+/**
+ * Write data from multiple buffers to the provided handle.
+ *
+ * @param handle the handle to write to
+ * @param iov the buffers to write from
+ * @param iovcnt the number of buffers to write from
+ * @param nwritten a pointer in which to store the number of bytes written
+ */
+__wasi_errno_t
+os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+          size_t *nwritten);
+
+/**
+ * Allocate storage space for the file associated with the provided handle. This
+ * is similar to the POSIX function posix_fallocate.
+ *
+ * @param handle the handle to allocate space for
+ * @param offset the offset to allocate space at
+ * @param length the amount of space to allocate
+ */
+__wasi_errno_t
+os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
+             __wasi_filesize_t length);
+
+/**
+ * Adjust the size of an open file.
+ *
+ * @param handle the associated file handle for which to adjust the size
+ * @param size the new size of the file
+ */
+__wasi_errno_t
+os_ftruncate(os_file_handle handle, __wasi_filesize_t size);
+
+/**
+ * Set file access and modification times on an open file or directory.
+ *
+ * @param handle the associated file handle for which to adjust the
+ * access/modification times
+ * @param access_time the timestamp for the new access time
+ * @param modification_time the timestamp for the new modification time
+ * @param fstflags a bitmask to indicate which timestamps to adjust
+ */
+__wasi_errno_t
+os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
+            __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags);
+
+/**
+ * Set file access and modification times on an open file or directory.
+ *
+ * @param handle the directory handle from which to resolve the path
+ * @param path the relative path of the file or directory for which to adjust
+ * the access/modification times
+ * @param access_time the timestamp for the new access time
+ * @param modification_time the timestamp for the new modification time
+ * @param fstflags a bitmask to indicate which timestamps to adjust
+ * @param lookup_flags whether to follow symlinks when resolving the path
+ */
+__wasi_errno_t
+os_utimensat(os_file_handle handle, const char *path,
+             __wasi_timestamp_t access_time,
+             __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
+             __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Read the contents of a symbolic link relative to the provided directory
+ * handle.
+ *
+ * @param handle the directory handle
+ * @param path the relative path of the symbolic link from which to read
+ * @param buf the buffer to read the link contents into
+ * @param bufsize the size of the provided buffer
+ * @param nread a pointer in which to store the number of bytes read into the
+ * buffer
+ */
+__wasi_errno_t
+os_readlinkat(os_file_handle handle, const char *path, char *buf,
+              size_t bufsize, size_t *nread);
+
+/**
+ * Create a link from one path to another path.
+ *
+ * @param from_handle the directory handle from which to resolve the origin path
+ * @param from_path the origin path to link from
+ * @param to_handle the directory handle from which to resolve the destination
+ * path
+ * @param to_path the destination path at which to create the link
+ * @param lookup_flags whether to follow symlinks when resolving the origin path
+ */
+__wasi_errno_t
+os_linkat(os_file_handle from_handle, const char *from_path,
+          os_file_handle to_handle, const char *to_path,
+          __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Create a symbolic link from one path to another path.
+ *
+ * @param old_path the symbolic link contents
+ * @param handle the directory handle from which to resolve the destination path
+ * @param new_path the destination path at which to create the symbolic link
+ */
+__wasi_errno_t
+os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path);
+
+/**
+ * Create a directory relative to the provided directory handle.
+ *
+ * @param handle the directory handle
+ * @param path the relative path of the directory to create
+ */
+__wasi_errno_t
+os_mkdirat(os_file_handle handle, const char *path);
+
+/**
+ * Rename a file or directory.
+ *
+ * @param old_handle the directory handle from which to resolve the old path
+ * @param old_path the source path to rename
+ * @param new_handle the directory handle from which to resolve the destination
+ * path
+ * @param new_path the destination path to which to rename the file or directory
+ */
+__wasi_errno_t
+os_renameat(os_file_handle old_handle, const char *old_path,
+            os_file_handle new_handle, const char *new_path);
+
+/**
+ * Unlink a file or directory.
+ *
+ * @param handle the directory handle from which to resolve the path
+ * @param path the relative path of the file or directory to unlink
+ * @param is_dir whether the provided handle refers to a directory or file
+ */
+__wasi_errno_t
+os_unlinkat(os_file_handle handle, const char *path, bool is_dir);
+
+/**
+ * Move the read/write offset of an open file.
+ *
+ * @param handle the associated file handle for which to adjust the offset
+ * @param offset the number of bytes to adjust the offset by
+ * @param whence the position whence to adjust the offset
+ * @param new_offset a pointer in which to store the new offset
+ */
+__wasi_errno_t
+os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
+         __wasi_whence_t whence, __wasi_filesize_t *new_offset);
+
+/**
+ * Provide file advisory information for the given handle. This is similar to
+ * the POSIX function posix_fadvise.
+ *
+ * @param handle the associated file handle for which to provide advisory
+ * information
+ * @param offset the offset within the file to which the advisory
+ * information applies
+ * @param length the length of the region for which the advisory information
+ * applies
+ * @param advice the advice to provide
+ */
+__wasi_errno_t
+os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
+           __wasi_filesize_t length, __wasi_advice_t advice);
+
+/**
+ * Determine if the given handle refers to a terminal device. __WASI_ESUCCESS
+ * will be returned if the handle is associated with a terminal device,
+ * otherwise an appropriate error code will be returned.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_isatty(os_file_handle handle);
+
+/**
+ * Converts a raw file handle to STDIN to a corresponding file handle to STDIN.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDIN will be used.
+ *
+ * @param raw_stdin a raw file handle to STDIN
+ *
+ * @return a handle to STDIN
+ */
+os_file_handle
+os_convert_stdin_handle(os_raw_file_handle raw_stdin);
+
+/**
+ * Converts a raw file handle to STDOUT to a correponding file handle to STDOUT.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDOUT will be used.
+ *
+ * @param raw_stdout a raw file handle to STDOUT
+ *
+ * @return a handle to STDOUT
+ */
+os_file_handle
+os_convert_stdout_handle(os_raw_file_handle raw_stdout);
+
+/**
+ * Converts a raw file handle to STDERR to a correponding file handle to STDERR.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDERR will be used.
+ *
+ * @param raw_stderr a raw file handle to STDERR
+ *
+ * @return a handle to STDERR
+ */
+os_file_handle
+os_convert_stderr_handle(os_raw_file_handle raw_stderr);
+
+/**
+ * Open a directory stream for the provided directory handle. The returned
+ * directory stream will be positioned at the first entry in the directory.
+ *
+ * @param handle the directory handle
+ * @param dir_stream a pointer in which to store the new directory stream
+ */
+__wasi_errno_t
+os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream);
+
+/**
+ * Reset the position of a directory stream to the beginning of the directory.
+ *
+ * @param dir_stream the directory stream for which to reset the position
+ */
+__wasi_errno_t
+os_rewinddir(os_dir_stream dir_stream);
+
+/**
+ * Set the position of the given directory stream.
+ *
+ * @param dir_stream the directory stream for which to set the position
+ * @param position the position to set
+ */
+__wasi_errno_t
+os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position);
+
+/**
+ * Read a directory entry from the given directory stream. The directory name
+ * will be NULL if the end of the directory is reached or an error is
+ * encountered.
+ *
+ * @param dir_stream the directory stream from which to read the entry
+ * @param entry a pointer in which to store the directory entry
+ * @param d_name a pointer in which to store the directory entry name
+ */
+__wasi_errno_t
+os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
+           const char **d_name);
+
+/**
+ * Close the given directory stream. The handle associated with the directory
+ * stream will also be closed.
+ *
+ * @param dir_stream the directory stream to close
+ */
+__wasi_errno_t
+os_closedir(os_dir_stream dir_stream);
+
+/**
+ * Returns an invalid directory stream that is guaranteed to cause failure when
+ * called with any directory filesystem operation.
+ *
+ * @return the invalid directory stream
+ */
+os_dir_stream
+os_get_invalid_dir_stream();
+
+/**
+ * Checks whether the given directory stream is valid. An invalid directory
+ * stream is guaranteed to cause failure when called with any directory
+ * filesystem operation.
+ *
+ * @param dir_stream a pointer to a directory stream
+ */
+bool
+os_is_dir_stream_valid(os_dir_stream *dir_stream);
+
+/**
+ * Returns an invalid handle that is guaranteed to cause failure when
+ * called with any filesystem operation.
+ *
+ * @return the invalid handle
+ */
+os_file_handle
+os_get_invalid_handle();
+
+/**
+ * Checks whether the given file handle is valid. An invalid handle is
+ * guaranteed to cause failure when called with any filesystem operation.
+ *
+ * @param handle a pointer to a file handle
+ */
+bool
+os_is_handle_valid(os_file_handle *handle);
+
+/**
+ * Resolve a pathname. The generated pathname will be stored as a
+ * null-terminated string, with a maximum length of PATH_MAX bytes.
+ *
+ * @param path the path to resolve
+ * @param resolved_path the buffer to store the resolved path in
+ *
+ * @return the resolved path if success, NULL otherwise
+ */
+char *
+os_realpath(const char *path, char *resolved_path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _PLATFORM_WASI_H */

+ 4 - 0
core/shared/platform/linux-sgx/platform_internal.h

@@ -69,6 +69,10 @@ strcpy(char *dest, const char *src);
 #define os_memory_order_seq_cst __ATOMIC_SEQ_CST
 #define os_atomic_thread_fence __atomic_thread_fence
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 1
core/shared/platform/linux-sgx/sgx_ipfs.h

@@ -7,7 +7,6 @@
 #define _LIBC_WASI_SGX_PFS_H
 
 #include "bh_hashmap.h"
-#include "wasmtime_ssp.h"
 
 #ifdef __cplusplus
 extern "C" {

+ 8 - 4
core/shared/platform/linux-sgx/shared_platform.cmake

@@ -20,16 +20,20 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1)
                        ${SGX_SDK_DIR}/include/libcxx)
 endif ()
 
-if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
-  add_definitions(-DSGX_DISABLE_WASI)
-endif ()
-
 if (NOT WAMR_BUILD_THREAD_MGR EQUAL 1)
   add_definitions(-DSGX_DISABLE_PTHREAD)
 endif ()
 
 file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c)
 
+if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
+  add_definitions(-DSGX_DISABLE_WASI)
+else()
+  list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c)
+  include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
+  set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif()
+
 file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c)
 
 set (PLATFORM_SHARED_SOURCE ${source_all})

+ 4 - 0
core/shared/platform/linux/platform_internal.h

@@ -122,6 +122,10 @@ os_sigreturn();
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 0
core/shared/platform/nuttx/platform_internal.h

@@ -130,6 +130,10 @@ fdopendir(int fd);
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #ifdef __cplusplus
 }
 #endif

+ 6 - 0
core/shared/platform/nuttx/shared_platform.cmake

@@ -10,5 +10,11 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
 
 file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
 
+if (WAMR_BUILD_LIBC_WASI EQUAL 1)
+  list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c)
+  include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
+  set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif ()
+
 set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
 

+ 4 - 0
core/shared/platform/riot/platform_internal.h

@@ -52,6 +52,10 @@ typedef struct korp_cond {
 #define os_printf printf
 #define os_vprintf vprintf
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WA_MATH
 /* clang-format off */
 /* math functions which are not provided by os*/

+ 4 - 0
core/shared/platform/rt-thread/platform_internal.h

@@ -45,4 +45,8 @@ typedef rt_int16_t int16_t;
 typedef rt_uint64_t uint64_t;
 typedef rt_int64_t int64_t;
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #endif /* RTTHREAD_PLATFORM_INTERNAL_H */

+ 4 - 0
core/shared/platform/vxworks/platform_internal.h

@@ -61,6 +61,10 @@ typedef sem_t korp_sem;
 
 #define os_thread_local_attribute __thread
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WASM_DISABLE_HW_BOUND_CHECK == 0
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
     || defined(BUILD_TARGET_AARCH64)

+ 8 - 0
core/shared/platform/windows/platform_internal.h

@@ -137,6 +137,14 @@ bh_atomic_thread_fence(int mem_order);
 
 #define os_atomic_thread_fence bh_atomic_thread_fence
 
+typedef HANDLE os_file_handle;
+typedef void *os_dir_stream;
+#if WASM_ENABLE_UVWASI != 1
+typedef HANDLE os_raw_file_handle;
+#else
+typedef uint32_t os_raw_file_handle;
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 7 - 0
core/shared/platform/windows/shared_platform.cmake

@@ -13,6 +13,13 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
 file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c
 			      ${PLATFORM_SHARED_DIR}/*.cpp)
 
+if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
+    list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/win_file.c)
+else()
+    include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
+    set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif()
+
 set (PLATFORM_SHARED_SOURCE ${source_all})
 
 file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h)

+ 267 - 0
core/shared/platform/windows/win_file.c

@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_extension.h"
+#include "platform_internal.h"
+
+__wasi_errno_t
+os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_fstatat(os_file_handle handle, const char *path,
+           struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_file_get_access_mode(os_file_handle handle,
+                        wasi_libc_file_access_mode *access_mode)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_fdatasync(os_file_handle handle)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_fsync(os_file_handle handle)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_open_preopendir(const char *path, os_file_handle *out)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
+          __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags,
+          wasi_libc_file_access_mode read_write_mode, os_file_handle *out)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_close(os_file_handle handle, bool is_stdio)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+          __wasi_filesize_t offset, size_t *nread)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+           __wasi_filesize_t offset, size_t *nwritten)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+         size_t *nread)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+          size_t *nwritten)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
+             __wasi_filesize_t length)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
+            __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_utimensat(os_file_handle handle, const char *path,
+             __wasi_timestamp_t access_time,
+             __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
+             __wasi_lookupflags_t lookup_flags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_readlinkat(os_file_handle handle, const char *path, char *buf,
+              size_t bufsize, size_t *nread)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_linkat(os_file_handle from_handle, const char *from_path,
+          os_file_handle to_handle, const char *to_path,
+          __wasi_lookupflags_t lookup_flags)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_mkdirat(os_file_handle handle, const char *path)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_renameat(os_file_handle old_handle, const char *old_path,
+            os_file_handle new_handle, const char *new_path)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
+         __wasi_whence_t whence, __wasi_filesize_t *new_offset)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
+           __wasi_filesize_t length, __wasi_advice_t advice)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_isatty(os_file_handle handle)
+{
+    return __WASI_ENOSYS;
+}
+
+os_file_handle
+os_convert_stdin_handle(os_raw_file_handle raw_stdin)
+{
+    return INVALID_HANDLE_VALUE;
+}
+
+os_file_handle
+os_convert_stdout_handle(os_raw_file_handle raw_stdout)
+{
+    return INVALID_HANDLE_VALUE;
+}
+
+os_file_handle
+os_convert_stderr_handle(os_raw_file_handle raw_stderr)
+{
+    return INVALID_HANDLE_VALUE;
+}
+
+__wasi_errno_t
+os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_rewinddir(os_dir_stream dir_stream)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
+           const char **d_name)
+{
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+os_closedir(os_dir_stream dir_stream)
+{
+    return __WASI_ENOSYS;
+}
+
+os_dir_stream
+os_get_invalid_dir_stream()
+{
+    return NULL;
+}
+
+bool
+os_is_dir_stream_valid(os_dir_stream *dir_stream)
+{
+    return false;
+}
+
+os_file_handle
+os_get_invalid_handle()
+{
+    return INVALID_HANDLE_VALUE;
+}
+
+bool
+os_is_handle_valid(os_file_handle *handle)
+{
+    return false;
+}
+
+char *
+os_realpath(const char *path, char *resolved_path)
+{
+    return NULL;
+}

+ 4 - 0
core/shared/platform/zephyr/platform_internal.h

@@ -146,4 +146,8 @@ void
 set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func,
                         exec_mem_free_func_t free_func);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #endif

+ 4 - 0
product-mini/platforms/nuttx/wamr.mk

@@ -246,8 +246,11 @@ ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_WASI),y)
 CFLAGS += -DWASM_ENABLE_LIBC_WASI=1
 CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src
 CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/include
+CFLAGS += -I${SHARED_ROOT}/platform/common/libc-util
 CSRCS += blocking_op.c
 CSRCS += posix_socket.c
+CSRCS += posix_file.c
+CSRCS += libc_errno.c
 CSRCS += libc_wasi_wrapper.c
 VPATH += $(IWASM_ROOT)/libraries/libc-wasi
 CSRCS += posix.c
@@ -387,6 +390,7 @@ ASRCS += $(INVOKE_NATIVE)
 
 VPATH += $(SHARED_ROOT)/platform/nuttx
 VPATH += $(SHARED_ROOT)/platform/common/posix
+VPATH += $(SHARED_ROOT)/platform/common/libc-util
 VPATH += $(SHARED_ROOT)/mem-alloc
 VPATH += $(SHARED_ROOT)/mem-alloc/ems
 VPATH += $(SHARED_ROOT)/utils

+ 6 - 0
wamr-compiler/CMakeLists.txt

@@ -198,6 +198,12 @@ include_directories (${SHARED_DIR}/include
 
 enable_language (ASM)
 
+if (NOT MINGW AND NOT MSVC)
+    set(WAMR_BUILD_LIBC_WASI 1)
+else()
+    set(WAMR_BUILD_LIBC_UVWASI 1)
+endif()
+
 include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
 include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
 include (${SHARED_DIR}/utils/shared_utils.cmake)

Неке датотеке нису приказане због велике количине промена