diff --git a/lib/std/event/batch.zig b/lib/std/event/batch.zig index 82dadb91be..af59b32490 100644 --- a/lib/std/event/batch.zig +++ b/lib/std/event/batch.zig @@ -109,13 +109,13 @@ pub fn Batch( test "std.event.Batch" { var count: usize = 0; - var batch = Batch(void, 2).init(); + var batch = Batch(void, 2, .auto_async).init(); batch.add(&async sleepALittle(&count)); batch.add(&async increaseByTen(&count)); batch.wait(); testing.expect(count == 11); - var another = Batch(anyerror!void, 2).init(); + var another = Batch(anyerror!void, 2, .auto_async).init(); another.add(&async somethingElse()); another.add(&async doSomethingThatFails()); testing.expectError(error.ItBroke, another.wait()); diff --git a/lib/std/fs.zig b/lib/std/fs.zig index c96aeeafc7..bc9ae6aa2d 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -818,6 +818,13 @@ pub const Dir = struct { ) File.OpenError!File { const w = os.windows; + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return error.IsDir; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return error.IsDir; + } + var result = File{ .handle = undefined, .io_mode = .blocking, @@ -839,12 +846,6 @@ pub const Dir = struct { .SecurityDescriptor = null, .SecurityQualityOfService = null, }; - if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { - return error.IsDir; - } - if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { - return error.IsDir; - } var io: w.IO_STATUS_BLOCK = undefined; const rc = w.ntdll.NtCreateFile( &result.handle, @@ -1332,12 +1333,20 @@ pub const Dir = struct { /// For example, instead of testing if a file exists and then opening it, just /// open it and handle the error for file not found. pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void { + if (builtin.os == .windows) { + const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); + return self.accessW(&sub_path_w, flags); + } const path_c = try os.toPosixPath(sub_path); return self.accessZ(&path_c, flags); } /// Same as `access` except the path parameter is null-terminated. pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void { + if (builtin.os == .windows) { + const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path); + return self.accessW(&sub_path_w, flags); + } const os_mode = if (flags.write and flags.read) @as(u32, os.R_OK | os.W_OK) else if (flags.write) @@ -1351,9 +1360,13 @@ pub const Dir = struct { return result; } - /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. - pub fn accessW(self: Dir, sub_path: [*:0]const u16, flags: File.OpenFlags) AccessError!void { - return os.faccessatW(self.fd, sub_path, 0, 0); + /// Same as `access` except asserts the target OS is Windows and the path parameter is + /// * WTF-16 encoded + /// * null-terminated + /// * NtDll prefixed + /// TODO currently this ignores `flags`. + pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { + return os.faccessatW(self.fd, sub_path_w, 0, 0); } }; diff --git a/lib/std/os.zig b/lib/std/os.zig index fd85f8801b..ff2296d928 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2553,10 +2553,42 @@ 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 null-terminated WTF-16 encoded. +/// is NtDll-prefixed, null-terminated, WTF-16 encoded. /// TODO currently this ignores `mode` and `flags` -pub fn faccessatW(dirfd: fd_t, path: [*:0]const u16, mode: u32, flags: u32) AccessError!void { - @compileError("TODO implement faccessatW on Windows"); +pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void { + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return; + } + + const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { + error.Overflow => return error.NameTooLong, + }; + var nt_name = windows.UNICODE_STRING{ + .Length = path_len_bytes, + .MaximumLength = path_len_bytes, + .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + }; + var attr = windows.OBJECT_ATTRIBUTES{ + .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd, + .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. + .ObjectName = &nt_name, + .SecurityDescriptor = null, + .SecurityQualityOfService = null, + }; + var basic_info: windows.FILE_BASIC_INFORMATION = undefined; + switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) { + .SUCCESS => return, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .INVALID_PARAMETER => unreachable, + .ACCESS_DENIED => return error.PermissionDenied, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + else => |rc| return windows.unexpectedStatus(rc), + } } pub const PipeError = error{ diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 08f22386f9..e98a2e6a87 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile( Length: ULONG, FileInformationClass: FILE_INFORMATION_CLASS, ) callconv(.Stdcall) NTSTATUS; + +pub extern "NtDll" fn NtQueryAttributesFile( + ObjectAttributes: *OBJECT_ATTRIBUTES, + FileAttributes: *FILE_BASIC_INFORMATION, +) callconv(.Stdcall) NTSTATUS; + pub extern "NtDll" fn NtCreateFile( FileHandle: *HANDLE, DesiredAccess: ACCESS_MASK,