Commit f0ed2ed67f

Jakub Konka <kubkon@jakubkonka.com>
2020-07-27 17:08:25
Replace DeviceIoControl with FsControlFile
This commit replaces `windows.DeviceIoControl` with `windows.FsControlFile` which is a wrapper around the NT-based syscall `ntdll.NtFsControlFile`.
1 parent d1755e7
Changed files (2)
lib
std
lib/std/os/windows/ntdll.zig
@@ -54,6 +54,18 @@ pub extern "NtDll" fn NtDeviceIoControlFile(
     OutputBuffer: ?PVOID,
     OutputBufferLength: ULONG,
 ) callconv(.Stdcall) NTSTATUS;
+pub extern "NtDll" fn NtFsControlFile(
+    FileHandle: HANDLE,
+    Event: ?HANDLE,
+    ApcRoutine: ?IO_APC_ROUTINE,
+    ApcContext: ?*c_void,
+    IoStatusBlock: *IO_STATUS_BLOCK,
+    FsControlCode: ULONG,
+    InputBuffer: ?*const c_void,
+    InputBufferLength: ULONG,
+    OutputBuffer: ?PVOID,
+    OutputBufferLength: ULONG,
+) callconv(.Stdcall) NTSTATUS;
 pub extern "NtDll" fn NtClose(Handle: HANDLE) callconv(.Stdcall) NTSTATUS;
 pub extern "NtDll" fn RtlDosPathNameToNtPathName_U(
     DosPathName: [*:0]const u16,
lib/std/os/windows.zig
@@ -215,30 +215,34 @@ pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: [*:0]const u16,
     }
 }
 
-pub fn DeviceIoControl(
+pub const FsControlFileError = error{Unexpected};
+
+// TODO work out if we need to expose other arguments to the underlying
+// NtFsControlFile syscall
+pub fn FsControlFile(
     h: HANDLE,
-    ioControlCode: DWORD,
+    fsControlCode: ULONG,
     in: ?[]const u8,
     out: ?[]u8,
-    overlapped: ?*OVERLAPPED,
-) !DWORD {
-    var bytes: DWORD = undefined;
-    if (kernel32.DeviceIoControl(
+) FsControlFileError!void {
+    var io: IO_STATUS_BLOCK = undefined;
+    const rc = ntdll.NtFsControlFile(
         h,
-        ioControlCode,
+        null,
+        null,
+        null,
+        &io,
+        fsControlCode,
         if (in) |i| i.ptr else null,
-        if (in) |i| @intCast(u32, i.len) else 0,
+        if (in) |i| @intCast(ULONG, i.len) else 0,
         if (out) |o| o.ptr else null,
-        if (out) |o| @intCast(u32, o.len) else 0,
-        &bytes,
-        overlapped,
-    ) == 0) {
-        switch (kernel32.GetLastError()) {
-            .IO_PENDING => if (overlapped == null) unreachable,
-            else => |err| return unexpectedError(err),
-        }
+        if (out) |o| @intCast(ULONG, o.len) else 0,
+    );
+    switch (rc) {
+        .SUCCESS => {},
+        .INVALID_PARAMETER => unreachable,
+        else => return unexpectedStatus(rc),
     }
-    return bytes;
 }
 
 pub fn GetOverlappedResult(h: HANDLE, overlapped: *OVERLAPPED, wait: bool) !DWORD {
@@ -727,8 +731,7 @@ pub fn CreateSymbolicLinkW(
     @memcpy(buffer[@sizeOf(SYMLINK_DATA)..], @ptrCast([*]const u8, target_path), target_path.len * 2);
     const paths_start = @sizeOf(SYMLINK_DATA) + target_path.len * 2;
     @memcpy(buffer[paths_start..].ptr, @ptrCast([*]const u8, target_path), target_path.len * 2);
-    // TODO replace with NtDeviceIoControl
-    _ = try DeviceIoControl(symlink_handle, FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null, null);
+    _ = try FsControlFile(symlink_handle, FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null);
 }
 
 pub const ReadLinkError = error{
@@ -806,7 +809,7 @@ pub fn ReadLinkW(dir: ?HANDLE, sub_path_w: [*:0]const u16, out_buffer: []u8) Rea
     defer CloseHandle(result_handle);
 
     var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
-    _ = try DeviceIoControl(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);
+    _ = try FsControlFile(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]);
 
     const reparse_struct = @ptrCast(*const REPARSE_DATA_BUFFER, @alignCast(@alignOf(REPARSE_DATA_BUFFER), &reparse_buf[0]));
     switch (reparse_struct.ReparseTag) {