Commit 67726e36b0

Andrew Kelley <andrew@ziglang.org>
2019-05-19 06:53:24
extract posix functions from std/os.zig to std/os/posix.zig
See #2380
1 parent df7aa9a
doc/langref.html.in
@@ -195,7 +195,7 @@ const std = @import("std");
 
 pub fn main() !void {
     // If this program is run without stdout attached, exit with an error.
-    const stdout_file = try std.io.getStdOut();
+    const stdout_file = try std.os.File.stdout();
     // If this program encounters pipe failure when printing to stdout, exit
     // with an error.
     try stdout_file.write("Hello, world!\n");
example/hello_world/hello.zig
@@ -1,9 +1,5 @@
 const std = @import("std");
 
-pub fn main() !void {
-    // If this program is run without stdout attached, exit with an error.
-    const stdout_file = try std.io.getStdOut();
-    // If this program encounters pipe failure when printing to stdout, exit
-    // with an error.
-    try stdout_file.write("Hello, world!\n");
+pub fn main() void {
+    std.debug.warn("Hello, world!\n");
 }
example/hello_world/hello_libc.zig
@@ -2,13 +2,9 @@ const c = @cImport({
     // See https://github.com/ziglang/zig/issues/515
     @cDefine("_NO_CRT_STDIO_INLINE", "1");
     @cInclude("stdio.h");
-    @cInclude("string.h");
 });
 
-const msg = c"Hello, world!\n";
-
-export fn main(argc: c_int, argv: **u8) c_int {
-    if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
-
+export fn main(argc: c_int, argv: [*]?[*]u8) c_int {
+    c.fprintf(c.stderr, c"Hello, world!\n");
     return 0;
 }
std/event/net.zig
@@ -89,14 +89,7 @@ pub const Server = struct {
                     },
                 };
             } else |err| switch (err) {
-                error.ProcessFdQuotaExceeded => {
-                    errdefer os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
-                    suspend {
-                        self.waiting_for_emfile_node = PromiseNode.init(@handle());
-                        os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
-                    }
-                    continue;
-                },
+                error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
                 error.ConnectionAborted => continue,
 
                 error.FileDescriptorNotASocket => unreachable,
std/os/linux/tls.zig
@@ -126,7 +126,7 @@ pub fn initTLS() void {
     var tls_phdr: ?*elf.Phdr = null;
     var img_base: usize = 0;
 
-    const auxv = std.os.linux_elf_aux_maybe.?;
+    const auxv = std.os.linux.elf_aux_maybe.?;
     var at_phent: usize = undefined;
     var at_phnum: usize = undefined;
     var at_phdr: usize = undefined;
std/os/wasi/core.zig
@@ -1,374 +0,0 @@
-// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
-// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
-
-pub const advice_t = u8;
-pub const ADVICE_NORMAL: advice_t = 0;
-pub const ADVICE_SEQUENTIAL: advice_t = 1;
-pub const ADVICE_RANDOM: advice_t = 2;
-pub const ADVICE_WILLNEED: advice_t = 3;
-pub const ADVICE_DONTNEED: advice_t = 4;
-pub const ADVICE_NOREUSE: advice_t = 5;
-
-pub const ciovec_t = extern struct {
-    buf: [*]const u8,
-    buf_len: usize,
-};
-
-pub const clockid_t = u32;
-pub const CLOCK_REALTIME: clockid_t = 0;
-pub const CLOCK_MONOTONIC: clockid_t = 1;
-pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
-pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
-
-pub const device_t = u64;
-
-pub const dircookie_t = u64;
-pub const DIRCOOKIE_START: dircookie_t = 0;
-
-pub const dirent_t = extern struct {
-    d_next: dircookie_t,
-    d_ino: inode_t,
-    d_namlen: u32,
-    d_type: filetype_t,
-};
-
-pub const errno_t = u16;
-pub const ESUCCESS: errno_t = 0;
-pub const E2BIG: errno_t = 1;
-pub const EACCES: errno_t = 2;
-pub const EADDRINUSE: errno_t = 3;
-pub const EADDRNOTAVAIL: errno_t = 4;
-pub const EAFNOSUPPORT: errno_t = 5;
-pub const EAGAIN: errno_t = 6;
-pub const EALREADY: errno_t = 7;
-pub const EBADF: errno_t = 8;
-pub const EBADMSG: errno_t = 9;
-pub const EBUSY: errno_t = 10;
-pub const ECANCELED: errno_t = 11;
-pub const ECHILD: errno_t = 12;
-pub const ECONNABORTED: errno_t = 13;
-pub const ECONNREFUSED: errno_t = 14;
-pub const ECONNRESET: errno_t = 15;
-pub const EDEADLK: errno_t = 16;
-pub const EDESTADDRREQ: errno_t = 17;
-pub const EDOM: errno_t = 18;
-pub const EDQUOT: errno_t = 19;
-pub const EEXIST: errno_t = 20;
-pub const EFAULT: errno_t = 21;
-pub const EFBIG: errno_t = 22;
-pub const EHOSTUNREACH: errno_t = 23;
-pub const EIDRM: errno_t = 24;
-pub const EILSEQ: errno_t = 25;
-pub const EINPROGRESS: errno_t = 26;
-pub const EINTR: errno_t = 27;
-pub const EINVAL: errno_t = 28;
-pub const EIO: errno_t = 29;
-pub const EISCONN: errno_t = 30;
-pub const EISDIR: errno_t = 31;
-pub const ELOOP: errno_t = 32;
-pub const EMFILE: errno_t = 33;
-pub const EMLINK: errno_t = 34;
-pub const EMSGSIZE: errno_t = 35;
-pub const EMULTIHOP: errno_t = 36;
-pub const ENAMETOOLONG: errno_t = 37;
-pub const ENETDOWN: errno_t = 38;
-pub const ENETRESET: errno_t = 39;
-pub const ENETUNREACH: errno_t = 40;
-pub const ENFILE: errno_t = 41;
-pub const ENOBUFS: errno_t = 42;
-pub const ENODEV: errno_t = 43;
-pub const ENOENT: errno_t = 44;
-pub const ENOEXEC: errno_t = 45;
-pub const ENOLCK: errno_t = 46;
-pub const ENOLINK: errno_t = 47;
-pub const ENOMEM: errno_t = 48;
-pub const ENOMSG: errno_t = 49;
-pub const ENOPROTOOPT: errno_t = 50;
-pub const ENOSPC: errno_t = 51;
-pub const ENOSYS: errno_t = 52;
-pub const ENOTCONN: errno_t = 53;
-pub const ENOTDIR: errno_t = 54;
-pub const ENOTEMPTY: errno_t = 55;
-pub const ENOTRECOVERABLE: errno_t = 56;
-pub const ENOTSOCK: errno_t = 57;
-pub const ENOTSUP: errno_t = 58;
-pub const ENOTTY: errno_t = 59;
-pub const ENXIO: errno_t = 60;
-pub const EOVERFLOW: errno_t = 61;
-pub const EOWNERDEAD: errno_t = 62;
-pub const EPERM: errno_t = 63;
-pub const EPIPE: errno_t = 64;
-pub const EPROTO: errno_t = 65;
-pub const EPROTONOSUPPORT: errno_t = 66;
-pub const EPROTOTYPE: errno_t = 67;
-pub const ERANGE: errno_t = 68;
-pub const EROFS: errno_t = 69;
-pub const ESPIPE: errno_t = 70;
-pub const ESRCH: errno_t = 71;
-pub const ESTALE: errno_t = 72;
-pub const ETIMEDOUT: errno_t = 73;
-pub const ETXTBSY: errno_t = 74;
-pub const EXDEV: errno_t = 75;
-pub const ENOTCAPABLE: errno_t = 76;
-
-pub const event_t = extern struct {
-    userdata: userdata_t,
-    @"error": errno_t,
-    @"type": eventtype_t,
-    u: extern union {
-        fd_readwrite: extern struct {
-            nbytes: filesize_t,
-            flags: eventrwflags_t,
-        },
-    },
-};
-
-pub const eventrwflags_t = u16;
-pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
-
-pub const eventtype_t = u8;
-pub const EVENTTYPE_CLOCK: eventtype_t = 0;
-pub const EVENTTYPE_FD_READ: eventtype_t = 1;
-pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
-
-pub const exitcode_t = u32;
-
-pub const fd_t = u32;
-
-pub const fdflags_t = u16;
-pub const FDFLAG_APPEND: fdflags_t = 0x0001;
-pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
-pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
-pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
-pub const FDFLAG_SYNC: fdflags_t = 0x0010;
-
-const fdstat_t = extern struct {
-    fs_filetype: filetype_t,
-    fs_flags: fdflags_t,
-    fs_rights_base: rights_t,
-    fs_rights_inheriting: rights_t,
-};
-
-pub const filedelta_t = i64;
-
-pub const filesize_t = u64;
-
-pub const filestat_t = extern struct {
-    st_dev: device_t,
-    st_ino: inode_t,
-    st_filetype: filetype_t,
-    st_nlink: linkcount_t,
-    st_size: filesize_t,
-    st_atim: timestamp_t,
-    st_mtim: timestamp_t,
-    st_ctim: timestamp_t,
-};
-
-pub const filetype_t = u8;
-pub const FILETYPE_UNKNOWN: filetype_t = 0;
-pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
-pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
-pub const FILETYPE_DIRECTORY: filetype_t = 3;
-pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
-pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
-pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
-pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
-
-pub const fstflags_t = u16;
-pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
-pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
-pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
-pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
-
-pub const inode_t = u64;
-
-pub const iovec_t = extern struct {
-    buf: [*]u8,
-    buf_len: usize,
-};
-
-pub const linkcount_t = u32;
-
-pub const lookupflags_t = u32;
-pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
-
-pub const oflags_t = u16;
-pub const O_CREAT: oflags_t = 0x0001;
-pub const O_DIRECTORY: oflags_t = 0x0002;
-pub const O_EXCL: oflags_t = 0x0004;
-pub const O_TRUNC: oflags_t = 0x0008;
-
-pub const preopentype_t = u8;
-pub const PREOPENTYPE_DIR: preopentype_t = 0;
-
-pub const prestat_t = extern struct {
-    pr_type: preopentype_t,
-    u: extern union {
-        dir: extern struct {
-            pr_name_len: usize,
-        },
-    },
-};
-
-pub const riflags_t = u16;
-pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
-pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
-
-pub const rights_t = u64;
-pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
-pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
-pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
-pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
-pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
-pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
-pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
-pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
-pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
-pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
-pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
-pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
-pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
-pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
-pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
-pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
-pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
-pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
-pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
-pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
-pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
-pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
-pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
-pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
-pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
-pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
-pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
-pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
-pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
-
-pub const roflags_t = u16;
-pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
-
-pub const sdflags_t = u8;
-pub const SHUT_RD: sdflags_t = 0x01;
-pub const SHUT_WR: sdflags_t = 0x02;
-
-pub const siflags_t = u16;
-
-pub const signal_t = u8;
-pub const SIGHUP: signal_t = 1;
-pub const SIGINT: signal_t = 2;
-pub const SIGQUIT: signal_t = 3;
-pub const SIGILL: signal_t = 4;
-pub const SIGTRAP: signal_t = 5;
-pub const SIGABRT: signal_t = 6;
-pub const SIGBUS: signal_t = 7;
-pub const SIGFPE: signal_t = 8;
-pub const SIGKILL: signal_t = 9;
-pub const SIGUSR1: signal_t = 10;
-pub const SIGSEGV: signal_t = 11;
-pub const SIGUSR2: signal_t = 12;
-pub const SIGPIPE: signal_t = 13;
-pub const SIGALRM: signal_t = 14;
-pub const SIGTERM: signal_t = 15;
-pub const SIGCHLD: signal_t = 16;
-pub const SIGCONT: signal_t = 17;
-pub const SIGSTOP: signal_t = 18;
-pub const SIGTSTP: signal_t = 19;
-pub const SIGTTIN: signal_t = 20;
-pub const SIGTTOU: signal_t = 21;
-pub const SIGURG: signal_t = 22;
-pub const SIGXCPU: signal_t = 23;
-pub const SIGXFSZ: signal_t = 24;
-pub const SIGVTALRM: signal_t = 25;
-pub const SIGPROF: signal_t = 26;
-pub const SIGWINCH: signal_t = 27;
-pub const SIGPOLL: signal_t = 28;
-pub const SIGPWR: signal_t = 29;
-pub const SIGSYS: signal_t = 30;
-
-pub const subclockflags_t = u16;
-pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
-
-pub const subscription_t = extern struct {
-    userdata: userdata_t,
-    @"type": eventtype_t,
-    u: extern union {
-        clock: extern struct {
-            identifier: userdata_t,
-            clock_id: clockid_t,
-            timeout: timestamp_t,
-            precision: timestamp_t,
-            flags: subclockflags_t,
-        },
-        fd_readwrite: extern struct {
-            fd: fd_t,
-        },
-    },
-};
-
-pub const timestamp_t = u64;
-
-pub const userdata_t = u64;
-
-pub const whence_t = u8;
-pub const WHENCE_CUR: whence_t = 0;
-pub const WHENCE_END: whence_t = 1;
-pub const WHENCE_SET: whence_t = 2;
-
-pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
-pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
-
-pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
-pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
-
-pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
-pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
-
-pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
-pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
-
-pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
-pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
-pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
-
-pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
-pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
-
-pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
-pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
-pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
-pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
-pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
-pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
-
-pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
-pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
-
-pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn sched_yield() errno_t;
-
-pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
-pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
-pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/windows/errno.zig
@@ -0,0 +1,1 @@
+// TODO get these values from msvcrt
std/os/windows/util.zig
@@ -8,12 +8,6 @@ const mem = std.mem;
 const BufMap = std.BufMap;
 const cstr = std.cstr;
 
-// > The maximum path of 32,767 characters is approximate, because the "\\?\"
-// > prefix may be expanded to a longer string by the system at run time, and
-// > this expansion applies to the total length.
-// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
-pub const PATH_MAX_WIDE = 32767;
-
 pub const WaitError = error{
     WaitAbandoned,
     WaitTimeOut,
@@ -38,131 +32,6 @@ pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) Wa
     };
 }
 
-pub fn windowsClose(handle: windows.HANDLE) void {
-    assert(windows.CloseHandle(handle) != 0);
-}
-
-pub const ReadError = error{
-    OperationAborted,
-    BrokenPipe,
-    Unexpected,
-};
-
-pub const WriteError = error{
-    SystemResources,
-    OperationAborted,
-    BrokenPipe,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
-    var bytes_written: windows.DWORD = undefined;
-    if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
-        const err = windows.GetLastError();
-        return switch (err) {
-            windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
-            windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
-            windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
-            windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
-            windows.ERROR.IO_PENDING => unreachable,
-            windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
-            else => os.unexpectedErrorWindows(err),
-        };
-    }
-}
-
-pub fn windowsIsTty(handle: windows.HANDLE) bool {
-    if (windowsIsCygwinPty(handle))
-        return true;
-
-    var out: windows.DWORD = undefined;
-    return windows.GetConsoleMode(handle, &out) != 0;
-}
-
-pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
-    const size = @sizeOf(windows.FILE_NAME_INFO);
-    var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
-
-    if (windows.GetFileInformationByHandleEx(
-        handle,
-        windows.FileNameInfo,
-        @ptrCast(*c_void, &name_info_bytes[0]),
-        @intCast(u32, name_info_bytes.len),
-    ) == 0) {
-        return false;
-    }
-
-    const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
-    const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
-    const name_wide = @bytesToSlice(u16, name_bytes);
-    return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
-        mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
-}
-
-pub const OpenError = error{
-    SharingViolation,
-    PathAlreadyExists,
-
-    /// When any of the path components can not be found or the file component can not
-    /// be found. Some operating systems distinguish between path components not found and
-    /// file components not found, but they are collapsed into FileNotFound to gain
-    /// consistency across operating systems.
-    FileNotFound,
-
-    AccessDenied,
-    PipeBusy,
-    NameTooLong,
-
-    /// On Windows, file paths must be valid Unicode.
-    InvalidUtf8,
-
-    /// On Windows, file paths cannot contain these characters:
-    /// '/', '*', '?', '"', '<', '>', '|'
-    BadPathName,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn windowsOpenW(
-    file_path_w: [*]const u16,
-    desired_access: windows.DWORD,
-    share_mode: windows.DWORD,
-    creation_disposition: windows.DWORD,
-    flags_and_attrs: windows.DWORD,
-) OpenError!windows.HANDLE {
-    const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
-
-    if (result == windows.INVALID_HANDLE_VALUE) {
-        const err = windows.GetLastError();
-        switch (err) {
-            windows.ERROR.SHARING_VIOLATION => return OpenError.SharingViolation,
-            windows.ERROR.ALREADY_EXISTS => return OpenError.PathAlreadyExists,
-            windows.ERROR.FILE_EXISTS => return OpenError.PathAlreadyExists,
-            windows.ERROR.FILE_NOT_FOUND => return OpenError.FileNotFound,
-            windows.ERROR.PATH_NOT_FOUND => return OpenError.FileNotFound,
-            windows.ERROR.ACCESS_DENIED => return OpenError.AccessDenied,
-            windows.ERROR.PIPE_BUSY => return OpenError.PipeBusy,
-            else => return os.unexpectedErrorWindows(err),
-        }
-    }
-
-    return result;
-}
-
-pub fn windowsOpen(
-    file_path: []const u8,
-    desired_access: windows.DWORD,
-    share_mode: windows.DWORD,
-    creation_disposition: windows.DWORD,
-    flags_and_attrs: windows.DWORD,
-) OpenError!windows.HANDLE {
-    const file_path_w = try sliceToPrefixedFileW(file_path);
-    return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
-}
-
 /// Caller must free result.
 pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
     // count bytes needed
@@ -278,39 +147,3 @@ pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_t
     }
     return WindowsWaitResult.Normal;
 }
-
-pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
-    return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
-}
-
-pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
-    return sliceToPrefixedSuffixedFileW(s, []u16{0});
-}
-
-pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
-    // TODO well defined copy elision
-    var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
-
-    // > File I/O functions in the Windows API convert "/" to "\" as part of
-    // > converting the name to an NT-style name, except when using the "\\?\"
-    // > prefix as detailed in the following sections.
-    // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
-    // Because we want the larger maximum path length for absolute paths, we
-    // disallow forward slashes in zig std lib file functions on Windows.
-    for (s) |byte| {
-        switch (byte) {
-            '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
-            else => {},
-        }
-    }
-    const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
-        const prefix = []u16{ '\\', '\\', '?', '\\' };
-        mem.copy(u16, result[0..], prefix);
-        break :blk prefix.len;
-    };
-    const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
-    assert(end_index <= result.len);
-    if (end_index + suffix.len > result.len) return error.NameTooLong;
-    mem.copy(u16, result[end_index..], suffix);
-    return result;
-}
std/os/child_process.zig
@@ -415,7 +415,7 @@ pub const ChildProcess = struct {
                 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
             }
 
-            os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
+            os.posix.execve(self.allocator, self.argv, env_map) catch |err| forkChildErrReport(err_pipe[1], err);
         }
 
         // we are the parent
std/os/darwin.zig
@@ -1,9 +1,16 @@
+const builtin = @import("builtin");
 const std = @import("../std.zig");
 const c = std.c;
 const assert = std.debug.assert;
 const maxInt = std.math.maxInt;
 
-pub use @import("darwin/errno.zig");
+pub const is_the_target = switch (builtin.os) {
+    .ios, .macosx, .watchos, .tvos => true,
+    else => false,
+};
+
+pub const errno_codes = @import("darwin/errno.zig");
+pub use errno_codes;
 
 pub const PATH_MAX = 1024;
 
std/os/file.zig
@@ -223,9 +223,18 @@ pub const File = struct {
         os.close(self.handle);
     }
 
-    /// Calls `os.isTty` on `self.handle`.
+    /// Test whether the file refers to a terminal.
+    /// See also `supportsAnsiEscapeCodes`.
     pub fn isTty(self: File) bool {
-        return os.isTty(self.handle);
+        return posix.isatty(self.handle);
+    }
+
+    /// Test whether ANSI escape codes will be treated as such.
+    pub fn supportsAnsiEscapeCodes(self: File) bool {
+        if (windows.is_the_target) {
+            return posix.isCygwinPty(self.handle);
+        }
+        return self.isTty();
     }
 
     pub const SeekError = error{
@@ -389,43 +398,16 @@ pub const File = struct {
         }
     }
 
-    pub const ReadError = os.WindowsReadError || os.PosixReadError;
+    pub const ReadError = posix.ReadError;
 
     pub fn read(self: File, buffer: []u8) ReadError!usize {
-        if (is_posix) {
-            return os.posixRead(self.handle, buffer);
-        } else if (is_windows) {
-            var index: usize = 0;
-            while (index < buffer.len) {
-                const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(maxInt(windows.DWORD)), buffer.len - index));
-                var amt_read: windows.DWORD = undefined;
-                if (windows.ReadFile(self.handle, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
-                    const err = windows.GetLastError();
-                    return switch (err) {
-                        windows.ERROR.OPERATION_ABORTED => continue,
-                        windows.ERROR.BROKEN_PIPE => return index,
-                        else => os.unexpectedErrorWindows(err),
-                    };
-                }
-                if (amt_read == 0) return index;
-                index += amt_read;
-            }
-            return index;
-        } else {
-            @compileError("Unsupported OS");
-        }
+        return posix.read(self.handle, buffer);
     }
 
