mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
975 lines
34 KiB
C
975 lines
34 KiB
C
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "panic.h"
|
|
|
|
#define LOG_TRACE 0
|
|
|
|
enum wasi_errno {
|
|
wasi_errno_success = 0,
|
|
wasi_errno_2big = 1,
|
|
wasi_errno_acces = 2,
|
|
wasi_errno_addrinuse = 3,
|
|
wasi_errno_addrnotavail = 4,
|
|
wasi_errno_afnosupport = 5,
|
|
wasi_errno_again = 6,
|
|
wasi_errno_already = 7,
|
|
wasi_errno_badf = 8,
|
|
wasi_errno_badmsg = 9,
|
|
wasi_errno_busy = 10,
|
|
wasi_errno_canceled = 11,
|
|
wasi_errno_child = 12,
|
|
wasi_errno_connaborted = 13,
|
|
wasi_errno_connrefused = 14,
|
|
wasi_errno_connreset = 15,
|
|
wasi_errno_deadlk = 16,
|
|
wasi_errno_destaddrreq = 17,
|
|
wasi_errno_dom = 18,
|
|
wasi_errno_dquot = 19,
|
|
wasi_errno_exist = 20,
|
|
wasi_errno_fault = 21,
|
|
wasi_errno_fbig = 22,
|
|
wasi_errno_hostunreach = 23,
|
|
wasi_errno_idrm = 24,
|
|
wasi_errno_ilseq = 25,
|
|
wasi_errno_inprogress = 26,
|
|
wasi_errno_intr = 27,
|
|
wasi_errno_inval = 28,
|
|
wasi_errno_io = 29,
|
|
wasi_errno_isconn = 30,
|
|
wasi_errno_isdir = 31,
|
|
wasi_errno_loop = 32,
|
|
wasi_errno_mfile = 33,
|
|
wasi_errno_mlink = 34,
|
|
wasi_errno_msgsize = 35,
|
|
wasi_errno_multihop = 36,
|
|
wasi_errno_nametoolong = 37,
|
|
wasi_errno_netdown = 38,
|
|
wasi_errno_netreset = 39,
|
|
wasi_errno_netunreach = 40,
|
|
wasi_errno_nfile = 41,
|
|
wasi_errno_nobufs = 42,
|
|
wasi_errno_nodev = 43,
|
|
wasi_errno_noent = 44,
|
|
wasi_errno_noexec = 45,
|
|
wasi_errno_nolck = 46,
|
|
wasi_errno_nolink = 47,
|
|
wasi_errno_nomem = 48,
|
|
wasi_errno_nomsg = 49,
|
|
wasi_errno_noprotoopt = 50,
|
|
wasi_errno_nospc = 51,
|
|
wasi_errno_nosys = 52,
|
|
wasi_errno_notconn = 53,
|
|
wasi_errno_notdir = 54,
|
|
wasi_errno_notempty = 55,
|
|
wasi_errno_notrecoverable = 56,
|
|
wasi_errno_notsock = 57,
|
|
wasi_errno_opnotsupp = 58,
|
|
wasi_errno_notty = 59,
|
|
wasi_errno_nxio = 60,
|
|
wasi_errno_overflow = 61,
|
|
wasi_errno_ownerdead = 62,
|
|
wasi_errno_perm = 63,
|
|
wasi_errno_pipe = 64,
|
|
wasi_errno_proto = 65,
|
|
wasi_errno_protonosupport = 66,
|
|
wasi_errno_prototype = 67,
|
|
wasi_errno_range = 68,
|
|
wasi_errno_rofs = 69,
|
|
wasi_errno_spipe = 70,
|
|
wasi_errno_srch = 71,
|
|
wasi_errno_stale = 72,
|
|
wasi_errno_timedout = 73,
|
|
wasi_errno_txtbsy = 74,
|
|
wasi_errno_xdev = 75,
|
|
wasi_errno_notcapable = 76,
|
|
};
|
|
|
|
enum wasi_oflags {
|
|
wasi_oflags_creat = 1 << 0,
|
|
wasi_oflags_directory = 1 << 1,
|
|
wasi_oflags_excl = 1 << 2,
|
|
wasi_oflags_trunc = 1 << 3,
|
|
};
|
|
|
|
enum wasi_rights {
|
|
wasi_rights_fd_datasync = 1ull << 0,
|
|
wasi_rights_fd_read = 1ull << 1,
|
|
wasi_rights_fd_seek = 1ull << 2,
|
|
wasi_rights_fd_fdstat_set_flags = 1ull << 3,
|
|
wasi_rights_fd_sync = 1ull << 4,
|
|
wasi_rights_fd_tell = 1ull << 5,
|
|
wasi_rights_fd_write = 1ull << 6,
|
|
wasi_rights_fd_advise = 1ull << 7,
|
|
wasi_rights_fd_allocate = 1ull << 8,
|
|
wasi_rights_path_create_directory = 1ull << 9,
|
|
wasi_rights_path_create_file = 1ull << 10,
|
|
wasi_rights_path_link_source = 1ull << 11,
|
|
wasi_rights_path_link_target = 1ull << 12,
|
|
wasi_rights_path_open = 1ull << 13,
|
|
wasi_rights_fd_readdir = 1ull << 14,
|
|
wasi_rights_path_readlink = 1ull << 15,
|
|
wasi_rights_path_rename_source = 1ull << 16,
|
|
wasi_rights_path_rename_target = 1ull << 17,
|
|
wasi_rights_path_filestat_get = 1ull << 18,
|
|
wasi_rights_path_filestat_set_size = 1ull << 19,
|
|
wasi_rights_path_filestat_set_times = 1ull << 20,
|
|
wasi_rights_fd_filestat_get = 1ull << 21,
|
|
wasi_rights_fd_filestat_set_size = 1ull << 22,
|
|
wasi_rights_fd_filestat_set_times = 1ull << 23,
|
|
wasi_rights_path_symlink = 1ull << 24,
|
|
wasi_rights_path_remove_directory = 1ull << 25,
|
|
wasi_rights_path_unlink_file = 1ull << 26,
|
|
wasi_rights_poll_fd_readwrite = 1ull << 27,
|
|
wasi_rights_sock_shutdown = 1ull << 28,
|
|
wasi_rights_sock_accept = 1ull << 29,
|
|
};
|
|
|
|
enum wasi_clockid {
|
|
wasi_clockid_realtime = 0,
|
|
wasi_clockid_monotonic = 1,
|
|
wasi_clockid_process_cputime_id = 2,
|
|
wasi_clockid_thread_cputime_id = 3,
|
|
};
|
|
|
|
enum wasi_filetype {
|
|
wasi_filetype_unknown = 0,
|
|
wasi_filetype_block_device = 1,
|
|
wasi_filetype_character_device = 2,
|
|
wasi_filetype_directory = 3,
|
|
wasi_filetype_regular_file = 4,
|
|
wasi_filetype_socket_dgram = 5,
|
|
wasi_filetype_socket_stream = 6,
|
|
wasi_filetype_symbolic_link = 7,
|
|
};
|
|
|
|
enum wasi_fdflags {
|
|
wasi_fdflags_append = 1 << 0,
|
|
wasi_fdflags_dsync = 1 << 1,
|
|
wasi_fdflags_nonblock = 1 << 2,
|
|
wasi_fdflags_rsync = 1 << 3,
|
|
wasi_fdflags_sync = 1 << 4,
|
|
};
|
|
|
|
struct wasi_filestat {
|
|
uint64_t dev;
|
|
uint64_t ino;
|
|
uint64_t filetype;
|
|
uint64_t nlink;
|
|
uint64_t size;
|
|
uint64_t atim;
|
|
uint64_t mtim;
|
|
uint64_t ctim;
|
|
};
|
|
|
|
struct wasi_fdstat {
|
|
uint16_t fs_filetype;
|
|
uint16_t fs_flags;
|
|
uint32_t padding;
|
|
uint64_t fs_rights_inheriting;
|
|
};
|
|
|
|
struct wasi_ciovec {
|
|
uint32_t ptr;
|
|
uint32_t len;
|
|
};
|
|
|
|
extern uint8_t **const wasm_memory;
|
|
extern void wasm__start(void);
|
|
|
|
static int global_argc;
|
|
static char **global_argv;
|
|
|
|
static uint32_t de_len;
|
|
struct DirEntry {
|
|
enum wasi_filetype filetype;
|
|
time_t atim;
|
|
time_t mtim;
|
|
time_t ctim;
|
|
char *guest_path;
|
|
char *host_path;
|
|
} *des;
|
|
|
|
static uint32_t fd_len;
|
|
static struct FileDescriptor {
|
|
uint32_t de;
|
|
FILE *stream;
|
|
} *fds;
|
|
|
|
static void *dupe(const void *data, size_t len) {
|
|
void *copy = malloc(len);
|
|
if (copy == NULL) panic("out of memory");
|
|
memcpy(copy, data, len);
|
|
return copy;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc < 2) {
|
|
fprintf(stderr, "usage: %s <zig-lib-path> <args...>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
global_argc = argc;
|
|
global_argv = argv;
|
|
|
|
time_t now = time(NULL);
|
|
srand((unsigned)now);
|
|
|
|
de_len = 4;
|
|
des = calloc(de_len, sizeof(struct DirEntry));
|
|
if (des == NULL) panic("out of memory");
|
|
|
|
des[0].filetype = wasi_filetype_character_device;
|
|
|
|
des[1].filetype = wasi_filetype_directory;
|
|
des[1].guest_path = dupe(".", sizeof("."));
|
|
des[1].host_path = dupe(".", sizeof("."));
|
|
|
|
des[2].filetype = wasi_filetype_directory;
|
|
des[2].guest_path = dupe("/cache", sizeof("/cache"));
|
|
des[2].atim = now;
|
|
des[2].mtim = now;
|
|
des[2].ctim = now;
|
|
|
|
des[3].filetype = wasi_filetype_directory;
|
|
des[3].guest_path = dupe("/lib", sizeof("/lib"));
|
|
des[3].host_path = dupe(argv[1], strlen(argv[1]) + 1);
|
|
|
|
fd_len = 6;
|
|
fds = calloc(sizeof(struct FileDescriptor), fd_len);
|
|
if (fds == NULL) panic("out of memory");
|
|
fds[0].stream = stdin;
|
|
fds[1].stream = stdout;
|
|
fds[2].stream = stderr;
|
|
fds[3].de = 1;
|
|
fds[4].de = 2;
|
|
fds[5].de = 3;
|
|
|
|
wasm__start();
|
|
}
|
|
|
|
static bool isLetter(char c) {
|
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
|
}
|
|
static bool isPathSep(char c) {
|
|
return c == '/' || c == '\\';
|
|
}
|
|
static bool isAbsPath(const char *path, uint32_t path_len) {
|
|
if (path_len >= 1 && isPathSep(path[0])) return true;
|
|
if (path_len >= 3 && isLetter(path[0]) && path[1] == ':' && isPathSep(path[2])) return true;
|
|
return false;
|
|
}
|
|
static bool isSamePath(const char *a, const char *b, uint32_t len) {
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
if (isPathSep(a[i]) && isPathSep(b[i])) continue;
|
|
if (a[i] != b[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32_t path_len, enum wasi_filetype filetype, time_t tim, uint32_t *res_de) {
|
|
if (isAbsPath(path, path_len)) {
|
|
if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
|
|
if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
|
}
|
|
|
|
struct DirEntry *new_des = realloc(des, (de_len + 1) * sizeof(struct DirEntry));
|
|
if (new_des == NULL) return wasi_errno_nomem;
|
|
des = new_des;
|
|
|
|
struct DirEntry *de = &des[de_len];
|
|
de->filetype = filetype;
|
|
de->atim = tim;
|
|
de->mtim = tim;
|
|
de->ctim = tim;
|
|
if (isAbsPath(path, path_len)) {
|
|
de->guest_path = malloc(path_len + 1);
|
|
if (de->guest_path == NULL) return wasi_errno_nomem;
|
|
memcpy(&de->guest_path[0], path, path_len);
|
|
de->guest_path[path_len] = '\0';
|
|
|
|
de->host_path = malloc(path_len + 1);
|
|
if (de->host_path == NULL) return wasi_errno_nomem;
|
|
memcpy(&de->host_path[0], path, path_len);
|
|
de->host_path[path_len] = '\0';
|
|
} else {
|
|
const struct DirEntry *dir_de = &des[fds[dir_fd].de];
|
|
if (dir_de->guest_path != NULL) {
|
|
size_t dir_guest_path_len = strlen(dir_de->guest_path);
|
|
de->guest_path = malloc(dir_guest_path_len + 1 + path_len + 1);
|
|
if (de->guest_path == NULL) return wasi_errno_nomem;
|
|
memcpy(&de->guest_path[0], dir_de->guest_path, dir_guest_path_len);
|
|
de->guest_path[dir_guest_path_len] = '/';
|
|
memcpy(&de->guest_path[dir_guest_path_len + 1], path, path_len);
|
|
de->guest_path[dir_guest_path_len + 1 + path_len] = '\0';
|
|
} else de->guest_path = NULL;
|
|
|
|
if (dir_de->host_path != NULL) {
|
|
size_t dir_host_path_len = strlen(dir_de->host_path);
|
|
de->host_path = malloc(dir_host_path_len + 1 + path_len + 1);
|
|
if (de->host_path == NULL) { free(de->guest_path); return wasi_errno_nomem; }
|
|
memcpy(&de->host_path[0], dir_de->host_path, dir_host_path_len);
|
|
de->host_path[dir_host_path_len] = '/';
|
|
memcpy(&de->host_path[dir_host_path_len + 1], path, path_len);
|
|
de->host_path[dir_host_path_len + 1 + path_len] = '\0';
|
|
} else de->host_path = NULL;
|
|
}
|
|
|
|
if (res_de != NULL) *res_de = de_len;
|
|
de_len += 1;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) {
|
|
(void)flags;
|
|
if (isAbsPath(path, path_len)) {
|
|
for (uint32_t de = 0; de < de_len; de += 1) {
|
|
if (des[de].guest_path == NULL) continue;
|
|
if (!isSamePath(&des[de].guest_path[0], path, path_len)) continue;
|
|
if (des[de].guest_path[path_len] != '\0') continue;
|
|
if (res_de != NULL) *res_de = de;
|
|
return wasi_errno_success;
|
|
}
|
|
} else {
|
|
if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
|
|
const struct DirEntry *dir_de = &des[fds[dir_fd].de];
|
|
if (dir_de->filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
|
|
|
size_t dir_guest_path_len = strlen(dir_de->guest_path);
|
|
for (uint32_t de = 0; de < de_len; de += 1) {
|
|
if (des[de].guest_path == NULL) continue;
|
|
if (!isSamePath(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len)) continue;
|
|
if (!isPathSep(des[de].guest_path[dir_guest_path_len])) continue;
|
|
if (!isSamePath(&des[de].guest_path[dir_guest_path_len + 1], path, path_len)) continue;
|
|
if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue;
|
|
if (res_de != NULL) *res_de = de;
|
|
return wasi_errno_success;
|
|
}
|
|
}
|
|
return wasi_errno_noent;
|
|
}
|
|
|
|
static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) {
|
|
res_filestat->dev = 0;
|
|
res_filestat->ino = de;
|
|
res_filestat->filetype = des[de].filetype;
|
|
res_filestat->nlink = 1;
|
|
res_filestat->size = 0;
|
|
res_filestat->atim = des[de].atim * UINT64_C(1000000000);
|
|
res_filestat->mtim = des[de].mtim * UINT64_C(1000000000);
|
|
res_filestat->ctim = des[de].ctim * UINT64_C(1000000000);
|
|
}
|
|
|
|
static void DirEntry_unlink(uint32_t de) {
|
|
free(des[de].guest_path);
|
|
des[de].guest_path = NULL;
|
|
free(des[de].host_path);
|
|
des[de].host_path = NULL;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv_buf_size) {
|
|
uint8_t *const m = *wasm_memory;
|
|
uint32_t *argv_size_ptr = (uint32_t *)&m[argv_size];
|
|
uint32_t *argv_buf_size_ptr = (uint32_t *)&m[argv_buf_size];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_args_sizes_get()\n");
|
|
#endif
|
|
|
|
int c_argc = global_argc;
|
|
char **c_argv = global_argv;
|
|
uint32_t size = 0;
|
|
for (int i = 0; i < c_argc; i += 1) {
|
|
if (i == 1) continue;
|
|
size += strlen(c_argv[i]) + 1;
|
|
}
|
|
*argv_size_ptr = c_argc - 1;
|
|
*argv_buf_size_ptr = size;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) {
|
|
uint8_t *const m = *wasm_memory;
|
|
uint32_t *argv_ptr = (uint32_t *)&m[argv];
|
|
char *argv_buf_ptr = (char *)&m[argv_buf];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_args_get()\n");
|
|
#endif
|
|
|
|
int c_argc = global_argc;
|
|
char **c_argv = global_argv;
|
|
uint32_t dst_i = 0;
|
|
uint32_t argv_buf_i = 0;
|
|
for (int src_i = 0; src_i < c_argc; src_i += 1) {
|
|
if (src_i == 1) continue;
|
|
argv_ptr[dst_i] = argv_buf + argv_buf_i;
|
|
dst_i += 1;
|
|
strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]);
|
|
argv_buf_i += strlen(c_argv[src_i]) + 1;
|
|
}
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat) {
|
|
uint8_t *const m = *wasm_memory;
|
|
uint32_t *res_prestat_ptr = (uint32_t *)&m[res_prestat];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_get(%u)\n", fd);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
|
|
res_prestat_ptr[0] = 0;
|
|
res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path);
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path, uint32_t path_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
char *path_ptr = (char *)&m[path];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_dir_name(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
strncpy(path_ptr, des[fds[fd].de].guest_path, path_len);
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
void wasi_snapshot_preview1_proc_exit(uint32_t rval) {
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_proc_exit(%u)\n", rval);
|
|
#endif
|
|
|
|
exit(rval);
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_close(uint32_t fd) {
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_close(%u)\n", fd);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
if (fds[fd].stream != NULL) fclose(fds[fd].stream);
|
|
|
|
fds[fd].de = ~0;
|
|
fds[fd].stream = NULL;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_create_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *path_ptr = (const char *)&m[path];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_create_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
|
#endif
|
|
|
|
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, NULL);
|
|
switch (lookup_errno) {
|
|
case wasi_errno_success: return wasi_errno_exist;
|
|
case wasi_errno_noent: break;
|
|
default: return lookup_errno;
|
|
}
|
|
return DirEntry_create(fd, path_ptr, path_len, wasi_filetype_directory, time(NULL), NULL);
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
|
|
uint8_t *const m = *wasm_memory;
|
|
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
|
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_read(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
switch (des[fds[fd].de].filetype) {
|
|
case wasi_filetype_character_device: break;
|
|
case wasi_filetype_regular_file: break;
|
|
case wasi_filetype_directory: return wasi_errno_inval;
|
|
default: panic("unimplemented");
|
|
}
|
|
|
|
size_t size = 0;
|
|
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
|
size_t read_size = 0;
|
|
if (fds[fd].stream != NULL)
|
|
read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
|
else
|
|
panic("unimplemented");
|
|
size += read_size;
|
|
if (read_size < iovs_ptr[i].len) break;
|
|
}
|
|
|
|
if (size > 0) des[fds[fd].de].atim = time(NULL);
|
|
*res_size_ptr = size;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filestat) {
|
|
uint8_t *const m = *wasm_memory;
|
|
struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_get(%u)\n", fd);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
DirEntry_filestat(fds[fd].de, res_filestat_ptr);
|
|
if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_success;
|
|
if (fds[fd].stream == NULL) return wasi_errno_success;
|
|
fpos_t pos;
|
|
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
|
|
long size = ftell(fds[fd].stream);
|
|
if (size < 0) return wasi_errno_io;
|
|
res_filestat_ptr->size = size;
|
|
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_rename(uint32_t fd, uint32_t old_path, uint32_t old_path_len, uint32_t new_fd, uint32_t new_path, uint32_t new_path_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *old_path_ptr = (const char *)&m[old_path];
|
|
const char *new_path_ptr = (const char *)&m[new_path];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_rename(%u, \"%.*s\", %u, \"%.*s\")\n", fd, (int)old_path_len, old_path_ptr, new_fd, (int)new_path_len, new_path_ptr);
|
|
#endif
|
|
|
|
uint32_t old_de;
|
|
enum wasi_errno old_lookup_errno = DirEntry_lookup(fd, 0, old_path_ptr, old_path_len, &old_de);
|
|
if (old_lookup_errno != wasi_errno_success) return old_lookup_errno;
|
|
DirEntry_unlink(old_de);
|
|
|
|
uint32_t de;
|
|
enum wasi_errno new_lookup_errno = DirEntry_lookup(new_fd, 0, new_path_ptr, new_path_len, &de);
|
|
switch (new_lookup_errno) {
|
|
case wasi_errno_success: DirEntry_unlink(de); break;
|
|
case wasi_errno_noent: break;
|
|
default: return new_lookup_errno;
|
|
}
|
|
|
|
uint32_t new_de;
|
|
enum wasi_errno create_errno =
|
|
DirEntry_create(new_fd, new_path_ptr, new_path_len, des[old_de].filetype, 0, &new_de);
|
|
if (create_errno != wasi_errno_success) return create_errno;
|
|
des[new_de].atim = des[old_de].atim;
|
|
des[new_de].mtim = des[old_de].mtim;
|
|
des[new_de].ctim = time(NULL);
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) {
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_size(%u, %llu)\n", fd, (unsigned long long)size);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_inval;
|
|
|
|
if (fds[fd].stream == NULL) return wasi_errno_success;
|
|
fpos_t pos;
|
|
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
|
|
long old_size = ftell(fds[fd].stream);
|
|
if (old_size < 0) return wasi_errno_io;
|
|
if (size != (unsigned long)old_size) {
|
|
if (size > 0 && fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io;
|
|
if (size < (unsigned long)old_size) {
|
|
// Note that this destroys the contents on resize might have to save truncated
|
|
// file in memory if this becomes an issue.
|
|
FILE *trunc = fopen(des[fds[fd].de].host_path, "wb");
|
|
if (trunc == NULL) return wasi_errno_io;
|
|
fclose(trunc);
|
|
}
|
|
if (size > 0) fputc(0, fds[fd].stream);
|
|
}
|
|
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
|
|
uint8_t *const m = *wasm_memory;
|
|
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
|
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_pwrite(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
switch (des[fds[fd].de].filetype) {
|
|
case wasi_filetype_character_device: break;
|
|
case wasi_filetype_regular_file: break;
|
|
case wasi_filetype_directory: return wasi_errno_inval;
|
|
default: panic("unimplemented");
|
|
}
|
|
|
|
fpos_t pos;
|
|
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
|
|
|
|
size_t size = 0;
|
|
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
|
size_t written_size = 0;
|
|
if (fds[fd].stream != NULL)
|
|
written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
|
else
|
|
written_size = iovs_ptr[i].len;
|
|
size += written_size;
|
|
if (written_size < iovs_ptr[i].len) break;
|
|
}
|
|
|
|
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
|
|
if (size > 0) {
|
|
time_t now = time(NULL);
|
|
des[fds[fd].de].atim = now;
|
|
des[fds[fd].de].mtim = now;
|
|
}
|
|
*res_size_ptr = size;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_random_get(uint32_t buf, uint32_t buf_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
uint8_t *buf_ptr = (uint8_t *)&m[buf];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_random_get(%u)\n", buf_len);
|
|
#endif
|
|
|
|
for (uint32_t i = 0; i < buf_len; i += 1) buf_ptr[i] = (uint8_t)rand();
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) {
|
|
(void)fd;
|
|
(void)atim;
|
|
(void)mtim;
|
|
(void)fst_flags;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_times(%u, %llu, %llu, 0x%X)\n", fd, (unsigned long long)atim, (unsigned long long)mtim, fst_flags);
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_t environ_buf_size) {
|
|
(void)environ_size;
|
|
(void)environ_buf_size;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n");
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_buf) {
|
|
(void)environ;
|
|
(void)environ_buf;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n");
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, uint32_t path, uint32_t path_len, uint32_t res_filestat) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *path_ptr = (const char *)&m[path];
|
|
struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_filestat_get(%u, 0x%X, \"%.*s\")\n", fd, flags, (int)path_len, path_ptr);
|
|
#endif
|
|
|
|
uint32_t de;
|
|
enum wasi_errno lookup_errno = DirEntry_lookup(fd, flags, path_ptr, path_len, &de);
|
|
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
|
DirEntry_filestat(de, res_filestat_ptr);
|
|
if (des[de].filetype == wasi_filetype_regular_file && des[de].host_path != NULL) {
|
|
FILE *stream = fopen(des[de].host_path, "rb");
|
|
if (stream != NULL) {
|
|
if (fseek(stream, 0, SEEK_END) >= 0) {
|
|
long size = ftell(stream);
|
|
if (size >= 0) res_filestat_ptr->size = size;
|
|
}
|
|
fclose(stream);
|
|
}
|
|
}
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat) {
|
|
(void)fd;
|
|
(void)res_fdstat;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_fdstat_get(%u)\n", fd);
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t buf_len, uint64_t cookie, uint32_t res_size) {
|
|
(void)fd;
|
|
(void)buf;
|
|
(void)buf_len;
|
|
(void)cookie;
|
|
(void)res_size;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie);
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
|
|
uint8_t *const m = *wasm_memory;
|
|
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
|
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_write(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
switch (des[fds[fd].de].filetype) {
|
|
case wasi_filetype_character_device: break;
|
|
case wasi_filetype_regular_file: break;
|
|
case wasi_filetype_directory: return wasi_errno_inval;
|
|
default: panic("unimplemented");
|
|
}
|
|
|
|
size_t size = 0;
|
|
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
|
size_t written_size = 0;
|
|
if (fds[fd].stream != NULL)
|
|
written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
|
else
|
|
written_size = iovs_ptr[i].len;
|
|
size += written_size;
|
|
if (written_size < iovs_ptr[i].len) break;
|
|
}
|
|
|
|
if (size > 0) {
|
|
time_t now = time(NULL);
|
|
des[fds[fd].de].atim = now;
|
|
des[fds[fd].de].mtim = now;
|
|
}
|
|
*res_size_ptr = size;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32_t path, uint32_t path_len, uint32_t oflags, uint64_t fs_rights_base, uint64_t fs_rights_inheriting, uint32_t fdflags, uint32_t res_fd) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *path_ptr = (const char *)&m[path];
|
|
(void)fs_rights_inheriting;
|
|
uint32_t *res_fd_ptr = (uint32_t *)&m[res_fd];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_open(%u, 0x%X, \"%.*s\", 0x%X, 0x%llX, 0x%llX, 0x%X)\n", fd, dirflags, (int)path_len, path_ptr, oflags, (unsigned long long)fs_rights_base, (unsigned long long)fs_rights_inheriting, fdflags);
|
|
#endif
|
|
|
|
bool creat = (oflags & wasi_oflags_creat) != 0;
|
|
bool directory = (oflags & wasi_oflags_directory) != 0;
|
|
bool excl = (oflags & wasi_oflags_excl) != 0;
|
|
bool trunc = (oflags & wasi_oflags_trunc) != 0;
|
|
bool append = (fdflags & wasi_fdflags_append) != 0;
|
|
|
|
uint32_t de;
|
|
enum wasi_errno lookup_errno = DirEntry_lookup(fd, dirflags, path_ptr, path_len, &de);
|
|
if (lookup_errno == wasi_errno_success) {
|
|
if (directory && des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
|
|
|
struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
|
|
if (new_fds == NULL) return wasi_errno_nomem;
|
|
fds = new_fds;
|
|
|
|
fds[fd_len].de = de;
|
|
switch (des[de].filetype) {
|
|
case wasi_filetype_directory: fds[fd_len].stream = NULL; break;
|
|
default: panic("unimplemented");
|
|
}
|
|
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "fd = %u\n", fd_len);
|
|
#endif
|
|
*res_fd_ptr = fd_len;
|
|
fd_len += 1;
|
|
}
|
|
if (lookup_errno != wasi_errno_noent) return lookup_errno;
|
|
|
|
struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
|
|
if (new_fds == NULL) return wasi_errno_nomem;
|
|
fds = new_fds;
|
|
|
|
enum wasi_filetype filetype = directory ? wasi_filetype_directory : wasi_filetype_regular_file;
|
|
enum wasi_errno create_errno = DirEntry_create(fd, path_ptr, path_len, filetype, 0, &de);
|
|
if (create_errno != wasi_errno_success) return create_errno;
|
|
FILE *stream;
|
|
if (!directory) {
|
|
if (des[de].host_path == NULL) {
|
|
if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
|
|
time_t now = time(NULL);
|
|
des[de].atim = now;
|
|
des[de].mtim = now;
|
|
des[de].ctim = now;
|
|
stream = NULL;
|
|
} else {
|
|
if (oflags != (append ? wasi_oflags_creat : wasi_oflags_creat | wasi_oflags_trunc)) {
|
|
char mode[] = "rb+";
|
|
if ((fs_rights_base & wasi_rights_fd_write) == 0) mode[2] = '\0';
|
|
stream = fopen(des[de].host_path, mode);
|
|
if (stream != NULL) {
|
|
if (append || excl || trunc) fclose(stream);
|
|
if (excl) {
|
|
DirEntry_unlink(de);
|
|
de_len -= 1;
|
|
return wasi_errno_exist;
|
|
}
|
|
} else if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
|
|
}
|
|
if (append || trunc || stream == NULL) {
|
|
char mode[] = "wb+";
|
|
if ((fs_rights_base & wasi_rights_fd_read) == 0) mode[2] = '\0';
|
|
if (trunc || !append) {
|
|
stream = fopen(des[de].host_path, mode);
|
|
if (append && stream != NULL) fclose(stream);
|
|
}
|
|
if (append) {
|
|
mode[0] = 'a';
|
|
stream = fopen(des[de].host_path, mode);
|
|
}
|
|
}
|
|
if (stream == NULL) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_isdir; }
|
|
}
|
|
} else stream = NULL;
|
|
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "fd = %u\n", fd_len);
|
|
#endif
|
|
fds[fd_len].de = de;
|
|
fds[fd_len].stream = stream;
|
|
*res_fd_ptr = fd_len;
|
|
fd_len += 1;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision, uint32_t res_timestamp) {
|
|
uint8_t *const m = *wasm_memory;
|
|
(void)precision;
|
|
uint64_t *res_timestamp_ptr = (uint64_t *)&m[res_timestamp];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_clock_time_get(%u, %llu)\n", id, (unsigned long long)precision);
|
|
#endif
|
|
|
|
switch (id) {
|
|
case wasi_clockid_realtime:
|
|
*res_timestamp_ptr = time(NULL) * UINT64_C(1000000000);
|
|
break;
|
|
case wasi_clockid_monotonic:
|
|
case wasi_clockid_process_cputime_id:
|
|
case wasi_clockid_thread_cputime_id:
|
|
*res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC);
|
|
break;
|
|
default: return wasi_errno_inval;
|
|
}
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_remove_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *path_ptr = (const char *)&m[path];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_remove_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
|
#endif
|
|
|
|
uint32_t de;
|
|
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
|
|
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
|
if (des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
|
DirEntry_unlink(de);
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uint32_t path_len) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *path_ptr = (const char *)&m[path];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_path_unlink_file(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
|
#endif
|
|
|
|
uint32_t de;
|
|
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
|
|
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
|
if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir;
|
|
if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented");
|
|
DirEntry_unlink(de);
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
|
|
uint8_t *const m = *wasm_memory;
|
|
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
|
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_fd_pread(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
|
#endif
|
|
|
|
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
|
switch (des[fds[fd].de].filetype) {
|
|
case wasi_filetype_character_device: break;
|
|
case wasi_filetype_regular_file: break;
|
|
case wasi_filetype_directory: return wasi_errno_inval;
|
|
default: panic("unimplemented");
|
|
}
|
|
|
|
fpos_t pos;
|
|
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
|
|
|
|
size_t size = 0;
|
|
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
|
size_t read_size = 0;
|
|
if (fds[fd].stream != NULL)
|
|
read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
|
else
|
|
panic("unimplemented");
|
|
size += read_size;
|
|
if (read_size < iovs_ptr[i].len) break;
|
|
}
|
|
|
|
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
|
|
|
if (size > 0) des[fds[fd].de].atim = time(NULL);
|
|
*res_size_ptr = size;
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t nsubscriptions, uint32_t res_nevents) {
|
|
(void)in;
|
|
(void)out;
|
|
(void)nsubscriptions;
|
|
(void)res_nevents;
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions);
|
|
#endif
|
|
|
|
panic("unimplemented");
|
|
return wasi_errno_success;
|
|
}
|
|
|
|
|
|
void wasi_snapshot_preview1_debug(uint32_t string, uint64_t x) {
|
|
uint8_t *const m = *wasm_memory;
|
|
const char *string_ptr = (const char *)&m[string];
|
|
#if LOG_TRACE
|
|
fprintf(stderr, "wasi_snapshot_preview1_debug(\"%s\", %llu, 0x%llX)\n", string_ptr, (unsigned long long)x, (unsigned long long)x);
|
|
#endif
|
|
|
|
(void)string_ptr;
|
|
(void)x;
|
|
}
|