diff --git a/src/platform.zig b/src/platform.zig index 2c2b68b97..ea7e18dc7 100644 --- a/src/platform.zig +++ b/src/platform.zig @@ -131,6 +131,15 @@ fn linuxResultAsIsize(rc: usize) isize { return @bitCast(rc); } +fn linuxResultAsI32(rc: usize) i32 { + const e = std.os.linux.errno(rc); + if (e != .SUCCESS) { + std.c._errno().* = @intFromEnum(e); + return -1; + } + return 0; +} + fn linuxResultAsI64(rc: usize) i64 { const e = std.os.linux.errno(rc); if (e != .SUCCESS) { @@ -241,6 +250,63 @@ pub fn pfdClose(handle: std.posix.fd_t) void { } } +// Path-based helpers. All POSIX-only (callers of these helpers already +// branch to a `std.Io.Dir` path on Windows before reaching here). The +// `.windows` arms return -1 so compilation succeeds on Windows builds; +// the helpers themselves are never reached at runtime on Windows. +pub fn pfdMkdirAt(dirfd: std.posix.fd_t, path: [*:0]const u8, mode: u32) i32 { + switch (comptime builtin.os.tag) { + .windows => return -1, + .linux => return linuxResultAsI32(std.os.linux.mkdirat(dirfd, path, mode)), + else => return @intCast(std.c.mkdirat(dirfd, path, @intCast(mode))), + } +} + +pub fn pfdUnlinkAt(dirfd: std.posix.fd_t, path: [*:0]const u8, flags: u32) i32 { + switch (comptime builtin.os.tag) { + .windows => return -1, + .linux => return linuxResultAsI32(std.os.linux.unlinkat(dirfd, path, flags)), + else => return @intCast(std.c.unlinkat(dirfd, path, @intCast(flags))), + } +} + +pub fn pfdRenameAt( + old_dirfd: std.posix.fd_t, + old_path: [*:0]const u8, + new_dirfd: std.posix.fd_t, + new_path: [*:0]const u8, +) i32 { + switch (comptime builtin.os.tag) { + .windows => return -1, + .linux => return linuxResultAsI32(std.os.linux.renameat(old_dirfd, old_path, new_dirfd, new_path)), + else => return @intCast(std.c.renameat(old_dirfd, old_path, new_dirfd, new_path)), + } +} + +pub fn pfdReadlinkAt(dirfd: std.posix.fd_t, path: [*:0]const u8, buf: []u8) isize { + switch (comptime builtin.os.tag) { + .windows => return -1, + .linux => return linuxResultAsIsize(std.os.linux.readlinkat(dirfd, path, buf.ptr, buf.len)), + else => return std.c.readlinkat(dirfd, path, buf.ptr, buf.len), + } +} + +pub fn pfdDup(fd: std.posix.fd_t) i32 { + switch (comptime builtin.os.tag) { + .windows => return -1, + .linux => { + const rc = std.os.linux.dup(fd); + const e = std.os.linux.errno(rc); + if (e != .SUCCESS) { + std.c._errno().* = @intFromEnum(e); + return -1; + } + return @intCast(rc); + }, + else => return @intCast(std.c.dup(fd)), + } +} + pub fn pfdFsync(handle: std.posix.fd_t) i32 { switch (comptime builtin.os.tag) { .windows => return if (FlushFileBuffers(handle) == windows.BOOL.FALSE) -1 else 0, diff --git a/src/wasi.zig b/src/wasi.zig index 9107ebc3d..09cb24d59 100644 --- a/src/wasi.zig +++ b/src/wasi.zig @@ -1652,7 +1652,7 @@ pub fn path_create_directory(ctx: *anyopaque, _: usize) anyerror!void { try pushErrno(vm, .NAMETOOLONG); return; }; - if (std.c.mkdirat(host_fd, path_z.ptr, 0o777) != 0) { + if (platform.pfdMkdirAt(host_fd, path_z.ptr, 0o777) != 0) { try pushErrno(vm, cErrnoToWasi()); return; } @@ -1697,7 +1697,7 @@ pub fn path_remove_directory(ctx: *anyopaque, _: usize) anyerror!void { try pushErrno(vm, .NAMETOOLONG); return; }; - if (std.c.unlinkat(host_fd, path_z.ptr, @intCast(posix.AT.REMOVEDIR)) != 0) { + if (platform.pfdUnlinkAt(host_fd, path_z.ptr, @intCast(posix.AT.REMOVEDIR)) != 0) { try pushErrno(vm, cErrnoToWasi()); return; } @@ -1742,7 +1742,7 @@ pub fn path_unlink_file(ctx: *anyopaque, _: usize) anyerror!void { try pushErrno(vm, .NAMETOOLONG); return; }; - if (std.c.unlinkat(host_fd, path_z.ptr, 0) != 0) { + if (platform.pfdUnlinkAt(host_fd, path_z.ptr, 0) != 0) { try pushErrno(vm, cErrnoToWasi()); return; } @@ -1802,7 +1802,7 @@ pub fn path_rename(ctx: *anyopaque, _: usize) anyerror!void { try pushErrno(vm, .NAMETOOLONG); return; }; - if (std.c.renameat(old_host_fd, old_z.ptr, new_host_fd, new_z.ptr) != 0) { + if (platform.pfdRenameAt(old_host_fd, old_z.ptr, new_host_fd, new_z.ptr) != 0) { try pushErrno(vm, cErrnoToWasi()); return; } @@ -2053,7 +2053,17 @@ pub fn fd_filestat_set_times(ctx: *anyopaque, _: usize) anyerror!void { }; const times = wasiTimesToTimespec(fst_flags, atim_ns, mtim_ns); - if (std.c.futimens(host_fd, ×) != 0) { + const failed = switch (comptime builtin.os.tag) { + .linux => blk: { + // utimensat(fd, NULL, times, 0) == futimens(fd, times) + const rc = std.os.linux.utimensat(host_fd, null, ×, 0); + const e = std.os.linux.errno(rc); + if (e != .SUCCESS) std.c._errno().* = @intFromEnum(e); + break :blk e != .SUCCESS; + }, + else => std.c.futimens(host_fd, ×) != 0, + }; + if (failed) { try pushErrno(vm, cErrnoToWasi()); return; } @@ -2301,7 +2311,7 @@ pub fn fd_renumber(ctx: *anyopaque, _: usize) anyerror!void { // Dup host fd and assign to fd_to slot const new_host = blk: { if (builtin.os.tag == .windows) unreachable; - const rc = std.c.dup(from_host); + const rc = platform.pfdDup(from_host); if (rc < 0) { try pushErrno(vm, cErrnoToWasi()); return; @@ -2486,7 +2496,7 @@ pub fn path_readlink(ctx: *anyopaque, _: usize) anyerror!void { try pushErrno(vm, .NAMETOOLONG); return; }; - const rc = std.c.readlinkat(host_fd, path_z.ptr, buf.ptr, buf.len); + const rc = platform.pfdReadlinkAt(host_fd, path_z.ptr, buf); if (rc < 0) { try pushErrno(vm, cErrnoToWasi()); return;