-    pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
+    pub const WriteError = posix.WriteError;
 
     pub fn write(self: File, bytes: []const u8) WriteError!void {
-        if (is_posix) {
-            try os.posixWrite(self.handle, bytes);
-        } else if (is_windows) {
-            try os.windowsWrite(self.handle, bytes);
-        } else {
-            @compileError("Unsupported OS");
-        }
+        return posix.write(self.handle, bytes);
     }
 
     pub fn inStream(file: File) InStream {
@@ -509,4 +491,19 @@ pub const File = struct {
             return self.file.getPos();
         }
     };
+
+    pub fn stdout() !File {
+        const handle = try posix.GetStdHandle(posix.STD_OUTPUT_HANDLE);
+        return openHandle(handle);
+    }
+
+    pub fn stderr() !File {
+        const handle = try posix.GetStdHandle(posix.STD_ERROR_HANDLE);
+        return openHandle(handle);
+    }
+
+    pub fn stdin() !File {
+        const handle = try posix.GetStdHandle(posix.STD_INPUT_HANDLE);
+        return openHandle(handle);
+    }
 };
std/os/linux.zig
@@ -12,7 +12,12 @@ pub use switch (builtin.arch) {
     builtin.Arch.aarch64 => @import("linux/arm64.zig"),
     else => @compileError("unsupported arch"),
 };
-pub use @import("linux/errno.zig");
+pub const is_the_target = builtin.os == .linux;
+pub const errno_codes = @import("linux/errno.zig");
+pub use errno_codes;
+
+/// See `std.os.posix.getauxval`.
+pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
 
 pub const PATH_MAX = 4096;
 pub const IOV_MAX = 1024;
@@ -697,9 +702,9 @@ pub const winsize = extern struct {
 };
 
 /// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
+pub fn getErrno(r: usize) u12 {
     const signed_r = @bitCast(isize, r);
-    return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+    return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0;
 }
 
 pub fn dup2(old: i32, new: i32) usize {
@@ -766,11 +771,6 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
     return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
 }
 
-pub fn isatty(fd: i32) bool {
-    var wsz: winsize = undefined;
-    return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
-}
-
 // TODO https://github.com/ziglang/zig/issues/265
 pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
     return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
@@ -1137,15 +1137,6 @@ pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
 pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
 pub const empty_sigset = []usize{0} ** sigset_t.len;
 
-pub fn raise(sig: i32) usize {
-    var set: sigset_t = undefined;
-    blockAppSignals(&set);
-    const tid = syscall0(SYS_gettid);
-    const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
-    restoreSignals(&set);
-    return ret;
-}
-
 fn blockAllSignals(set: *sigset_t) void {
     _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
 }
