From 2156197f5606365720d2090feed1a2ac601557d6 Mon Sep 17 00:00:00 2001 From: notcancername <119271574+notcancername@users.noreply.github.com> Date: Sat, 13 May 2023 21:57:47 +0200 Subject: [PATCH 1/2] Implement access and faccessat with W_OK on Windows `windows.GetFileAttributesW` seems to already handle the errors checked for in `accessW`. --- lib/std/c/windows.zig | 2 ++ lib/std/os.zig | 32 +++++++++++++++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/std/c/windows.zig b/lib/std/c/windows.zig index b6ce03d21e50..397790b90fa1 100644 --- a/lib/std/c/windows.zig +++ b/lib/std/c/windows.zig @@ -199,6 +199,8 @@ pub const E = enum(u16) { pub const STRUNCATE = 80; pub const F_OK = 0; +// pub const R_OK = 1; +pub const W_OK = 2; /// Remove directory instead of unlinking file pub const AT = struct { diff --git a/lib/std/os.zig b/lib/std/os.zig index db07614ce9f5..af1963ff71ba 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4447,11 +4447,12 @@ pub const AccessError = error{ } || UnexpectedError; /// check user's permissions for a file -/// TODO currently this assumes `mode` is `F.OK` on Windows. pub fn access(path: []const u8, mode: u32) AccessError!void { if (builtin.os.tag == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); - _ = try windows.GetFileAttributesW(path_w.span().ptr); + const attrs = try windows.GetFileAttributesW(path_w.span().ptr); + if (mode & W_OK != 0 and attrs & windows.FILE_ATTRIBUTE_READONLY != 0) + return error.PermissionDenied; return; } else if (builtin.os.tag == .wasi and !builtin.link_libc) { return faccessat(wasi.AT.FDCWD, path, mode, 0); @@ -4464,7 +4465,9 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { if (builtin.os.tag == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); - _ = try windows.GetFileAttributesW(path_w.span().ptr); + const attrs = try windows.GetFileAttributesW(path_w.span().ptr); + if (mode & W_OK != 0 and attrs & windows.FILE_ATTRIBUTE_READONLY != 0) + return error.PermissionDenied; return; } else if (builtin.os.tag == .wasi and !builtin.link_libc) { return access(mem.sliceTo(path, 0), mode); @@ -4488,19 +4491,11 @@ pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { /// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string. /// Otherwise use `access` or `accessC`. -/// TODO currently this ignores `mode`. pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!void { - _ = mode; const ret = try windows.GetFileAttributesW(path); - if (ret != windows.INVALID_FILE_ATTRIBUTES) { - return; - } - switch (windows.kernel32.GetLastError()) { - .FILE_NOT_FOUND => return error.FileNotFound, - .PATH_NOT_FOUND => return error.FileNotFound, - .ACCESS_DENIED => return error.PermissionDenied, - else => |err| return windows.unexpectedError(err), - } + if (mode & W_OK != 0 and ret & windows.FILE_ATTRIBUTE_READONLY != 0) + return error.PermissionDenied; + return; } /// Check user's permissions for a file, based on an open directory handle. @@ -4574,9 +4569,8 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces /// Same as `faccessat` except asserts the target is Windows and the path parameter /// is NtDll-prefixed, null-terminated, WTF-16 encoded. -/// TODO currently this ignores `mode` and `flags` +/// TODO currently this ignores `flags` pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void { - _ = mode; _ = flags; if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { return; @@ -4601,7 +4595,11 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32 }; var basic_info: windows.FILE_BASIC_INFORMATION = undefined; switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) { - .SUCCESS => return, + .SUCCESS => { + if (mode & W_OK != 0 and basic_info.FileAttributes & windows.FILE_ATTRIBUTE_READONLY != 0) + return error.PermissionDenied; + return; + }, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, .OBJECT_NAME_INVALID => unreachable, From 64ddc872f85a05fc8dbb1fe21894b302320c2435 Mon Sep 17 00:00:00 2001 From: notcancername <119271574+notcancername@users.noreply.github.com> Date: Thu, 27 Jul 2023 01:00:41 +0200 Subject: [PATCH 2/2] remove R_OK comment --- lib/std/c/windows.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/c/windows.zig b/lib/std/c/windows.zig index 397790b90fa1..afd63fce702d 100644 --- a/lib/std/c/windows.zig +++ b/lib/std/c/windows.zig @@ -199,7 +199,6 @@ pub const E = enum(u16) { pub const STRUNCATE = 80; pub const F_OK = 0; -// pub const R_OK = 1; pub const W_OK = 2; /// Remove directory instead of unlinking file