From 5bb9689212d35f2c950fb2d542a9dca83b61937f Mon Sep 17 00:00:00 2001
From: Pat Tullmann <pat.github@tullmann.org>
Date: Sun, 28 Jul 2024 18:21:32 -0700
Subject: [PATCH 1/5] wasi: split with-libc and without-libc implementations

Make a clearer separation between the Posix defines for WASI without a
libc (the `system` defined in posix.zig) and the Posix defines for WASI
with a libc (which should mirror the Musl-based wasi-libc implementation,
and are defined in c.zig).

Make WASI `posix.O` look more POSIX-y when compiling without libc.  These
structures and constants do not need to mirror the with-libc Wasi API
(e.g., can use `.ACCMODE`).  This removes some Wasi-specific code in
Dir.zig and posix.zig by making the structure use names consistent with
other platforms.  Define `.S`, `.timespec`, and `.AT` structs for
Wasi-without-libc in posix.zig.  These are based on the wasi-with-libc
structures, but cleaned up to remove cruft like padding or wholly
unsupported fields.

Fix `.S` and `.AT` constants on wasi-with-libc (defined in c.zig) to match
wasi-libc headers.

Define `mode_t` type as `void` for wasi targets because file permissions
are not supported via the Posix APIS on these platforms.  Use `mode_t` as
the parameter type in Zig's mkdir\* and openat\* wrappers.

Re-enable a lot of tests that have accumulated stale not-on-wasi guards,
and simplify some tests (e.g., dropping unnecessary absolute paths) so
they can run on wasi targets.
---
 lib/std/Build/Step/Run.zig |   2 +-
 lib/std/c.zig              |  50 +++---
 lib/std/debug.zig          |  10 +-
 lib/std/fs/Dir.zig         |  93 +++++------
 lib/std/fs/File.zig        |  12 +-
 lib/std/fs/test.zig        |  79 ++++-----
 lib/std/os/linux.zig       |  12 +-
 lib/std/os/wasi.zig        |   2 +-
 lib/std/posix.zig          | 320 +++++++++++++++++++++++++++++--------
 lib/std/posix/test.zig     | 103 ++++++------
 10 files changed, 439 insertions(+), 244 deletions(-)

diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 0c011e25eddd..84658c091f8b 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -1089,7 +1089,7 @@ fn runCommand(
                         // the `--` before the module name. This appears to work for both old and
                         // new Wasmtime versions.
                         try interp_argv.append(bin_name);
-                        try interp_argv.append("--dir=.");
+                        try interp_argv.append("--dir=."); // Preopen '.' at file descriptor 3 for cwd
                         try interp_argv.append("--");
                         try interp_argv.append(argv[0]);
                         try interp_argv.appendSlice(argv[1..]);
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 611f707e15e2..e736391dc060 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -133,9 +133,11 @@ pub const dev_t = switch (native_os) {
 pub const mode_t = switch (native_os) {
     .linux => linux.mode_t,
     .emscripten => emscripten.mode_t,
-    .openbsd, .haiku, .netbsd, .solaris, .illumos, .wasi => u32,
+    .openbsd, .haiku, .netbsd, .solaris, .illumos => u32,
     .freebsd, .macos, .ios, .tvos, .watchos, .visionos => u16,
-    else => u0,
+    .wasi => void,
+    .windows => u0,
+    else => u0, // TODO: should be void?
 };
 
 pub const nlink_t = switch (native_os) {
@@ -1702,17 +1704,15 @@ pub const S = switch (native_os) {
     .linux => linux.S,
     .emscripten => emscripten.S,
     .wasi => struct {
-        pub const IEXEC = @compileError("TODO audit this");
+        // Match wasi-libc's libc-bottom-half/headers/public/__mode_t.h
         pub const IFBLK = 0x6000;
         pub const IFCHR = 0x2000;
         pub const IFDIR = 0x4000;
-        pub const IFIFO = 0xc000;
+        pub const IFIFO = 0x1000;
         pub const IFLNK = 0xa000;
-        pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
         pub const IFREG = 0x8000;
-        /// There's no concept of UNIX domain socket but we define this value here
-        /// in order to line with other OSes.
-        pub const IFSOCK = 0x1;
+        pub const IFSOCK = 0xc000;
+        pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
     },
     .macos, .ios, .tvos, .watchos, .visionos => struct {
         pub const IFMT = 0o170000;
@@ -6486,6 +6486,7 @@ pub const Stat = switch (native_os) {
     },
     .emscripten => emscripten.Stat,
     .wasi => extern struct {
+        // Matches wasi-libc's libc-bottom-half/headers/public/__struct_stat.h
         dev: dev_t,
         ino: ino_t,
         nlink: nlink_t,
@@ -7185,17 +7186,13 @@ pub const AT = switch (native_os) {
         pub const RECURSIVE = 0x8000;
     },
     .wasi => struct {
-        pub const SYMLINK_NOFOLLOW = 0x100;
-        pub const SYMLINK_FOLLOW = 0x400;
-        pub const REMOVEDIR: u32 = 0x4;
-        /// When linking libc, we follow their convention and use -2 for current working directory.
-        /// However, without libc, Zig does a different convention: it assumes the
-        /// current working directory is the first preopen. This behavior can be
-        /// overridden with a public function called `wasi_cwd` in the root source
-        /// file.
-        pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3;
+        // Match AT_* constants in wasi-libc libc-bottom-half/headers/public/__header_fcntl.h
+        pub const FDCWD = -2;
+        pub const EACCESS = 0x0;
+        pub const SYMLINK_NOFOLLOW = 0x1;
+        pub const SYMLINK_FOLLOW = 0x2;
+        pub const REMOVEDIR = 0x4;
     },
-
     else => void,
 };
 
@@ -7224,6 +7221,7 @@ pub const O = switch (native_os) {
         _: u9 = 0,
     },
     .wasi => packed struct(u32) {
+        // Match layout from wasi-libc libc-bottom-half/headers/public/__header_fcntl.h
         APPEND: bool = false,
         DSYNC: bool = false,
         NONBLOCK: bool = false,
@@ -7236,10 +7234,17 @@ pub const O = switch (native_os) {
         TRUNC: bool = false,
         _16: u8 = 0,
         NOFOLLOW: bool = false,
+
+        // Logical O_ACCMODE is the following 4 bits, note O_SEARCH is between RD and WR,
+        // so can't easily reuse std.posix.ACCMODE in this struct.
         EXEC: bool = false,
-        read: bool = false,
+        RDONLY: bool = true, // equivalent to "ACCMODE = .RDONLY" default
         SEARCH: bool = false,
-        write: bool = false,
+        WRONLY: bool = false,
+
+        // CLOEXEC, TTY_ININT, NOCTTY are mapped 0, so they're silently
+        // ignored in C code.
+
         _: u3 = 0,
     },
     .solaris, .illumos => packed struct(u32) {
@@ -9069,6 +9074,7 @@ pub const gettimeofday = switch (native_os) {
 
 pub const msync = switch (native_os) {
     .netbsd => private.__msync13,
+    .wasi => {},
     else => private.msync,
 };
 
@@ -9211,8 +9217,8 @@ pub const fork = switch (native_os) {
 pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int;
 pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int;
 pub extern "c" fn pipe(fds: *[2]fd_t) c_int;
-pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;
-pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;
+pub extern "c" fn mkdir(path: [*:0]const u8, mode: usize) c_int;
+pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: usize) c_int;
 pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;
 pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int;
 pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 826978abe42d..1a64ca0dee75 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -1034,7 +1034,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
-        const path = try fs.path.join(allocator, &.{ test_dir_path, "three_lines.zig" });
+        const path = try join(allocator, &.{ test_dir_path, "three_lines.zig" });
         defer allocator.free(path);
         try test_dir.dir.writeFile(.{
             .sub_path = "three_lines.zig",
@@ -1056,7 +1056,7 @@ test printLineFromFileAnyOs {
     {
         const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});
         defer file.close();
-        const path = try fs.path.join(allocator, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });
+        const path = try join(allocator, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });
         defer allocator.free(path);
 
         const overlap = 10;
@@ -1072,7 +1072,7 @@ test printLineFromFileAnyOs {
     {
         const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});
         defer file.close();
-        const path = try fs.path.join(allocator, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
+        const path = try join(allocator, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
         defer allocator.free(path);
 
         var writer = file.writer();
@@ -1085,7 +1085,7 @@ test printLineFromFileAnyOs {
     {
         const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});
         defer file.close();
-        const path = try fs.path.join(allocator, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
+        const path = try join(allocator, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
         defer allocator.free(path);
 
         var writer = file.writer();
@@ -1110,7 +1110,7 @@ test printLineFromFileAnyOs {
     {
         const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});
         defer file.close();
-        const path = try fs.path.join(allocator, &.{ test_dir_path, "file_of_newlines.zig" });
+        const path = try join(allocator, &.{ test_dir_path, "file_of_newlines.zig" });
         defer allocator.free(path);
 
         var writer = file.writer();
diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig
index d4ea8a010952..f0fecf67be84 100644
--- a/lib/std/fs/Dir.zig
+++ b/lib/std/fs/Dir.zig
@@ -2,7 +2,12 @@ fd: Handle,
 
 pub const Handle = posix.fd_t;
 
-pub const default_mode = 0o755;
+/// Default mode bits for a new directory.
+pub const default_mode = switch (posix.mode_t) {
+    void => {}, // wasi-without-libc has no mode suppport
+    u0 => 0, // Zig's Posix layer doesn't support modes on Windows
+    else => 0o755,
+};
 
 pub const Entry = struct {
     name: []const u8,
@@ -831,32 +836,19 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
 
 /// Same as `openFile` but the path parameter is null-terminated.
 pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
-    switch (native_os) {
-        .windows => {
-            const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path);
-            return self.openFileW(path_w.span(), flags);
-        },
-        // Use the libc API when libc is linked because it implements things
-        // such as opening absolute file paths.
-        .wasi => if (!builtin.link_libc) {
-            return openFile(self, mem.sliceTo(sub_path, 0), flags);
-        },
-        else => {},
+    if (native_os == .windows) {
+        const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path);
+        return self.openFileW(path_w.span(), flags);
+    }
+    if (native_os == .wasi and !builtin.link_libc) {
+        return openFile(self, mem.sliceTo(sub_path, 0), flags);
     }
 
-    var os_flags: posix.O = switch (native_os) {
-        .wasi => .{
-            .read = flags.mode != .write_only,
-            .write = flags.mode != .read_only,
-        },
-        else => .{
-            .ACCMODE = switch (flags.mode) {
-                .read_only => .RDONLY,
-                .write_only => .WRONLY,
-                .read_write => .RDWR,
-            },
-        },
-    };
+    var os_flags: posix.O = std.posix.makeOFlags(switch (flags.mode) {
+        .read_only => .RDONLY,
+        .write_only => .WRONLY,
+        .read_write => .RDWR,
+    }, .{});
     if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
     if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
     if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
@@ -879,7 +871,8 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
             },
         }
     }
-    const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
+    const mode = if (posix.mode_t == void) {} else 0;
+    const fd = try posix.openatZ(self.fd, sub_path, os_flags, mode);
     errdefer posix.close(fd);
 
     if (have_flock and !has_flock_open_flags and flags.lock != .none) {
@@ -1002,12 +995,11 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
         else => {},
     }
 
-    var os_flags: posix.O = .{
-        .ACCMODE = if (flags.read) .RDWR else .WRONLY,
+    var os_flags: posix.O = std.posix.makeOFlags(if (flags.read) .RDWR else .WRONLY, .{
         .CREAT = true,
         .TRUNC = flags.truncate,
         .EXCL = flags.exclusive,
-    };
+    });
     if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
     if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
 
@@ -1270,7 +1262,7 @@ pub const RealPathError = posix.RealPathError;
 /// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`.
 pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError![]u8 {
     if (native_os == .wasi) {
-        @compileError("realpath is not available on WASI");
+        @compileError("WASI does not support absolute paths");
     }
     if (native_os == .windows) {
         const pathname_w = try windows.sliceToPrefixedFileW(self.fd, pathname);
@@ -1283,22 +1275,18 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
 /// Same as `Dir.realpath` except `pathname` is null-terminated.
 /// See also `Dir.realpath`, `realpathZ`.
 pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {
+    if (native_os == .wasi) {
+        @compileError("WASI does not support absolute paths");
+    }
     if (native_os == .windows) {
         const pathname_w = try windows.cStrToPrefixedFileW(self.fd, pathname);
         return self.realpathW(pathname_w.span(), out_buffer);
     }
 
-    const flags: posix.O = switch (native_os) {
-        .linux => .{
-            .NONBLOCK = true,
-            .CLOEXEC = true,
-            .PATH = true,
-        },
-        else => .{
-            .NONBLOCK = true,
-            .CLOEXEC = true,
-        },
-    };
+    var flags: posix.O = .{};
+    if (@hasField(posix.O, "NONBLOCK")) flags.NONBLOCK = true;
+    if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true;
+    if (@hasField(posix.O, "PATH")) flags.PATH = true;
 
     const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) {
         error.FileLocksNotSupported => return error.Unexpected,
@@ -1511,19 +1499,13 @@ pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenOptions) OpenErr
         else => {},
     }
 
-    var symlink_flags: posix.O = switch (native_os) {
-        .wasi => .{
-            .read = true,
-            .NOFOLLOW = args.no_follow,
-            .DIRECTORY = true,
-        },
-        else => .{
-            .ACCMODE = .RDONLY,
-            .NOFOLLOW = args.no_follow,
-            .DIRECTORY = true,
-            .CLOEXEC = true,
-        },
-    };
+    var symlink_flags: posix.O = std.posix.makeOFlags(.RDONLY, .{
+        .NOFOLLOW = args.no_follow,
+        .DIRECTORY = true,
+    });
+
+    if (@hasField(posix.O, "CLOEXEC"))
+        symlink_flags.CLOEXEC = true;
 
     if (@hasField(posix.O, "PATH") and !args.iterate)
         symlink_flags.PATH = true;
@@ -1556,7 +1538,8 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenOptions) OpenEr
 /// Asserts `flags` has `DIRECTORY` set.
 fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError!Dir {
     assert(flags.DIRECTORY);
-    const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) {
+    const mode = if (posix.mode_t == void) {} else 0;
+    const fd = posix.openatZ(self.fd, sub_path_c, flags, mode) catch |err| switch (err) {
         error.FileTooBig => unreachable, // can't happen for directories
         error.IsDir => unreachable, // we're setting DIRECTORY
         error.NoSpaceLeft => unreachable, // not setting CREAT
diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig
index 36e7999bf79d..10c474ab4e3c 100644
--- a/lib/std/fs/File.zig
+++ b/lib/std/fs/File.zig
@@ -27,9 +27,9 @@ pub const Kind = enum {
 /// the `touch` command, which would correspond to `0o644`. However, POSIX
 /// libc implementations use `0o666` inside `fopen` and then rely on the
 /// process-scoped "umask" setting to adjust this number for file creation.
-pub const default_mode = switch (builtin.os.tag) {
-    .windows => 0,
-    .wasi => 0,
+pub const default_mode = switch (posix.mode_t) {
+    void => {}, // WASI-without-libc has no mode support
+    u0 => 0, // Zig's Posix layer doesn't support modes for Windows
     else => 0o666,
 };
 
@@ -381,7 +381,7 @@ pub const Stat = struct {
     /// is unique to each filesystem.
     inode: INode,
     size: u64,
-    /// This is available on POSIX systems and is always 0 otherwise.
+    /// This is available on POSIX systems and is {} otherwise.
     mode: Mode,
     kind: Kind,
 
@@ -399,7 +399,7 @@ pub const Stat = struct {
         return .{
             .inode = st.ino,
             .size = @bitCast(st.size),
-            .mode = st.mode,
+            .mode = if (Mode == void) {} else st.mode,
             .kind = k: {
                 const m = st.mode & posix.S.IFMT;
                 switch (m) {
@@ -455,7 +455,7 @@ pub const Stat = struct {
         return .{
             .inode = st.ino,
             .size = @bitCast(st.size),
-            .mode = 0,
+            .mode = {},
             .kind = switch (st.filetype) {
                 .BLOCK_DEVICE => .block_device,
                 .CHARACTER_DEVICE => .character_device,
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index b0810f81a548..4a20e58c2722 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -14,6 +14,16 @@ const File = std.fs.File;
 const tmpDir = testing.tmpDir;
 const SymLinkFlags = std.fs.Dir.SymLinkFlags;
 
+// Filter to skip tests on platforms that don't support absolute paths
+const supports_absolute_paths = std.os.isGetFdPathSupportedOnTarget(builtin.os);
+
+// Filter to skip tests on platforms that don't support file locking
+const supports_file_locking = (builtin.os.tag != .wasi);
+
+// Filter to skip tests on platforms that don't support file modes
+// WASI does not currently support chmod (but it should in the future)
+const supports_chmod = (builtin.os.tag != .wasi and builtin.os.tag != .windows);
+
 const PathType = enum {
     relative,
     absolute,
@@ -279,12 +289,11 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
                     const sub_path_c = try posix.toPosixPath("symlink");
                     // the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
                     // note that if O_DIRECTORY is set, then this will error with ENOTDIR
-                    const flags: posix.O = .{
+                    const flags: posix.O = std.posix.makeOFlags(.RDONLY, .{
                         .NOFOLLOW = true,
                         .PATH = true,
-                        .ACCMODE = .RDONLY,
                         .CLOEXEC = true,
-                    };
+                    });
                     const fd = try posix.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
                     break :linux_symlink Dir{ .fd = fd };
                 },
@@ -315,7 +324,7 @@ test "openDir" {
 }
 
 test "accessAbsolute" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -333,7 +342,7 @@ test "accessAbsolute" {
 }
 
 test "openDirAbsolute" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -369,7 +378,7 @@ test "openDir cwd parent '..'" {
 
 test "openDir non-cwd parent '..'" {
     switch (native_os) {
-        .wasi, .netbsd, .openbsd => return error.SkipZigTest,
+        .netbsd, .openbsd => return error.SkipZigTest,
         else => {},
     }
 
@@ -382,17 +391,23 @@ test "openDir non-cwd parent '..'" {
     var dir = try subdir.openDir("..", .{});
     defer dir.close();
 
-    const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
-    defer testing.allocator.free(expected_path);
+    if (supports_absolute_paths) {
+        const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
+        defer testing.allocator.free(expected_path);
 
-    const actual_path = try dir.realpathAlloc(testing.allocator, ".");
-    defer testing.allocator.free(actual_path);
+        const actual_path = try dir.realpathAlloc(testing.allocator, ".");
+        defer testing.allocator.free(actual_path);
 
-    try testing.expectEqualStrings(expected_path, actual_path);
+        try testing.expectEqualStrings(expected_path, actual_path);
+    }
+
+    const tmpStat = try tmp.dir.stat();
+    const dirStat = try dir.stat();
+    try testing.expectEqual(tmpStat.inode, dirStat.inode);
 }
 
 test "readLinkAbsolute" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -604,7 +619,7 @@ fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool {
 }
 
 test "Dir.realpath smoke test" {
-    if (!comptime std.os.isGetFdPathSupportedOnTarget(builtin.os)) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     try testWithAllSupportedPathTypes(struct {
         fn impl(ctx: *TestContext) !void {
@@ -728,7 +743,7 @@ test "directory operations on files" {
             try testing.expectError(error.NotDir, ctx.dir.openDir(test_file_name, .{}));
             try testing.expectError(error.NotDir, ctx.dir.deleteDir(test_file_name));
 
-            if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
+            if (ctx.path_type == .absolute and supports_absolute_paths) {
                 try testing.expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));
                 try testing.expectError(error.NotDir, fs.deleteDirAbsolute(test_file_name));
             }
@@ -769,7 +784,7 @@ test "file operations on directories" {
             // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
             try testing.expectError(error.IsDir, ctx.dir.openFile(test_dir_name, .{ .mode = .read_write }));
 
-            if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
+            if (ctx.path_type == .absolute and supports_absolute_paths) {
                 try testing.expectError(error.IsDir, fs.createFileAbsolute(test_dir_name, .{}));
                 try testing.expectError(error.IsDir, fs.deleteFileAbsolute(test_dir_name));
             }
@@ -980,7 +995,7 @@ test "rename" {
 }
 
 test "renameAbsolute" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     var tmp_dir = tmpDir(.{});
     defer tmp_dir.cleanup();
@@ -1524,7 +1539,7 @@ test "AtomicFile" {
 }
 
 test "open file with exclusive nonblocking lock twice" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_file_locking) return error.SkipZigTest;
 
     try testWithAllSupportedPathTypes(struct {
         fn impl(ctx: *TestContext) !void {
@@ -1540,7 +1555,7 @@ test "open file with exclusive nonblocking lock twice" {
 }
 
 test "open file with shared and exclusive nonblocking lock" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_file_locking) return error.SkipZigTest;
 
     try testWithAllSupportedPathTypes(struct {
         fn impl(ctx: *TestContext) !void {
@@ -1556,7 +1571,7 @@ test "open file with shared and exclusive nonblocking lock" {
 }
 
 test "open file with exclusive and shared nonblocking lock" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_file_locking) return error.SkipZigTest;
 
     try testWithAllSupportedPathTypes(struct {
         fn impl(ctx: *TestContext) !void {
@@ -1615,7 +1630,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
 }
 
 test "open file with exclusive nonblocking lock twice (absolute paths)" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_file_locking or !supports_absolute_paths) return error.SkipZigTest;
 
     var random_bytes: [12]u8 = undefined;
     std.crypto.random.bytes(&random_bytes);
@@ -1648,8 +1663,6 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
 }
 
 test "walker" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
-
     var tmp = tmpDir(.{ .iterate = true });
     defer tmp.cleanup();
 
@@ -1701,8 +1714,6 @@ test "walker" {
 }
 
 test "walker without fully iterating" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
-
     var tmp = tmpDir(.{ .iterate = true });
     defer tmp.cleanup();
 
@@ -1724,8 +1735,6 @@ test "walker without fully iterating" {
 }
 
 test "'.' and '..' in fs.Dir functions" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
-
     if (native_os == .windows and builtin.cpu.arch == .aarch64) {
         // https://github.com/ziglang/zig/issues/17134
         return error.SkipZigTest;
@@ -1764,7 +1773,7 @@ test "'.' and '..' in fs.Dir functions" {
 }
 
 test "'.' and '..' in absolute functions" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1808,8 +1817,7 @@ test "'.' and '..' in absolute functions" {
 }
 
 test "chmod" {
-    if (native_os == .windows or native_os == .wasi)
-        return error.SkipZigTest;
+    if (!supports_chmod) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1830,8 +1838,7 @@ test "chmod" {
 }
 
 test "chown" {
-    if (native_os == .windows or native_os == .wasi)
-        return error.SkipZigTest;
+    if (!supports_chmod) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1863,8 +1870,7 @@ test "File.Metadata" {
 }
 
 test "File.Permissions" {
-    if (native_os == .wasi)
-        return error.SkipZigTest;
+    if (!supports_chmod) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1889,8 +1895,7 @@ test "File.Permissions" {
 }
 
 test "File.PermissionsUnix" {
-    if (native_os == .windows or native_os == .wasi)
-        return error.SkipZigTest;
+    if (!supports_chmod) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -2033,7 +2038,7 @@ test "invalid UTF-8/WTF-8 paths" {
 
             try testing.expectError(expected_err, ctx.dir.statFile(invalid_path));
 
-            if (native_os != .wasi) {
+            if (supports_absolute_paths) {
                 try testing.expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
                 try testing.expectError(expected_err, ctx.dir.realpathZ(invalid_path, &[_]u8{}));
                 try testing.expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
@@ -2042,7 +2047,7 @@ test "invalid UTF-8/WTF-8 paths" {
             try testing.expectError(expected_err, fs.rename(ctx.dir, invalid_path, ctx.dir, invalid_path));
             try testing.expectError(expected_err, fs.renameZ(ctx.dir, invalid_path, ctx.dir, invalid_path));
 
-            if (native_os != .wasi and ctx.path_type != .relative) {
+            if (supports_absolute_paths and ctx.path_type != .relative) {
                 try testing.expectError(expected_err, fs.updateFileAbsolute(invalid_path, invalid_path, .{}));
                 try testing.expectError(expected_err, fs.copyFileAbsolute(invalid_path, invalid_path, .{}));
                 try testing.expectError(expected_err, fs.makeDirAbsolute(invalid_path));
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index a29b381c401c..7703b17371d7 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -802,7 +802,7 @@ pub fn readlinkat(dirfd: i32, noalias path: [*:0]const u8, noalias buf_ptr: [*]u
     return syscall4(.readlinkat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(buf_ptr), buf_len);
 }
 
-pub fn mkdir(path: [*:0]const u8, mode: u32) usize {
+pub fn mkdir(path: [*:0]const u8, mode: mode_t) usize {
     if (@hasField(SYS, "mkdir")) {
         return syscall2(.mkdir, @intFromPtr(path), mode);
     } else {
@@ -810,11 +810,11 @@ pub fn mkdir(path: [*:0]const u8, mode: u32) usize {
     }
 }
 
-pub fn mkdirat(dirfd: i32, path: [*:0]const u8, mode: u32) usize {
+pub fn mkdirat(dirfd: i32, path: [*:0]const u8, mode: mode_t) usize {
     return syscall3(.mkdirat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), mode);
 }
 
-pub fn mknod(path: [*:0]const u8, mode: u32, dev: u32) usize {
+pub fn mknod(path: [*:0]const u8, mode: mode_t, dev: u32) usize {
     if (@hasField(SYS, "mknod")) {
         return syscall3(.mknod, @intFromPtr(path), mode, dev);
     } else {
@@ -822,7 +822,7 @@ pub fn mknod(path: [*:0]const u8, mode: u32, dev: u32) usize {
     }
 }
 
-pub fn mknodat(dirfd: i32, path: [*:0]const u8, mode: u32, dev: u32) usize {
+pub fn mknodat(dirfd: i32, path: [*:0]const u8, mode: mode_t, dev: u32) usize {
     return syscall4(.mknodat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), mode, dev);
 }
 
@@ -1041,7 +1041,7 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: i64) usize {
     }
 }
 
-pub fn access(path: [*:0]const u8, mode: u32) usize {
+pub fn access(path: [*:0]const u8, mode: mode_t) usize {
     if (@hasField(SYS, "access")) {
         return syscall2(.access, @intFromPtr(path), mode);
     } else {
@@ -1049,7 +1049,7 @@ pub fn access(path: [*:0]const u8, mode: u32) usize {
     }
 }
 
-pub fn faccessat(dirfd: i32, path: [*:0]const u8, mode: u32, flags: u32) usize {
+pub fn faccessat(dirfd: i32, path: [*:0]const u8, mode: mode_t, flags: u32) usize {
     return syscall4(.faccessat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), mode, flags);
 }
 
diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig
index 2c7d0d327211..0d393b60d30e 100644
--- a/lib/std/os/wasi.zig
+++ b/lib/std/os/wasi.zig
@@ -1,7 +1,7 @@
 //! wasi_snapshot_preview1 spec available (in witx format) here:
 //! * typenames -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/typenames.witx
 //! * module -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/wasi_snapshot_preview1.witx
-//! Note that libc API does *not* go in this file. wasi libc API goes into std/c/wasi.zig instead.
+//! Note that libc API does *not* go in this file. wasi libc API goes into std/c.zig instead.
 const builtin = @import("builtin");
 const std = @import("std");
 const assert = std.debug.assert;
diff --git a/lib/std/posix.zig b/lib/std/posix.zig
index 665ea17788ac..5ab3440143eb 100644
--- a/lib/std/posix.zig
+++ b/lib/std/posix.zig
@@ -29,22 +29,194 @@ test {
     _ = @import("posix/test.zig");
 }
 
-/// Whether to use libc for the POSIX API layer.
-const use_libc = builtin.link_libc or switch (native_os) {
-    .windows, .wasi => true,
-    else => false,
-};
-
 const linux = std.os.linux;
 const windows = std.os.windows;
 const wasi = std.os.wasi;
 
 /// A libc-compatible API layer.
-pub const system = if (use_libc)
+pub const system = if (builtin.link_libc or native_os == .windows)
     std.c
 else switch (native_os) {
     .linux => linux,
     .plan9 => std.os.plan9,
+    .wasi => struct {
+        // This is the non-libc Wasi "system" implementation. See std.c
+        // for the with-libc variation.  WASI is somewhat limited in a
+        // couple key ways that reduce the POSIX compatibilty:
+        //
+        // - no notion of "absolute paths".  So calls to `realpath`
+        //   or to look up the path for a file descriptor will
+        //   @compileError.
+        //
+        // - no notion of file modes/permissions.  The POSIX `mode_t` is
+        //   void.
+        //
+        // - Immutable "current working directory".  So APIs to
+        //   change the working directory will @compileError.
+        //
+        // - No signals, mmap, fcntl, pipe, gethostname, fork, or pthread
+        //   support.
+
+        pub const PATH_MAX = 4096;
+        pub const STDIN_FILENO = 0;
+        pub const STDOUT_FILENO = 1;
+        pub const STDERR_FILENO = 2;
+        pub const E = wasi.errno_t;
+        pub const fd_t = wasi.fd_t;
+        pub const ino_t = wasi.inode_t;
+        pub const dev_t = wasi.device_t;
+        pub const nlink_t = wasi.linkcount_t;
+        pub const off_t = i64;
+        pub const time_t = i64;
+        pub const msync = {};
+        pub const pid_t = void;
+        pub const pollfd = void;
+        pub const rlimit_resource = void;
+        pub const ucontext_t = void;
+        pub const AT = struct {
+            pub const FDCWD = 3; // Needs no translation.  In Zig, fd 3 is a preopened cwd fd.
+            pub const SYMLINK_FOLLOW = 0x100; // for {sym,}linkat()
+            pub const SYMLINK_NOFOLLOW = 0x200; // for {f,}chmodat()
+            pub const REMOVEDIR = 0x400;
+        };
+
+        pub const Stat = struct {
+            // POSIX-y set of the fields supported by wasi.filestat_t.
+            dev: system.dev_t,
+            ino: system.ino_t,
+            nlink: system.nlink_t,
+            mode: u32, // only the file-type bits (S.IFMT) no permission bits
+            size: system.off_t,
+            atim: system.timespec,
+            mtim: system.timespec,
+            ctim: system.timespec,
+
+            pub fn atime(self: @This()) system.timespec {
+                return self.atim;
+            }
+
+            pub fn mtime(self: @This()) system.timespec {
+                return self.mtim;
+            }
+
+            pub fn ctime(self: @This()) system.timespec {
+                return self.ctim;
+            }
+
+            pub fn fromFilestat(st: wasi.filestat_t) @This() {
+                return .{
+                    .dev = st.dev,
+                    .ino = st.ino,
+                    .mode = switch (st.filetype) {
+                        .UNKNOWN => 0,
+                        .BLOCK_DEVICE => system.S.IFBLK,
+                        .CHARACTER_DEVICE => system.S.IFCHR,
+                        .DIRECTORY => system.S.IFDIR,
+                        .REGULAR_FILE => system.S.IFREG,
+                        .SOCKET_DGRAM => system.S.IFSOCK,
+                        .SOCKET_STREAM => system.S.IFIFO,
+                        .SYMBOLIC_LINK => system.S.IFLNK,
+                        _ => 0,
+                    },
+                    .nlink = st.nlink,
+                    .size = @intCast(st.size),
+                    .atim = system.timespec.fromTimestamp(st.atim),
+                    .mtim = system.timespec.fromTimestamp(st.mtim),
+                    .ctim = system.timespec.fromTimestamp(st.ctim),
+                };
+            }
+        };
+
+        pub const S = struct {
+            // These constants here are not tied to any existing C headers.
+            pub const IFBLK = 0x1000;
+            pub const IFCHR = 0x2000;
+            pub const IFDIR = 0x3000;
+            pub const IFLNK = 0x4000;
+            pub const IFREG = 0x5000;
+            pub const IFSOCK = 0x6000;
+            pub const IFIFO = 0x7000;
+            pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
+
+            pub fn ISBLK(m: u32) bool {
+                return m & IFMT == IFBLK;
+            }
+
+            pub fn ISCHR(m: u32) bool {
+                return m & IFMT == IFCHR;
+            }
+
+            pub fn ISDIR(m: u32) bool {
+                return m & IFMT == IFDIR;
+            }
+
+            pub fn ISFIFO(m: u32) bool {
+                return m & IFMT == IFIFO;
+            }
+
+            pub fn ISLNK(m: u32) bool {
+                return m & IFMT == IFLNK;
+            }
+
+            pub fn ISREG(m: u32) bool {
+                return m & IFMT == IFREG;
+            }
+
+            pub fn ISSOCK(m: u32) bool {
+                return m & IFMT == IFSOCK;
+            }
+        };
+
+        pub const timespec = struct {
+            sec: system.time_t,
+            nsec: isize,
+
+            pub fn fromTimestamp(tm: wasi.timestamp_t) @This() {
+                const sec: wasi.timestamp_t = tm / 1_000_000_000;
+                const nsec = tm - sec * 1_000_000_000;
+                return .{
+                    .sec = @as(system.time_t, @intCast(sec)),
+                    .nsec = @as(isize, @intCast(nsec)),
+                };
+            }
+
+            pub fn toTimestamp(ts: @This()) wasi.timestamp_t {
+                return @as(wasi.timestamp_t, @intCast(ts.sec * 1_000_000_000)) +
+                    @as(wasi.timestamp_t, @intCast(ts.nsec));
+            }
+        };
+
+        pub const mode_t = void; // Wasi does not (yet) support file mode/permission bits
+
+        pub const O = packed struct(u32) {
+            // Map POSIX-y open flags into an amalgam of Wasi oflags_t, lookupflags_t, fdflags_t
+            // and ACCMODE.  Doesn't need to match any existing C structure.
+            ACCMODE: ACCMODE = .RDONLY,
+
+            // oflags_t:
+            CREAT: bool = false,
+            DIRECTORY: bool = false,
+            EXCL: bool = false,
+            TRUNC: bool = false,
+
+            // fdflags_t:
+            APPEND: bool = false,
+            DSYNC: bool = false,
+            NONBLOCK: bool = false,
+            RSYNC: bool = false,
+            SYNC: bool = false,
+
+            // lookupflags_t:
+            NOFOLLOW: bool = false, // POSIX reverses the polarity of Wasi SYMLINK_FOLLOW
+
+            _: u20 = 0,
+        };
+
+        pub const F_OK = 0x000;
+        pub const X_OK = 0x001;
+        pub const W_OK = 0x002;
+        pub const R_OK = 0x004;
+    },
     else => struct {
         pub const ucontext_t = void;
         pub const pid_t = void;
@@ -52,6 +224,8 @@ else switch (native_os) {
         pub const fd_t = void;
         pub const uid_t = void;
         pub const gid_t = void;
+        pub const msync = {};
+        pub const rlimit_resource = void;
     },
 };
 
@@ -194,6 +368,19 @@ pub const ACCMODE = enum(u2) {
     RDWR = 2,
 };
 
+// Build O flags set from the access mode and given base flags.  This is only necessary
+// because of the Wasi-libc O flags do not put RDONLY and WRONLY in adjacent bits.
+pub fn makeOFlags(acc: std.posix.ACCMODE, baseFlags: std.posix.O) std.posix.O {
+    var flags = baseFlags;
+    if (comptime (native_os == .wasi and builtin.link_libc)) {
+        flags.RDONLY = (acc == .RDONLY or acc == .RDWR);
+        flags.WRONLY = (acc == .WRONLY or acc == .RDWR);
+    } else {
+        flags.ACCMODE = acc;
+    }
+    return flags;
+}
+
 pub const TCSA = enum(c_uint) {
     NOW,
     DRAIN,
@@ -243,7 +430,7 @@ pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t;
 /// function only returns a well-defined value when it is called directly after
 /// the system function call whose errno value is intended to be observed.
 pub fn errno(rc: anytype) E {
-    if (use_libc) {
+    if (builtin.link_libc) {
         return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
     }
     const signed: isize = @bitCast(rc);
@@ -1643,20 +1830,19 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: O, mode: mode_t) OpenE
     if (native_os == .windows) {
         @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
     } else if (native_os == .wasi and !builtin.link_libc) {
-        // `mode` is ignored on WASI, which does not support unix-style file permissions
         const opts = try openOptionsFromFlagsWasi(flags);
         const fd = try openatWasi(
             dir_fd,
             file_path,
             opts.lookup_flags,
             opts.oflags,
-            opts.fs_flags,
+            opts.fd_flags,
             opts.fs_rights_base,
             opts.fs_rights_inheriting,
         );
         errdefer close(fd);
 
-        if (flags.write) {
+        if (flags.ACCMODE == .WRONLY or flags.ACCMODE == .RDWR) {
             const info = try std.os.fstat_wasi(fd);
             if (info.filetype == .DIRECTORY)
                 return error.IsDir;
@@ -1683,7 +1869,6 @@ pub fn openatWasi(
         switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) {
             .SUCCESS => return fd,
             .INTR => continue,
-
             .FAULT => unreachable,
             // Provides INVAL with a linux host on a bad path name, but NOENT on Windows
             .INVAL => return error.BadPathName,
@@ -1717,42 +1902,45 @@ const WasiOpenOptions = struct {
     lookup_flags: wasi.lookupflags_t,
     fs_rights_base: wasi.rights_t,
     fs_rights_inheriting: wasi.rights_t,
-    fs_flags: wasi.fdflags_t,
+    fd_flags: wasi.fdflags_t,
 };
 
 /// Compute rights + flags corresponding to the provided POSIX access mode.
-fn openOptionsFromFlagsWasi(oflag: O) OpenError!WasiOpenOptions {
-    const w = std.os.wasi;
-
-    // Next, calculate the read/write rights to request, depending on the
+fn openOptionsFromFlagsWasi(posixFlags: O) OpenError!WasiOpenOptions {
+    // Calculate the read/write rights to request, depending on the
     // provided POSIX access mode
-    var rights: w.rights_t = .{};
-    if (oflag.read) {
+    var rights: std.os.wasi.rights_t = .{};
+    const accmode = posixFlags.ACCMODE;
+    if (accmode == .RDONLY or accmode == .RDWR) {
         rights.FD_READ = true;
         rights.FD_READDIR = true;
     }
-    if (oflag.write) {
+    if (accmode == .WRONLY or accmode == .RDWR) {
         rights.FD_DATASYNC = true;
         rights.FD_WRITE = true;
         rights.FD_ALLOCATE = true;
         rights.FD_FILESTAT_SET_SIZE = true;
     }
 
-    // https://github.com/ziglang/zig/issues/18882
-    const flag_bits: u32 = @bitCast(oflag);
-    const oflags_int: u16 = @as(u12, @truncate(flag_bits >> 12));
-    const fs_flags_int: u16 = @as(u12, @truncate(flag_bits));
-
     return .{
-        // https://github.com/ziglang/zig/issues/18882
-        .oflags = @bitCast(oflags_int),
+        .oflags = .{
+            .CREAT = posixFlags.CREAT,
+            .DIRECTORY = posixFlags.DIRECTORY,
+            .EXCL = posixFlags.EXCL,
+            .TRUNC = posixFlags.TRUNC,
+        },
         .lookup_flags = .{
-            .SYMLINK_FOLLOW = !oflag.NOFOLLOW,
+            .SYMLINK_FOLLOW = !posixFlags.NOFOLLOW,
         },
         .fs_rights_base = rights,
         .fs_rights_inheriting = rights,
-        // https://github.com/ziglang/zig/issues/18882
-        .fs_flags = @bitCast(fs_flags_int),
+        .fd_flags = .{
+            .APPEND = posixFlags.APPEND,
+            .NONBLOCK = posixFlags.NONBLOCK,
+            .DSYNC = posixFlags.DSYNC,
+            .RSYNC = posixFlags.RSYNC,
+            .SYNC = posixFlags.SYNC,
+        },
     };
 }
 
@@ -1771,7 +1959,8 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: O, mode: mode_t) O
 
     const openat_sym = if (lfs64_abi) system.openat64 else system.openat;
     while (true) {
-        const rc = openat_sym(dir_fd, file_path, flags, mode);
+        const syscall_mode = if (mode_t == void) @as(u32, 0) else mode;
+        const rc = openat_sym(dir_fd, file_path, flags, syscall_mode);
         switch (errno(rc)) {
             .SUCCESS => return @intCast(rc),
             .INTR => continue,
@@ -2070,7 +2259,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
     if (native_os == .windows) {
         @compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead");
     } else if (native_os == .wasi and !builtin.link_libc) {
-        return symlinkat(target_path, wasi.AT.FDCWD, sym_link_path);
+        return symlinkat(target_path, AT.FDCWD, sym_link_path);
     }
     const target_path_c = try toPosixPath(target_path);
     const sym_link_path_c = try toPosixPath(sym_link_path);
@@ -2240,7 +2429,7 @@ pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8) LinkError!void {
 /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
 pub fn link(oldpath: []const u8, newpath: []const u8) LinkError!void {
     if (native_os == .wasi and !builtin.link_libc) {
-        return linkat(wasi.AT.FDCWD, oldpath, wasi.AT.FDCWD, newpath, 0) catch |err| switch (err) {
+        return linkat(AT.FDCWD, oldpath, AT.FDCWD, newpath, 0) catch |err| switch (err) {
             error.NotDir => unreachable, // link() does not support directories
             else => |e| return e,
         };
@@ -2377,7 +2566,7 @@ pub const UnlinkError = error{
 /// See also `unlinkZ`.
 pub fn unlink(file_path: []const u8) UnlinkError!void {
     if (native_os == .wasi and !builtin.link_libc) {
-        return unlinkat(wasi.AT.FDCWD, file_path, 0) catch |err| switch (err) {
+        return unlinkat(AT.FDCWD, file_path, 0) catch |err| switch (err) {
             error.DirNotEmpty => unreachable, // only occurs when targeting directories
             else => |e| return e,
         };
@@ -2571,7 +2760,7 @@ pub const RenameError = error{
 /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
 pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
     if (native_os == .wasi and !builtin.link_libc) {
-        return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path);
+        return renameat(AT.FDCWD, old_path, AT.FDCWD, new_path);
     } else if (native_os == .windows) {
         const old_path_w = try windows.sliceToPrefixedFileW(null, old_path);
         const new_path_w = try windows.sliceToPrefixedFileW(null, new_path);
@@ -2845,7 +3034,7 @@ pub fn renameatW(
 /// On Windows, `sub_dir_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
 /// On WASI, `sub_dir_path` should be encoded as valid UTF-8.
 /// On other platforms, `sub_dir_path` is an opaque sequence of bytes with no particular encoding.
-pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
+pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: mode_t) MakeDirError!void {
     if (native_os == .windows) {
         const sub_dir_path_w = try windows.sliceToPrefixedFileW(dir_fd, sub_dir_path);
         return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);
@@ -2857,7 +3046,7 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v
     }
 }
 
-pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
+pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: mode_t) MakeDirError!void {
     _ = mode;
     switch (wasi.path_create_directory(dir_fd, sub_dir_path.ptr, sub_dir_path.len)) {
         .SUCCESS => return,
@@ -2882,14 +3071,15 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr
 }
 
 /// Same as `mkdirat` except the parameters are null-terminated.
-pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
+pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: mode_t) MakeDirError!void {
     if (native_os == .windows) {
         const sub_dir_path_w = try windows.cStrToPrefixedFileW(dir_fd, sub_dir_path);
         return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);
     } else if (native_os == .wasi and !builtin.link_libc) {
         return mkdirat(dir_fd, mem.sliceTo(sub_dir_path, 0), mode);
     }
-    switch (errno(system.mkdirat(dir_fd, sub_dir_path, mode))) {
+    const syscall_mode = if (mode_t == void) @as(u32, 0) else mode;
+    switch (errno(system.mkdirat(dir_fd, sub_dir_path, syscall_mode))) {
         .SUCCESS => return,
         .ACCES => return error.AccessDenied,
         .BADF => unreachable,
@@ -2916,7 +3106,7 @@ pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirErr
 }
 
 /// Windows-only. Same as `mkdirat` except the parameter WTF16 LE encoded.
-pub fn mkdiratW(dir_fd: fd_t, sub_path_w: []const u16, mode: u32) MakeDirError!void {
+pub fn mkdiratW(dir_fd: fd_t, sub_path_w: []const u16, mode: mode_t) MakeDirError!void {
     _ = mode;
     const sub_dir_handle = windows.OpenFile(sub_path_w, .{
         .dir = dir_fd,
@@ -2963,9 +3153,9 @@ pub const MakeDirError = error{
 /// On Windows, `dir_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
 /// On WASI, `dir_path` should be encoded as valid UTF-8.
 /// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
-pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
+pub fn mkdir(dir_path: []const u8, mode: mode_t) MakeDirError!void {
     if (native_os == .wasi and !builtin.link_libc) {
-        return mkdirat(wasi.AT.FDCWD, dir_path, mode);
+        return mkdirat(AT.FDCWD, dir_path, mode);
     } else if (native_os == .windows) {
         const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
         return mkdirW(dir_path_w.span(), mode);
@@ -2979,7 +3169,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
 /// On Windows, `dir_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
 /// On WASI, `dir_path` should be encoded as valid UTF-8.
 /// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
-pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
+pub fn mkdirZ(dir_path: [*:0]const u8, mode: mode_t) MakeDirError!void {
     if (native_os == .windows) {
         const dir_path_w = try windows.cStrToPrefixedFileW(null, dir_path);
         return mkdirW(dir_path_w.span(), mode);
@@ -3010,7 +3200,7 @@ pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
 }
 
 /// Windows-only. Same as `mkdir` but the parameters is WTF16LE encoded.
-pub fn mkdirW(dir_path_w: []const u16, mode: u32) MakeDirError!void {
+pub fn mkdirW(dir_path_w: []const u16, mode: mode_t) MakeDirError!void {
     _ = mode;
     const sub_dir_handle = windows.OpenFile(dir_path_w, .{
         .dir = fs.cwd().fd,
@@ -3053,7 +3243,7 @@ pub const DeleteDirError = error{
 /// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
 pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
     if (native_os == .wasi and !builtin.link_libc) {
-        return unlinkat(wasi.AT.FDCWD, dir_path, AT.REMOVEDIR) catch |err| switch (err) {
+        return unlinkat(AT.FDCWD, dir_path, AT.REMOVEDIR) catch |err| switch (err) {
             error.FileSystem => unreachable, // only occurs when targeting files
             error.IsDir => unreachable, // only occurs when targeting files
             else => |e| return e,
@@ -3242,7 +3432,7 @@ pub const ReadLinkError = error{
 /// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
 pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
     if (native_os == .wasi and !builtin.link_libc) {
-        return readlinkat(wasi.AT.FDCWD, file_path, out_buffer);
+        return readlinkat(AT.FDCWD, file_path, out_buffer);
     } else if (native_os == .windows) {
         const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
         return readlinkW(file_path_w.span(), out_buffer);
@@ -4381,10 +4571,9 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat
 /// See also `fstatat`.
 pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
     if (native_os == .wasi and !builtin.link_libc) {
-        const filestat = try std.os.fstatat_wasi(dirfd, mem.sliceTo(pathname, 0), .{
-            .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
-        });
-        return Stat.fromFilestat(filestat);
+        return fstatat(dirfd, mem.sliceTo(pathname, 0), flags);
+    } else if (native_os == .windows) {
+        @compileError("fstatatZ is not yet implemented on Windows");
     }
 
     const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
@@ -4793,7 +4982,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
         _ = try windows.GetFileAttributesW(path_w.span().ptr);
         return;
     } else if (native_os == .wasi and !builtin.link_libc) {
-        return faccessat(wasi.AT.FDCWD, path, mode, 0);
+        return faccessat(AT.FDCWD, path, mode, 0);
     }
     const path_c = try toPosixPath(path);
     return accessZ(&path_c, mode);
@@ -4842,16 +5031,17 @@ pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
 /// Windows. See `fs` for the cross-platform file system API.
 pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
     if (native_os == .windows) {
-        const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
+        const path_w = try windows.sliceToPrefixedFileW(dirfd, path) catch |err| switch (err) {
+            error.AccessDenied => return error.PermissionDenied,
+            else => |e| return e,
+        };
         return faccessatW(dirfd, path_w.span().ptr);
     } else if (native_os == .wasi and !builtin.link_libc) {
         const resolved: RelativePathWasi = .{ .dir_fd = dirfd, .relative_path = path };
 
-        const st = blk: {
-            break :blk std.os.fstatat_wasi(dirfd, path, .{
-                .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
-            });
-        } catch |err| switch (err) {
+        const st = std.os.fstatat_wasi(resolved.dir_fd, path, .{
+            .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
+        }) catch |err| switch (err) {
             error.AccessDenied => return error.PermissionDenied,
             else => |e| return e,
         };
@@ -5043,7 +5233,7 @@ pub fn sysctl(
     newlen: usize,
 ) SysCtlError!void {
     if (native_os == .wasi) {
-        @panic("unsupported"); // TODO should be compile error, not panic
+        @compileError("sysctl is not supported on WASI");
     }
     if (native_os == .haiku) {
         @panic("unsupported"); // TODO should be compile error, not panic
@@ -5068,7 +5258,7 @@ pub fn sysctlbynameZ(
     newlen: usize,
 ) SysCtlError!void {
     if (native_os == .wasi) {
-        @panic("unsupported"); // TODO should be compile error, not panic
+        @compileError("sysctlbynameZ is not supported on WASI");
     }
     if (native_os == .haiku) {
         @panic("unsupported"); // TODO should be compile error, not panic
@@ -5085,6 +5275,10 @@ pub fn sysctlbynameZ(
 }
 
 pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
+    if (native_os == .wasi and !builtin.link_libc) {
+        @compileError("gettimeofday is not implemented on no-libc WASI yet");
+    }
+
     switch (errno(system.gettimeofday(tv, tz))) {
         .SUCCESS => return,
         .INVAL => unreachable,
@@ -5391,8 +5585,8 @@ pub fn realpath(pathname: []const u8, out_buffer: *[max_path_bytes]u8) RealPathE
     if (native_os == .windows) {
         const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);
         return realpathW(pathname_w.span(), out_buffer);
-    } else if (native_os == .wasi and !builtin.link_libc) {
-        @compileError("WASI does not support os.realpath");
+    } else if (native_os == .wasi) {
+        @compileError("WASI has no support for absolute paths");
     }
     const pathname_c = try toPosixPath(pathname);
     return realpathZ(&pathname_c, out_buffer);
@@ -5405,8 +5599,8 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[max_path_bytes]u8) RealP
     if (native_os == .windows) {
         const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);
         return realpathW(pathname_w.span(), out_buffer);
-    } else if (native_os == .wasi and !builtin.link_libc) {
-        return realpath(mem.sliceTo(pathname, 0), out_buffer);
+    } else if (native_os == .wasi) {
+        @compileError("WASI has no support for absolute paths");
     }
     if (!builtin.link_libc) {
         const flags: O = switch (native_os) {
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
index 7ba9a7701eba..c6957d5296b7 100644
--- a/lib/std/posix/test.zig
+++ b/lib/std/posix/test.zig
@@ -22,6 +22,32 @@ const tmpDir = std.testing.tmpDir;
 const Dir = std.fs.Dir;
 const ArenaAllocator = std.heap.ArenaAllocator;
 
+// Filter to skip tests on platforms that don't support chdir.
+const supports_chdir = (native_os != .wasi);
+
+// Filter to skip tests on platforms that don't support absolute paths
+const supports_absolute_paths = (native_os != .wasi);
+
+// Tests that create/delete files in the current working directory are not safe to run
+// in CI.  So this is off by default.  But handy when testing.  Do not submit true.
+// Test should probably be fixed to use unique names to avoid races.
+//
+// https://github.com/ziglang/zig/issues/14968
+const enable_sketchy_cwd_tests = true;
+
+test "check WASI CWD" {
+    if (native_os == .wasi) {
+        if (std.options.wasiCwd() != 3) {
+            @panic("WASI code that uses cwd (like this test) needs a preopen for cwd (add '--dir=.' to wasmtime)");
+        }
+
+        if (!builtin.link_libc) {
+            // WASI without-libc hardcodes fd 3 as the FDCWD token so it can be passed directly to WASI calls
+            try expectEqual(3, posix.AT.FDCWD);
+        }
+    }
+}
+
 // https://github.com/ziglang/zig/issues/20288
 test "WTF-8 to WTF-16 conversion buffer overflows" {
     if (native_os != .windows) return error.SkipZigTest;
@@ -32,12 +58,8 @@ test "WTF-8 to WTF-16 conversion buffer overflows" {
 }
 
 test "chdir smoke test" {
-    if (native_os == .wasi) return error.SkipZigTest;
-
-    if (true) {
-        // https://github.com/ziglang/zig/issues/14968
-        return error.SkipZigTest;
-    }
+    if (!supports_chdir) return error.SkipZigTest;
+    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
 
     // Get current working directory path
     var old_cwd_buf: [fs.max_path_bytes]u8 = undefined;
@@ -95,8 +117,14 @@ test "chdir smoke test" {
     }
 }
 
+const default_mode = switch (posix.mode_t) {
+    void => {},
+    u0 => 0,
+    else => 0o666,
+};
+
 test "open smoke test" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest;
     if (native_os == .windows) return error.SkipZigTest;
 
     // TODO verify file attributes using `fstat`
@@ -116,7 +144,7 @@ test "open smoke test" {
 
     var file_path: []u8 = undefined;
     var fd: posix.fd_t = undefined;
-    const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
+    const mode: posix.mode_t = default_mode;
 
     // Create some file using `open`.
     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
@@ -151,7 +179,6 @@ test "open smoke test" {
 }
 
 test "openat smoke test" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
     if (native_os == .windows) return error.SkipZigTest;
 
     // TODO verify file attributes using `fstatat`
@@ -160,7 +187,7 @@ test "openat smoke test" {
     defer tmp.cleanup();
 
     var fd: posix.fd_t = undefined;
-    const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
+    const mode: posix.mode_t = default_mode;
 
     // Create some file using `openat`.
     fd = try posix.openat(tmp.dir.fd, "some_file", CommonOpenFlags.lower(.{
@@ -207,12 +234,8 @@ test "openat smoke test" {
 }
 
 test "symlink with relative paths" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
+    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
 
-    if (true) {
-        // https://github.com/ziglang/zig/issues/14968
-        return error.SkipZigTest;
-    }
     const cwd = fs.cwd();
     cwd.deleteFile("file.txt") catch {};
     cwd.deleteFile("symlinked") catch {};
@@ -262,16 +285,12 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
 }
 
 test "link with relative paths" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
-
     switch (native_os) {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
     }
-    if (true) {
-        // https://github.com/ziglang/zig/issues/14968
-        return error.SkipZigTest;
-    }
+    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
+
     var cwd = fs.cwd();
 
     cwd.deleteFile("example.txt") catch {};
@@ -305,16 +324,12 @@ test "link with relative paths" {
 }
 
 test "linkat with different directories" {
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
-
     switch (native_os) {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
     }
-    if (true) {
-        // https://github.com/ziglang/zig/issues/14968
-        return error.SkipZigTest;
-    }
+    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
+
     var cwd = fs.cwd();
     var tmp = tmpDir(.{});
 
@@ -365,7 +380,7 @@ test "fstatat" {
     defer file.close();
 
     // now repeat but using `fstatat` instead
-    const flags = if (native_os == .wasi) 0x0 else posix.AT.SYMLINK_NOFOLLOW;
+    const flags = posix.AT.SYMLINK_NOFOLLOW;
     const statat = try posix.fstatat(tmp.dir.fd, "file.txt", flags);
     try expectEqual(stat, statat);
 }
@@ -1014,7 +1029,7 @@ test "POSIX file locking with fcntl" {
 }
 
 test "rename smoke test" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
     if (native_os == .windows) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
@@ -1032,7 +1047,7 @@ test "rename smoke test" {
 
     var file_path: []u8 = undefined;
     var fd: posix.fd_t = undefined;
-    const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
+    const mode: posix.mode_t = default_mode;
 
     // Create some file using `open`.
     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
@@ -1071,7 +1086,7 @@ test "rename smoke test" {
 }
 
 test "access smoke test" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
     if (native_os == .windows) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
@@ -1089,7 +1104,7 @@ test "access smoke test" {
 
     var file_path: []u8 = undefined;
     var fd: posix.fd_t = undefined;
-    const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
+    const mode: posix.mode_t = default_mode;
 
     // Create some file using `open`.
     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
@@ -1146,7 +1161,7 @@ test "isatty" {
 }
 
 test "read with empty buffer" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1171,7 +1186,7 @@ test "read with empty buffer" {
 }
 
 test "pread with empty buffer" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1196,7 +1211,7 @@ test "pread with empty buffer" {
 }
 
 test "write with empty buffer" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1221,7 +1236,7 @@ test "write with empty buffer" {
 }
 
 test "pwrite with empty buffer" {
-    if (native_os == .wasi) return error.SkipZigTest;
+    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1299,22 +1314,14 @@ const CommonOpenFlags = packed struct {
     NONBLOCK: bool = false,
 
     pub fn lower(cof: CommonOpenFlags) posix.O {
-        if (native_os == .wasi) return .{
-            .read = cof.ACCMODE != .WRONLY,
-            .write = cof.ACCMODE != .RDONLY,
-            .CREAT = cof.CREAT,
-            .EXCL = cof.EXCL,
-            .DIRECTORY = cof.DIRECTORY,
-            .NONBLOCK = cof.NONBLOCK,
-        };
-        var result: posix.O = .{
-            .ACCMODE = cof.ACCMODE,
+        var result: posix.O = std.posix.makeOFlags(cof.ACCMODE, .{
             .CREAT = cof.CREAT,
             .EXCL = cof.EXCL,
             .DIRECTORY = cof.DIRECTORY,
             .NONBLOCK = cof.NONBLOCK,
-            .CLOEXEC = cof.CLOEXEC,
-        };
+        });
+
+        if (@hasField(posix.O, "CLOEXEC")) result.CLOEXEC = cof.CLOEXEC;
         if (@hasField(posix.O, "LARGEFILE")) result.LARGEFILE = cof.LARGEFILE;
         return result;
     }

From d5d7e2821b2b228ffd82d60a49627a89964d244c Mon Sep 17 00:00:00 2001
From: Pat Tullmann <pat.github@tullmann.org>
Date: Sun, 4 Aug 2024 09:56:21 -0700
Subject: [PATCH 2/5] windows: Posix mode_t is void, not u0 now

To be consistent with the Wasi mode_t, use 'void'.
---
 lib/std/c.zig          | 5 ++---
 lib/std/fs/Dir.zig     | 3 +--
 lib/std/fs/File.zig    | 5 ++---
 lib/std/posix/test.zig | 1 -
 src/link.zig           | 2 +-
 src/link/Wasm.zig      | 3 +--
 6 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/lib/std/c.zig b/lib/std/c.zig
index e736391dc060..17cfb7fd77aa 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -135,9 +135,8 @@ pub const mode_t = switch (native_os) {
     .emscripten => emscripten.mode_t,
     .openbsd, .haiku, .netbsd, .solaris, .illumos => u32,
     .freebsd, .macos, .ios, .tvos, .watchos, .visionos => u16,
-    .wasi => void,
-    .windows => u0,
-    else => u0, // TODO: should be void?
+    .wasi, .windows => void,
+    else => void,
 };
 
 pub const nlink_t = switch (native_os) {
diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig
index f0fecf67be84..99d7401183ba 100644
--- a/lib/std/fs/Dir.zig
+++ b/lib/std/fs/Dir.zig
@@ -4,8 +4,7 @@ pub const Handle = posix.fd_t;
 
 /// Default mode bits for a new directory.
 pub const default_mode = switch (posix.mode_t) {
-    void => {}, // wasi-without-libc has no mode suppport
-    u0 => 0, // Zig's Posix layer doesn't support modes on Windows
+    void => {},
     else => 0o755,
 };
 
diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig
index 10c474ab4e3c..5c4399b45ebf 100644
--- a/lib/std/fs/File.zig
+++ b/lib/std/fs/File.zig
@@ -28,8 +28,7 @@ pub const Kind = enum {
 /// libc implementations use `0o666` inside `fopen` and then rely on the
 /// process-scoped "umask" setting to adjust this number for file creation.
 pub const default_mode = switch (posix.mode_t) {
-    void => {}, // WASI-without-libc has no mode support
-    u0 => 0, // Zig's Posix layer doesn't support modes for Windows
+    void => {},
     else => 0o666,
 };
 
@@ -495,7 +494,7 @@ pub fn stat(self: File) StatError!Stat {
         return .{
             .inode = info.InternalInformation.IndexNumber,
             .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
-            .mode = 0,
+            .mode = {},
             .kind = if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) reparse_point: {
                 var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined;
                 const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation);
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
index c6957d5296b7..bf73cea84e67 100644
--- a/lib/std/posix/test.zig
+++ b/lib/std/posix/test.zig
@@ -119,7 +119,6 @@ test "chdir smoke test" {
 
 const default_mode = switch (posix.mode_t) {
     void => {},
-    u0 => 0,
     else => 0o666,
 };
 
diff --git a/src/link.zig b/src/link.zig
index 894074cddaad..44f264ad24d0 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -985,7 +985,7 @@ pub const File = struct {
         // with 0o755 permissions, but it works appropriately if the system is configured
         // more leniently. As another data point, C's fopen seems to open files with the
         // 666 mode.
-        const executable_mode = if (builtin.target.os.tag == .windows) 0 else 0o777;
+        const executable_mode = if (fs.File.Mode == void) {} else 0o777;
         switch (effectiveOutputMode(use_lld, output_mode)) {
             .Lib => return switch (link_mode) {
                 .dynamic => executable_mode,
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 2c5fc3fe7a28..d73dd8179a0a 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -439,8 +439,7 @@ pub fn createEmpty(
                 fs.File.default_mode | 0b001_000_000
             else
                 fs.File.default_mode
-        else
-            0,
+        else {},
     });
     wasm.name = sub_path;
 

From ddc776d6f83cc3394f13d7e075a447dc6e720fd3 Mon Sep 17 00:00:00 2001
From: Pat Tullmann <pat.github@tullmann.org>
Date: Mon, 5 Aug 2024 20:24:52 -0700
Subject: [PATCH 3/5] {fs,io,posix,debug} tests: clean up and Wasi improvements

Add `unique_fname` for creating unique-name files when testing in the
default CWD (though tests should still prefer tmpDir()).  Enable the tests
disabled because this is racy (#14968).

Add some WASI-specific behavior handling.

Other cleanups of the tests:
* use `realpathAlloc()`to get fullpath into tmpDir() instances
* use `testing.allocator` where that simplifies things (vs. manual ArenaAllocator for 1 or 2 allocs)
* Trust `TmpDir.cleanup()` to clean up sub-trees
* Remove some unnecessary absolute paths (to enable WASI tests)
* Drop some no-longer necessary `[_][]const u8` explicit types
* Put file cleanups into `defer`

Fixes #14968
---
 lib/std/debug.zig      |   9 +-
 lib/std/fs/test.zig    | 121 ++++++----
 lib/std/io/test.zig    |  16 +-
 lib/std/posix/test.zig | 525 ++++++++++++++++++++---------------------
 4 files changed, 341 insertions(+), 330 deletions(-)

diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 1a64ca0dee75..1a097c363d26 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -1017,12 +1017,12 @@ test printLineFromFileAnyOs {
 
     var test_dir = std.testing.tmpDir(.{});
     defer test_dir.cleanup();
-    // Relies on testing.tmpDir internals which is not ideal, but SourceLocation requires paths.
+    // Relies on testing.tmpDir internals which is not ideal, but SourceLocation requires paths relative to cwd.
     const test_dir_path = try join(allocator, &.{ ".zig-cache", "tmp", test_dir.sub_path[0..] });
     defer allocator.free(test_dir_path);
 
-    // Cases
     {
+        // no newlines in file
         const path = try join(allocator, &.{ test_dir_path, "one_line.zig" });
         defer allocator.free(path);
         try test_dir.dir.writeFile(.{ .sub_path = "one_line.zig", .data = "no new lines in this file, but one is printed anyway" });
@@ -1034,6 +1034,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
+        // print 1 & 3 of 3-line file
         const path = try join(allocator, &.{ test_dir_path, "three_lines.zig" });
         defer allocator.free(path);
         try test_dir.dir.writeFile(.{
@@ -1054,6 +1055,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
+        // mem.page_size boundary crossing line
         const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});
         defer file.close();
         const path = try join(allocator, &.{ test_dir_path, "line_overlaps_page_boundary.zig" });
@@ -1070,6 +1072,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
+        // ends on mem.page_size boundary
         const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});
         defer file.close();
         const path = try join(allocator, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
@@ -1083,6 +1086,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
+        // multi-mem.page_size "line"
         const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});
         defer file.close();
         const path = try join(allocator, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
@@ -1108,6 +1112,7 @@ test printLineFromFileAnyOs {
         output.clearRetainingCapacity();
     }
     {
+        // mem.page_size pages of newlines
         const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});
         defer file.close();
         const path = try join(allocator, &.{ test_dir_path, "file_of_newlines.zig" });
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 4a20e58c2722..da9405f3e510 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -329,14 +329,8 @@ test "accessAbsolute" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    const base_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
+    defer testing.allocator.free(base_path);
 
     try fs.accessAbsolute(base_path, .{});
 }
@@ -347,32 +341,62 @@ test "openDirAbsolute" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
+    const tmp_ino = (try tmp.dir.stat()).inode;
+
     try tmp.dir.makeDir("subdir");
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
+    const sub_path = try tmp.dir.realpathAlloc(testing.allocator, "subdir");
+    defer testing.allocator.free(sub_path);
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..], "subdir" });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    // Can open subdir
+    var tmp_sub = try fs.openDirAbsolute(sub_path, .{});
+    defer tmp_sub.close();
+
+    const sub_ino = (try tmp_sub.stat()).inode;
 
     {
-        var dir = try fs.openDirAbsolute(base_path, .{});
+        // Can open parent
+        const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, ".." });
+        defer testing.allocator.free(dir_path);
+
+        var dir = try fs.openDirAbsolute(dir_path, .{});
         defer dir.close();
+
+        const ino = (try dir.stat()).inode;
+        try testing.expectEqual(tmp_ino, ino);
     }
 
-    for ([_][]const u8{ ".", ".." }) |sub_path| {
-        const dir_path = try fs.path.join(allocator, &.{ base_path, sub_path });
+    {
+        // Can open subdir + "."
+        const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, "." });
+        defer testing.allocator.free(dir_path);
+
         var dir = try fs.openDirAbsolute(dir_path, .{});
         defer dir.close();
+
+        const ino = (try dir.stat()).inode;
+        try testing.expectEqual(sub_ino, ino);
+    }
+
+    {
+        // Can open subdir + "..", with extra "."
+        const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, ".", "..", "." });
+        defer testing.allocator.free(dir_path);
+
+        var dir = try fs.openDirAbsolute(dir_path, .{});
+        defer dir.close();
+
+        const ino = (try dir.stat()).inode;
+        try testing.expectEqual(tmp_ino, ino);
     }
 }
 
 test "openDir cwd parent '..'" {
-    if (native_os == .wasi) return error.SkipZigTest;
-
-    var dir = try fs.cwd().openDir("..", .{});
+    var dir = fs.cwd().openDir("..", .{}) catch |err| {
+        if (native_os == .wasi and err == error.AccessDenied) {
+            return; // This is okay. WASI disallows escaping from the fs sandbox
+        }
+        return err;
+    };
     defer dir.close();
 }
 
@@ -388,7 +412,15 @@ test "openDir non-cwd parent '..'" {
     var subdir = try tmp.dir.makeOpenPath("subdir", .{});
     defer subdir.close();
 
-    var dir = try subdir.openDir("..", .{});
+    var dir = subdir.openDir("..", .{}) catch |err| {
+        if (native_os == .wasi and err == error.AccessDenied) {
+            // This is odd (we're asking for the parent of a subdirectory,
+            // which should be safely inside the sandbox), but this is the
+            // current wasmtime behavior (with and without libc).
+            return error.SkipZigTest;
+        }
+        return err;
+    };
     defer dir.close();
 
     if (supports_absolute_paths) {
@@ -421,10 +453,7 @@ test "readLinkAbsolute" {
     defer arena.deinit();
     const allocator = arena.allocator();
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    const base_path = try tmp.dir.realpathAlloc(allocator, ".");
 
     {
         const target_path = try fs.path.join(allocator, &.{ base_path, "file.txt" });
@@ -760,7 +789,6 @@ test "directory operations on files" {
 test "file operations on directories" {
     // TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
     if (native_os == .freebsd) return error.SkipZigTest;
-    if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/20747
 
     try testWithAllSupportedPathTypes(struct {
         fn impl(ctx: *TestContext) !void {
@@ -771,18 +799,29 @@ test "file operations on directories" {
             try testing.expectError(error.IsDir, ctx.dir.createFile(test_dir_name, .{}));
             try testing.expectError(error.IsDir, ctx.dir.deleteFile(test_dir_name));
             switch (native_os) {
-                // no error when reading a directory.
-                .dragonfly, .netbsd => {},
-                // Currently, WASI will return error.Unexpected (via ENOTCAPABLE) when attempting fd_read on a directory handle.
-                // TODO: Re-enable on WASI once https://github.com/bytecodealliance/wasmtime/issues/1935 is resolved.
-                .wasi => {},
+                .dragonfly, .netbsd => {
+                    // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732
+                    const buf = try ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize));
+                    testing.allocator.free(buf);
+                },
+                .wasi => {
+                    // WASI return EBADF, which gets mapped to NotOpenForReading.
+                    // See https://github.com/bytecodealliance/wasmtime/issues/1935
+                    try testing.expectError(error.NotOpenForReading, ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize)));
+                },
                 else => {
                     try testing.expectError(error.IsDir, ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize)));
                 },
             }
-            // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.
-            // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
-            try testing.expectError(error.IsDir, ctx.dir.openFile(test_dir_name, .{ .mode = .read_write }));
+
+            if (native_os == .wasi and builtin.link_libc) {
+                // Older wasmtime errors here, newer ones do not, see https://github.com/ziglang/zig/issues/20747
+                _ = ctx.dir.openFile(test_dir_name, .{ .mode = .read_write }) catch {};
+            } else {
+                // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.
+                // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
+                try testing.expectError(error.IsDir, ctx.dir.openFile(test_dir_name, .{ .mode = .read_write }));
+            }
 
             if (ctx.path_type == .absolute and supports_absolute_paths) {
                 try testing.expectError(error.IsDir, fs.createFileAbsolute(test_dir_name, .{}));
@@ -1005,10 +1044,7 @@ test "renameAbsolute" {
     defer arena.deinit();
     const allocator = arena.allocator();
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp_dir.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    const base_path = try tmp_dir.dir.realpathAlloc(allocator, ".");
 
     try testing.expectError(error.FileNotFound, fs.renameAbsolute(
         try fs.path.join(allocator, &.{ base_path, "missing_file_name" }),
@@ -1398,7 +1434,6 @@ test "sendfile" {
     defer tmp.cleanup();
 
     try tmp.dir.makePath("os_test_tmp");
-    defer tmp.dir.deleteTree("os_test_tmp") catch {};
 
     var dir = try tmp.dir.openDir("os_test_tmp", .{});
     defer dir.close();
@@ -1463,7 +1498,6 @@ test "copyRangeAll" {
     defer tmp.cleanup();
 
     try tmp.dir.makePath("os_test_tmp");
-    defer tmp.dir.deleteTree("os_test_tmp") catch {};
 
     var dir = try tmp.dir.openDir("os_test_tmp", .{});
     defer dir.close();
@@ -1782,10 +1816,7 @@ test "'.' and '..' in absolute functions" {
     defer arena.deinit();
     const allocator = arena.allocator();
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    const base_path = try tmp.dir.realpathAlloc(allocator, ".");
 
     const subdir_path = try fs.path.join(allocator, &.{ base_path, "./subdir" });
     try fs.makeDirAbsolute(subdir_path);
diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig
index 5ac4bb65d2b5..0c2e480e47be 100644
--- a/lib/std/io/test.zig
+++ b/lib/std/io/test.zig
@@ -108,10 +108,7 @@ test "File seek ops" {
 
     const tmp_file_name = "temp_test_file.txt";
     var file = try tmp.dir.createFile(tmp_file_name, .{});
-    defer {
-        file.close();
-        tmp.dir.deleteFile(tmp_file_name) catch {};
-    }
+    defer file.close();
 
     try file.writeAll(&([_]u8{0x55} ** 8192));
 
@@ -135,10 +132,7 @@ test "setEndPos" {
 
     const tmp_file_name = "temp_test_file.txt";
     var file = try tmp.dir.createFile(tmp_file_name, .{});
-    defer {
-        file.close();
-        tmp.dir.deleteFile(tmp_file_name) catch {};
-    }
+    defer file.close();
 
     // Verify that the file size changes and the file offset is not moved
     try std.testing.expect((try file.getEndPos()) == 0);
@@ -161,10 +155,8 @@ test "updateTimes" {
 
     const tmp_file_name = "just_a_temporary_file.txt";
     var file = try tmp.dir.createFile(tmp_file_name, .{ .read = true });
-    defer {
-        file.close();
-        tmp.dir.deleteFile(tmp_file_name) catch {};
-    }
+    defer file.close();
+
     const stat_old = try file.stat();
     // Set atime and mtime to 5s before
     try file.updateTimes(
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
index bf73cea84e67..11282ba4dfcb 100644
--- a/lib/std/posix/test.zig
+++ b/lib/std/posix/test.zig
@@ -8,7 +8,6 @@ const io = std.io;
 const fs = std.fs;
 const mem = std.mem;
 const elf = std.elf;
-const File = std.fs.File;
 const Thread = std.Thread;
 const linux = std.os.linux;
 
@@ -19,8 +18,6 @@ const AtomicRmwOp = std.builtin.AtomicRmwOp;
 const AtomicOrder = std.builtin.AtomicOrder;
 const native_os = builtin.target.os.tag;
 const tmpDir = std.testing.tmpDir;
-const Dir = std.fs.Dir;
-const ArenaAllocator = std.heap.ArenaAllocator;
 
 // Filter to skip tests on platforms that don't support chdir.
 const supports_chdir = (native_os != .wasi);
@@ -28,13 +25,6 @@ const supports_chdir = (native_os != .wasi);
 // Filter to skip tests on platforms that don't support absolute paths
 const supports_absolute_paths = (native_os != .wasi);
 
-// Tests that create/delete files in the current working directory are not safe to run
-// in CI.  So this is off by default.  But handy when testing.  Do not submit true.
-// Test should probably be fixed to use unique names to avoid races.
-//
-// https://github.com/ziglang/zig/issues/14968
-const enable_sketchy_cwd_tests = true;
-
 test "check WASI CWD" {
     if (native_os == .wasi) {
         if (std.options.wasiCwd() != 3) {
@@ -57,9 +47,25 @@ test "WTF-8 to WTF-16 conversion buffer overflows" {
     try expectError(error.NameTooLong, posix.chdirZ(input_wtf8));
 }
 
-test "chdir smoke test" {
+// For tests that create entries in the current working directory, use
+// this to ensure a unique name.  Otherwise parallel test invocations
+// (e.g., running on multiple architectures on CI) might collide in the
+// working directory.  Tests should prefer tmpDir() over this.
+fn unique_fname(allocator: std.mem.Allocator, basename: []const u8) ![]u8 {
+    const byte_count = 12;
+    const char_count = comptime std.fs.base64_encoder.calcSize(byte_count);
+
+    var random_bytes: [byte_count]u8 = undefined;
+    std.crypto.random.bytes(&random_bytes);
+
+    var prefix: [char_count]u8 = undefined;
+    _ = std.fs.base64_encoder.encode(&prefix, &random_bytes);
+
+    return try std.fmt.allocPrint(allocator, "{s}-{s}", .{ prefix, basename });
+}
+
+test "chdir absolute parent" {
     if (!supports_chdir) return error.SkipZigTest;
-    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
 
     // Get current working directory path
     var old_cwd_buf: [fs.max_path_bytes]u8 = undefined;
@@ -74,47 +80,45 @@ test "chdir smoke test" {
     }
 
     // Next, change current working directory to one level above
-    if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
-        const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
-        try posix.chdir(parent);
+    const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
+    try posix.chdir(parent);
+    defer posix.chdir(old_cwd) catch unreachable;
 
-        // Restore cwd because process may have other tests that do not tolerate chdir.
-        defer posix.chdir(old_cwd) catch unreachable;
+    var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
+    const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
+    try expect(mem.eql(u8, parent, new_cwd));
+}
 
-        var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
-        const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
-        try expect(mem.eql(u8, parent, new_cwd));
-    }
+test "chdir relative subdir" {
+    if (!supports_chdir) return error.SkipZigTest;
 
-    // Next, change current working directory to a temp directory one level below
-    {
-        // Create a tmp directory
-        var tmp_dir_buf: [fs.max_path_bytes]u8 = undefined;
-        const tmp_dir_path = path: {
-            var allocator = std.heap.FixedBufferAllocator.init(&tmp_dir_buf);
-            break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{ old_cwd, "zig-test-tmp" });
-        };
-        var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
+    // Get current working directory path
+    var old_cwd_buf: [fs.max_path_bytes]u8 = undefined;
+    const old_cwd = try posix.getcwd(old_cwd_buf[0..]);
 
-        // Change current working directory to tmp directory
-        try posix.chdir("zig-test-tmp");
+    const dir_name = try unique_fname(a, "chdir-target");
+    defer a.free(dir_name);
 
-        var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
-        const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
+    // Create a new (sub)directory
+    const expected_tmp_dir_path = try fs.path.resolve(a, &.{ old_cwd, dir_name });
+    defer a.free(expected_tmp_dir_path);
 
-        // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
-        var resolved_cwd_buf: [fs.max_path_bytes]u8 = undefined;
-        const resolved_cwd = path: {
-            var allocator = std.heap.FixedBufferAllocator.init(&resolved_cwd_buf);
-            break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{new_cwd});
-        };
-        try expect(mem.eql(u8, tmp_dir_path, resolved_cwd));
+    var tmp_dir = try fs.cwd().makeOpenPath(dir_name, .{});
+    defer tmp_dir.close();
+    defer fs.cwd().deleteDir(dir_name) catch {};
 
-        // Restore cwd because process may have other tests that do not tolerate chdir.
-        tmp_dir.close();
-        posix.chdir(old_cwd) catch unreachable;
-        try fs.cwd().deleteDir("zig-test-tmp");
-    }
+    // Change current working directory to new directory
+    try posix.chdir(dir_name);
+    defer posix.chdir(old_cwd) catch unreachable;
+
+    var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
+    const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
+
+    // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
+    const resolved_cwd = try fs.path.resolve(a, &.{new_cwd});
+    defer a.free(resolved_cwd);
+
+    try expect(mem.eql(u8, expected_tmp_dir_path, resolved_cwd));
 }
 
 const default_mode = switch (posix.mode_t) {
@@ -131,50 +135,62 @@ test "open smoke test" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    // Get base abs path
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
+    const base_path = try tmp.dir.realpathAlloc(a, ".");
+    defer a.free(base_path);
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    var file_path: []u8 = undefined;
-    var fd: posix.fd_t = undefined;
     const mode: posix.mode_t = default_mode;
 
-    // Create some file using `open`.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
-    posix.close(fd);
+    {
+        // Create some file using `open`.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
+        posix.close(fd);
+    }
 
-    // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    try expectError(error.PathAlreadyExists, posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
+    {
+        // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        try expectError(error.PathAlreadyExists, posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
+    }
 
-    // Try opening without `EXCL` flag.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
-    posix.close(fd);
+    {
+        // Try opening without `EXCL` flag.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
+        posix.close(fd);
+    }
 
-    // Try opening as a directory which should fail.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    try expectError(error.NotDir, posix.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
+    {
+        // Try opening as a directory which should fail.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        try expectError(error.NotDir, posix.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
+    }
 
-    // Create some directory
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try posix.mkdir(file_path, mode);
+    {
+        // Create some directory
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        try posix.mkdir(file_path, mode);
+    }
 
-    // Open dir using `open`
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
-    posix.close(fd);
+    {
+        // Open dir using `open`
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
+        posix.close(fd);
+    }
 
-    // Try opening as file which should fail.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try expectError(error.IsDir, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
+    {
+        // Try opening as file which should fail.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        try expectError(error.IsDir, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
+    }
 }
 
 test "openat smoke test" {
@@ -227,46 +243,45 @@ test "openat smoke test" {
     posix.close(fd);
 
     // Try opening as file which should fail.
+    // Note on wasmtime v23.0.2 (at least) this returns a file descriptor (not the IsDir error).
     try expectError(error.IsDir, posix.openat(tmp.dir.fd, "some_dir", CommonOpenFlags.lower(.{
         .ACCMODE = .RDWR,
     }), mode));
 }
 
 test "symlink with relative paths" {
-    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
+    const targetName = try unique_fname(a, "symlink-target");
+    defer a.free(targetName);
+
+    const symlinkName = try unique_fname(a, "symlinked");
+    defer a.free(symlinkName);
 
     const cwd = fs.cwd();
-    cwd.deleteFile("file.txt") catch {};
-    cwd.deleteFile("symlinked") catch {};
 
-    // First, try relative paths in cwd
-    try cwd.writeFile(.{ .sub_path = "file.txt", .data = "nonsense" });
+    defer cwd.deleteFile(targetName) catch {};
+    defer cwd.deleteFile(symlinkName) catch {};
+
+    // Create the target file
+    try cwd.writeFile(.{ .sub_path = targetName, .data = "nonsense" });
 
     if (native_os == .windows) {
-        std.os.windows.CreateSymbolicLink(
-            cwd.fd,
-            &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
-            &[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
-            false,
-        ) catch |err| switch (err) {
+        const wtargetName = try std.unicode.wtf8ToWtf16LeAllocZ(a, targetName);
+        const wsymlinkName = try std.unicode.wtf8ToWtf16LeAllocZ(a, symlinkName);
+        defer a.free(wtargetName);
+        defer a.free(wsymlinkName);
+
+        std.os.windows.CreateSymbolicLink(cwd.fd, wsymlinkName, wtargetName, false) catch |err| switch (err) {
             // Symlink requires admin privileges on windows, so this test can legitimately fail.
-            error.AccessDenied => {
-                try cwd.deleteFile("file.txt");
-                try cwd.deleteFile("symlinked");
-                return error.SkipZigTest;
-            },
+            error.AccessDenied => return error.SkipZigTest,
             else => return err,
         };
     } else {
-        try posix.symlink("file.txt", "symlinked");
+        try posix.symlink(targetName, symlinkName);
     }
 
     var buffer: [fs.max_path_bytes]u8 = undefined;
-    const given = try posix.readlink("symlinked", buffer[0..]);
-    try expect(mem.eql(u8, "file.txt", given));
-
-    try cwd.deleteFile("file.txt");
-    try cwd.deleteFile("symlinked");
+    const given = try posix.readlink(symlinkName, buffer[0..]);
+    try expect(mem.eql(u8, targetName, given));
 }
 
 test "readlink on Windows" {
@@ -288,20 +303,25 @@ test "link with relative paths" {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
     }
-    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
+
+    const targetName = try unique_fname(a, "link-target");
+    defer a.free(targetName);
+
+    const linkName = try unique_fname(a, "newlink");
+    defer a.free(linkName);
 
     var cwd = fs.cwd();
 
-    cwd.deleteFile("example.txt") catch {};
-    cwd.deleteFile("new.txt") catch {};
+    defer cwd.deleteFile(targetName) catch {};
+    defer cwd.deleteFile(linkName) catch {};
 
-    try cwd.writeFile(.{ .sub_path = "example.txt", .data = "example" });
-    try posix.link("example.txt", "new.txt");
+    try cwd.writeFile(.{ .sub_path = targetName, .data = "example" });
+    try posix.link(targetName, linkName);
 
-    const efd = try cwd.openFile("example.txt", .{});
+    const efd = try cwd.openFile(targetName, .{});
     defer efd.close();
 
-    const nfd = try cwd.openFile("new.txt", .{});
+    const nfd = try cwd.openFile(linkName, .{});
     defer nfd.close();
 
     {
@@ -312,14 +332,12 @@ test "link with relative paths" {
         try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
     }
 
-    try posix.unlink("new.txt");
+    try posix.unlink(linkName);
 
     {
         const estat = try posix.fstat(efd.handle);
         try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
     }
-
-    try cwd.deleteFile("example.txt");
 }
 
 test "linkat with different directories" {
@@ -327,21 +345,25 @@ test "linkat with different directories" {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
     }
-    if (!enable_sketchy_cwd_tests) return error.SkipZigTest;
+
+    const targetName = try unique_fname(a, "link-target");
+    defer a.free(targetName);
+
+    const linkName = try unique_fname(a, "newlink");
+    defer a.free(linkName);
 
     var cwd = fs.cwd();
     var tmp = tmpDir(.{});
 
-    cwd.deleteFile("example.txt") catch {};
-    tmp.dir.deleteFile("new.txt") catch {};
+    defer cwd.deleteFile(targetName) catch {};
 
-    try cwd.writeFile(.{ .sub_path = "example.txt", .data = "example" });
-    try posix.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
+    try cwd.writeFile(.{ .sub_path = targetName, .data = "example" });
+    try posix.linkat(cwd.fd, targetName, tmp.dir.fd, linkName, 0);
 
-    const efd = try cwd.openFile("example.txt", .{});
+    const efd = try cwd.openFile(targetName, .{});
     defer efd.close();
 
-    const nfd = try tmp.dir.openFile("new.txt", .{});
+    const nfd = try tmp.dir.openFile(linkName, .{});
 
     {
         defer nfd.close();
@@ -352,14 +374,12 @@ test "linkat with different directories" {
         try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
     }
 
-    try posix.unlinkat(tmp.dir.fd, "new.txt", 0);
+    try posix.unlinkat(tmp.dir.fd, linkName, 0);
 
     {
         const estat = try posix.fstat(efd.handle);
         try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
     }
-
-    try cwd.deleteFile("example.txt");
 }
 
 test "fstatat" {
@@ -698,8 +718,6 @@ test "mmap" {
             try testing.expectEqual(i, try stream.readInt(u32, .little));
         }
     }
-
-    try tmp.dir.deleteFile(test_out_file);
 }
 
 test "getenv" {
@@ -725,10 +743,7 @@ test "fcntl" {
     const test_out_file = "os_tmp_test";
 
     const file = try tmp.dir.createFile(test_out_file, .{});
-    defer {
-        file.close();
-        tmp.dir.deleteFile(test_out_file) catch {};
-    }
+    defer file.close();
 
     // Note: The test assumes createFile opens the file with CLOEXEC
     {
@@ -764,10 +779,7 @@ test "sync" {
 
     const test_out_file = "os_tmp_test";
     const file = try tmp.dir.createFile(test_out_file, .{});
-    defer {
-        file.close();
-        tmp.dir.deleteFile(test_out_file) catch {};
-    }
+    defer file.close();
 
     posix.sync();
     try posix.syncfs(file.handle);
@@ -784,10 +796,7 @@ test "fsync" {
 
     const test_out_file = "os_tmp_test";
     const file = try tmp.dir.createFile(test_out_file, .{});
-    defer {
-        file.close();
-        tmp.dir.deleteFile(test_out_file) catch {};
-    }
+    defer file.close();
 
     try posix.fsync(file.handle);
     try posix.fdatasync(file.handle);
@@ -1034,54 +1043,65 @@ test "rename smoke test" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    // Get base abs path
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
+    const base_path = try tmp.dir.realpathAlloc(a, ".");
+    defer a.free(base_path);
 
-    var file_path: []u8 = undefined;
-    var fd: posix.fd_t = undefined;
     const mode: posix.mode_t = default_mode;
 
-    // Create some file using `open`.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
-    posix.close(fd);
-
-    // Rename the file
-    var new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
-    try posix.rename(file_path, new_file_path);
-
-    // Try opening renamed file
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);
-    posix.close(fd);
+    {
+        // Create some file using `open`.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
+        posix.close(fd);
+
+        // Rename the file
+        const new_file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
+        defer a.free(new_file_path);
+        try posix.rename(file_path, new_file_path);
+    }
 
-    // Try opening original file - should fail with error.FileNotFound
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
+    {
+        // Try opening renamed file
+        const file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);
+        posix.close(fd);
+    }
 
-    // Create some directory
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try posix.mkdir(file_path, mode);
+    {
+        // Try opening original file - should fail with error.FileNotFound
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
+    }
 
-    // Rename the directory
-    new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
-    try posix.rename(file_path, new_file_path);
+    {
+        // Create some directory
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        try posix.mkdir(file_path, mode);
+
+        // Rename the directory
+        const new_file_path = try fs.path.join(a, &.{ base_path, "some_other_dir" });
+        defer a.free(new_file_path);
+        try posix.rename(file_path, new_file_path);
+    }
 
-    // Try opening renamed directory
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
-    posix.close(fd);
+    {
+        // Try opening renamed directory
+        const file_path = try fs.path.join(a, &.{ base_path, "some_other_dir" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
+        posix.close(fd);
+    }
 
-    // Try opening original directory - should fail with error.FileNotFound
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
+    {
+        // Try opening original directory - should fail with error.FileNotFound
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
+    }
 }
 
 test "access smoke test" {
@@ -1091,44 +1111,51 @@ test "access smoke test" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    // Get base abs path
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
+    const base_path = try tmp.dir.realpathAlloc(a, ".");
+    defer a.free(base_path);
 
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    var file_path: []u8 = undefined;
-    var fd: posix.fd_t = undefined;
     const mode: posix.mode_t = default_mode;
 
-    // Create some file using `open`.
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
-    posix.close(fd);
+    {
+        // Create some file using `open`.
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
+        posix.close(fd);
+    }
 
-    // Try to access() the file
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    if (native_os == .windows) {
-        try posix.access(file_path, posix.F_OK);
-    } else {
-        try posix.access(file_path, posix.F_OK | posix.W_OK | posix.R_OK);
+    {
+        // Try to access() the file
+        const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
+        defer a.free(file_path);
+        if (native_os == .windows) {
+            try posix.access(file_path, posix.F_OK);
+        } else {
+            try posix.access(file_path, posix.F_OK | posix.W_OK | posix.R_OK);
+        }
     }
 
-    // Try to access() a non-existent file - should fail with error.FileNotFound
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
-    try expectError(error.FileNotFound, posix.access(file_path, posix.F_OK));
+    {
+        // Try to access() a non-existent file - should fail with error.FileNotFound
+        const file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
+        defer a.free(file_path);
+        try expectError(error.FileNotFound, posix.access(file_path, posix.F_OK));
+    }
 
-    // Create some directory
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try posix.mkdir(file_path, mode);
+    {
+        // Create some directory
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
+        try posix.mkdir(file_path, mode);
+    }
+
+    {
+        // Try to access() the directory
+        const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
+        defer a.free(file_path);
 
-    // Try to access() the directory
-    file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
-    try posix.access(file_path, posix.F_OK);
+        try posix.access(file_path, posix.F_OK);
+    }
 }
 
 test "timerfd" {
@@ -1160,103 +1187,59 @@ test "isatty" {
 }
 
 test "read with empty buffer" {
-    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
-
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    // Get base abs path
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    const file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    var file = try fs.cwd().createFile(file_path, .{ .read = true });
+    var file = try tmp.dir.createFile("read_empty", .{ .read = true });
     defer file.close();
 
-    const bytes = try allocator.alloc(u8, 0);
+    const bytes = try a.alloc(u8, 0);
+    defer a.free(bytes);
 
-    _ = try posix.read(file.handle, bytes);
+    const rc = try posix.read(file.handle, bytes);
+    try expectEqual(rc, 0);
 }
 
 test "pread with empty buffer" {
-    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
-
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    // Get base abs path
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    const file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    var file = try fs.cwd().createFile(file_path, .{ .read = true });
+    var file = try tmp.dir.createFile("pread_empty", .{ .read = true });
     defer file.close();
 
-    const bytes = try allocator.alloc(u8, 0);
+    const bytes = try a.alloc(u8, 0);
+    defer a.free(bytes);
 
-    _ = try posix.pread(file.handle, bytes, 0);
+    const rc = try posix.pread(file.handle, bytes, 0);
+    try expectEqual(rc, 0);
 }
 
 test "write with empty buffer" {
-    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
-
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    // Get base abs path
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    const file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    var file = try fs.cwd().createFile(file_path, .{});
+    var file = try tmp.dir.createFile("write_empty", .{});
     defer file.close();
 
-    const bytes = try allocator.alloc(u8, 0);
+    const bytes = try a.alloc(u8, 0);
+    defer a.free(bytes);
 
-    _ = try posix.write(file.handle, bytes);
+    const rc = try posix.write(file.handle, bytes);
+    try expectEqual(rc, 0);
 }
 
 test "pwrite with empty buffer" {
-    if (!supports_absolute_paths) return error.SkipZigTest; // Or fix test to use relative paths
-
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    const allocator = arena.allocator();
-
-    // Get base abs path
-    const base_path = blk: {
-        const relative_path = try fs.path.join(allocator, &[_][]const u8{ ".zig-cache", "tmp", tmp.sub_path[0..] });
-        break :blk try fs.realpathAlloc(allocator, relative_path);
-    };
-
-    const file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
-    var file = try fs.cwd().createFile(file_path, .{});
+    var file = try tmp.dir.createFile("pwrite_empty", .{});
     defer file.close();
 
-    const bytes = try allocator.alloc(u8, 0);
+    const bytes = try a.alloc(u8, 0);
+    defer a.free(bytes);
 
-    _ = try posix.pwrite(file.handle, bytes, 0);
+    const rc = try posix.pwrite(file.handle, bytes, 0);
+    try expectEqual(rc, 0);
 }
 
 fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {

From 46e72c16413fa75581d9d9bf30726f8441c01331 Mon Sep 17 00:00:00 2001
From: Pat Tullmann <pat.github@tullmann.org>
Date: Mon, 5 Aug 2024 23:51:20 -0700
Subject: [PATCH 4/5] wasi: fstat{at,} support

Add a test for fstat{,at} with symlinks (for everyone, not just wasi)

Fix the wasi-libc Stat.mode field, and add the expected accessors to the S
struct.

Fixes #20890
---
 lib/std/c.zig          | 30 +++++++++++++++++-
 lib/std/posix/test.zig | 71 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 94 insertions(+), 7 deletions(-)

diff --git a/lib/std/c.zig b/lib/std/c.zig
index 17cfb7fd77aa..2829069dce84 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -1712,6 +1712,34 @@ pub const S = switch (native_os) {
         pub const IFREG = 0x8000;
         pub const IFSOCK = 0xc000;
         pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
+
+        pub fn ISBLK(m: u32) bool {
+            return m & IFMT == IFBLK;
+        }
+
+        pub fn ISCHR(m: u32) bool {
+            return m & IFMT == IFCHR;
+        }
+
+        pub fn ISDIR(m: u32) bool {
+            return m & IFMT == IFDIR;
+        }
+
+        pub fn ISFIFO(m: u32) bool {
+            return m & IFMT == IFIFO;
+        }
+
+        pub fn ISLNK(m: u32) bool {
+            return m & IFMT == IFLNK;
+        }
+
+        pub fn ISREG(m: u32) bool {
+            return m & IFMT == IFREG;
+        }
+
+        pub fn ISSOCK(m: u32) bool {
+            return m & IFMT == IFSOCK;
+        }
     },
     .macos, .ios, .tvos, .watchos, .visionos => struct {
         pub const IFMT = 0o170000;
@@ -6489,7 +6517,7 @@ pub const Stat = switch (native_os) {
         dev: dev_t,
         ino: ino_t,
         nlink: nlink_t,
-        mode: mode_t,
+        mode: c_uint, // only the file-type bits (S.IFMT), no permission bits
         uid: uid_t,
         gid: gid_t,
         __pad0: c_uint = 0,
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
index 11282ba4dfcb..7c0203b9c7aa 100644
--- a/lib/std/posix/test.zig
+++ b/lib/std/posix/test.zig
@@ -25,6 +25,9 @@ const supports_chdir = (native_os != .wasi);
 // Filter to skip tests on platforms that don't support absolute paths
 const supports_absolute_paths = (native_os != .wasi);
 
+// Filter to skip tests on platforms that don't (yet) suppport fstat/fstatat
+const supports_fstat = (native_os != .windows);
+
 test "check WASI CWD" {
     if (native_os == .wasi) {
         if (std.options.wasiCwd() != 3) {
@@ -299,6 +302,8 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
 }
 
 test "link with relative paths" {
+    if (!supports_fstat) return error.SkipZigTest;
+
     switch (native_os) {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
@@ -341,6 +346,8 @@ test "link with relative paths" {
 }
 
 test "linkat with different directories" {
+    if (!supports_fstat) return error.SkipZigTest;
+
     switch (native_os) {
         .wasi, .linux, .solaris, .illumos => {},
         else => return error.SkipZigTest,
@@ -382,9 +389,8 @@ test "linkat with different directories" {
     }
 }
 
-test "fstatat" {
-    // enable when `fstat` and `fstatat` are implemented on Windows
-    if (native_os == .windows) return error.SkipZigTest;
+test "fstat(at) file" {
+    if (!supports_fstat) return error.SkipZigTest;
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -396,14 +402,66 @@ test "fstatat" {
     // fetch file's info on the opened fd directly
     const file = try tmp.dir.openFile("file.txt", .{});
     const stat = try posix.fstat(file.handle);
-    defer file.close();
+    file.close();
 
     // now repeat but using `fstatat` instead
-    const flags = posix.AT.SYMLINK_NOFOLLOW;
-    const statat = try posix.fstatat(tmp.dir.fd, "file.txt", flags);
+    const statat = try posix.fstatat(tmp.dir.fd, "file.txt", 0);
     try expectEqual(stat, statat);
 }
 
+test "fstat(at) symlink" {
+    if (!supports_fstat) return error.SkipZigTest;
+
+    var tmp = testing.tmpDir(.{});
+    defer tmp.cleanup();
+
+    try tmp.dir.writeFile(.{ .sub_path = "target.txt", .data = "irrelevant" });
+
+    const target = try tmp.dir.openFile("target.txt", .{});
+    const statTarget = try posix.fstat(target.handle);
+    target.close();
+
+    // Set up symlink
+    try tmp.dir.symLink("target.txt", "sym.lnk", .{});
+
+    // Openat (+follow) + fstat() the symlink
+    const linkFollowFd = try posix.openat(tmp.dir.fd, "sym.lnk", .{}, default_mode);
+    defer posix.close(linkFollowFd);
+    const statLinkFollow = try posix.fstat(linkFollowFd);
+
+    // fstatat (with and without follow) the symlink
+    const statatLinkFollow = try posix.fstatat(tmp.dir.fd, "sym.lnk", 0);
+    const statatLinkNoFollow = try posix.fstatat(tmp.dir.fd, "sym.lnk", posix.AT.SYMLINK_NOFOLLOW);
+
+    if (@hasField(posix.O, "PATH")) {
+        // Can only openat() a symlink with NOFOLLOW if O.PATH is
+        // supported.  Result should exactly match result from the
+        // no-follow fstatat() call.
+
+        const linkNoFollowFd = try posix.openat(tmp.dir.fd, "sym.lnk", .{ .NOFOLLOW = true, .PATH = true }, default_mode);
+        defer posix.close(linkNoFollowFd);
+
+        const statLinkNoFollow = try posix.fstat(linkNoFollowFd);
+        try testing.expectEqual(statLinkNoFollow, statatLinkNoFollow);
+    }
+
+    // Link following should have followed the link
+    try testing.expectEqual(statTarget, statLinkFollow);
+    try testing.expectEqual(statTarget, statatLinkFollow);
+
+    // symlink and target are different:
+    try testing.expect(statTarget.ino != statatLinkNoFollow.ino);
+    try testing.expect(statTarget.mode != statatLinkNoFollow.mode);
+
+    // target is a regular, non-link file:
+    try testing.expect(posix.S.ISREG(statTarget.mode));
+    try testing.expect(!posix.S.ISLNK(statTarget.mode));
+
+    // symlink is a non-regular, link file:
+    try testing.expect(!posix.S.ISREG(statatLinkNoFollow.mode));
+    try testing.expect(posix.S.ISLNK(statatLinkNoFollow.mode));
+}
+
 test "readlinkat" {
     var tmp = tmpDir(.{});
     defer tmp.cleanup();
@@ -1249,6 +1307,7 @@ fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
 
 test "fchmodat smoke test" {
     if (!std.fs.has_executable_bit) return error.SkipZigTest;
+    if (!supports_fstat) return error.SkipZigTest; // for expectMode()
 
     var tmp = tmpDir(.{});
     defer tmp.cleanup();

From 3be1ed05101f73d65971c3dacae677a1edf3b983 Mon Sep 17 00:00:00 2001
From: Pat Tullmann <pat.github@tullmann.org>
Date: Thu, 15 Aug 2024 23:28:09 -0700
Subject: [PATCH 5/5] wasi c.zig: Update comments around wasi-libc constants

Point to the correct header files where the wasi-libc constants are
defined that the Zig lib/std/c.zig is replicating.

Zig's current copy of wasi-libc has a bug in the file-mode constants.
Both S_IFIFO and S_IFSOCK are 0xc000, but S_IFIFO should be 0x1000.  See
https://github.com/WebAssembly/wasi-libc/pull/463.
---
 lib/std/c.zig | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lib/std/c.zig b/lib/std/c.zig
index 2829069dce84..6a0a57ae04e4 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -672,6 +672,7 @@ pub const F = switch (native_os) {
     .linux => linux.F,
     .emscripten => emscripten.F,
     .wasi => struct {
+        // Match F_* constants from lib/libc/include/wasm-wasi-musl/__header_fcntl.h
         pub const GETFD = 1;
         pub const SETFD = 2;
         pub const GETFL = 3;
@@ -1703,14 +1704,20 @@ pub const S = switch (native_os) {
     .linux => linux.S,
     .emscripten => emscripten.S,
     .wasi => struct {
-        // Match wasi-libc's libc-bottom-half/headers/public/__mode_t.h
+        // Match S_* constants from lib/libc/include/wasm-wasi-musl/__mode_t.h
+        //
+        // Note, a bug in wasi-libc means both IFIFO and IFSOCK have the same value (0xc000).
+        // IFIFO should be 0x1000 (see https://github.com/WebAssembly/wasi-libc/pull/463), and
+        // 0x1000 is used by the wasi-libc bottom-half.  So we use 0x1000 here.  But the actual bit
+        // values we get back from a wasi-libc may get masked with the wrong values, or may get
+        // mistranslated.  So the FIFO and Socket file-type bits are not trustworthy.
         pub const IFBLK = 0x6000;
         pub const IFCHR = 0x2000;
         pub const IFDIR = 0x4000;
-        pub const IFIFO = 0x1000;
+        pub const IFIFO = 0x1000; // buggy
         pub const IFLNK = 0xa000;
         pub const IFREG = 0x8000;
-        pub const IFSOCK = 0xc000;
+        pub const IFSOCK = 0xc000; // buggy
         pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
 
         pub fn ISBLK(m: u32) bool {
@@ -6513,7 +6520,7 @@ pub const Stat = switch (native_os) {
     },
     .emscripten => emscripten.Stat,
     .wasi => extern struct {
-        // Matches wasi-libc's libc-bottom-half/headers/public/__struct_stat.h
+        // Matches wasi-libc's struct stat in lib/libc/include/wasm-wasi-musl/__struct_stat.h
         dev: dev_t,
         ino: ino_t,
         nlink: nlink_t,
@@ -7213,7 +7220,7 @@ pub const AT = switch (native_os) {
         pub const RECURSIVE = 0x8000;
     },
     .wasi => struct {
-        // Match AT_* constants in wasi-libc libc-bottom-half/headers/public/__header_fcntl.h
+        // Match AT_* constants in lib/libc/include/wasm-wasi-musl/__header_fcntl.h
         pub const FDCWD = -2;
         pub const EACCESS = 0x0;
         pub const SYMLINK_NOFOLLOW = 0x1;
@@ -7248,7 +7255,7 @@ pub const O = switch (native_os) {
         _: u9 = 0,
     },
     .wasi => packed struct(u32) {
-        // Match layout from wasi-libc libc-bottom-half/headers/public/__header_fcntl.h
+        // Match O_* bits from lib/libc/include/wasm-wasi-musl/__header_fcntl.h
         APPEND: bool = false,
         DSYNC: bool = false,
         NONBLOCK: bool = false,