@@ -1672,7 +1663,7 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
 }
 
 test "import" {
-    if (builtin.os == builtin.Os.linux) {
+    if (is_the_target) {
         _ = @import("linux/test.zig");
     }
 }
std/os/posix.zig
@@ -0,0 +1,2159 @@
+// This is the "Zig-flavored POSIX" API layer.
+// The purpose is not to match POSIX as closely as possible. Instead,
+// the goal is to provide a very specific layer of abstraction:
+// * Implement the POSIX functions, types, and definitions where possible,
+//   using lower-level target-specific API. For example, on Linux `rename` might call
+//   SYS_renameat or SYS_rename depending on the architecture.
+// * When null-terminated byte buffers are required, provide APIs which accept
+//   slices as well as APIs which accept null-terminated byte buffers. Same goes
+//   for UTF-16LE encoding.
+// * Convert "errno"-style error codes into Zig errors.
+// * Work around kernel bugs and limitations. For example, if a function accepts
+//   a `usize` number of bytes to write, but the kernel can only handle maxInt(u32)
+//   number of bytes, this API layer should introduce a loop to make multiple
+//   syscalls so that the full `usize` number of bytes are written.
+// * Implement the OS-specific functions, types, and definitions that the Zig
+//   standard library needs, at the same API abstraction layer as outlined above.
+//   this includes, for example Windows functions.
+// * When there exists a corresponding libc function and linking libc, call the
+//   libc function.
+// Note: The Zig standard library does not support POSIX thread cancellation, and
+// in general EINTR is handled by trying again.
+
+const std = @import("../std.zig");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+const os = @import("../os.zig");
+const system = os.system;
+const mem = std.mem;
+const BufMap = std.BufMap;
+const Allocator = mem.Allocator;
+const windows = os.windows;
+const wasi = os.wasi;
+const linux = os.linux;
+const testing = std.testing;
+
+pub const FileHandle = if (windows.is_the_target) windows.HANDLE else if (wasi.is_the_target) wasi.fd_t else i32;
+pub use system.errno_codes;
+
+pub const PATH_MAX = system.PATH_MAX;
+
+/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
+/// > prefix may be expanded to a longer string by the system at run time, and
+/// > this expansion applies to the total length.
+/// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
+pub const PATH_MAX_WIDE = 32767;
+
+pub const iovec = system.iovec;
+pub const iovec_const = system.iovec_const;
+
+/// See also `getenv`.
+pub var environ: [][*]u8 = undefined;
+
+/// To obtain errno, call this function with the return value of the
+/// system function call. For some systems this will obtain the value directly
+/// from the return code; for others it will use a thread-local errno variable.
+/// Therefore, this function only returns a well-defined value when it is called
+/// directly after the system function call which one wants to learn the errno
+/// value of.
+pub const errno = system.getErrno;
+
+/// Closes the file handle.
+/// This function is not capable of returning any indication of failure. An
+/// application which wants to ensure writes have succeeded before closing
+/// must call `fsync` before `close`.
+/// Note: The Zig standard library does not support POSIX thread cancellation.
+pub fn close(handle: FileHandle) void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        assert(windows.CloseHandle(handle) != 0);
+        return;
+    }
+    if (wasi.is_the_target) {
+        switch (wasi.fd_close(handle)) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+    switch (system.getErrno(system.close(handle))) {
+        EBADF => unreachable, // Always a race condition.
+        EINTR => return, // This is still a success. See https://github.com/ziglang/zig/issues/2425
+        else => return,
+    }
+}
+
+pub const GetRandomError = error{};
+
+/// Obtain a series of random bytes. These bytes can be used to seed user-space
+/// random number generators or for cryptographic purposes.
+/// When linking against libc, this calls the
+/// appropriate OS-specific library call. Otherwise it uses the zig standard
+/// library implementation.
+pub fn getrandom(buf: []u8) GetRandomError!void {
+    if (windows.is_the_target) {
+        // Call RtlGenRandom() instead of CryptGetRandom() on Windows
+        // https://github.com/rust-lang-nursery/rand/issues/111
+        // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
+        if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
+            const err = windows.GetLastError();
+            return switch (err) {
+                else => unexpectedErrorWindows(err),
+            };
+        }
+        return;
+    }
+    if (linux.is_the_target) {
+        while (true) {
+            switch (system.getErrno(system.getrandom(buf.ptr, buf.len, 0))) {
+                0 => return,
+                EINVAL => unreachable,
+                EFAULT => unreachable,
+                EINTR => continue,
+                ENOSYS => return getRandomBytesDevURandom(buf),
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+    }
+    if (wasi.is_the_target) {
+        switch (os.wasi.random_get(buf.ptr, buf.len)) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+    return getRandomBytesDevURandom(buf);
+}
+
+fn getRandomBytesDevURandom(buf: []u8) !void {
+    const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
+    defer close(fd);
+
+    const stream = &os.File.openHandle(fd).inStream().stream;
+    stream.readNoEof(buf) catch return error.Unexpected;
+}
+
+test "os.getRandomBytes" {
+    var buf_a: [50]u8 = undefined;
+    var buf_b: [50]u8 = undefined;
+    try getRandomBytes(&buf_a);
+    try getRandomBytes(&buf_b);
+    // If this test fails the chance is significantly higher that there is a bug than
+    // that two sets of 50 bytes were equal.
+    testing.expect(!mem.eql(u8, buf_a, buf_b));
+}
+
+/// Causes abnormal process termination.
+/// If linking against libc, this calls the abort() libc function. Otherwise
+/// it raises SIGABRT followed by SIGKILL and finally lo
+pub fn abort() noreturn {
+    @setCold(true);
+    if (builtin.link_libc) {
+        c.abort();
+    }
+    if (windows.is_the_target) {
+        if (builtin.mode == .Debug) {
+            @breakpoint();
+        }
+        windows.ExitProcess(3);
+    }
+    if (builtin.os == .uefi) {
+        // TODO there must be a better thing to do here than loop forever
+        while (true) {}
+    }
+
+    raise(SIGABRT);
+
+    // TODO the rest of the implementation of abort() from musl libc here
+
+    raise(SIGKILL);
+    exit(127);
+}
+
+pub const RaiseError = error{};
+
+pub fn raise(sig: u8) RaiseError!void {
+    if (builtin.link_libc) {
+        switch (system.getErrno(system.raise(sig))) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+
+    if (wasi.is_the_target) {
+        switch (wasi.proc_raise(SIGABRT)) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+
+    if (windows.is_the_target) {
+        @compileError("TODO implement std.posix.raise for Windows");
+    }
+
+    var set: system.sigset_t = undefined;
+    system.blockAppSignals(&set);
+    const tid = system.syscall0(system.SYS_gettid);
+    const rc = system.syscall2(system.SYS_tkill, tid, sig);
+    system.restoreSignals(&set);
+    switch (system.getErrno(rc)) {
+        0 => return,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+/// Exits the program cleanly with the specified status code.
+pub fn exit(status: u8) noreturn {
+    if (builtin.link_libc) {
+        std.c.exit(status);
+    }
+    if (windows.is_the_target) {
+        windows.ExitProcess(status);
+    }
+    if (wasi.is_the_target) {
+        wasi.proc_exit(status);
+    }
+    if (linux.is_the_target and !builtin.single_threaded) {
+        linux.exit_group(status);
+    }
+    system.exit(status);
+}
+
+pub const ReadError = error{
+    InputOutput,
+    SystemResources,
+    IsDir,
+    OperationAborted,
+    BrokenPipe,
+    Unexpected,
+};
+
+/// Returns the number of bytes that were read, which can be less than
+/// buf.len. If 0 bytes were read, that means EOF.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `readAsync`.
+pub fn read(fd: FileHandle, buf: []u8) ReadError!usize {
+    if (windows.is_the_target and !builtin.link_libc) {
+        var index: usize = 0;
+        while (index < buffer.len) {
+            const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(math.maxInt(windows.DWORD)), buffer.len - index));
+            var amt_read: windows.DWORD = undefined;
+            if (windows.ReadFile(fd, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
+                const err = windows.GetLastError();
+                return switch (err) {
+                    windows.ERROR.OPERATION_ABORTED => continue,
+                    windows.ERROR.BROKEN_PIPE => return index,
+                    else => unexpectedErrorWindows(err),
+                };
+            }
+            if (amt_read == 0) return index;
+            index += amt_read;
+        }
+        return index;
+    }
+
+    if (wasi.is_the_target and !builtin.link_libc) {
+        const iovs = [1]was.iovec_t{wasi.iovec_t{
+            .buf = buf.ptr,
+            .buf_len = buf.len,
+        }};
+
+        var nread: usize = undefined;
+        switch (fd_read(fd, &iovs, iovs.len, &nread)) {
+            0 => return nread,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+
+    // Linux can return EINVAL when read amount is > 0x7ffff000
+    // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
+    const max_buf_len = 0x7ffff000;
+
+    var index: usize = 0;
+    while (index < buf.len) {
+        const want_to_read = math.min(buf.len - index, usize(max_buf_len));
+        const rc = system.read(fd, buf.ptr + index, want_to_read);
+        switch (system.getErrno(rc)) {
+            0 => {
+                index += rc;
+                if (rc == want_to_read) continue;
+                // Read returned less than buf.len.
+                return index;
+            },
+            EINTR => continue,
+            EINVAL => unreachable,
+            EFAULT => unreachable,
+            EAGAIN => unreachable, // This function is for blocking reads.
+            EBADF => unreachable, // Always a race condition.
+            EIO => return error.InputOutput,
+            EISDIR => return error.IsDir,
+            ENOBUFS => return error.SystemResources,
+            ENOMEM => return error.SystemResources,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+    return index;
+}
+
+/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `preadvAsync`.
+pub fn preadv(fd: FileHandle, iov: [*]const iovec, count: usize, offset: u64) ReadError!usize {
+    if (os.darwin.is_the_target) {
+        // Darwin does not have preadv but it does have pread.
+        var off: usize = 0;
+        var iov_i: usize = 0;
+        var inner_off: usize = 0;
+        while (true) {
+            const v = iov[iov_i];
+            const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+            const err = darwin.getErrno(rc);
+            switch (err) {
+                0 => {
+                    off += rc;
+                    inner_off += rc;
+                    if (inner_off == v.iov_len) {
+                        iov_i += 1;
+                        inner_off = 0;
+                        if (iov_i == count) {
+                            return off;
+                        }
+                    }
+                    if (rc == 0) return off; // EOF
+                    continue;
+                },
+                EINTR => continue,
+                EINVAL => unreachable,
+                EFAULT => unreachable,
+                ESPIPE => unreachable, // fd is not seekable
+                EAGAIN => unreachable, // This function is for blocking reads.
+                EBADF => unreachable, // always a race condition
+                EIO => return error.InputOutput,
+                EISDIR => return error.IsDir,
+                ENOBUFS => return error.SystemResources,
+                ENOMEM => return error.SystemResources,
+                else => return unexpectedErrno(err),
+            }
+        }
+    }
+    while (true) {
+        const rc = system.preadv(fd, iov, count, offset);
+        const err = system.getErrno(rc);
+        switch (err) {
+            0 => return rc,
+            EINTR => continue,
+            EINVAL => unreachable,
+            EFAULT => unreachable,
+            EAGAIN => unreachable, // This function is for blocking reads.
+            EBADF => unreachable, // always a race condition
+            EIO => return error.InputOutput,
+            EISDIR => return error.IsDir,
+            ENOBUFS => return error.SystemResources,
+            ENOMEM => return error.SystemResources,
+            else => return unexpectedErrno(err),
+        }
+    }
+}
+
+pub const WriteError = error{
+    DiskQuota,
+    FileTooBig,
+    InputOutput,
+    NoSpaceLeft,
+    AccessDenied,
+    BrokenPipe,
+    SystemResources,
+    OperationAborted,
+    Unexpected,
+};
+
+/// Write to a file descriptor. Keeps trying if it gets interrupted.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `writeAsync`.
+pub fn write(fd: FileHandle, bytes: []const u8) WriteError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        var bytes_written: windows.DWORD = undefined;
+        // TODO replace this @intCast with a loop that writes all the bytes
+        if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
+            switch (windows.GetLastError()) {
+                windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources,
+                windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
+                windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
+                windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
+                windows.ERROR.IO_PENDING => unreachable,
+                windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
+                else => |err| return unexpectedErrorWindows(err),
+            }
+        }
+    }
+
+    if (wasi.is_the_target and !builtin.link_libc) {
+        const ciovs = [1]wasi.ciovec_t{wasi.ciovec_t{
+            .buf = bytes.ptr,
+            .buf_len = bytes.len,
+        }};
+        var nwritten: usize = undefined;
+        switch (fd_write(fd, &ciovs, ciovs.len, &nwritten)) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+
+    // Linux can return EINVAL when write amount is > 0x7ffff000
+    // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
+    const max_bytes_len = 0x7ffff000;
+
+    var index: usize = 0;
+    while (index < bytes.len) {
+        const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
+        const rc = system.write(fd, bytes.ptr + index, amt_to_write);
+        const write_err = system.getErrno(rc);
+        switch (write_err) {
+            0 => {
+                index += rc;
+                continue;
+            },
+            EINTR => continue,
+            EINVAL => unreachable,
+            EFAULT => unreachable,
+            EAGAIN => unreachable, // This function is for blocking writes.
+            EBADF => unreachable, // Always a race condition.
+            EDESTADDRREQ => unreachable, // `connect` was never called.
+            EDQUOT => return error.DiskQuota,
+            EFBIG => return error.FileTooBig,
+            EIO => return error.InputOutput,
+            ENOSPC => return error.NoSpaceLeft,
+            EPERM => return error.AccessDenied,
+            EPIPE => return error.BrokenPipe,
+            else => return unexpectedErrno(write_err),
+        }
+    }
+}
+
+/// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `pwritevAsync`.
+pub fn pwritev(fd: FileHandle, iov: [*]const iovec_const, count: usize, offset: u64) WriteError!void {
+    if (darwin.is_the_target) {
+        // Darwin does not have pwritev but it does have pwrite.
+        var off: usize = 0;
+        var iov_i: usize = 0;
+        var inner_off: usize = 0;
+        while (true) {
+            const v = iov[iov_i];
+            const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+            const err = darwin.getErrno(rc);
+            switch (err) {
+                0 => {
+                    off += rc;
+                    inner_off += rc;
+                    if (inner_off == v.iov_len) {
+                        iov_i += 1;
+                        inner_off = 0;
+                        if (iov_i == count) {
+                            return;
+                        }
+                    }
+                    continue;
+                },
+                EINTR => continue,
+                ESPIPE => unreachable, // `fd` is not seekable.
+                EINVAL => unreachable,
+                EFAULT => unreachable,
+                EAGAIN => unreachable, // This function is for blocking writes.
+                EBADF => unreachable, // Always a race condition.
+                EDESTADDRREQ => unreachable, // `connect` was never called.
+                EDQUOT => return error.DiskQuota,
+                EFBIG => return error.FileTooBig,
+                EIO => return error.InputOutput,
+                ENOSPC => return error.NoSpaceLeft,
+                EPERM => return error.AccessDenied,
+                EPIPE => return error.BrokenPipe,
+                else => return unexpectedErrno(err),
+            }
+        }
+    }
+
+    while (true) {
+        const rc = system.pwritev(fd, iov, count, offset);
+        const err = system.getErrno(rc);
+        switch (err) {
+            0 => return,
+            EINTR => continue,
+            EINVAL => unreachable,
+            EFAULT => unreachable,
+            EAGAIN => unreachable, // This function is for blocking writes.
+            EBADF => unreachable, // Always a race condition.
+            EDESTADDRREQ => unreachable, // `connect` was never called.
+            EDQUOT => return error.DiskQuota,
+            EFBIG => return error.FileTooBig,
+            EIO => return error.InputOutput,
+            ENOSPC => return error.NoSpaceLeft,
+            EPERM => return error.AccessDenied,
+            EPIPE => return error.BrokenPipe,
+            else => return unexpectedErrno(err),
+        }
+    }
+}
+
+pub const OpenError = error{
+    AccessDenied,
+    FileTooBig,
+    IsDir,
+    SymLinkLoop,
+    ProcessFdQuotaExceeded,
+    NameTooLong,
+    SystemFdQuotaExceeded,
+    NoDevice,
+    FileNotFound,
+    SystemResources,
+    NoSpaceLeft,
+    NotDir,
+    PathAlreadyExists,
+    DeviceBusy,
+    Unexpected,
+};
+
+/// Open and possibly create a file. Keeps trying if it gets interrupted.
+/// `file_path` needs to be copied in memory to add a null terminating byte.
+/// See also `openC`.
+pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!FileHandle {
+    const file_path_c = try toPosixPath(file_path);
+    return openC(&file_path_c, flags, perm);
+}
+
+/// Open and possibly create a file. Keeps trying if it gets interrupted.
+/// See also `open`.
+/// TODO https://github.com/ziglang/zig/issues/265
+pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!FileHandle {
+    while (true) {
+        const rc = system.open(file_path, flags, perm);
+        switch (system.getErrno(rc)) {
+            0 => return @intCast(FileHandle, rc),
+            EINTR => continue,
+
+            EFAULT => unreachable,
+            EINVAL => unreachable,
+            EACCES => return error.AccessDenied,
+            EFBIG => return error.FileTooBig,
+            EOVERFLOW => return error.FileTooBig,
+            EISDIR => return error.IsDir,
+            ELOOP => return error.SymLinkLoop,
+            EMFILE => return error.ProcessFdQuotaExceeded,
+            ENAMETOOLONG => return error.NameTooLong,
+            ENFILE => return error.SystemFdQuotaExceeded,
+            ENODEV => return error.NoDevice,
+            ENOENT => return error.FileNotFound,
+            ENOMEM => return error.SystemResources,
+            ENOSPC => return error.NoSpaceLeft,
+            ENOTDIR => return error.NotDir,
+            EPERM => return error.AccessDenied,
+            EEXIST => return error.PathAlreadyExists,
+            EBUSY => return error.DeviceBusy,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+}
+
+pub const WindowsOpenError = error{
+    SharingViolation,
+    PathAlreadyExists,
+
+    /// When any of the path components can not be found or the file component can not
+    /// be found. Some operating systems distinguish between path components not found and
+    /// file components not found, but they are collapsed into FileNotFound to gain
+    /// consistency across operating systems.
+    FileNotFound,
+
+    AccessDenied,
+    PipeBusy,
+    NameTooLong,
+
+    /// On Windows, file paths must be valid Unicode.
+    InvalidUtf8,
+
+    /// On Windows, file paths cannot contain these characters:
+    /// '/', '*', '?', '"', '<', '>', '|'
+    BadPathName,
+
+    Unexpected,
+};
+
+pub fn openWindows(
+    file_path: []const u8,
+    desired_access: windows.DWORD,
+    share_mode: windows.DWORD,
+    creation_disposition: windows.DWORD,
+    flags_and_attrs: windows.DWORD,
+) WindowsOpenError!FileHandle {
+    const file_path_w = try sliceToPrefixedFileW(file_path);
+    return openW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
+}
+
+pub fn openW(
+    file_path_w: [*]const u16,
+    desired_access: windows.DWORD,
+    share_mode: windows.DWORD,
+    creation_disposition: windows.DWORD,
+    flags_and_attrs: windows.DWORD,
+) WindowsOpenError!windows.HANDLE {
+    const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
+
+    if (result == windows.INVALID_HANDLE_VALUE) {
+        const err = windows.GetLastError();
+        switch (err) {
+            windows.ERROR.SHARING_VIOLATION => return error.SharingViolation,
+            windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
+            windows.ERROR.FILE_EXISTS => return error.PathAlreadyExists,
+            windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+            windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+            windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
+            windows.ERROR.PIPE_BUSY => return error.PipeBusy,
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+
+    return result;
+}
+
+pub fn dup2(old_fd: FileHandle, new_fd: FileHandle) !void {
+    while (true) {
+        switch (system.getErrno(system.dup2(old_fd, new_fd))) {
+            0 => return,
+            EBUSY, EINTR => continue,
+            EMFILE => return error.ProcessFdQuotaExceeded,
+            EINVAL => unreachable,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+}
+
+/// This function must allocate memory to add a null terminating bytes on path and each arg.
+/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
+/// pointers after the args and after the environment variables.
+/// `argv[0]` is the executable path.
+/// This function also uses the PATH environment variable to get the full path to the executable.
+pub fn execve(allocator: *Allocator, argv: []const []const u8, env_map: *const BufMap) !void {
+    const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
+    mem.set(?[*]u8, argv_buf, null);
+    defer {
+        for (argv_buf) |arg| {
+            const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
+            allocator.free(arg_buf);
+        }
+        allocator.free(argv_buf);
+    }
+    for (argv) |arg, i| {
+        const arg_buf = try allocator.alloc(u8, arg.len + 1);
+        @memcpy(arg_buf.ptr, arg.ptr, arg.len);
+        arg_buf[arg.len] = 0;
+
+        argv_buf[i] = arg_buf.ptr;
+    }
+    argv_buf[argv.len] = null;
+
+    const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
+    defer freeNullDelimitedEnvMap(allocator, envp_buf);
+
+    const exe_path = argv[0];
+    if (mem.indexOfScalar(u8, exe_path, '/') != null) {
+        return execveErrnoToErr(system.getErrno(system.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
+    }
+
+    const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
+    // PATH.len because it is >= the largest search_path
+    // +1 for the / to join the search path and exe_path
+    // +1 for the null terminating byte
+    const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
+    defer allocator.free(path_buf);
+    var it = mem.tokenize(PATH, ":");
+    var seen_eacces = false;
+    var err: usize = undefined;
+    while (it.next()) |search_path| {
+        mem.copy(u8, path_buf, search_path);
+        path_buf[search_path.len] = '/';
+        mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
+        path_buf[search_path.len + exe_path.len + 1] = 0;
+        err = system.getErrno(system.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
+        assert(err > 0);
+        if (err == EACCES) {
+            seen_eacces = true;
+        } else if (err != ENOENT) {
+            return execveErrnoToErr(err);
+        }
+    }
+    if (seen_eacces) {
+        err = EACCES;
+    }
+    return execveErrnoToErr(err);
+}
+
+pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
+    const envp_count = env_map.count();
+    const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
+    mem.set(?[*]u8, envp_buf, null);
+    errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
+    {
+        var it = env_map.iterator();
+        var i: usize = 0;
+        while (it.next()) |pair| : (i += 1) {
+            const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
+            @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
+            env_buf[pair.key.len] = '=';
+            @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
+            env_buf[env_buf.len - 1] = 0;
+
+            envp_buf[i] = env_buf.ptr;
+        }
+        assert(i == envp_count);
+    }
+    assert(envp_buf[envp_count] == null);
+    return envp_buf;
+}
+
+pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
+    for (envp_buf) |env| {
+        const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
+        allocator.free(env_buf);
+    }
+    allocator.free(envp_buf);
+}
+
+pub const ExecveError = error{
+    SystemResources,
+    AccessDenied,
+    InvalidExe,
+    FileSystem,
+    IsDir,
+    FileNotFound,
+    NotDir,
+    FileBusy,
+
+    Unexpected,
+};
+
+fn execveErrnoToErr(err: usize) ExecveError {
+    assert(err > 0);
+    switch (err) {
+        EFAULT => unreachable,
+        E2BIG => return error.SystemResources,
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        ENOMEM => return error.SystemResources,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EINVAL => return error.InvalidExe,
+        ENOEXEC => return error.InvalidExe,
+        EIO => return error.FileSystem,
+        ELOOP => return error.FileSystem,
+        EISDIR => return error.IsDir,
+        ENOENT => return error.FileNotFound,
+        ENOTDIR => return error.NotDir,
+        ETXTBSY => return error.FileBusy,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Get an environment variable.
+/// See also `getenvC`.
+/// TODO make this go through libc when we have it
+pub fn getenv(key: []const u8) ?[]const u8 {
+    for (environ) |ptr| {
+        var line_i: usize = 0;
+        while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
+        const this_key = ptr[0..line_i];
+        if (!mem.eql(u8, key, this_key)) continue;
+
+        var end_i: usize = line_i;
+        while (ptr[end_i] != 0) : (end_i += 1) {}
+        const this_value = ptr[line_i + 1 .. end_i];
+
+        return this_value;
+    }
+    return null;
+}
+
+/// Get an environment variable with a null-terminated name.
+/// See also `getenv`.
+/// TODO https://github.com/ziglang/zig/issues/265
+pub fn getenvC(key: [*]const u8) ?[]const u8 {
+    if (builtin.link_libc) {
+        const value = std.c.getenv(key) orelse return null;
+        return mem.toSliceConst(u8, value);
+    }
+    return getenv(mem.toSliceConst(u8, key));
+}
+
+/// See std.elf for the constants.
+pub fn getauxval(index: usize) usize {
+    if (builtin.link_libc) {
+        return usize(std.c.getauxval(index));
+    } else if (linux.elf_aux_maybe) |auxv| {
+        var i: usize = 0;
+        while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
+            if (auxv[i].a_type == index)
+                return auxv[i].a_un.a_val;
+        }
+    }
+    return 0;
+}
+
+pub const GetCwdError = error{
+    NameTooLong,
+    CurrentWorkingDirectoryUnlinked,
+    Unexpected,
+};
+
+/// The result is a slice of out_buffer, indexed from 0.
+pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
+    if (windows.is_the_target and !builtin.link_libc) {
+        var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+        const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
+        const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
+        const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
+        if (result == 0) {
+            const err = windows.GetLastError();
+            switch (err) {
+                else => return unexpectedErrorWindows(err),
+            }
+        }
+        assert(result <= utf16le_buf.len);
+        const utf16le_slice = utf16le_buf[0..result];
+        // Trust that Windows gives us valid UTF-16LE.
+        var end_index: usize = 0;
+        var it = std.unicode.Utf16LeIterator.init(utf16le);
+        while (it.nextCodepoint() catch unreachable) |codepoint| {
+            if (end_index + std.unicode.utf8CodepointSequenceLength(codepoint) >= out_buffer.len)
+                return error.NameTooLong;
+            end_index += utf8Encode(codepoint, out_buffer[end_index..]) catch unreachable;
+        }
+        return out_buffer[0..end_index];
+    }
+
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.getcwd(out_buffer.ptr, out_buffer.len)) |_| 0 else std.c._errno().*;
+    } else blk: {
+        break :blk system.getErrno(system.getcwd(out_buffer, out_buffer.len));
+    };
+    switch (err) {
+        0 => return mem.toSlice(u8, out_buffer),
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        ENOENT => return error.CurrentWorkingDirectoryUnlinked,
+        ERANGE => return error.NameTooLong,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+test "getcwd" {
+    // at least call it so it gets compiled
+    var buf: [os.MAX_PATH_BYTES]u8 = undefined;
+    _ = getcwd(&buf) catch {};
+}
+
+pub const SymLinkError = error{
+    AccessDenied,
+    DiskQuota,
+    PathAlreadyExists,
+    FileSystem,
+    SymLinkLoop,
+    FileNotFound,
+    SystemResources,
+    NoSpaceLeft,
+    ReadOnlyFileSystem,
+    NotDir,
+    NameTooLong,
+    InvalidUtf8,
+    BadPathName,
+    Unexpected,
+};
+
+/// Creates a symbolic link named `new_path` which contains the string `target_path`.
+/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
+/// one; the latter case is known as a dangling link.
+/// If `new_path` exists, it will not be overwritten.
+/// See also `symlinkC` and `symlinkW`.
+pub fn symlink(target_path: []const u8, new_path: []const u8) SymLinkError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const target_path_w = try cStrToPrefixedFileW(target_path);
+        const new_path_w = try cStrToPrefixedFileW(new_path);
+        return symlinkW(&target_path_w, &new_path_w);
+    } else {
+        const target_path_c = try toPosixPath(target_path);
+        const new_path_c = try toPosixPath(new_path);
+        return symlinkC(&target_path_c, &new_path_c);
+    }
+}
+
+pub fn symlinkat(target_path: []const u8, newdirfd: FileHandle, new_path: []const u8) SymLinkError!void {
+    const target_path_c = try toPosixPath(target_path);
+    const new_path_c = try toPosixPath(new_path);
+    return symlinkatC(target_path_c, newdirfd, new_path_c);
+}
+
+pub fn symlinkatC(target_path: [*]const u8, newdirfd: FileHandle, new_path: [*]const u8) SymLinkError!void {
+    const err = blk: {
+        if (builtin.link_libc) {
+            break :blk if (std.c.symlinkat(target_path, newdirfd, new_path) == -1) errno().* else 0;
+        } else {
+            break :blk system.getErrno(system.symlinkat(target_path, newdirfd, new_path));
+        }
+    };
+    switch (err) {
+        0 => return,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EDQUOT => return error.DiskQuota,
+        EEXIST => return error.PathAlreadyExists,
+        EIO => return error.FileSystem,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOTDIR => return error.NotDir,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.NoSpaceLeft,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// This is the same as `symlink` except the parameters are null-terminated pointers.
+/// See also `symlink` and `symlinkW`.
+pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const target_path_w = try cStrToPrefixedFileW(target_path);
+        const new_path_w = try cStrToPrefixedFileW(new_path);
+        return symlinkW(&target_path_w, &new_path_w);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.symlink(target_path, new_path) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "symlink")) blk: {
+        break :blk system.getErrno(system.symlink(target_path, new_path));
+    } else blk: {
+        break :blk system.getErrno(system.symlinkat(target_path, AT_FDCWD, new_path));
+    };
+    switch (err) {
+        0 => return,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EDQUOT => return error.DiskQuota,
+        EEXIST => return error.PathAlreadyExists,
+        EIO => return error.FileSystem,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOTDIR => return error.NotDir,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.NoSpaceLeft,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// This is the same as `symlink` except the parameters are null-terminated pointers to
+/// UTF-16LE encoded strings.
+/// See also `symlink` and `symlinkC`.
+/// TODO handle when linking libc
+pub fn symlinkW(target_path_w: [*]const u16, new_path_w: [*]const u16) SymLinkError!void {
+    if (windows.CreateSymbolicLinkW(target_path_w, new_path_w, 0) == 0) {
+        const err = windows.GetLastError();
+        switch (err) {
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+}
+
+pub const UnlinkError = error{
+    FileNotFound,
+    AccessDenied,
+    FileBusy,
+    FileSystem,
+    IsDir,
+    SymLinkLoop,
+    NameTooLong,
+    NotDir,
+    SystemResources,
+    ReadOnlyFileSystem,
+    Unexpected,
+
+    /// On Windows, file paths must be valid Unicode.
+    InvalidUtf8,
+
+    /// On Windows, file paths cannot contain these characters:
+    /// '/', '*', '?', '"', '<', '>', '|'
+    BadPathName,
+};
+
+/// Delete a name and possibly the file it refers to.
+pub fn unlink(file_path: []const u8) UnlinkError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const file_path_w = try sliceToPrefixedFileW(file_path);
+        return unlinkW(&file_path_w);
+    } else {
+        const file_path_c = try toPosixPath(file_path);
+        return unlinkC(&file_path_c);
+    }
+}
+
+/// Same as `unlink` except the parameter is a UTF16LE-encoded string.
+/// TODO handle when linking libc
+pub fn unlinkW(file_path: [*]const u16) UnlinkError!void {
+    if (windows.unlinkW(file_path) == 0) {
+        const err = windows.GetLastError();
+        switch (err) {
+            windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+            windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
+            windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
+            windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+}
+
+/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
+pub fn unlinkC(file_path: [*]const u8) UnlinkError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const file_path_w = try cStrToPrefixedFileW(file_path);
+        return unlinkW(&file_path_w);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.unlink(file_path) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "unlink")) blk: {
+        break :blk system.getErrno(system.unlink(file_path));
+    } else blk: {
+        break :blk system.getErrno(system.unlinkat(AT_FDCWD, file_path, 0));
+    };
+    switch (err) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EBUSY => return error.FileBusy,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        EIO => return error.FileSystem,
+        EISDIR => return error.IsDir,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOTDIR => return error.NotDir,
+        ENOMEM => return error.SystemResources,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => return unexpectedErrno(err),
+    }
+}
+
+const RenameError = error{}; // TODO
+
+/// Change the name or location of a file.
+pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const old_path_w = try sliceToPrefixedFileW(old_path);
+        const new_path_w = try sliceToPrefixedFileW(new_path);
+        return renameW(&old_path_w, &new_path_w);
+    } else {
+        const old_path_c = try toPosixPath(old_path);
+        const new_path_c = try toPosixPath(new_path);
+        return renameC(&old_path_c, &new_path_c);
+    }
+}
+
+/// Same as `rename` except the parameters are null-terminated byte arrays.
+pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const old_path_w = try cStrToPrefixedFileW(old_path);
+        const new_path_w = try cStrToPrefixedFileW(new_path);
+        return renameW(&old_path_w, &new_path_w);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.rename(old_path, new_path) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "rename")) blk: {
+        break :blk system.getErrno(system.rename(old_path, new_path));
+    } else if (@hasDecl(system, "renameat")) blk: {
+        break :blk system.getErrno(system.renameat(AT_FDCWD, old_path, AT_FDCWD, new_path));
+    } else blk: {
+        break :blk system.getErrno(system.renameat2(AT_FDCWD, old_path, AT_FDCWD, new_path, 0));
+    };
+    switch (err) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EBUSY => return error.FileBusy,
+        EDQUOT => return error.DiskQuota,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        EISDIR => return error.IsDir,
+        ELOOP => return error.SymLinkLoop,
+        EMLINK => return error.LinkQuotaExceeded,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOTDIR => return error.NotDir,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.NoSpaceLeft,
+        EEXIST => return error.PathAlreadyExists,
+        ENOTEMPTY => return error.PathAlreadyExists,
+        EROFS => return error.ReadOnlyFileSystem,
+        EXDEV => return error.RenameAcrossMountPoints,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Same as `rename` except the parameters are null-terminated UTF16LE-encoded strings.
+/// TODO handle when linking libc
+pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
+    const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
+    if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
+        const err = windows.GetLastError();
+        switch (err) {
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+}
+
+pub const MakeDirError = error{};
+
+/// Create a directory.
+/// `mode` is ignored on Windows.
+pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try sliceToPrefixedFileW(dir_path);
+        return mkdirW(&dir_path_w, mode);
+    } else {
+        const dir_path_c = try toPosixPath(dir_path);
+        return mkdirC(&dir_path_c, mode);
+    }
+}
+
+/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
+pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try cStrToPrefixedFileW(dir_path);
+        return mkdirW(&dir_path_w, mode);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.mkdir(dir_path, mode) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "mkdir")) blk: {
+        break :blk system.getErrno(system.mkdir(dir_path, mode));
+    } else blk: {
+        break :blk system.getErrno(system.mkdirat(AT_FDCWD, dir_path, mode));
+    };
+    switch (err) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EDQUOT => return error.DiskQuota,
+        EEXIST => return error.PathAlreadyExists,
+        EFAULT => unreachable,
+        ELOOP => return error.SymLinkLoop,
+        EMLINK => return error.LinkQuotaExceeded,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.NoSpaceLeft,
+        ENOTDIR => return error.NotDir,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Same as `mkdir` but the parameter is a null-terminated UTF16LE-encoded string.
+pub fn mkdirW(dir_path: []const u8, mode: u32) MakeDirError!void {
+    const dir_path_w = try sliceToPrefixedFileW(dir_path);
+
+    if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
+        const err = windows.GetLastError();
+        switch (err) {
+            windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
+            windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+}
+
+pub const DeleteDirError = error{
+    AccessDenied,
+    FileBusy,
+    SymLinkLoop,
+    NameTooLong,
+    FileNotFound,
+    SystemResources,
+    NotDir,
+    DirNotEmpty,
+    ReadOnlyFileSystem,
+    InvalidUtf8,
+    BadPathName,
+    Unexpected,
+};
+
+/// Deletes an empty directory.
+pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try sliceToPrefixedFileW(dir_path);
+        return rmdirW(&dir_path_w);
+    } else {
+        const dir_path_c = try toPosixPath(dir_path);
+        return rmdirC(&dir_path_c);
+    }
+}
+
+/// Same as `rmdir` except the parameter is a null-terminated UTF8-encoded string.
+pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try cStrToPrefixedFileW(dir_path);
+        return rmdirW(&dir_path_w);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.rmdir(dir_path) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "rmdir")) blk: {
+        break :blk system.getErrno(system.rmdir(dir_path));
+    } else blk: {
+        break :blk system.getErrno(system.unlinkat(AT_FDCWD, dir_path, AT_REMOVEDIR));
+    };
+    switch (err) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EPERM => return error.AccessDenied,
+        EBUSY => return error.FileBusy,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOTDIR => return error.NotDir,
+        EEXIST => return error.DirNotEmpty,
+        ENOTEMPTY => return error.DirNotEmpty,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Same as `rmdir` except the parameter is a null-terminated UTF16LE-encoded string.
+/// TODO handle linking libc
+pub fn rmdirW(dir_path_w: [*]const u16) DeleteDirError!void {
+    if (windows.RemoveDirectoryW(dir_path_w) == 0) {
+        const err = windows.GetLastError();
+        switch (err) {
+            windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+            windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
+            else => return unexpectedErrorWindows(err),
+        }
+    }
+}
+
+pub const ChangeCurDirError = error{};
+
+/// Changes the current working directory of the calling process.
+/// `dir_path` is recommended to be a UTF-8 encoded string.
+pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try sliceToPrefixedFileW(dir_path);
+        return chdirW(&dir_path_w);
+    } else {
+        const dir_path_c = try toPosixPath(dir_path);
+        return chdirC(&dir_path_c);
+    }
+}
+
+/// Same as `chdir` except the parameter is null-terminated.
+pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const dir_path_w = try cStrToPrefixedFileW(dir_path);
+        return chdirW(&dir_path_w);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.chdir(dir_path) == -1) errno().* else 0;
+    } else blk: {
+        break :blk system.getErrno(system.chdir(dir_path));
+    };
+    switch (err) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EFAULT => unreachable,
+        EIO => return error.FileSystem,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOTDIR => return error.NotDir,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Same as `chdir` except the parameter is a null-terminated, UTF16LE-encoded string.
+/// TODO handle linking libc
+pub fn chdirW(dir_path: [*]const u16) ChangeCurDirError!void {
+    @compileError("TODO implement chdir for Windows");
+}
+
+pub const ReadLinkError = error{};
+
+/// Read value of a symbolic link.
+/// The return value is a slice of `out_buffer` from index 0.
+pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const file_path_w = try sliceToPrefixedFileW(file_path);
+        return readlinkW(&file_path_w, out_buffer);
+    } else {
+        const file_path_c = try toPosixPath(file_path);
+        return readlinkC(&file_path_c, out_buffer);
+    }
+}
+
+/// Same as `readlink` except `file_path` is null-terminated.
+pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
+    if (windows.is_the_target and !builtin.link_libc) {
+        const file_path_w = try cStrToPrefixedFileW(file_path);
+        return readlinkW(&file_path_w, out_buffer);
+    }
+    const err = if (builtin.link_libc) blk: {
+        break :blk if (std.c.readlink(file_path, out_buffer.ptr, out_buffer.len) == -1) errno().* else 0;
+    } else if (@hasDecl(system, "readlink")) blk: {
+        break :blk system.getErrno(system.readlink(file_path, out_buffer.ptr, out_buffer.len));
+    } else blk: {
+        break :blk system.getErrno(system.readlinkat(AT_FDCWD, file_path, out_buffer.ptr, out_buffer.len));
+    };
+    const rc = system.readlink(file_path, out_buffer, out_buffer.len);
+    switch (system.getErrno(rc)) {
+        0 => return out_buffer[0..rc],
+        EACCES => return error.AccessDenied,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        EIO => return error.FileSystem,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOTDIR => return error.NotDir,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const SetIdError = error{
+    ResourceLimitReached,
+    InvalidUserId,
+    PermissionDenied,
+    Unexpected,
+};
+
+pub fn setuid(uid: u32) SetIdError!void {
+    switch (system.getErrno(system.setuid(uid))) {
+        0 => return,
+        EAGAIN => return error.ResourceLimitReached,
+        EINVAL => return error.InvalidUserId,
+        EPERM => return error.PermissionDenied,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub fn setreuid(ruid: u32, euid: u32) SetIdError!void {
+    switch (system.getErrno(system.setreuid(ruid, euid))) {
+        0 => return,
+        EAGAIN => return error.ResourceLimitReached,
+        EINVAL => return error.InvalidUserId,
+        EPERM => return error.PermissionDenied,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub fn setgid(gid: u32) SetIdError!void {
+    switch (system.getErrno(system.setgid(gid))) {
+        0 => return,
+        EAGAIN => return error.ResourceLimitReached,
+        EINVAL => return error.InvalidUserId,
+        EPERM => return error.PermissionDenied,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
+    switch (system.getErrno(system.setregid(rgid, egid))) {
+        0 => return,
+        EAGAIN => return error.ResourceLimitReached,
+        EINVAL => return error.InvalidUserId,
+        EPERM => return error.PermissionDenied,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const GetStdHandleError = error{
+    NoStandardHandleAttached,
+    Unexpected,
+};
+
+pub fn GetStdHandle(handle_id: windows.DWORD) GetStdHandleError!FileHandle {
+    if (windows.is_the_target) {
+        const handle = windows.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached;
+        if (handle == windows.INVALID_HANDLE_VALUE) {
+            switch (windows.GetLastError()) {
+                else => |err| unexpectedErrorWindows(err),
+            }
+        }
+        return handle;
+    }
+
+    switch (handle_id) {
+        windows.STD_ERROR_HANDLE => return STDERR_FILENO,
+        windows.STD_OUTPUT_HANDLE => return STDOUT_FILENO,
+        windows.STD_INPUT_HANDLE => return STDIN_FILENO,
+        else => unreachable,
+    }
+}
+
+/// Test whether a file descriptor refers to a terminal.
+pub fn isatty(handle: FileHandle) bool {
+    if (builtin.link_libc) {
+        return c.isatty(handle) != 0;
+    }
+    if (windows.is_the_target) {
+        if (isCygwinPty(handle))
+            return true;
+
+        var out: windows.DWORD = undefined;
+        return windows.GetConsoleMode(handle, &out) != 0;
+    }
+    if (wasi.is_the_target) {
+        @compileError("TODO implement std.os.posix.isatty for WASI");
+    }
+
+    var wsz: system.winsize = undefined;
+    return system.syscall3(system.SYS_ioctl, @bitCast(usize, isize(handle)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
+}
+
+pub fn isCygwinPty(handle: FileHandle) bool {
+    if (!windows.is_the_target) return false;
+
+    const size = @sizeOf(windows.FILE_NAME_INFO);
+    var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
+
+    if (windows.GetFileInformationByHandleEx(
+        handle,
+        windows.FileNameInfo,
+        @ptrCast(*c_void, &name_info_bytes[0]),
+        @intCast(u32, name_info_bytes.len),
+    ) == 0) {
+        return false;
+    }
+
+    const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
+    const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
+    const name_wide = @bytesToSlice(u16, name_bytes);
+    return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
+        mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
+}
+
+pub const SocketError = error{
+    /// Permission to create a socket of the specified type and/or
+    /// proโ€tocol is denied.
+    PermissionDenied,
+
+    /// The implementation does not support the specified address family.
+    AddressFamilyNotSupported,
+
+    /// Unknown protocol, or protocol family not available.
+    ProtocolFamilyNotAvailable,
+
+    /// The per-process limit on the number of open file descriptors has been reached.
+    ProcessFdQuotaExceeded,
+
+    /// The system-wide limit on the total number of open files has been reached.
+    SystemFdQuotaExceeded,
+
+    /// Insufficient memory is available. The socket cannot be created until sufficient
+    /// resources are freed.
+    SystemResources,
+
+    /// The protocol type or the specified protocol is not supported within this domain.
+    ProtocolNotSupported,
+
+    Unexpected,
+};
+
+pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 {
+    const rc = system.socket(domain, socket_type, protocol);
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        EACCES => return error.PermissionDenied,
+        EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+        EINVAL => return error.ProtocolFamilyNotAvailable,
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        ENOBUFS, ENOMEM => return error.SystemResources,
+        EPROTONOSUPPORT => return error.ProtocolNotSupported,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const BindError = error{
+    /// The address is protected, and the user is not the superuser.
+    /// For UNIX domain sockets: Search permission is denied on  a  component
+    /// of  the  path  prefix.
+    AccessDenied,
+
+    /// The given address is already in use, or in the case of Internet domain sockets,
+    /// The  port number was specified as zero in the socket
+    /// address structure, but, upon attempting to bind to  an  ephemeral  port,  it  was
+    /// determined  that  all  port  numbers in the ephemeral port range are currently in
+    /// use.  See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
+    AddressInUse,
+
+    /// A nonexistent interface was requested or the requested address was not local.
+    AddressNotAvailable,
+
+    /// Too many symbolic links were encountered in resolving addr.
+    SymLinkLoop,
+
+    /// addr is too long.
+    NameTooLong,
+
+    /// A component in the directory prefix of the socket pathname does not exist.
+    FileNotFound,
+
+    /// Insufficient kernel memory was available.
+    SystemResources,
+
+    /// A component of the path prefix is not a directory.
+    NotDir,
+
+    /// The socket inode would reside on a read-only filesystem.
+    ReadOnlyFileSystem,
+
+    Unexpected,
+};
+
+/// addr is `*const T` where T is one of the sockaddr
+pub fn bind(fd: i32, addr: *const sockaddr) BindError!void {
+    const rc = system.bind(fd, system, @sizeOf(sockaddr));
+    switch (system.getErrno(rc)) {
+        0 => return,
+        EACCES => return error.AccessDenied,
+        EADDRINUSE => return error.AddressInUse,
+        EBADF => unreachable, // always a race condition if this error is returned
+        EINVAL => unreachable,
+        ENOTSOCK => unreachable,
+        EADDRNOTAVAIL => return error.AddressNotAvailable,
+        EFAULT => unreachable,
+        ELOOP => return error.SymLinkLoop,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOTDIR => return error.NotDir,
+        EROFS => return error.ReadOnlyFileSystem,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+const ListenError = error{
+    /// Another socket is already listening on the same port.
+    /// For Internet domain sockets, the  socket referred to by sockfd had not previously
+    /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
+    /// was determined that all port numbers in the ephemeral port range are currently in
+    /// use.  See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
+    AddressInUse,
+
+    /// The file descriptor sockfd does not refer to a socket.
+    FileDescriptorNotASocket,
+
+    /// The socket is not of a type that supports the listen() operation.
+    OperationNotSupported,
+
+    Unexpected,
+};
+
+pub fn listen(sockfd: i32, backlog: u32) ListenError!void {
+    const rc = system.listen(sockfd, backlog);
+    switch (system.getErrno(rc)) {
+        0 => return,
+        EADDRINUSE => return error.AddressInUse,
+        EBADF => unreachable,
+        ENOTSOCK => return error.FileDescriptorNotASocket,
+        EOPNOTSUPP => return error.OperationNotSupported,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const AcceptError = error{
+    ConnectionAborted,
+
+    /// The per-process limit on the number of open file descriptors has been reached.
+    ProcessFdQuotaExceeded,
+
+    /// The system-wide limit on the total number of open files has been reached.
+    SystemFdQuotaExceeded,
+
+    /// Not enough free memory.  This often means that the memory allocation  is  limited
+    /// by the socket buffer limits, not by the system memory.
+    SystemResources,
+
+    /// The file descriptor sockfd does not refer to a socket.
+    FileDescriptorNotASocket,
+
+    /// The referenced socket is not of type SOCK_STREAM.
+    OperationNotSupported,
+
+    ProtocolFailure,
+
+    /// Firewall rules forbid connection.
+    BlockedByFirewall,
+
+    Unexpected,
+};
+
+/// Accept a connection on a socket. `fd` must be opened in blocking mode.
+/// See also `accept4_async`.
+pub fn accept4(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
+    while (true) {
+        var sockaddr_size = u32(@sizeOf(sockaddr));
+        const rc = system.accept4(fd, addr, &sockaddr_size, flags);
+        switch (system.getErrno(rc)) {
+            0 => return @intCast(i32, rc),
+            EINTR => continue,
+            else => |err| return unexpectedErrno(err),
+
+            EAGAIN => unreachable, // This function is for blocking only.
+            EBADF => unreachable, // always a race condition
+            ECONNABORTED => return error.ConnectionAborted,
+            EFAULT => unreachable,
+            EINVAL => unreachable,
+            EMFILE => return error.ProcessFdQuotaExceeded,
+            ENFILE => return error.SystemFdQuotaExceeded,
+            ENOBUFS => return error.SystemResources,
+            ENOMEM => return error.SystemResources,
+            ENOTSOCK => return error.FileDescriptorNotASocket,
+            EOPNOTSUPP => return error.OperationNotSupported,
+            EPROTO => return error.ProtocolFailure,
+            EPERM => return error.BlockedByFirewall,
+        }
+    }
+}
+
+/// This is the same as `accept4` except `fd` is expected to be non-blocking.
+/// Returns -1 if would block.
+pub fn accept4_async(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
+    while (true) {
+        var sockaddr_size = u32(@sizeOf(sockaddr));
+        const rc = system.accept4(fd, addr, &sockaddr_size, flags);
+        switch (system.getErrno(rc)) {
+            0 => return @intCast(i32, rc),
+            EINTR => continue,
+            else => |err| return unexpectedErrno(err),
+
+            EAGAIN => return -1,
+            EBADF => unreachable, // always a race condition
+            ECONNABORTED => return error.ConnectionAborted,
+            EFAULT => unreachable,
+            EINVAL => unreachable,
+            EMFILE => return error.ProcessFdQuotaExceeded,
+            ENFILE => return error.SystemFdQuotaExceeded,
+            ENOBUFS => return error.SystemResources,
+            ENOMEM => return error.SystemResources,
+            ENOTSOCK => return error.FileDescriptorNotASocket,
+            EOPNOTSUPP => return error.OperationNotSupported,
+            EPROTO => return error.ProtocolFailure,
+            EPERM => return error.BlockedByFirewall,
+        }
+    }
+}
+
+pub const EpollCreateError = error{
+    /// The  per-user   limit   on   the   number   of   epoll   instances   imposed   by
+    /// /proc/sys/fs/epoll/max_user_instances  was encountered.  See epoll(7) for further
+    /// details.
+    /// Or, The per-process limit on the number of open file descriptors has been reached.
+    ProcessFdQuotaExceeded,
+
+    /// The system-wide limit on the total number of open files has been reached.
+    SystemFdQuotaExceeded,
+
+    /// There was insufficient memory to create the kernel object.
+    SystemResources,
+
+    Unexpected,
+};
+
+pub fn epoll_create1(flags: u32) EpollCreateError!i32 {
+    const rc = system.epoll_create1(flags);
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        else => |err| return unexpectedErrno(err),
+
+        EINVAL => unreachable,
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        ENOMEM => return error.SystemResources,
+    }
+}
+
+pub const EpollCtlError = error{
+    /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is  already  registered
+    /// with this epoll instance.
+    FileDescriptorAlreadyPresentInSet,
+
+    /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
+    /// circular loop of epoll instances monitoring one another.
+    OperationCausesCircularLoop,
+
+    /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with  this  epoll
+    /// instance.
+    FileDescriptorNotRegistered,
+
+    /// There was insufficient memory to handle the requested op control operation.
+    SystemResources,
+
+    /// The  limit  imposed  by /proc/sys/fs/epoll/max_user_watches was encountered while
+    /// trying to register (EPOLL_CTL_ADD) a new file descriptor on  an  epoll  instance.
+    /// See epoll(7) for further details.
+    UserResourceLimitReached,
+
+    /// The target file fd does not support epoll.  This error can occur if fd refers to,
+    /// for example, a regular file or a directory.
+    FileDescriptorIncompatibleWithEpoll,
+
+    Unexpected,
+};
+
+pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: *epoll_event) EpollCtlError!void {
+    const rc = system.epoll_ctl(epfd, op, fd, event);
+    switch (system.getErrno(rc)) {
+        0 => return,
+        else => |err| return unexpectedErrno(err),
+
+        EBADF => unreachable, // always a race condition if this happens
+        EEXIST => return error.FileDescriptorAlreadyPresentInSet,
+        EINVAL => unreachable,
+        ELOOP => return error.OperationCausesCircularLoop,
+        ENOENT => return error.FileDescriptorNotRegistered,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.UserResourceLimitReached,
+        EPERM => return error.FileDescriptorIncompatibleWithEpoll,
+    }
+}
+
+/// Waits for an I/O event on an epoll file descriptor.
+/// Returns the number of file descriptors ready for the requested I/O,
+/// or zero if no file descriptor became ready during the requested timeout milliseconds.
+pub fn epoll_wait(epfd: i32, events: []epoll_event, timeout: i32) usize {
+    while (true) {
+        // TODO get rid of the @intCast
+        const rc = system.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
+        switch (system.getErrno(rc)) {
+            0 => return rc,
+            EINTR => continue,
+            EBADF => unreachable,
+            EFAULT => unreachable,
+            EINVAL => unreachable,
+            else => unreachable,
+        }
+    }
+}
+
+pub const EventFdError = error{
+    SystemResources,
+    ProcessFdQuotaExceeded,
+    SystemFdQuotaExceeded,
+    Unexpected,
+};
+
+pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
+    const rc = system.eventfd(initval, flags);
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        else => |err| return unexpectedErrno(err),
+
+        EINVAL => unreachable, // invalid parameters
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        ENODEV => return error.SystemResources,
+        ENOMEM => return error.SystemResources,
+    }
+}
+
+pub const GetSockNameError = error{
+    /// Insufficient resources were available in the system to perform the operation.
+    SystemResources,
+
+    Unexpected,
+};
+
+pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr {
+    var addr: sockaddr = undefined;
+    var addrlen: socklen_t = @sizeOf(sockaddr);
+    switch (system.getErrno(system.getsockname(sockfd, &addr, &addrlen))) {
+        0 => return addr,
+        else => |err| return unexpectedErrno(err),
+
+        EBADF => unreachable, // always a race condition
+        EFAULT => unreachable,
+        EINVAL => unreachable, // invalid parameters
+        ENOTSOCK => unreachable,
+        ENOBUFS => return error.SystemResources,
+    }
+}
+
+pub const ConnectError = error{
+    /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on  the  socket
+    /// file,  or  search  permission  is  denied  for  one of the directories in the path prefix.
+    /// or
+    /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled  or
+    /// the connection request failed because of a local firewall rule.
+    PermissionDenied,
+
+    /// Local address is already in use.
+    AddressInUse,
+
+    /// (Internet  domain  sockets)  The  socket  referred  to  by sockfd had not previously been bound to an
+    /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
+    /// in    the    ephemeral    port    range    are   currently   in   use.    See   the   discussion   of
+    /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
+    AddressNotAvailable,
+
+    /// The passed address didn't have the correct address family in its sa_family field.
+    AddressFamilyNotSupported,
+
+    /// Insufficient entries in the routing cache.
+    SystemResources,
+
+    /// A connect() on a stream socket found no one listening on the remote address.
+    ConnectionRefused,
+
+    /// Network is unreachable.
+    NetworkUnreachable,
+
+    /// Timeout  while  attempting  connection.   The server may be too busy to accept new connections.  Note
+    /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
+    ConnectionTimedOut,
+
+    Unexpected,
+};
+
+/// Initiate a connection on a socket.
+/// This is for blocking file descriptors only.
+/// For non-blocking, see `connect_async`.
+pub fn connect(sockfd: i32, sockaddr: *const sockaddr) ConnectError!void {
+    while (true) {
+        switch (system.getErrno(system.connect(sockfd, sockaddr, @sizeOf(sockaddr)))) {
+            0 => return,
+            else => |err| return unexpectedErrno(err),
+
+            EACCES => return error.PermissionDenied,
+            EPERM => return error.PermissionDenied,
+            EADDRINUSE => return error.AddressInUse,
+            EADDRNOTAVAIL => return error.AddressNotAvailable,
+            EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+            EAGAIN => return error.SystemResources,
+            EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+            EBADF => unreachable, // sockfd is not a valid open file descriptor.
+            ECONNREFUSED => return error.ConnectionRefused,
+            EFAULT => unreachable, // The socket structure address is outside the user's address space.
+            EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
+            EINTR => continue,
+            EISCONN => unreachable, // The socket is already connected.
+            ENETUNREACH => return error.NetworkUnreachable,
+            ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+            EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+            ETIMEDOUT => return error.ConnectionTimedOut,
+        }
+    }
+}
+
+/// Same as `connect` except it is for blocking socket file descriptors.
+/// It expects to receive EINPROGRESS`.
+pub fn connect_async(sockfd: i32, sockaddr: *const c_void, len: u32) ConnectError!void {
+    while (true) {
+        switch (system.getErrno(system.connect(sockfd, sockaddr, len))) {
+            0, EINPROGRESS => return,
+            EINTR => continue,
+            else => return unexpectedErrno(err),
+
+            EACCES => return error.PermissionDenied,
+            EPERM => return error.PermissionDenied,
+            EADDRINUSE => return error.AddressInUse,
+            EADDRNOTAVAIL => return error.AddressNotAvailable,
+            EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+            EAGAIN => return error.SystemResources,
+            EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+            EBADF => unreachable, // sockfd is not a valid open file descriptor.
+            ECONNREFUSED => return error.ConnectionRefused,
+            EFAULT => unreachable, // The socket structure address is outside the user's address space.
+            EISCONN => unreachable, // The socket is already connected.
+            ENETUNREACH => return error.NetworkUnreachable,
+            ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+            EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+            ETIMEDOUT => return error.ConnectionTimedOut,
+        }
+    }
+}
+
+pub fn getsockoptError(sockfd: i32) ConnectError!void {
+    var err_code: i32 = undefined;
+    var size: u32 = @sizeOf(i32);
+    const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);
+    assert(size == 4);
+    switch (system.getErrno(rc)) {
+        0 => switch (err_code) {
+            0 => return,
+            EACCES => return error.PermissionDenied,
+            EPERM => return error.PermissionDenied,
+            EADDRINUSE => return error.AddressInUse,
+            EADDRNOTAVAIL => return error.AddressNotAvailable,
+            EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+            EAGAIN => return error.SystemResources,
+            EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+            EBADF => unreachable, // sockfd is not a valid open file descriptor.
+            ECONNREFUSED => return error.ConnectionRefused,
+            EFAULT => unreachable, // The socket structure address is outside the user's address space.
+            EISCONN => unreachable, // The socket is already connected.
+            ENETUNREACH => return error.NetworkUnreachable,
+            ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+            EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+            ETIMEDOUT => return error.ConnectionTimedOut,
+            else => |err| return unexpectedErrno(err),
+        },
+        EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
+        EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
+        EINVAL => unreachable,
+        ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
+        ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub fn wait(pid: i32) i32 {
+    var status: i32 = undefined;
+    while (true) {
+        switch (system.getErrno(system.waitpid(pid, &status, 0))) {
+            0 => return status,
+            EINTR => continue,
+            ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
+            EINVAL => unreachable, // The options argument was invalid
+            else => unreachable,
+        }
+    }
+}
+
+pub fn fstat(fd: FileHandle) !Stat {
+    var stat: Stat = undefined;
+    switch (system.getErrno(system.fstat(fd, &stat))) {
+        0 => return stat,
+        EBADF => unreachable, // Always a race condition.
+        ENOMEM => return error.SystemResources,
+        else => |err| return unexpectedErrno(err),
+    }
+
+    return stat;
+}
+
+pub const KQueueError = error{
+    /// The per-process limit on the number of open file descriptors has been reached.
+    ProcessFdQuotaExceeded,
+
+    /// The system-wide limit on the total number of open files has been reached.
+    SystemFdQuotaExceeded,
+
+    Unexpected,
+};
+
+pub fn kqueue() KQueueError!i32 {
+    const rc = system.kqueue();
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const KEventError = error{
+    /// The process does not have permission to register a filter.
+    AccessDenied,
+
+    /// The event could not be found to be modified or deleted.
+    EventNotFound,
+
+    /// No memory was available to register the event.
+    SystemResources,
+
+    /// The specified process to attach to does not exist.
+    ProcessNotFound,
+};
+
+pub fn kevent(
+    kq: i32,
+    changelist: []const Kevent,
+    eventlist: []Kevent,
+    timeout: ?*const timespec,
+) KEventError!usize {
+    while (true) {
+        const rc = system.kevent(kq, changelist, eventlist, timeout);
+        switch (system.getErrno(rc)) {
+            0 => return rc,
+            EACCES => return error.AccessDenied,
+            EFAULT => unreachable,
+            EBADF => unreachable, // Always a race condition.
+            EINTR => continue,
+            EINVAL => unreachable,
+            ENOENT => return error.EventNotFound,
+            ENOMEM => return error.SystemResources,
+            ESRCH => return error.ProcessNotFound,
+            else => unreachable,
+        }
+    }
+}
+
+pub const INotifyInitError = error{
+    ProcessFdQuotaExceeded,
+    SystemFdQuotaExceeded,
+    SystemResources,
+    Unexpected,
+};
+
+/// initialize an inotify instance
+pub fn inotify_init1(flags: u32) INotifyInitError!i32 {
+    const rc = system.inotify_init1(flags);
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        EINVAL => unreachable,
+        EMFILE => return error.ProcessFdQuotaExceeded,
+        ENFILE => return error.SystemFdQuotaExceeded,
+        ENOMEM => return error.SystemResources,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+pub const INotifyAddWatchError = error{
+    AccessDenied,
+    NameTooLong,
+    FileNotFound,
+    SystemResources,
+    UserResourceLimitReached,
+    Unexpected,
+};
+
+/// add a watch to an initialized inotify instance
+pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 {
+    const pathname_c = try toPosixPath(pathname);
+    return inotify_add_watchC(inotify_fd, &pathname_c, mask);
+}
+
+/// Same as `inotify_add_watch` except pathname is null-terminated.
+pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 {
+    const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
+    switch (system.getErrno(rc)) {
+        0 => return @intCast(i32, rc),
+        EACCES => return error.AccessDenied,
+        EBADF => unreachable,
+        EFAULT => unreachable,
+        EINVAL => unreachable,
+        ENAMETOOLONG => return error.NameTooLong,
+        ENOENT => return error.FileNotFound,
+        ENOMEM => return error.SystemResources,
+        ENOSPC => return error.UserResourceLimitReached,
+        else => |err| return unexpectedErrno(err),
+    }
+}
+
+/// remove an existing watch from an inotify instance
+pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
+    switch (system.getErrno(system.inotify_rm_watch(inotify_fd, wd))) {
+        0 => return,
+        EBADF => unreachable,
+        EINVAL => unreachable,
+        else => unreachable,
+    }
+}
+
+pub const MProtectError = error{
+    AccessDenied,
+    OutOfMemory,
+    Unexpected,
+};
+
+/// address and length must be page-aligned
+pub fn mprotect(address: usize, length: usize, protection: u32) MProtectError!void {
+    const negative_page_size = @bitCast(usize, -isize(page_size));
+    const aligned_address = address & negative_page_size;
+    const aligned_end = (address + length + page_size - 1) & negative_page_size;
+    assert(address == aligned_address);
+    assert(length == aligned_end - aligned_address);
+    switch (system.getErrno(system.mprotect(address, length, protection))) {
+        0 => return,
+        EINVAL => unreachable,
+        EACCES => return error.AccessDenied,
+        ENOMEM => return error.OutOfMemory,
+        else => return unexpectedErrno(err),
+    }
+}
+
+/// Used to convert a slice to a null terminated slice on the stack.
+/// TODO https://github.com/ziglang/zig/issues/287
+pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
+    var path_with_null: [PATH_MAX]u8 = undefined;
+    // >= rather than > to make room for the null byte
+    if (file_path.len >= PATH_MAX) return error.NameTooLong;
+    mem.copy(u8, &path_with_null, file_path);
+    path_with_null[file_path.len] = 0;
+    return path_with_null;
+}
+
+const unexpected_error_tracing = builtin.mode == .Debug;
+const UnexpectedError = error{
+    /// The Operating System returned an undocumented error code.
+    Unexpected,
+};
+
+/// Call this when you made a syscall or something that sets errno
+/// and you get an unexpected error.
+pub fn unexpectedErrno(errno: usize) UnexpectedError {
+    if (unexpected_error_tracing) {
+        std.debug.warn("unexpected errno: {}\n", errno);
+        std.debug.dumpCurrentStackTrace(null);
+    }
+    return error.Unexpected;
+}
+
+/// Call this when you made a windows DLL call or something that does SetLastError
+/// and you get an unexpected error.
+pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
+    if (unexpected_error_tracing) {
+        std.debug.warn("unexpected GetLastError(): {}\n", err);
+        std.debug.dumpCurrentStackTrace(null);
+    }
+    return error.Unexpected;
+}
+
+pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
+    return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
+}
+
+pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
+    return sliceToPrefixedSuffixedFileW(s, []u16{0});
+}
+
+pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
+    // TODO well defined copy elision
+    var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
+
+    // > File I/O functions in the Windows API convert "/" to "\" as part of
+    // > converting the name to an NT-style name, except when using the "\\?\"
+    // > prefix as detailed in the following sections.
+    // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
+    // Because we want the larger maximum path length for absolute paths, we
+    // disallow forward slashes in zig std lib file functions on Windows.
+    for (s) |byte| {
+        switch (byte) {
+            '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
+            else => {},
+        }
+    }
+    const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
+        const prefix = []u16{ '\\', '\\', '?', '\\' };
+        mem.copy(u16, result[0..], prefix);
+        break :blk prefix.len;
+    };
+    const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
+    assert(end_index <= result.len);
+    if (end_index + suffix.len > result.len) return error.NameTooLong;
+    mem.copy(u16, result[end_index..], suffix);
+    return result;
+}
std/os/wasi.zig
@@ -1,42 +1,393 @@
-pub use @import("wasi/core.zig");
+// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
+// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
+const std = @import("std");
+const assert = std.debug.assert;
+
+pub const is_the_target = @import("builtin").os == .wasi;
 
 pub const STDIN_FILENO = 0;
 pub const STDOUT_FILENO = 1;
 pub const STDERR_FILENO = 2;
 
-pub fn getErrno(r: usize) usize {
-    const signed_r = @bitCast(isize, r);
-    return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+comptime {
+    assert(@alignOf(i8) == 1);
+    assert(@alignOf(u8) == 1);
+    assert(@alignOf(i16) == 2);
+    assert(@alignOf(u16) == 2);
+    assert(@alignOf(i32) == 4);
+    assert(@alignOf(u32) == 4);
+    assert(@alignOf(i64) == 8);
+    assert(@alignOf(u64) == 8);
 }
 
-pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
-    var nwritten: usize = undefined;
+pub const advice_t = u8;
+pub const ADVICE_NORMAL: advice_t = 0;
+pub const ADVICE_SEQUENTIAL: advice_t = 1;
+pub const ADVICE_RANDOM: advice_t = 2;
+pub const ADVICE_WILLNEED: advice_t = 3;
+pub const ADVICE_DONTNEED: advice_t = 4;
+pub const ADVICE_NOREUSE: advice_t = 5;
 
-    const ciovs = ciovec_t{
-        .buf = buf,
-        .buf_len = count,
-    };
+pub const ciovec_t = extern struct {
+    buf: [*]const u8,
+    buf_len: usize,
+};
 
-    const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten);
-    if (err == ESUCCESS) {
-        return nwritten;
-    } else {
-        return @bitCast(usize, -isize(err));
-    }
-}
+pub const clockid_t = u32;
+pub const CLOCK_REALTIME: clockid_t = 0;
+pub const CLOCK_MONOTONIC: clockid_t = 1;
+pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
+pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
 
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
-    var nread: usize = undefined;
+pub const device_t = u64;
 
-    const iovs = iovec_t{
-        .buf = buf,
-        .buf_len = nbyte,
-    };
+pub const dircookie_t = u64;
+pub const DIRCOOKIE_START: dircookie_t = 0;
 
-    const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread);
-    if (err == ESUCCESS) {
-        return nread;
-    } else {
-        return @bitCast(usize, -isize(err));
-    }
-}
+pub const dirent_t = extern struct {
+    d_next: dircookie_t,
+    d_ino: inode_t,
+    d_namlen: u32,
+    d_type: filetype_t,
+};
+
+pub const errno_t = u16;
+pub const ESUCCESS: errno_t = 0;
+pub const E2BIG: errno_t = 1;
+pub const EACCES: errno_t = 2;
+pub const EADDRINUSE: errno_t = 3;
+pub const EADDRNOTAVAIL: errno_t = 4;
+pub const EAFNOSUPPORT: errno_t = 5;
+pub const EAGAIN: errno_t = 6;
+pub const EALREADY: errno_t = 7;
+pub const EBADF: errno_t = 8;
+pub const EBADMSG: errno_t = 9;
+pub const EBUSY: errno_t = 10;
+pub const ECANCELED: errno_t = 11;
+pub const ECHILD: errno_t = 12;
+pub const ECONNABORTED: errno_t = 13;
+pub const ECONNREFUSED: errno_t = 14;
+pub const ECONNRESET: errno_t = 15;
+pub const EDEADLK: errno_t = 16;
+pub const EDESTADDRREQ: errno_t = 17;
+pub const EDOM: errno_t = 18;
+pub const EDQUOT: errno_t = 19;
+pub const EEXIST: errno_t = 20;
+pub const EFAULT: errno_t = 21;
+pub const EFBIG: errno_t = 22;
+pub const EHOSTUNREACH: errno_t = 23;
+pub const EIDRM: errno_t = 24;
+pub const EILSEQ: errno_t = 25;
+pub const EINPROGRESS: errno_t = 26;
+pub const EINTR: errno_t = 27;
+pub const EINVAL: errno_t = 28;
+pub const EIO: errno_t = 29;
+pub const EISCONN: errno_t = 30;
+pub const EISDIR: errno_t = 31;
+pub const ELOOP: errno_t = 32;
+pub const EMFILE: errno_t = 33;
+pub const EMLINK: errno_t = 34;
+pub const EMSGSIZE: errno_t = 35;
+pub const EMULTIHOP: errno_t = 36;
+pub const ENAMETOOLONG: errno_t = 37;
+pub const ENETDOWN: errno_t = 38;
+pub const ENETRESET: errno_t = 39;
+pub const ENETUNREACH: errno_t = 40;
+pub const ENFILE: errno_t = 41;
+pub const ENOBUFS: errno_t = 42;
+pub const ENODEV: errno_t = 43;
+pub const ENOENT: errno_t = 44;
+pub const ENOEXEC: errno_t = 45;
+pub const ENOLCK: errno_t = 46;
+pub const ENOLINK: errno_t = 47;
+pub const ENOMEM: errno_t = 48;
+pub const ENOMSG: errno_t = 49;
+pub const ENOPROTOOPT: errno_t = 50;
+pub const ENOSPC: errno_t = 51;
+pub const ENOSYS: errno_t = 52;
+pub const ENOTCONN: errno_t = 53;
+pub const ENOTDIR: errno_t = 54;
+pub const ENOTEMPTY: errno_t = 55;
+pub const ENOTRECOVERABLE: errno_t = 56;
+pub const ENOTSOCK: errno_t = 57;
+pub const ENOTSUP: errno_t = 58;
+pub const ENOTTY: errno_t = 59;
+pub const ENXIO: errno_t = 60;
+pub const EOVERFLOW: errno_t = 61;
+pub const EOWNERDEAD: errno_t = 62;
+pub const EPERM: errno_t = 63;
+pub const EPIPE: errno_t = 64;
+pub const EPROTO: errno_t = 65;
+pub const EPROTONOSUPPORT: errno_t = 66;
+pub const EPROTOTYPE: errno_t = 67;
+pub const ERANGE: errno_t = 68;
+pub const EROFS: errno_t = 69;
+pub const ESPIPE: errno_t = 70;
+pub const ESRCH: errno_t = 71;
+pub const ESTALE: errno_t = 72;
+pub const ETIMEDOUT: errno_t = 73;
+pub const ETXTBSY: errno_t = 74;
+pub const EXDEV: errno_t = 75;
+pub const ENOTCAPABLE: errno_t = 76;
+
+pub const event_t = extern struct {
+    userdata: userdata_t,
+    @"error": errno_t,
+    @"type": eventtype_t,
+    u: extern union {
+        fd_readwrite: extern struct {
+            nbytes: filesize_t,
+            flags: eventrwflags_t,
+        },
+    },
+};
+
+pub const eventrwflags_t = u16;
+pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
+
+pub const eventtype_t = u8;
+pub const EVENTTYPE_CLOCK: eventtype_t = 0;
+pub const EVENTTYPE_FD_READ: eventtype_t = 1;
+pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
+
+pub const exitcode_t = u32;
+
+pub const fd_t = u32;
+
+pub const fdflags_t = u16;
+pub const FDFLAG_APPEND: fdflags_t = 0x0001;
+pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
+pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
+pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
+pub const FDFLAG_SYNC: fdflags_t = 0x0010;
+
+const fdstat_t = extern struct {
+    fs_filetype: filetype_t,
+    fs_flags: fdflags_t,
+    fs_rights_base: rights_t,
+    fs_rights_inheriting: rights_t,
+};
+
+pub const filedelta_t = i64;
+
+pub const filesize_t = u64;
+
+pub const filestat_t = extern struct {
+    st_dev: device_t,
+    st_ino: inode_t,
+    st_filetype: filetype_t,
+    st_nlink: linkcount_t,
+    st_size: filesize_t,
+    st_atim: timestamp_t,
+    st_mtim: timestamp_t,
+    st_ctim: timestamp_t,
+};
+
+pub const filetype_t = u8;
+pub const FILETYPE_UNKNOWN: filetype_t = 0;
+pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
+pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
+pub const FILETYPE_DIRECTORY: filetype_t = 3;
+pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
+pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
+pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
+pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
+
+pub const fstflags_t = u16;
+pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
+pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
+pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
+pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
+
+pub const inode_t = u64;
+
+pub const iovec_t = extern struct {
+    buf: [*]u8,
+    buf_len: usize,
+};
+
+pub const linkcount_t = u32;
+
+pub const lookupflags_t = u32;
+pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
+
+pub const oflags_t = u16;
+pub const O_CREAT: oflags_t = 0x0001;
+pub const O_DIRECTORY: oflags_t = 0x0002;
+pub const O_EXCL: oflags_t = 0x0004;
+pub const O_TRUNC: oflags_t = 0x0008;
+
+pub const preopentype_t = u8;
+pub const PREOPENTYPE_DIR: preopentype_t = 0;
+
+pub const prestat_t = extern struct {
+    pr_type: preopentype_t,
+    u: extern union {
+        dir: extern struct {
+            pr_name_len: usize,
+        },
+    },
+};
+
+pub const riflags_t = u16;
+pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
+pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
+
+pub const rights_t = u64;
+pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
+pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
+pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
+pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
+pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
+pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
+pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
+pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
+pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
+pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
+pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
+pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
+pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
+pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
+pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
+pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
+pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
+pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
+pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
+pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
+pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
+pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
+pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
+pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
+pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
+pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
+pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
+pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
+pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
+
+pub const roflags_t = u16;
+pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
+
+pub const sdflags_t = u8;
+pub const SHUT_RD: sdflags_t = 0x01;
+pub const SHUT_WR: sdflags_t = 0x02;
+
+pub const siflags_t = u16;
+
+pub const signal_t = u8;
+pub const SIGHUP: signal_t = 1;
+pub const SIGINT: signal_t = 2;
+pub const SIGQUIT: signal_t = 3;
+pub const SIGILL: signal_t = 4;
+pub const SIGTRAP: signal_t = 5;
+pub const SIGABRT: signal_t = 6;
+pub const SIGBUS: signal_t = 7;
+pub const SIGFPE: signal_t = 8;
+pub const SIGKILL: signal_t = 9;
+pub const SIGUSR1: signal_t = 10;
+pub const SIGSEGV: signal_t = 11;
+pub const SIGUSR2: signal_t = 12;
+pub const SIGPIPE: signal_t = 13;
+pub const SIGALRM: signal_t = 14;
+pub const SIGTERM: signal_t = 15;
+pub const SIGCHLD: signal_t = 16;
+pub const SIGCONT: signal_t = 17;
+pub const SIGSTOP: signal_t = 18;
+pub const SIGTSTP: signal_t = 19;
+pub const SIGTTIN: signal_t = 20;
+pub const SIGTTOU: signal_t = 21;
+pub const SIGURG: signal_t = 22;
+pub const SIGXCPU: signal_t = 23;
+pub const SIGXFSZ: signal_t = 24;
+pub const SIGVTALRM: signal_t = 25;
+pub const SIGPROF: signal_t = 26;
+pub const SIGWINCH: signal_t = 27;
+pub const SIGPOLL: signal_t = 28;
+pub const SIGPWR: signal_t = 29;
+pub const SIGSYS: signal_t = 30;
+
+pub const subclockflags_t = u16;
+pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
+
+pub const subscription_t = extern struct {
+    userdata: userdata_t,
+    @"type": eventtype_t,
+    u: extern union {
+        clock: extern struct {
+            identifier: userdata_t,
+            clock_id: clockid_t,
+            timeout: timestamp_t,
+            precision: timestamp_t,
+            flags: subclockflags_t,
+        },
+        fd_readwrite: extern struct {
+            fd: fd_t,
+        },
+    },
+};
+
+pub const timestamp_t = u64;
+
+pub const userdata_t = u64;
+
+pub const whence_t = u8;
+pub const WHENCE_CUR: whence_t = 0;
+pub const WHENCE_END: whence_t = 1;
+pub const WHENCE_SET: whence_t = 2;
+
+pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
+
+pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
+pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
+
+pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
+
+pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
+pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, nread: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
+
+pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
+pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
+pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
+
+pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
+pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
+
+pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
+pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
+pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
+pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
+pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
+pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
+
+pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
+pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
+
+pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn sched_yield() errno_t;
+
+pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
+pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
+pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/windows.zig
@@ -2,6 +2,11 @@ const std = @import("../std.zig");
 const assert = std.debug.assert;
 const maxInt = std.math.maxInt;
 
+pub const is_the_target = switch (builtin.os) {
+    .windows => true,
+    else => false,
+};
+
 pub use @import("windows/advapi32.zig");
 pub use @import("windows/kernel32.zig");
 pub use @import("windows/ntdll.zig");
@@ -9,10 +14,13 @@ pub use @import("windows/ole32.zig");
 pub use @import("windows/shell32.zig");
 
 test "import" {
-    _ = @import("windows/util.zig");
+    if (is_the_target) {
+        _ = @import("windows/util.zig");
+    }
 }
 
 pub const ERROR = @import("windows/error.zig");
+pub const errno_codes = @import("windows/errno.zig");
 
 pub const SHORT = c_short;
 pub const BOOL = c_int;
std/special/bootstrap.zig
@@ -81,7 +81,7 @@ fn posixCallMainAndExit() noreturn {
     if (builtin.os == builtin.Os.linux) {
         // Find the beginning of the auxiliary vector
         const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
-        std.os.linux_elf_aux_maybe = auxv;
+        std.os.linux.elf_aux_maybe = auxv;
         // Initialize the TLS area
         std.os.linux.tls.initTLS();
 
@@ -99,7 +99,7 @@ fn posixCallMainAndExit() noreturn {
 // and we want fewer call frames in stack traces.
 inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
     std.os.ArgIteratorPosix.raw = argv[0..argc];
-    std.os.posix_environ_raw = envp;
+    std.os.posix.environ = envp;
     return callMain();
 }
 
std/c.zig
@@ -1,15 +1,24 @@
 const builtin = @import("builtin");
-const Os = builtin.Os;
+
+pub const is_the_target = builtin.link_libc;
 
 pub use switch (builtin.os) {
-    Os.linux => @import("c/linux.zig"),
-    Os.windows => @import("c/windows.zig"),
-    Os.macosx, Os.ios => @import("c/darwin.zig"),
-    Os.freebsd => @import("c/freebsd.zig"),
-    Os.netbsd => @import("c/netbsd.zig"),
+    .linux => @import("c/linux.zig"),
+    .windows => @import("c/windows.zig"),
+    .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
+    .freebsd => @import("c/freebsd.zig"),
+    .netbsd => @import("c/netbsd.zig"),
     else => struct {},
 };
 
+pub fn getErrno(rc: var) u12 {
+    if (rc == -1) {
+        return @intCast(u12, _errno().*);
+    } else {
+        return 0;
+    }
+}
+
 // TODO https://github.com/ziglang/zig/issues/265 on this whole file
 
 pub const FILE = @OpaqueType();
@@ -56,6 +65,7 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
 pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
 pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
 pub extern "c" fn rmdir(path: [*]const u8) c_int;
+pub extern "c" fn getenv(name: [*]const u8) ?[*]u8;
 
 pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
 pub extern "c" fn malloc(usize) ?*c_void;
std/io.zig
@@ -18,23 +18,6 @@ const testing = std.testing;
 const is_posix = builtin.os != builtin.Os.windows;
 const is_windows = builtin.os == builtin.Os.windows;
 
-const GetStdIoErrs = os.WindowsGetStdHandleErrs;
-
-pub fn getStdErr() GetStdIoErrs!File {
-    const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
-    return File.openHandle(handle);
-}
-
-pub fn getStdOut() GetStdIoErrs!File {
-    const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
-    return File.openHandle(handle);
-}
-
-pub fn getStdIn() GetStdIoErrs!File {
-    const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
-    return File.openHandle(handle);
-}
-
 pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
 pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream;
 pub const COutStream = @import("io/c_out_stream.zig").COutStream;
std/os.zig
@@ -2,10 +2,6 @@ const std = @import("std.zig");
 const builtin = @import("builtin");
 const Os = builtin.Os;
 const is_windows = builtin.os == Os.windows;
-const is_posix = switch (builtin.os) {
-    builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
-    else => false,
-};
 const os = @This();
 
 comptime {
@@ -36,13 +32,13 @@ pub const zen = @import("os/zen.zig");
 pub const uefi = @import("os/uefi.zig");
 pub const wasi = @import("os/wasi.zig");
 
-pub const posix = switch (builtin.os) {
-    Os.linux => linux,
-    Os.macosx, Os.ios => darwin,
-    Os.freebsd => freebsd,
-    Os.netbsd => netbsd,
-    Os.zen => zen,
-    Os.wasi => wasi,
+pub const system = if (builtin.link_libc) c else switch (builtin.os) {
+    .linux => linux,
+    .macosx, .ios, .watchos, .tvos => darwin,
+    .freebsd => freebsd,
+    .netbsd => netbsd,
+    .zen => zen,
+    .wasi => wasi,
     else => @compileError("Unsupported OS"),
 };
 
@@ -58,13 +54,17 @@ pub const page_size = switch (builtin.arch) {
     else => 4 * 1024,
 };
 
+/// This represents the maximum size of a UTF-8 encoded file path.
+/// All file system operations which return a path are guaranteed to
+/// fit into a UTF-8 encoded array of this length.
+/// path being too long if it is this 0long
 pub const MAX_PATH_BYTES = switch (builtin.os) {
-    Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
+    .linux, .macosx, .ios, .freebsd, .netbsd => posix.PATH_MAX,
     // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
     // If it would require 4 UTF-8 bytes, then there would be a surrogate
     // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
     // +1 for the null byte at the end, which can be encoded in 1 byte.
-    Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
+    .windows => posix.PATH_MAX_WIDE * 3 + 1,
     else => @compileError("Unsupported OS"),
 };
 
@@ -98,6 +98,22 @@ pub const FileHandle = if (is_windows) windows.HANDLE else i32;
 pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
 pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
 
+pub const getRandomBytes = posix.getrandom;
+pub const abort = posix.abort;
+pub const exit = posix.exit;
+pub const symLink = posix.symlink;
+pub const symLinkC = posix.symlinkC;
+pub const symLinkW = posix.symlinkW;
+pub const deleteFile = posix.unlink;
+pub const deleteFileC = posix.unlinkC;
+pub const deleteFileW = posix.unlinkW;
+pub const rename = posix.rename;
+pub const renameC = posix.renameC;
+pub const renameW = posix.renameW;
+pub const changeCurDir = posix.chdir;
+pub const changeCurDirC = posix.chdirC;
+pub const changeCurDirW = posix.chdirW;
+
 const debug = std.debug;
 const assert = debug.assert;
 const testing = std.testing;
@@ -116,610 +132,6 @@ const ArrayList = std.ArrayList;
 const Buffer = std.Buffer;
 const math = std.math;
 
-/// Fills `buf` with random bytes. If linking against libc, this calls the
-/// appropriate OS-specific library call. Otherwise it uses the zig standard
-/// library implementation.
-pub fn getRandomBytes(buf: []u8) !void {
-    switch (builtin.os) {
-        Os.linux => while (true) {
-            // TODO check libc version and potentially call c.getrandom.
-            // See #397
-            const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
-            switch (errno) {
-                0 => return,
-                posix.EINVAL => unreachable,
-                posix.EFAULT => unreachable,
-                posix.EINTR => continue,
-                posix.ENOSYS => return getRandomBytesDevURandom(buf),
-                else => return unexpectedErrorPosix(errno),
-            }
-        },
-        Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
-        Os.windows => {
-            // Call RtlGenRandom() instead of CryptGetRandom() on Windows
-            // https://github.com/rust-lang-nursery/rand/issues/111
-            // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
-            if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
-                const err = windows.GetLastError();
-                return switch (err) {
-                    else => unexpectedErrorWindows(err),
-                };
-            }
-        },
-        Os.wasi => {
-            const random_get_result = os.wasi.random_get(buf.ptr, buf.len);
-            if (random_get_result != os.wasi.ESUCCESS) {
-                return error.Unknown;
-            }
-        },
-        Os.zen => {
-            const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
-            var i: usize = 0;
-            while (i < buf.len) : (i += 1) {
-                if (i > randomness.len) return error.Unknown;
-                buf[i] = randomness[i];
-            }
-        },
-        else => @compileError("Unsupported OS"),
-    }
-}
-
-fn getRandomBytesDevURandom(buf: []u8) !void {
-    const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
-    defer close(fd);
-
-    const stream = &File.openHandle(fd).inStream().stream;
-    stream.readNoEof(buf) catch |err| switch (err) {
-        error.EndOfStream => unreachable,
-        error.OperationAborted => unreachable,
-        error.BrokenPipe => unreachable,
-        error.Unexpected => return error.Unexpected,
-        error.InputOutput => return error.Unexpected,
-        error.SystemResources => return error.Unexpected,
-        error.IsDir => unreachable,
-    };
-}
-
-test "os.getRandomBytes" {
-    var buf_a: [50]u8 = undefined;
-    var buf_b: [50]u8 = undefined;
-    // Call Twice
-    try getRandomBytes(buf_a[0..]);
-    try getRandomBytes(buf_b[0..]);
-
-    // Check if random (not 100% conclusive)
-    testing.expect(!mem.eql(u8, buf_a, buf_b));
-}
-
-/// Raises a signal in the current kernel thread, ending its execution.
-/// If linking against libc, this calls the abort() libc function. Otherwise
-/// it uses the zig standard library implementation.
-pub fn abort() noreturn {
-    @setCold(true);
-    if (builtin.link_libc) {
-        c.abort();
-    }
-    switch (builtin.os) {
-        Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
-            _ = posix.raise(posix.SIGABRT);
-            _ = posix.raise(posix.SIGKILL);
-            while (true) {}
-        },
-        Os.windows => {
-            if (builtin.mode == builtin.Mode.Debug) {
-                @breakpoint();
-            }
-            windows.ExitProcess(3);
-        },
-        Os.wasi => {
-            _ = wasi.proc_raise(wasi.SIGABRT);
-            // TODO: Is SIGKILL even necessary?
-            _ = wasi.proc_raise(wasi.SIGKILL);
-            while (true) {}
-        },
-        Os.uefi => {
-            // TODO there's gotta be a better thing to do here than loop forever
-            while (true) {}
-        },
-        else => @compileError("Unsupported OS"),
-    }
-}
-
-/// Exits the program cleanly with the specified status code.
-pub fn exit(status: u8) noreturn {
-    @setCold(true);
-    if (builtin.link_libc) {
-        c.exit(status);
-    }
-    switch (builtin.os) {
-        Os.linux => {
-            if (builtin.single_threaded) {
-                linux.exit(status);
-            } else {
-                linux.exit_group(status);
-            }
-        },
-        Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
-            posix.exit(status);
-        },
-        Os.windows => {
-            windows.ExitProcess(status);
-        },
-        Os.wasi => {
-            wasi.proc_exit(status);
-        },
-        else => @compileError("Unsupported OS"),
-    }
-}
-
-/// When a file descriptor is closed on linux, it pops the first
-/// node from this queue and resumes it.
-/// Async functions which get the EMFILE error code can suspend,
-/// putting their coroutine handle into this list.
-/// TODO make this an atomic linked list
-pub var emfile_promise_queue = std.LinkedList(promise).init();
-
-/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
-pub fn close(handle: FileHandle) void {
-    if (is_windows) {
-        windows_util.windowsClose(handle);
-    } else {
-        while (true) {
-            const err = posix.getErrno(posix.close(handle));
-            switch (err) {
-                posix.EINTR => continue,
-                else => {
-                    if (emfile_promise_queue.popFirst()) |p| resume p.data;
-                    return;
-                },
-            }
-        }
-    }
-}
-
-pub const PosixReadError = error{
-    InputOutput,
-    SystemResources,
-    IsDir,
-    Unexpected,
-};
-
-/// Returns the number of bytes that were read, which can be less than
-/// buf.len. If 0 bytes were read, that means EOF.
-pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
-    // Linux can return EINVAL when read amount is > 0x7ffff000
-    // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
-    const max_buf_len = 0x7ffff000;
-
-    var index: usize = 0;
-    while (index < buf.len) {
-        const want_to_read = math.min(buf.len - index, usize(max_buf_len));
-        const rc = posix.read(fd, buf.ptr + index, want_to_read);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => {
-                index += rc;
-                if (rc == want_to_read) continue;
-                // Read returned less than buf.len.
-                return index;
-            },
-            posix.EINTR => continue,
-            posix.EINVAL => unreachable,
-            posix.EFAULT => unreachable,
-            posix.EAGAIN => unreachable,
-            posix.EBADF => unreachable, // always a race condition
-            posix.EIO => return error.InputOutput,
-            posix.EISDIR => return error.IsDir,
-            posix.ENOBUFS => return error.SystemResources,
-            posix.ENOMEM => return error.SystemResources,
-            else => return unexpectedErrorPosix(err),
-        }
-    }
-    return index;
-}
-
-/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
-pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
-    switch (builtin.os) {
-        builtin.Os.macosx => {
-            // Darwin does not have preadv but it does have pread.
-            var off: usize = 0;
-            var iov_i: usize = 0;
-            var inner_off: usize = 0;
-            while (true) {
-                const v = iov[iov_i];
-                const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
-                const err = darwin.getErrno(rc);
-                switch (err) {
-                    0 => {
-                        off += rc;
-                        inner_off += rc;
-                        if (inner_off == v.iov_len) {
-                            iov_i += 1;
-                            inner_off = 0;
-                            if (iov_i == count) {
-                                return off;
-                            }
-                        }
-                        if (rc == 0) return off; // EOF
-                        continue;
-                    },
-                    posix.EINTR => continue,
-                    posix.EINVAL => unreachable,
-                    posix.EFAULT => unreachable,
-                    posix.ESPIPE => unreachable, // fd is not seekable
-                    posix.EAGAIN => unreachable, // this function is not for non blocking
-                    posix.EBADF => unreachable, // always a race condition
-                    posix.EIO => return error.InputOutput,
-                    posix.EISDIR => return error.IsDir,
-                    posix.ENOBUFS => return error.SystemResources,
-                    posix.ENOMEM => return error.SystemResources,
-                    else => return unexpectedErrorPosix(err),
-                }
-            }
-        },
-        builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
-            const rc = posix.preadv(fd, iov, count, offset);
-            const err = posix.getErrno(rc);
-            switch (err) {
-                0 => return rc,
-                posix.EINTR => continue,
-                posix.EINVAL => unreachable,
-                posix.EFAULT => unreachable,
-                posix.EAGAIN => unreachable, // don't call this function for non blocking
-                posix.EBADF => unreachable, // always a race condition
-                posix.EIO => return error.InputOutput,
-                posix.EISDIR => return error.IsDir,
-                posix.ENOBUFS => return error.SystemResources,
-                posix.ENOMEM => return error.SystemResources,
-                else => return unexpectedErrorPosix(err),
-            }
-        },
-        else => @compileError("Unsupported OS"),
-    }
-}
-
-pub const PosixWriteError = error{
-    DiskQuota,
-    FileTooBig,
-    InputOutput,
-    NoSpaceLeft,
-    AccessDenied,
-    BrokenPipe,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-/// Calls POSIX write, and keeps trying if it gets interrupted.
-pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
-    // Linux can return EINVAL when write amount is > 0x7ffff000
-    // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
-    const max_bytes_len = 0x7ffff000;
-
-    var index: usize = 0;
-    while (index < bytes.len) {
-        const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
-        const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
-        const write_err = posix.getErrno(rc);
-        switch (write_err) {
-            0 => {
-                index += rc;
-                continue;
-            },
-            posix.EINTR => continue,
-            posix.EINVAL => unreachable,
-            posix.EFAULT => unreachable,
-            posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
-            posix.EBADF => unreachable, // always a race condition
-            posix.EDESTADDRREQ => unreachable, // connect was never called
-            posix.EDQUOT => return PosixWriteError.DiskQuota,
-            posix.EFBIG => return PosixWriteError.FileTooBig,
-            posix.EIO => return PosixWriteError.InputOutput,
-            posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
-            posix.EPERM => return PosixWriteError.AccessDenied,
-            posix.EPIPE => return PosixWriteError.BrokenPipe,
-            else => return unexpectedErrorPosix(write_err),
-        }
-    }
-}
-
-pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
-    switch (builtin.os) {
-        builtin.Os.macosx => {
-            // Darwin does not have pwritev but it does have pwrite.
-            var off: usize = 0;
-            var iov_i: usize = 0;
-            var inner_off: usize = 0;
-            while (true) {
-                const v = iov[iov_i];
-                const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
-                const err = darwin.getErrno(rc);
-                switch (err) {
-                    0 => {
-                        off += rc;
-                        inner_off += rc;
-                        if (inner_off == v.iov_len) {
-                            iov_i += 1;
-                            inner_off = 0;
-                            if (iov_i == count) {
-                                return;
-                            }
-                        }
-                        continue;
-                    },
-                    posix.EINTR => continue,
-                    posix.ESPIPE => unreachable, // fd is not seekable
-                    posix.EINVAL => unreachable,
-                    posix.EFAULT => unreachable,
-                    posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
-                    posix.EBADF => unreachable, // always a race condition
-                    posix.EDESTADDRREQ => unreachable, // connect was never called
-                    posix.EDQUOT => return PosixWriteError.DiskQuota,
-                    posix.EFBIG => return PosixWriteError.FileTooBig,
-                    posix.EIO => return PosixWriteError.InputOutput,
-                    posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
-                    posix.EPERM => return PosixWriteError.AccessDenied,
-                    posix.EPIPE => return PosixWriteError.BrokenPipe,
-                    else => return unexpectedErrorPosix(err),
-                }
-            }
-        },
-        builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
-            const rc = posix.pwritev(fd, iov, count, offset);
-            const err = posix.getErrno(rc);
-            switch (err) {
-                0 => return,
-                posix.EINTR => continue,
-                posix.EINVAL => unreachable,
-                posix.EFAULT => unreachable,
-                posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
-                posix.EBADF => unreachable, // always a race condition
-                posix.EDESTADDRREQ => unreachable, // connect was never called
-                posix.EDQUOT => return PosixWriteError.DiskQuota,
-                posix.EFBIG => return PosixWriteError.FileTooBig,
-                posix.EIO => return PosixWriteError.InputOutput,
-                posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
-                posix.EPERM => return PosixWriteError.AccessDenied,
-                posix.EPIPE => return PosixWriteError.BrokenPipe,
-                else => return unexpectedErrorPosix(err),
-            }
-        },
-        else => @compileError("Unsupported OS"),
-    }
-}
-
-pub const PosixOpenError = error{
-    AccessDenied,
-    FileTooBig,
-    IsDir,
-    SymLinkLoop,
-    ProcessFdQuotaExceeded,
-    NameTooLong,
-    SystemFdQuotaExceeded,
-    NoDevice,
-    FileNotFound,
-    SystemResources,
-    NoSpaceLeft,
-    NotDir,
-    PathAlreadyExists,
-    DeviceBusy,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-/// ::file_path needs to be copied in memory to add a null terminating byte.
-/// Calls POSIX open, keeps trying if it gets interrupted, and translates
-/// the return value into zig errors.
-pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
-    const file_path_c = try toPosixPath(file_path);
-    return posixOpenC(&file_path_c, flags, perm);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
-    while (true) {
-        const result = posix.open(file_path, flags, perm);
-        const err = posix.getErrno(result);
-        if (err > 0) {
-            switch (err) {
-                posix.EINTR => continue,
-
-                posix.EFAULT => unreachable,
-                posix.EINVAL => unreachable,
-                posix.EACCES => return PosixOpenError.AccessDenied,
-                posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
-                posix.EISDIR => return PosixOpenError.IsDir,
-                posix.ELOOP => return PosixOpenError.SymLinkLoop,
-                posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
-                posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
-                posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
-                posix.ENODEV => return PosixOpenError.NoDevice,
-                posix.ENOENT => return PosixOpenError.FileNotFound,
-                posix.ENOMEM => return PosixOpenError.SystemResources,
-                posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
-                posix.ENOTDIR => return PosixOpenError.NotDir,
-                posix.EPERM => return PosixOpenError.AccessDenied,
-                posix.EEXIST => return PosixOpenError.PathAlreadyExists,
-                posix.EBUSY => return PosixOpenError.DeviceBusy,
-                else => return unexpectedErrorPosix(err),
-            }
-        }
-        return @intCast(i32, result);
-    }
-}
-
-/// Used to convert a slice to a null terminated slice on the stack.
-/// TODO well defined copy elision
-pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
-    var path_with_null: [posix.PATH_MAX]u8 = undefined;
-    if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
-    mem.copy(u8, path_with_null[0..], file_path);
-    path_with_null[file_path.len] = 0;
-    return path_with_null;
-}
-
-pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
-    while (true) {
-        const err = posix.getErrno(posix.dup2(old_fd, new_fd));
-        if (err > 0) {
-            return switch (err) {
-                posix.EBUSY, posix.EINTR => continue,
-                posix.EMFILE => error.ProcessFdQuotaExceeded,
-                posix.EINVAL => unreachable,
-                else => unexpectedErrorPosix(err),
-            };
-        }
-        return;
-    }
-}
-
-pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
-    const envp_count = env_map.count();
-    const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
-    mem.set(?[*]u8, envp_buf, null);
-    errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
-    {
-        var it = env_map.iterator();
-        var i: usize = 0;
-        while (it.next()) |pair| : (i += 1) {
-            const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
-            @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
-            env_buf[pair.key.len] = '=';
-            @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
-            env_buf[env_buf.len - 1] = 0;
-
-            envp_buf[i] = env_buf.ptr;
-        }
-        assert(i == envp_count);
-    }
-    assert(envp_buf[envp_count] == null);
-    return envp_buf;
-}
-
-pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
-    for (envp_buf) |env| {
-        const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
-        allocator.free(env_buf);
-    }
-    allocator.free(envp_buf);
-}
-
-/// This function must allocate memory to add a null terminating bytes on path and each arg.
-/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
-/// pointers after the args and after the environment variables.
-/// `argv[0]` is the executable path.
-/// This function also uses the PATH environment variable to get the full path to the executable.
-pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
-    const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
-    mem.set(?[*]u8, argv_buf, null);
-    defer {
-        for (argv_buf) |arg| {
-            const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
-            allocator.free(arg_buf);
-        }
-        allocator.free(argv_buf);
-    }
-    for (argv) |arg, i| {
-        const arg_buf = try allocator.alloc(u8, arg.len + 1);
-        @memcpy(arg_buf.ptr, arg.ptr, arg.len);
-        arg_buf[arg.len] = 0;
-
-        argv_buf[i] = arg_buf.ptr;
-    }
-    argv_buf[argv.len] = null;
-
-    const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
-    defer freeNullDelimitedEnvMap(allocator, envp_buf);
-
-    const exe_path = argv[0];
-    if (mem.indexOfScalar(u8, exe_path, '/') != null) {
-        return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
-    }
-
-    const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
-    // PATH.len because it is >= the largest search_path
-    // +1 for the / to join the search path and exe_path
-    // +1 for the null terminating byte
-    const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
-    defer allocator.free(path_buf);
-    var it = mem.tokenize(PATH, ":");
-    var seen_eacces = false;
-    var err: usize = undefined;
-    while (it.next()) |search_path| {
-        mem.copy(u8, path_buf, search_path);
-        path_buf[search_path.len] = '/';
-        mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
-        path_buf[search_path.len + exe_path.len + 1] = 0;
-        err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
-        assert(err > 0);
-        if (err == posix.EACCES) {
-            seen_eacces = true;
-        } else if (err != posix.ENOENT) {
-            return posixExecveErrnoToErr(err);
-        }
-    }
-    if (seen_eacces) {
-        err = posix.EACCES;
-    }
-    return posixExecveErrnoToErr(err);
-}
-
-pub const PosixExecveError = error{
-    SystemResources,
-    AccessDenied,
-    InvalidExe,
-    FileSystem,
-    IsDir,
-    FileNotFound,
-    NotDir,
-    FileBusy,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-fn posixExecveErrnoToErr(err: usize) PosixExecveError {
-    assert(err > 0);
-    switch (err) {
-        posix.EFAULT => unreachable,
-        posix.E2BIG => return error.SystemResources,
-        posix.EMFILE => return error.SystemResources,
-        posix.ENAMETOOLONG => return error.SystemResources,
-        posix.ENFILE => return error.SystemResources,
-        posix.ENOMEM => return error.SystemResources,
-        posix.EACCES => return error.AccessDenied,
-        posix.EPERM => return error.AccessDenied,
-        posix.EINVAL => return error.InvalidExe,
-        posix.ENOEXEC => return error.InvalidExe,
-        posix.EIO => return error.FileSystem,
-        posix.ELOOP => return error.FileSystem,
-        posix.EISDIR => return error.IsDir,
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOTDIR => return error.NotDir,
-        posix.ETXTBSY => return error.FileBusy,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
-pub var posix_environ_raw: [][*]u8 = undefined;
-
-/// See std.elf for the constants.
-pub fn linuxGetAuxVal(index: usize) usize {
-    if (builtin.link_libc) {
-        return usize(std.c.getauxval(index));
-    } else if (linux_elf_aux_maybe) |auxv| {
-        var i: usize = 0;
-        while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
-            if (auxv[i].a_type == index)
-                return auxv[i].a_un.a_val;
-        }
-    }
-    return 0;
-}
-
 pub fn getBaseAddress() usize {
     switch (builtin.os) {
         builtin.Os.linux => {
@@ -803,7 +215,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
         }
         return result;
     } else {
-        for (posix_environ_raw) |ptr| {
+        for (posix.environ) |ptr| {
             var line_i: usize = 0;
             while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
             const key = ptr[0..line_i];
@@ -823,23 +235,6 @@ test "os.getEnvMap" {
     defer env.deinit();
 }
 
-/// TODO make this go through libc when we have it
-pub fn getEnvPosix(key: []const u8) ?[]const u8 {
-    for (posix_environ_raw) |ptr| {
-        var line_i: usize = 0;
-        while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
-        const this_key = ptr[0..line_i];
-        if (!mem.eql(u8, key, this_key)) continue;
-
-        var end_i: usize = line_i;
-        while (ptr[end_i] != 0) : (end_i += 1) {}
-        const this_value = ptr[line_i + 1 .. end_i];
-
-        return this_value;
-    }
-    return null;
-}
-
 pub const GetEnvVarOwnedError = error{
     OutOfMemory,
     EnvironmentVariableNotFound,
@@ -896,130 +291,22 @@ test "os.getEnvVarOwned" {
     testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
 }
 
-/// Caller must free the returned memory.
-pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
-    var buf: [MAX_PATH_BYTES]u8 = undefined;
-    return mem.dupe(allocator, u8, try getCwd(&buf));
+/// The result is a slice of `out_buffer`, from index `0`.
+pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
+    return posix.getcwd(out_buffer);
 }
 
-pub const GetCwdError = error{Unexpected};
-
-/// The result is a slice of out_buffer.
-pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
-    switch (builtin.os) {
-        Os.windows => {
-            var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
-            const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
-            const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
-            const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
-            if (result == 0) {
-                const err = windows.GetLastError();
-                switch (err) {
-                    else => return unexpectedErrorWindows(err),
-                }
-            }
-            assert(result <= utf16le_buf.len);
-            const utf16le_slice = utf16le_buf[0..result];
-            // Trust that Windows gives us valid UTF-16LE.
-            const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
-            return out_buffer[0..end_index];
-        },
-        else => {
-            const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
-            switch (err) {
-                0 => return cstr.toSlice(out_buffer),
-                posix.ERANGE => unreachable,
-                else => return unexpectedErrorPosix(err),
-            }
-        },
-    }
+/// Caller must free the returned memory.
+pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
+    var buf: [os.MAX_PATH_BYTES]u8 = undefined;
+    return mem.dupe(allocator, u8, try posix.getcwd(&buf));
 }
 
-test "os.getCwd" {
+test "getCwdAlloc" {
     // at least call it so it gets compiled
-    _ = getCwdAlloc(debug.global_allocator) catch undefined;
-    var buf: [MAX_PATH_BYTES]u8 = undefined;
-    _ = getCwd(&buf) catch undefined;
-}
-
-pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
-
-/// TODO add a symLinkC variant
-pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
-    if (is_windows) {
-        return symLinkWindows(existing_path, new_path);
-    } else {
-        return symLinkPosix(existing_path, new_path);
-    }
-}
-
-pub const WindowsSymLinkError = error{
-    NameTooLong,
-    InvalidUtf8,
-    BadPathName,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
-    if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
-        const err = windows.GetLastError();
-        switch (err) {
-            else => return unexpectedErrorWindows(err),
-        }
-    }
-}
-
-pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
-    const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
-    const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
-    return symLinkW(&existing_path_w, &new_path_w);
-}
-
-pub const PosixSymLinkError = error{
-    AccessDenied,
-    DiskQuota,
-    PathAlreadyExists,
-    FileSystem,
-    SymLinkLoop,
-    NameTooLong,
-    FileNotFound,
-    SystemResources,
-    NoSpaceLeft,
-    ReadOnlyFileSystem,
-    NotDir,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
-    const err = posix.getErrno(posix.symlink(existing_path, new_path));
-    switch (err) {
-        0 => return,
-        posix.EFAULT => unreachable,
-        posix.EINVAL => unreachable,
-        posix.EACCES => return error.AccessDenied,
-        posix.EPERM => return error.AccessDenied,
-        posix.EDQUOT => return error.DiskQuota,
-        posix.EEXIST => return error.PathAlreadyExists,
-        posix.EIO => return error.FileSystem,
-        posix.ELOOP => return error.SymLinkLoop,
-        posix.ENAMETOOLONG => return error.NameTooLong,
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOTDIR => return error.NotDir,
-        posix.ENOMEM => return error.SystemResources,
-        posix.ENOSPC => return error.NoSpaceLeft,
-        posix.EROFS => return error.ReadOnlyFileSystem,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
-    const existing_path_c = try toPosixPath(existing_path);
-    const new_path_c = try toPosixPath(new_path);
-    return symLinkPosixC(&existing_path_c, &new_path_c);
+    var buf: [1000]u8 = undefined;
+    const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator;
+    _ = getCwdAlloc(allocator) catch {};
 }
 
 // here we replace the standard +/ with -_ so that it can be used in a file name
@@ -1054,78 +341,6 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
     }
 }
 
-pub const DeleteFileError = error{
-    FileNotFound,
-    AccessDenied,
-    FileBusy,
-    FileSystem,
-    IsDir,
-    SymLinkLoop,
-    NameTooLong,
-    NotDir,
-    SystemResources,
-    ReadOnlyFileSystem,
-
-    /// On Windows, file paths must be valid Unicode.
-    InvalidUtf8,
-
-    /// On Windows, file paths cannot contain these characters:
-    /// '/', '*', '?', '"', '<', '>', '|'
-    BadPathName,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
-    if (builtin.os == Os.windows) {
-        const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
-        return deleteFileW(&file_path_w);
-    } else {
-        const file_path_c = try toPosixPath(file_path);
-        return deleteFileC(&file_path_c);
-    }
-}
-
-pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
-    if (windows.DeleteFileW(file_path) == 0) {
-        const err = windows.GetLastError();
-        switch (err) {
-            windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
-            windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
-            windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
-            windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
-            else => return unexpectedErrorWindows(err),
-        }
-    }
-}
-
-pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
-    if (is_windows) {
-        const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
-        return deleteFileW(&file_path_w);
-    } else {
-        const err = posix.getErrno(posix.unlink(file_path));
-        switch (err) {
-            0 => return,
-            posix.EACCES => return error.AccessDenied,
-            posix.EPERM => return error.AccessDenied,
-            posix.EBUSY => return error.FileBusy,
-            posix.EFAULT => unreachable,
-            posix.EINVAL => unreachable,
-            posix.EIO => return error.FileSystem,
-            posix.EISDIR => return error.IsDir,
-            posix.ELOOP => return error.SymLinkLoop,
-            posix.ENAMETOOLONG => return error.NameTooLong,
-            posix.ENOENT => return error.FileNotFound,
-            posix.ENOTDIR => return error.NotDir,
-            posix.ENOMEM => return error.SystemResources,
-            posix.EROFS => return error.ReadOnlyFileSystem,
-            else => return unexpectedErrorPosix(err),
-        }
-    }
-}
-
 /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
 /// merged and readily available,
 /// there is a possibility of power loss or application termination leaving temporary files present
