authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 17:10:43-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 17:10:43-05:00
log8173fbfb66132f0fca42a3c8415381ad9f5d632d
treea33289790cdc09c1a71ff14f6a35e82a54d082b8
parent4b02a39aa93b0043f05de0d90443051c019643ab
signature Commit is signed but in an unrecognized format.

implement os.faccessat for Windows


4 files changed, 65 insertions(+), 14 deletions(-)

lib/std/event/batch.zig+2-2
...@@ -109,13 +109,13 @@ pub fn Batch(...@@ -109,13 +109,13 @@ pub fn Batch(
109109
110test "std.event.Batch" {110test "std.event.Batch" {
111 var count: usize = 0;111 var count: usize = 0;
112 var batch = Batch(void, 2).init();112 var batch = Batch(void, 2, .auto_async).init();
113 batch.add(&async sleepALittle(&count));113 batch.add(&async sleepALittle(&count));
114 batch.add(&async increaseByTen(&count));114 batch.add(&async increaseByTen(&count));
115 batch.wait();115 batch.wait();
116 testing.expect(count == 11);116 testing.expect(count == 11);
117117
118 var another = Batch(anyerror!void, 2).init();118 var another = Batch(anyerror!void, 2, .auto_async).init();
119 another.add(&async somethingElse());119 another.add(&async somethingElse());
120 another.add(&async doSomethingThatFails());120 another.add(&async doSomethingThatFails());
121 testing.expectError(error.ItBroke, another.wait());121 testing.expectError(error.ItBroke, another.wait());
lib/std/fs.zig+22-9
...@@ -818,6 +818,13 @@ pub const Dir = struct {...@@ -818,6 +818,13 @@ pub const Dir = struct {
818 ) File.OpenError!File {818 ) File.OpenError!File {
819 const w = os.windows;819 const w = os.windows;
820820
821 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
822 return error.IsDir;
823 }
824 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
825 return error.IsDir;
826 }
827
821 var result = File{828 var result = File{
822 .handle = undefined,829 .handle = undefined,
823 .io_mode = .blocking,830 .io_mode = .blocking,
...@@ -839,12 +846,6 @@ pub const Dir = struct {...@@ -839,12 +846,6 @@ pub const Dir = struct {
839 .SecurityDescriptor = null,846 .SecurityDescriptor = null,
840 .SecurityQualityOfService = null,847 .SecurityQualityOfService = null,
841 };848 };
842 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
843 return error.IsDir;
844 }
845 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
846 return error.IsDir;
847 }
848 var io: w.IO_STATUS_BLOCK = undefined;849 var io: w.IO_STATUS_BLOCK = undefined;
849 const rc = w.ntdll.NtCreateFile(850 const rc = w.ntdll.NtCreateFile(
850 &result.handle,851 &result.handle,
...@@ -1332,12 +1333,20 @@ pub const Dir = struct {...@@ -1332,12 +1333,20 @@ pub const Dir = struct {
1332 /// For example, instead of testing if a file exists and then opening it, just1333 /// For example, instead of testing if a file exists and then opening it, just
1333 /// open it and handle the error for file not found.1334 /// open it and handle the error for file not found.
1334 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {1335 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
1336 if (builtin.os == .windows) {
1337 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1338 return self.accessW(&sub_path_w, flags);
1339 }
1335 const path_c = try os.toPosixPath(sub_path);1340 const path_c = try os.toPosixPath(sub_path);
1336 return self.accessZ(&path_c, flags);1341 return self.accessZ(&path_c, flags);
1337 }1342 }
13381343
1339 /// Same as `access` except the path parameter is null-terminated.1344 /// Same as `access` except the path parameter is null-terminated.
1340 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {1345 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
1346 if (builtin.os == .windows) {
1347 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
1348 return self.accessW(&sub_path_w, flags);
1349 }
1341 const os_mode = if (flags.write and flags.read)1350 const os_mode = if (flags.write and flags.read)
1342 @as(u32, os.R_OK | os.W_OK)1351 @as(u32, os.R_OK | os.W_OK)
1343 else if (flags.write)1352 else if (flags.write)
...@@ -1351,9 +1360,13 @@ pub const Dir = struct {...@@ -1351,9 +1360,13 @@ pub const Dir = struct {
1351 return result;1360 return result;
1352 }1361 }
13531362
1354 /// Same as `access` except the parameter is null-terminated UTF16LE-encoded.1363 /// Same as `access` except asserts the target OS is Windows and the path parameter is
1355 pub fn accessW(self: Dir, sub_path: [*:0]const u16, flags: File.OpenFlags) AccessError!void {1364 /// * WTF-16 encoded
1356 return os.faccessatW(self.fd, sub_path, 0, 0);1365 /// * null-terminated
1366 /// * NtDll prefixed
1367 /// TODO currently this ignores `flags`.
1368 pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
1369 return os.faccessatW(self.fd, sub_path_w, 0, 0);
1357 }1370 }
1358};1371};
13591372
lib/std/os.zig+35-3
...@@ -2553,10 +2553,42 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces...@@ -2553,10 +2553,42 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces
2553}2553}
25542554
2555/// Same as `faccessat` except asserts the target is Windows and the path parameter2555/// Same as `faccessat` except asserts the target is Windows and the path parameter
2556/// is null-terminated WTF-16 encoded.2556/// is NtDll-prefixed, null-terminated, WTF-16 encoded.
2557/// TODO currently this ignores `mode` and `flags`2557/// TODO currently this ignores `mode` and `flags`
2558pub fn faccessatW(dirfd: fd_t, path: [*:0]const u16, mode: u32, flags: u32) AccessError!void {2558pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void {
2559 @compileError("TODO implement faccessatW on Windows");2559 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
2560 return;
2561 }
2562 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
2563 return;
2564 }
2565
2566 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
2567 error.Overflow => return error.NameTooLong,
2568 };
2569 var nt_name = windows.UNICODE_STRING{
2570 .Length = path_len_bytes,
2571 .MaximumLength = path_len_bytes,
2572 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
2573 };
2574 var attr = windows.OBJECT_ATTRIBUTES{
2575 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
2576 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd,
2577 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
2578 .ObjectName = &nt_name,
2579 .SecurityDescriptor = null,
2580 .SecurityQualityOfService = null,
2581 };
2582 var basic_info: windows.FILE_BASIC_INFORMATION = undefined;
2583 switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) {
2584 .SUCCESS => return,
2585 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2586 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2587 .INVALID_PARAMETER => unreachable,
2588 .ACCESS_DENIED => return error.PermissionDenied,
2589 .OBJECT_PATH_SYNTAX_BAD => unreachable,
2590 else => |rc| return windows.unexpectedStatus(rc),
2591 }
2560}2592}
25612593
2562pub const PipeError = error{2594pub const PipeError = error{
lib/std/os/windows/ntdll.zig+6
...@@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile(...@@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile(
8 Length: ULONG,8 Length: ULONG,
9 FileInformationClass: FILE_INFORMATION_CLASS,9 FileInformationClass: FILE_INFORMATION_CLASS,
10) callconv(.Stdcall) NTSTATUS;10) callconv(.Stdcall) NTSTATUS;
11
12pub extern "NtDll" fn NtQueryAttributesFile(
13 ObjectAttributes: *OBJECT_ATTRIBUTES,
14 FileAttributes: *FILE_BASIC_INFORMATION,
15) callconv(.Stdcall) NTSTATUS;
16
11pub extern "NtDll" fn NtCreateFile(17pub extern "NtDll" fn NtCreateFile(
12 FileHandle: *HANDLE,18 FileHandle: *HANDLE,
13 DesiredAccess: ACCESS_MASK,19 DesiredAccess: ACCESS_MASK,