@@ -1236,8 +451,8 @@ pub const AtomicFile = struct {
             const dest_path_c = try toPosixPath(self.dest_path);
             return renameC(&self.tmp_path_buf, &dest_path_c);
         } else if (is_windows) {
-            const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
-            const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
+            const dest_path_w = try posix.sliceToPrefixedFileW(self.dest_path);
+            const tmp_path_w = try posix.cStrToPrefixedFileW(&self.tmp_path_buf);
             return renameW(&tmp_path_w, &dest_path_w);
         } else {
             @compileError("Unsupported OS");
@@ -1245,109 +460,27 @@ pub const AtomicFile = struct {
     }
 };
 
-pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
-    if (is_windows) {
-        const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
-        const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
-        return renameW(&old_path_w, &new_path_w);
-    } else {
-        const err = posix.getErrno(posix.rename(old_path, new_path));
-        switch (err) {
-            0 => return,
-            posix.EACCES => return error.AccessDenied,
-            posix.EPERM => return error.AccessDenied,
-            posix.EBUSY => return error.FileBusy,
-            posix.EDQUOT => return error.DiskQuota,
-            posix.EFAULT => unreachable,
-            posix.EINVAL => unreachable,
-            posix.EISDIR => return error.IsDir,
-            posix.ELOOP => return error.SymLinkLoop,
-            posix.EMLINK => return error.LinkQuotaExceeded,
-            posix.ENAMETOOLONG => return error.NameTooLong,
-            posix.ENOENT => return error.FileNotFound,
-            posix.ENOTDIR => return error.NotDir,
-            posix.ENOMEM => return error.SystemResources,
-            posix.ENOSPC => return error.NoSpaceLeft,
-            posix.EEXIST => return error.PathAlreadyExists,
-            posix.ENOTEMPTY => return error.PathAlreadyExists,
-            posix.EROFS => return error.ReadOnlyFileSystem,
-            posix.EXDEV => return error.RenameAcrossMountPoints,
-            else => return unexpectedErrorPosix(err),
-        }
-    }
-}
-
-pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
-    const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
-    if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
-        const err = windows.GetLastError();
-        switch (err) {
-            else => return unexpectedErrorWindows(err),
-        }
-    }
-}
-
-pub fn rename(old_path: []const u8, new_path: []const u8) !void {
-    if (is_windows) {
-        const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
-        const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
-        return renameW(&old_path_w, &new_path_w);
-    } else {
-        const old_path_c = try toPosixPath(old_path);
-        const new_path_c = try toPosixPath(new_path);
-        return renameC(&old_path_c, &new_path_c);
-    }
-}
+const default_new_dir_mode = 0o755;
 
+/// Create a new directory.
 pub fn makeDir(dir_path: []const u8) !void {
-    if (is_windows) {
-        return makeDirWindows(dir_path);
-    } else {
-        return makeDirPosix(dir_path);
-    }
+    return posix.mkdir(dir_path, default_new_dir_mode);
 }
 
-pub fn makeDirWindows(dir_path: []const u8) !void {
-    const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
-
-    if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
-        const err = windows.GetLastError();
-        return switch (err) {
-            windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
-            windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
-            else => unexpectedErrorWindows(err),
-        };
-    }
+/// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string.
+pub fn makeDirC(dir_path: [*]const u8) !void {
+    return posix.mkdirC(dir_path, default_new_dir_mode);
 }
 
-pub fn makeDirPosixC(dir_path: [*]const u8) !void {
-    const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
-    switch (err) {
-        0 => return,
-        posix.EACCES => return error.AccessDenied,
-        posix.EPERM => return error.AccessDenied,
-        posix.EDQUOT => return error.DiskQuota,
-        posix.EEXIST => return error.PathAlreadyExists,
-        posix.EFAULT => unreachable,
-        posix.ELOOP => return error.SymLinkLoop,
-        posix.EMLINK => return error.LinkQuotaExceeded,
-        posix.ENAMETOOLONG => return error.NameTooLong,
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOMEM => return error.SystemResources,
-        posix.ENOSPC => return error.NoSpaceLeft,
-        posix.ENOTDIR => return error.NotDir,
-        posix.EROFS => return error.ReadOnlyFileSystem,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub fn makeDirPosix(dir_path: []const u8) !void {
-    const dir_path_c = try toPosixPath(dir_path);
-    return makeDirPosixC(&dir_path_c);
+/// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string.
+pub fn makeDirW(dir_path: [*]const u16) !void {
+    return posix.mkdirW(dir_path, default_new_dir_mode);
 }
 
 /// Calls makeDir recursively to make an entire path. Returns success if the path
 /// already exists and is a directory.
+/// This function is not atomic, and if it returns an error, the file system may
+/// have been modified regardless.
 /// TODO determine if we can remove the allocator requirement from this function
 pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
     const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
@@ -1381,78 +514,20 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
     }
 }
 
-pub const DeleteDirError = error{
-    AccessDenied,
-    FileBusy,
-    SymLinkLoop,
-    NameTooLong,
-    FileNotFound,
-    SystemResources,
-    NotDir,
-    DirNotEmpty,
-    ReadOnlyFileSystem,
-    InvalidUtf8,
-    BadPathName,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
-    switch (builtin.os) {
-        Os.windows => {
-            const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
-            return deleteDirW(&dir_path_w);
-        },
-        Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
-            const err = posix.getErrno(posix.rmdir(dir_path));
-            switch (err) {
-                0 => return,
-                posix.EACCES => return error.AccessDenied,
-                posix.EPERM => return error.AccessDenied,
-                posix.EBUSY => return error.FileBusy,
-                posix.EFAULT => unreachable,
-                posix.EINVAL => unreachable,
-                posix.ELOOP => return error.SymLinkLoop,
-                posix.ENAMETOOLONG => return error.NameTooLong,
-                posix.ENOENT => return error.FileNotFound,
-                posix.ENOMEM => return error.SystemResources,
-                posix.ENOTDIR => return error.NotDir,
-                posix.EEXIST => return error.DirNotEmpty,
-                posix.ENOTEMPTY => return error.DirNotEmpty,
-                posix.EROFS => return error.ReadOnlyFileSystem,
-                else => return unexpectedErrorPosix(err),
-            }
-        },
-        else => @compileError("unimplemented"),
-    }
+/// Returns `error.DirNotEmpty` if the directory is not empty.
+/// To delete a directory recursively, see `deleteTree`.
+pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
+    return posix.rmdir(dir_path);
 }
 
-pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
-    if (windows.RemoveDirectoryW(dir_path_w) == 0) {
-        const err = windows.GetLastError();
-        switch (err) {
-            windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
-            windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
-            else => return unexpectedErrorWindows(err),
-        }
-    }
+/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
+pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
+    return posix.rmdirC(dir_path);
 }
 
-/// Returns ::error.DirNotEmpty if the directory is not empty.
-/// To delete a directory recursively, see ::deleteTree
-pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
-    switch (builtin.os) {
-        Os.windows => {
-            const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
-            return deleteDirW(&dir_path_w);
-        },
-        Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
-            const dir_path_c = try toPosixPath(dir_path);
-            return deleteDirC(&dir_path_c);
-        },
-        else => @compileError("unimplemented"),
-    }
+/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
+pub fn deleteDirW(dir_path: [*]const u16) DeleteDirError!void {
+    return posix.rmdirW(dir_path);
 }
 
 /// Whether ::full_path describes a symlink, file, or directory, this function
@@ -1486,7 +561,6 @@ const DeleteTreeError = error{
     /// '/', '*', '?', '"', '<', '>', '|'
     BadPathName,
 
-    /// See https://github.com/ziglang/zig/issues/1396
     Unexpected,
 };
 
@@ -1624,7 +698,6 @@ pub const Dir = struct {
         BadPathName,
         DeviceBusy,
 
-        /// See https://github.com/ziglang/zig/issues/1396
         Unexpected,
     };
 
@@ -1878,121 +951,23 @@ pub const Dir = struct {
                 posix.DT_WHT => Entry.Kind.Whiteout,
                 else => Entry.Kind.Unknown,
             };
-            return Entry{
-                .name = name,
-                .kind = entry_kind,
-            };
-        }
-    }
-};
-
-pub fn changeCurDir(dir_path: []const u8) !void {
-    const dir_path_c = try toPosixPath(dir_path);
-    const err = posix.getErrno(posix.chdir(&dir_path_c));
-    switch (err) {
-        0 => return,
-        posix.EACCES => return error.AccessDenied,
-        posix.EFAULT => unreachable,
-        posix.EIO => return error.FileSystem,
-        posix.ELOOP => return error.SymLinkLoop,
-        posix.ENAMETOOLONG => return error.NameTooLong,
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOMEM => return error.SystemResources,
-        posix.ENOTDIR => return error.NotDir,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
-    const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return out_buffer[0..rc],
-        posix.EACCES => return error.AccessDenied,
-        posix.EFAULT => unreachable,
-        posix.EINVAL => unreachable,
-        posix.EIO => return error.FileSystem,
-        posix.ELOOP => return error.SymLinkLoop,
-        posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOMEM => return error.SystemResources,
-        posix.ENOTDIR => return error.NotDir,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
-    const file_path_c = try toPosixPath(file_path);
-    return readLinkC(out_buffer, &file_path_c);
-}
-
-pub fn posix_setuid(uid: u32) !void {
-    const err = posix.getErrno(posix.setuid(uid));
-    if (err == 0) return;
-    return switch (err) {
-        posix.EAGAIN => error.ResourceLimitReached,
-        posix.EINVAL => error.InvalidUserId,
-        posix.EPERM => error.PermissionDenied,
-        else => unexpectedErrorPosix(err),
-    };
-}
-
-pub fn posix_setreuid(ruid: u32, euid: u32) !void {
-    const err = posix.getErrno(posix.setreuid(ruid, euid));
-    if (err == 0) return;
-    return switch (err) {
-        posix.EAGAIN => error.ResourceLimitReached,
-        posix.EINVAL => error.InvalidUserId,
-        posix.EPERM => error.PermissionDenied,
-        else => unexpectedErrorPosix(err),
-    };
-}
-
-pub fn posix_setgid(gid: u32) !void {
-    const err = posix.getErrno(posix.setgid(gid));
-    if (err == 0) return;
-    return switch (err) {
-        posix.EAGAIN => error.ResourceLimitReached,
-        posix.EINVAL => error.InvalidUserId,
-        posix.EPERM => error.PermissionDenied,
-        else => unexpectedErrorPosix(err),
-    };
-}
-
-pub fn posix_setregid(rgid: u32, egid: u32) !void {
-    const err = posix.getErrno(posix.setregid(rgid, egid));
-    if (err == 0) return;
-    return switch (err) {
-        posix.EAGAIN => error.ResourceLimitReached,
-        posix.EINVAL => error.InvalidUserId,
-        posix.EPERM => error.PermissionDenied,
-        else => unexpectedErrorPosix(err),
-    };
-}
-
-pub const WindowsGetStdHandleErrs = error{
-    NoStdHandles,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
-    if (windows.GetStdHandle(handle_id)) |handle| {
-        if (handle == windows.INVALID_HANDLE_VALUE) {
-            const err = windows.GetLastError();
-            return switch (err) {
-                else => os.unexpectedErrorWindows(err),
-            };
+            return Entry{
+                .name = name,
+                .kind = entry_kind,
+            };
         }
-        return handle;
-    } else {
-        return error.NoStdHandles;
     }
+};
+
+/// Read value of a symbolic link.
+/// The return value is a slice of buffer, from index `0`.
+pub fn readLink(buffer: *[posix.PATH_MAX]u8, pathname: []const u8) ![]u8 {
+    return posix.readlink(pathname, buffer);
+}
+
+/// Same as `readLink`, except the `pathname` parameter is null-terminated.
+pub fn readLinkC(buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
+    return posix.readlinkC(pathname, buffer);
 }
 
 pub const ArgIteratorPosix = struct {
@@ -2328,34 +1303,6 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
     testing.expect(it.next(debug.global_allocator) == null);
 }
 
-// TODO make this a build variable that you can set
-const unexpected_error_tracing = false;
-const UnexpectedError = error{
-    /// The Operating System returned an undocumented error code.
-    Unexpected,
-};
-
-/// Call this when you made a syscall or something that sets errno
-/// and you get an unexpected error.
-pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
-    if (unexpected_error_tracing) {
-        debug.warn("unexpected errno: {}\n", errno);
-        debug.dumpCurrentStackTrace(null);
-    }
-    return error.Unexpected;
-}
-
-/// Call this when you made a windows DLL call or something that does SetLastError
-/// and you get an unexpected error.
-pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
-    if (unexpected_error_tracing) {
-        debug.warn("unexpected GetLastError(): {}\n", err);
-        @breakpoint();
-        debug.dumpCurrentStackTrace(null);
-    }
-    return error.Unexpected;
-}
-
 pub fn openSelfExe() !os.File {
     switch (builtin.os) {
         Os.linux => return os.File.openReadC(c"/proc/self/exe"),
@@ -2366,7 +1313,7 @@ pub fn openSelfExe() !os.File {
             return os.File.openReadC(self_exe_path.ptr);
         },
         Os.windows => {
-            var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+            var buf: [posix.PATH_MAX_WIDE]u16 = undefined;
             const wide_slice = try selfExePathW(&buf);
             return os.File.openReadW(wide_slice.ptr);
         },
@@ -2381,7 +1328,7 @@ test "openSelfExe" {
     }
 }
 
-pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
+pub fn selfExePathW(out_buffer: *[posix.PATH_MAX_WIDE]u16) ![]u16 {
     const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
     const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
     assert(rc <= out_buffer.len);
@@ -2434,7 +1381,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
             };
         },
         Os.windows => {
-            var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+            var utf16le_buf: [posix.PATH_MAX_WIDE]u16 = undefined;
             const utf16le_slice = try selfExePathW(&utf16le_buf);
             // Trust that Windows gives us valid UTF-16LE.
             const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
@@ -2481,521 +1428,6 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
     }
 }
 
-pub fn isTty(handle: FileHandle) bool {
-    if (is_windows) {
-        return windows_util.windowsIsTty(handle);
-    } else {
-        if (builtin.link_libc) {
-            return c.isatty(handle) != 0;
-        } else {
-            return posix.isatty(handle);
-        }
-    }
-}
-
-pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
-    if (is_windows) {
-        return windows_util.windowsIsCygwinPty(handle);
-    } else {
-        if (builtin.link_libc) {
-            return c.isatty(handle) != 0;
-        } else {
-            return posix.isatty(handle);
-        }
-    }
-}
-
-pub const PosixSocketError = error{
-    /// Permission to create a socket of the specified type and/or
-    /// proโ€tocol is denied.
-    PermissionDenied,
-
-    /// The implementation does not support the specified address family.
-    AddressFamilyNotSupported,
-
-    /// Unknown protocol, or protocol family not available.
-    ProtocolFamilyNotAvailable,
-
-    /// The per-process limit on the number of open file descriptors has been reached.
-    ProcessFdQuotaExceeded,
-
-    /// The system-wide limit on the total number of open files has been reached.
-    SystemFdQuotaExceeded,
-
-    /// Insufficient memory is available. The socket cannot be created until sufficient
-    /// resources are freed.
-    SystemResources,
-
-    /// The protocol type or the specified protocol is not supported within this domain.
-    ProtocolNotSupported,
-};
-
-pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
-    const rc = posix.socket(domain, socket_type, protocol);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        posix.EACCES => return PosixSocketError.PermissionDenied,
-        posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
-        posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
-        posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
-        posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
-        posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
-        posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub const PosixBindError = error{
-    /// The address is protected, and the user is not the superuser.
-    /// For UNIX domain sockets: Search permission is denied on  a  component
-    /// of  the  path  prefix.
-    AccessDenied,
-
-    /// The given address is already in use, or in the case of Internet domain sockets,
-    /// The  port number was specified as zero in the socket
-    /// address structure, but, upon attempting to bind to  an  ephemeral  port,  it  was
-    /// determined  that  all  port  numbers in the ephemeral port range are currently in
-    /// use.  See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
-    AddressInUse,
-
-    /// A nonexistent interface was requested or the requested address was not local.
-    AddressNotAvailable,
-
-    /// Too many symbolic links were encountered in resolving addr.
-    SymLinkLoop,
-
-    /// addr is too long.
-    NameTooLong,
-
-    /// A component in the directory prefix of the socket pathname does not exist.
-    FileNotFound,
-
-    /// Insufficient kernel memory was available.
-    SystemResources,
-
-    /// A component of the path prefix is not a directory.
-    NotDir,
-
-    /// The socket inode would reside on a read-only filesystem.
-    ReadOnlyFileSystem,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-/// addr is `&const T` where T is one of the sockaddr
-pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
-    const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return,
-        posix.EACCES => return PosixBindError.AccessDenied,
-        posix.EADDRINUSE => return PosixBindError.AddressInUse,
-        posix.EBADF => unreachable, // always a race condition if this error is returned
-        posix.EINVAL => unreachable,
-        posix.ENOTSOCK => unreachable,
-        posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
-        posix.EFAULT => unreachable,
-        posix.ELOOP => return PosixBindError.SymLinkLoop,
-        posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
-        posix.ENOENT => return PosixBindError.FileNotFound,
-        posix.ENOMEM => return PosixBindError.SystemResources,
-        posix.ENOTDIR => return PosixBindError.NotDir,
-        posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-const PosixListenError = error{
-    /// Another socket is already listening on the same port.
-    /// For Internet domain sockets, the  socket referred to by sockfd had not previously
-    /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
-    /// was determined that all port numbers in the ephemeral port range are currently in
-    /// use.  See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
-    AddressInUse,
-
-    /// The file descriptor sockfd does not refer to a socket.
-    FileDescriptorNotASocket,
-
-    /// The socket is not of a type that supports the listen() operation.
-    OperationNotSupported,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
-    const rc = posix.listen(sockfd, backlog);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return,
-        posix.EADDRINUSE => return PosixListenError.AddressInUse,
-        posix.EBADF => unreachable,
-        posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
-        posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub const PosixAcceptError = error{
-    ConnectionAborted,
-
-    /// The per-process limit on the number of open file descriptors has been reached.
-    ProcessFdQuotaExceeded,
-
-    /// The system-wide limit on the total number of open files has been reached.
-    SystemFdQuotaExceeded,
-
-    /// Not enough free memory.  This often means that the memory allocation  is  limited
-    /// by the socket buffer limits, not by the system memory.
-    SystemResources,
-
-    /// The file descriptor sockfd does not refer to a socket.
-    FileDescriptorNotASocket,
-
-    /// The referenced socket is not of type SOCK_STREAM.
-    OperationNotSupported,
-
-    ProtocolFailure,
-
-    /// Firewall rules forbid connection.
-    BlockedByFirewall,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
-    while (true) {
-        var sockaddr_size = u32(@sizeOf(posix.sockaddr));
-        const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => return @intCast(i32, rc),
-            posix.EINTR => continue,
-            else => return unexpectedErrorPosix(err),
-
-            posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
-            posix.EBADF => unreachable, // always a race condition
-            posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
-            posix.EFAULT => unreachable,
-            posix.EINVAL => unreachable,
-            posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
-            posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
-            posix.ENOBUFS => return PosixAcceptError.SystemResources,
-            posix.ENOMEM => return PosixAcceptError.SystemResources,
-            posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
-            posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
-            posix.EPROTO => return PosixAcceptError.ProtocolFailure,
-            posix.EPERM => return PosixAcceptError.BlockedByFirewall,
-        }
-    }
-}
-
-/// Returns -1 if would block.
-pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
-    while (true) {
-        var sockaddr_size = u32(@sizeOf(posix.sockaddr));
-        const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => return @intCast(i32, rc),
-            posix.EINTR => continue,
-            else => return unexpectedErrorPosix(err),
-
-            posix.EAGAIN => return -1,
-            posix.EBADF => unreachable, // always a race condition
-            posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
-            posix.EFAULT => unreachable,
-            posix.EINVAL => unreachable,
-            posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
-            posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
-            posix.ENOBUFS => return PosixAcceptError.SystemResources,
-            posix.ENOMEM => return PosixAcceptError.SystemResources,
-            posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
-            posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
-            posix.EPROTO => return PosixAcceptError.ProtocolFailure,
-            posix.EPERM => return PosixAcceptError.BlockedByFirewall,
-        }
-    }
-}
-
-pub const LinuxEpollCreateError = error{
-    /// The  per-user   limit   on   the   number   of   epoll   instances   imposed   by
-    /// /proc/sys/fs/epoll/max_user_instances  was encountered.  See epoll(7) for further
-    /// details.
-    /// Or, The per-process limit on the number of open file descriptors has been reached.
-    ProcessFdQuotaExceeded,
-
-    /// The system-wide limit on the total number of open files has been reached.
-    SystemFdQuotaExceeded,
-
-    /// There was insufficient memory to create the kernel object.
-    SystemResources,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
-    const rc = posix.epoll_create1(flags);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        else => return unexpectedErrorPosix(err),
-
-        posix.EINVAL => unreachable,
-        posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
-        posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
-        posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
-    }
-}
-
-pub const LinuxEpollCtlError = error{
-    /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is  already  registered
-    /// with this epoll instance.
-    FileDescriptorAlreadyPresentInSet,
-
-    /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
-    /// circular loop of epoll instances monitoring one another.
-    OperationCausesCircularLoop,
-
-    /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with  this  epoll
-    /// instance.
-    FileDescriptorNotRegistered,
-
-    /// There was insufficient memory to handle the requested op control operation.
-    SystemResources,
-
-    /// The  limit  imposed  by /proc/sys/fs/epoll/max_user_watches was encountered while
-    /// trying to register (EPOLL_CTL_ADD) a new file descriptor on  an  epoll  instance.
-    /// See epoll(7) for further details.
-    UserResourceLimitReached,
-
-    /// The target file fd does not support epoll.  This error can occur if fd refers to,
-    /// for example, a regular file or a directory.
-    FileDescriptorIncompatibleWithEpoll,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
-    const rc = posix.epoll_ctl(epfd, op, fd, event);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return,
-        else => return unexpectedErrorPosix(err),
-
-        posix.EBADF => unreachable, // always a race condition if this happens
-        posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
-        posix.EINVAL => unreachable,
-        posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
-        posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
-        posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
-        posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
-        posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
-    }
-}
-
-pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
-    while (true) {
-        const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => return rc,
-            posix.EINTR => continue,
-            posix.EBADF => unreachable,
-            posix.EFAULT => unreachable,
-            posix.EINVAL => unreachable,
-            else => unreachable,
-        }
-    }
-}
-
-pub const LinuxEventFdError = error{
-    InvalidFlagValue,
-    SystemResources,
-    ProcessFdQuotaExceeded,
-    SystemFdQuotaExceeded,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
-    const rc = posix.eventfd(initval, flags);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        else => return unexpectedErrorPosix(err),
-
-        posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
-        posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
-        posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
-        posix.ENODEV => return LinuxEventFdError.SystemResources,
-        posix.ENOMEM => return LinuxEventFdError.SystemResources,
-    }
-}
-
-pub const PosixGetSockNameError = error{
-    /// Insufficient resources were available in the system to perform the operation.
-    SystemResources,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
-    var addr: posix.sockaddr = undefined;
-    var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
-    const rc = posix.getsockname(sockfd, &addr, &addrlen);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return addr,
-        else => return unexpectedErrorPosix(err),
-
-        posix.EBADF => unreachable,
-        posix.EFAULT => unreachable,
-        posix.EINVAL => unreachable,
-        posix.ENOTSOCK => unreachable,
-        posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
-    }
-}
-
-pub const PosixConnectError = error{
-    /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on  the  socket
-    /// file,  or  search  permission  is  denied  for  one of the directories in the path prefix.
-    /// or
-    /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled  or
-    /// the connection request failed because of a local firewall rule.
-    PermissionDenied,
-
-    /// Local address is already in use.
-    AddressInUse,
-
-    /// (Internet  domain  sockets)  The  socket  referred  to  by sockfd had not previously been bound to an
-    /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
-    /// in    the    ephemeral    port    range    are   currently   in   use.    See   the   discussion   of
-    /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
-    AddressNotAvailable,
-
-    /// The passed address didn't have the correct address family in its sa_family field.
-    AddressFamilyNotSupported,
-
-    /// Insufficient entries in the routing cache.
-    SystemResources,
-
-    /// A connect() on a stream socket found no one listening on the remote address.
-    ConnectionRefused,
-
-    /// Network is unreachable.
-    NetworkUnreachable,
-
-    /// Timeout  while  attempting  connection.   The server may be too busy to accept new connections.  Note
-    /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
-    ConnectionTimedOut,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
-    while (true) {
-        const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => return,
-            else => return unexpectedErrorPosix(err),
-
-            posix.EACCES => return PosixConnectError.PermissionDenied,
-            posix.EPERM => return PosixConnectError.PermissionDenied,
-            posix.EADDRINUSE => return PosixConnectError.AddressInUse,
-            posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
-            posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
-            posix.EAGAIN => return PosixConnectError.SystemResources,
-            posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
-            posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
-            posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
-            posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
-            posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
-            posix.EINTR => continue,
-            posix.EISCONN => unreachable, // The socket is already connected.
-            posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
-            posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
-            posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
-            posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
-        }
-    }
-}
-
-/// Same as posixConnect except it is for blocking socket file descriptors.
-/// It expects to receive EINPROGRESS.
-pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
-    while (true) {
-        const rc = posix.connect(sockfd, sockaddr, len);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0, posix.EINPROGRESS => return,
-            else => return unexpectedErrorPosix(err),
-
-            posix.EACCES => return PosixConnectError.PermissionDenied,
-            posix.EPERM => return PosixConnectError.PermissionDenied,
-            posix.EADDRINUSE => return PosixConnectError.AddressInUse,
-            posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
-            posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
-            posix.EAGAIN => return PosixConnectError.SystemResources,
-            posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
-            posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
-            posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
-            posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
-            posix.EINTR => continue,
-            posix.EISCONN => unreachable, // The socket is already connected.
-            posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
-            posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
-            posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
-            posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
-        }
-    }
-}
-
-pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
-    var err_code: i32 = undefined;
-    var size: u32 = @sizeOf(i32);
-    const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
-    assert(size == 4);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => switch (err_code) {
-            0 => return,
-            else => return unexpectedErrorPosix(err),
-
-            posix.EACCES => return PosixConnectError.PermissionDenied,
-            posix.EPERM => return PosixConnectError.PermissionDenied,
-            posix.EADDRINUSE => return PosixConnectError.AddressInUse,
-            posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
-            posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
-            posix.EAGAIN => return PosixConnectError.SystemResources,
-            posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
-            posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
-            posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
-            posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
-            posix.EISCONN => unreachable, // The socket is already connected.
-            posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
-            posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
-            posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
-            posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
-        },
-        else => return unexpectedErrorPosix(err),
-        posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
-        posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
-        posix.EINVAL => unreachable,
-        posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
-        posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
-    }
-}
-
 pub const Thread = struct {
     data: Data,
 
@@ -3123,7 +1555,6 @@ pub const SpawnThreadError = error{
     /// Not enough userland memory to spawn the thread.
     OutOfMemory,
 
-    /// See https://github.com/ziglang/zig/issues/1396
     Unexpected,
 };
 
@@ -3301,47 +1732,16 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
     }
 }
 
-pub fn posixWait(pid: i32) i32 {
-    var status: i32 = undefined;
-    while (true) {
-        const err = posix.getErrno(posix.waitpid(pid, &status, 0));
-        switch (err) {
-            0 => return status,
-            posix.EINTR => continue,
-            posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
-            posix.EINVAL => unreachable, // The options argument was invalid
-            else => unreachable,
-        }
-    }
-}
-
-pub fn posixFStat(fd: i32) !posix.Stat {
-    var stat: posix.Stat = undefined;
-    const err = posix.getErrno(posix.fstat(fd, &stat));
-    if (err > 0) {
-        return switch (err) {
-            // We do not make this an error code because if you get EBADF it's always a bug,
-            // since the fd could have been reused.
-            posix.EBADF => unreachable,
-            posix.ENOMEM => error.SystemResources,
-            else => os.unexpectedErrorPosix(err),
-        };
-    }
-
-    return stat;
-}
-
 pub const CpuCountError = error{
     OutOfMemory,
     PermissionDenied,
 
-    /// See https://github.com/ziglang/zig/issues/1396
     Unexpected,
 };
 
 pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
     switch (builtin.os) {
-        builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
+        .macosx, .freebsd, .netbsd => {
             var count: c_int = undefined;
             var count_len: usize = @sizeOf(c_int);
             const rc = posix.sysctlbyname(switch (builtin.os) {
@@ -3361,7 +1761,7 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
                 else => return os.unexpectedErrorPosix(err),
             }
         },
-        builtin.Os.linux => {
+        .linux => {
             const usize_count = 16;
             const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
 
@@ -3393,7 +1793,7 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
                 }
             }
         },
-        builtin.Os.windows => {
+        .windows => {
             var system_info: windows.SYSTEM_INFO = undefined;
             windows.GetSystemInfo(&system_info);
             return @intCast(usize, system_info.dwNumberOfProcessors);
@@ -3401,128 +1801,3 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
         else => @compileError("unsupported OS"),
     }
 }
-
-pub const BsdKQueueError = error{
-    /// The per-process limit on the number of open file descriptors has been reached.
-    ProcessFdQuotaExceeded,
-
-    /// The system-wide limit on the total number of open files has been reached.
-    SystemFdQuotaExceeded,
-
-    /// See https://github.com/ziglang/zig/issues/1396
-    Unexpected,
-};
-
-pub fn bsdKQueue() BsdKQueueError!i32 {
-    const rc = posix.kqueue();
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
-        posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub const BsdKEventError = error{
-    /// The process does not have permission to register a filter.
-    AccessDenied,
-
-    /// The event could not be found to be modified or deleted.
-    EventNotFound,
-
-    /// No memory was available to register the event.
-    SystemResources,
-
-    /// The specified process to attach to does not exist.
-    ProcessNotFound,
-};
-
-pub fn bsdKEvent(
-    kq: i32,
-    changelist: []const posix.Kevent,
-    eventlist: []posix.Kevent,
-    timeout: ?*const posix.timespec,
-) BsdKEventError!usize {
-    while (true) {
-        const rc = posix.kevent(kq, changelist, eventlist, timeout);
-        const err = posix.getErrno(rc);
-        switch (err) {
-            0 => return rc,
-            posix.EACCES => return BsdKEventError.AccessDenied,
-            posix.EFAULT => unreachable,
-            posix.EBADF => unreachable,
-            posix.EINTR => continue,
-            posix.EINVAL => unreachable,
-            posix.ENOENT => return BsdKEventError.EventNotFound,
-            posix.ENOMEM => return BsdKEventError.SystemResources,
-            posix.ESRCH => return BsdKEventError.ProcessNotFound,
-            else => unreachable,
-        }
-    }
-}
-
-pub fn linuxINotifyInit1(flags: u32) !i32 {
-    const rc = linux.inotify_init1(flags);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        posix.EINVAL => unreachable,
-        posix.EMFILE => return error.ProcessFdQuotaExceeded,
-        posix.ENFILE => return error.SystemFdQuotaExceeded,
-        posix.ENOMEM => return error.SystemResources,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
-    const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return @intCast(i32, rc),
-        posix.EACCES => return error.AccessDenied,
-        posix.EBADF => unreachable,
-        posix.EFAULT => unreachable,
-        posix.EINVAL => unreachable,
-        posix.ENAMETOOLONG => return error.NameTooLong,
-        posix.ENOENT => return error.FileNotFound,
-        posix.ENOMEM => return error.SystemResources,
-        posix.ENOSPC => return error.UserResourceLimitReached,
-        else => return unexpectedErrorPosix(err),
-    }
-}
-
-pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
-    const rc = linux.inotify_rm_watch(inotify_fd, wd);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return rc,
-        posix.EBADF => unreachable,
-        posix.EINVAL => unreachable,
-        else => unreachable,
-    }
-}
-
-pub const MProtectError = error{
-    AccessDenied,
-    OutOfMemory,
-    Unexpected,
-};
-
-/// address and length must be page-aligned
-pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {
-    const negative_page_size = @bitCast(usize, -isize(page_size));
-    const aligned_address = address & negative_page_size;
-    const aligned_end = (address + length + page_size - 1) & negative_page_size;
-    assert(address == aligned_address);
-    assert(length == aligned_end - aligned_address);
-    const rc = posix.mprotect(address, length, protection);
-    const err = posix.getErrno(rc);
-    switch (err) {
-        0 => return,
-        posix.EINVAL => unreachable,
-        posix.EACCES => return error.AccessDenied,
-        posix.ENOMEM => return error.OutOfMemory,
-        else => return unexpectedErrorPosix(err),
-    }
-}
CMakeLists.txt
@@ -621,9 +621,9 @@ set(ZIG_STD_FILES
     "os/time.zig"
     "os/uefi.zig"
     "os/wasi.zig"
-    "os/wasi/core.zig"
     "os/windows.zig"
     "os/windows/advapi32.zig"
+    "os/windows/errno.zig"
     "os/windows/error.zig"
     "os/windows/kernel32.zig"
     "os/windows/ntdll.zig"