authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-06 04:36:32-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-07 00:02:50-05:00
logb5bd4946067d3796855e0b4b12219dfc28e15e8f
tree5fc2b5e02c308f0b9123c24e8c7c88925899d180
parent12cb5b92851f601c44d48deadea9934146edcffa

std.Threaded: replace more kernel32 functions with ntdll


27 files changed, 1674 insertions(+), 2241 deletions(-)

ci/x86_64-windows-debug.ps1+15-16
...@@ -35,7 +35,7 @@ Set-Location -Path 'build-debug'...@@ -35,7 +35,7 @@ Set-Location -Path 'build-debug'
3535
36# CMake gives a syntax error when file paths with backward slashes are used.36# CMake gives a syntax error when file paths with backward slashes are used.
37# Here, we use forward slashes only to work around this.37# Here, we use forward slashes only to work around this.
38& cmake .. `38cmake .. `
39 -GNinja `39 -GNinja `
40 -DCMAKE_INSTALL_PREFIX="stage3-debug" `40 -DCMAKE_INSTALL_PREFIX="stage3-debug" `
41 -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" `41 -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" `
...@@ -54,7 +54,7 @@ ninja install...@@ -54,7 +54,7 @@ ninja install
54CheckLastExitCode54CheckLastExitCode
5555
56Write-Output "Main test suite..."56Write-Output "Main test suite..."
57& "stage3-debug\bin\zig.exe" build test docs `57stage3-debug\bin\zig build test docs `
58 --maxrss $ZSF_MAX_RSS `58 --maxrss $ZSF_MAX_RSS `
59 --zig-lib-dir "$ZIG_LIB_DIR" `59 --zig-lib-dir "$ZIG_LIB_DIR" `
60 --search-prefix "$PREFIX_PATH" `60 --search-prefix "$PREFIX_PATH" `
...@@ -66,26 +66,25 @@ Write-Output "Main test suite..."...@@ -66,26 +66,25 @@ Write-Output "Main test suite..."
66CheckLastExitCode66CheckLastExitCode
6767
68Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..."68Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..."
69& "stage3-debug\bin\zig.exe" test `69stage3-debug\bin\zig build-obj `
70 ..\test\behavior.zig `
71 --zig-lib-dir "$ZIG_LIB_DIR" `70 --zig-lib-dir "$ZIG_LIB_DIR" `
72 -ofmt=c `71 -ofmt=c `
73 -femit-bin="test-x86_64-windows-msvc.c" `72 -OReleaseSmall `
74 --test-no-exec `73 --name compiler_rt `
74 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
75 -target x86_64-windows-msvc `75 -target x86_64-windows-msvc `
76 -lc76 -lc `
77 ..\lib\compiler_rt.zig
77CheckLastExitCode78CheckLastExitCode
7879
79& "stage3-debug\bin\zig.exe" build-obj `80stage3-debug\bin\zig test `
80 --zig-lib-dir "$ZIG_LIB_DIR" `81 --zig-lib-dir "$ZIG_LIB_DIR" `
81 -ofmt=c `82 -ofmt=c `
82 -OReleaseSmall `83 -femit-bin="behavior-x86_64-windows-msvc.c" `
83 --name compiler_rt `84 --test-no-exec `
84 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
85 --dep build_options `
86 -target x86_64-windows-msvc `85 -target x86_64-windows-msvc `
87 -Mroot="..\lib\compiler_rt.zig" `86 -lc `
88 -Mbuild_options="config.zig"87 ..\test\behavior.zig
89CheckLastExitCode88CheckLastExitCode
9089
91Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"90Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
...@@ -97,8 +96,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\...@@ -97,8 +96,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\
97CheckLastExitCode96CheckLastExitCode
9897
99Write-Output "Build and run behavior tests with msvc..."98Write-Output "Build and run behavior tests with msvc..."
100& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib99cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib
101CheckLastExitCode100CheckLastExitCode
102101
103& .\test-x86_64-windows-msvc.exe102.\behavior-x86_64-windows-msvc
104CheckLastExitCode103CheckLastExitCode
ci/x86_64-windows-release.ps1+16-17
...@@ -35,7 +35,7 @@ Set-Location -Path 'build-release'...@@ -35,7 +35,7 @@ Set-Location -Path 'build-release'
3535
36# CMake gives a syntax error when file paths with backward slashes are used.36# CMake gives a syntax error when file paths with backward slashes are used.
37# Here, we use forward slashes only to work around this.37# Here, we use forward slashes only to work around this.
38& cmake .. `38cmake .. `
39 -GNinja `39 -GNinja `
40 -DCMAKE_INSTALL_PREFIX="stage3-release" `40 -DCMAKE_INSTALL_PREFIX="stage3-release" `
41 -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" `41 -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" `
...@@ -54,7 +54,7 @@ ninja install...@@ -54,7 +54,7 @@ ninja install
54CheckLastExitCode54CheckLastExitCode
5555
56Write-Output "Main test suite..."56Write-Output "Main test suite..."
57& "stage3-release\bin\zig.exe" build test docs `57stage3-release\bin\zig.exe build test docs `
58 --maxrss $ZSF_MAX_RSS `58 --maxrss $ZSF_MAX_RSS `
59 --zig-lib-dir "$ZIG_LIB_DIR" `59 --zig-lib-dir "$ZIG_LIB_DIR" `
60 --search-prefix "$PREFIX_PATH" `60 --search-prefix "$PREFIX_PATH" `
...@@ -67,7 +67,7 @@ CheckLastExitCode...@@ -67,7 +67,7 @@ CheckLastExitCode
6767
68# Ensure that stage3 and stage4 are byte-for-byte identical.68# Ensure that stage3 and stage4 are byte-for-byte identical.
69Write-Output "Build and compare stage4..."69Write-Output "Build and compare stage4..."
70& "stage3-release\bin\zig.exe" build `70stage3-release\bin\zig.exe build `
71 --prefix stage4-release `71 --prefix stage4-release `
72 -Denable-llvm `72 -Denable-llvm `
73 -Dno-lib `73 -Dno-lib `
...@@ -85,26 +85,25 @@ Compare-Object (Get-Content stage3-release\bin\zig.exe) (Get-Content stage4-rele...@@ -85,26 +85,25 @@ Compare-Object (Get-Content stage3-release\bin\zig.exe) (Get-Content stage4-rele
85CheckLastExitCode85CheckLastExitCode
8686
87Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..."87Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..."
88& "stage3-release\bin\zig.exe" test `88stage3-release\bin\zig.exe build-obj `
89 ..\test\behavior.zig `
90 --zig-lib-dir "$ZIG_LIB_DIR" `89 --zig-lib-dir "$ZIG_LIB_DIR" `
91 -ofmt=c `90 -ofmt=c `
92 -femit-bin="test-x86_64-windows-msvc.c" `91 -OReleaseSmall `
93 --test-no-exec `92 --name compiler_rt `
93 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
94 -target x86_64-windows-msvc `94 -target x86_64-windows-msvc `
95 -lc95 -lc `
96 ..\lib\compiler_rt.zig
96CheckLastExitCode97CheckLastExitCode
9798
98& "stage3-release\bin\zig.exe" build-obj `99stage3-release\bin\zig.exe test `
99 --zig-lib-dir "$ZIG_LIB_DIR" `100 --zig-lib-dir "$ZIG_LIB_DIR" `
100 -ofmt=c `101 -ofmt=c `
101 -OReleaseSmall `102 -femit-bin="behavior-x86_64-windows-msvc.c" `
102 --name compiler_rt `103 --test-no-exec `
103 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
104 --dep build_options `
105 -target x86_64-windows-msvc `104 -target x86_64-windows-msvc `
106 -Mroot="..\lib\compiler_rt.zig" `105 -lc `
107 -Mbuild_options="config.zig"106 ..\test\behavior.zig
108CheckLastExitCode107CheckLastExitCode
109108
110Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"109Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
...@@ -116,8 +115,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\...@@ -116,8 +115,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\
116CheckLastExitCode115CheckLastExitCode
117116
118Write-Output "Build and run behavior tests with msvc..."117Write-Output "Build and run behavior tests with msvc..."
119& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib118cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib
120CheckLastExitCode119CheckLastExitCode
121120
122& .\test-x86_64-windows-msvc.exe121.\behavior-x86_64-windows-msvc
123CheckLastExitCode122CheckLastExitCode
lib/compiler/build_runner.zig+1-1
...@@ -621,7 +621,7 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -621,7 +621,7 @@ pub fn main(init: process.Init.Minimal) !void {
621 }) catch &caption_buf;621 }) catch &caption_buf;
622 var debouncing_node = main_progress_node.start(caption, 0);622 var debouncing_node = main_progress_node.start(caption, 0);
623 var in_debounce = false;623 var in_debounce = false;
624 while (true) switch (try w.wait(gpa, if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) {624 while (true) switch (try w.wait(gpa, io, if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) {
625 .timeout => {625 .timeout => {
626 assert(in_debounce);626 assert(in_debounce);
627 debouncing_node.end();627 debouncing_node.end();
lib/fuzzer.zig+1-1
...@@ -632,7 +632,7 @@ export fn fuzzer_main(limit_kind: abi.LimitKind, amount: u64) void {...@@ -632,7 +632,7 @@ export fn fuzzer_main(limit_kind: abi.LimitKind, amount: u64) void {
632632
633export fn fuzzer_unslide_address(addr: usize) usize {633export fn fuzzer_unslide_address(addr: usize) usize {
634 const si = std.debug.getSelfDebugInfo() catch @compileError("unsupported");634 const si = std.debug.getSelfDebugInfo() catch @compileError("unsupported");
635 const slide = si.getModuleSlide(std.debug.getDebugInfoAllocator(), io, addr) catch |err| {635 const slide = si.getModuleSlide(io, addr) catch |err| {
636 std.debug.panic("failed to find virtual address slide: {t}", .{err});636 std.debug.panic("failed to find virtual address slide: {t}", .{err});
637 };637 };
638 return addr - slide;638 return addr - slide;
lib/std/Build/Watch.zig+145-133
...@@ -180,7 +180,7 @@ const Os = switch (builtin.os.tag) {...@@ -180,7 +180,7 @@ const Os = switch (builtin.os.tag) {
180 const gop = try w.dir_table.getOrPut(gpa, path);180 const gop = try w.dir_table.getOrPut(gpa, path);
181 if (!gop.found_existing) {181 if (!gop.found_existing) {
182 var mount_id: MountId = undefined;182 var mount_id: MountId = undefined;
183 const dir_handle = Os.getDirHandle(gpa, path, &mount_id) catch |err| switch (err) {183 const dir_handle = getDirHandle(gpa, path, &mount_id) catch |err| switch (err) {
184 error.FileNotFound => {184 error.FileNotFound => {
185 std.debug.assert(w.dir_table.swapRemove(path));185 std.debug.assert(w.dir_table.swapRemove(path));
186 continue;186 continue;
...@@ -291,12 +291,13 @@ const Os = switch (builtin.os.tag) {...@@ -291,12 +291,13 @@ const Os = switch (builtin.os.tag) {
291 w.dir_count = w.dir_table.count();291 w.dir_count = w.dir_table.count();
292 }292 }
293293
294 fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {294 fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult {
295 _ = io;
295 const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms());296 const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms());
296 if (events_len == 0)297 if (events_len == 0)
297 return .timeout;298 return .timeout;
298 for (w.os.poll_fds.values()) |poll_fd| {299 for (w.os.poll_fds.values()) |poll_fd| {
299 if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try Os.markDirtySteps(w, gpa, poll_fd.fd))300 if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try markDirtySteps(w, gpa, poll_fd.fd))
300 return .dirty;301 return .dirty;
301 }302 }
302 return .clean;303 return .clean;
...@@ -306,12 +307,8 @@ const Os = switch (builtin.os.tag) {...@@ -306,12 +307,8 @@ const Os = switch (builtin.os.tag) {
306 const windows = std.os.windows;307 const windows = std.os.windows;
307308
308 /// Keyed differently but indexes correspond 1:1 with `dir_table`.309 /// Keyed differently but indexes correspond 1:1 with `dir_table`.
309 handle_table: HandleTable,310 handle_table: std.ArrayHashMapUnmanaged(*Directory, void, Directory.TableAdapter, false),
310 dir_list: std.AutoArrayHashMapUnmanaged(usize, *Directory),311 ready_dirs: std.DoublyLinkedList,
311 io_cp: ?windows.HANDLE,
312 counter: usize = 0,
313
314 const HandleTable = std.AutoArrayHashMapUnmanaged(FileId, ReactionSet);
315312
316 const FileId = struct {313 const FileId = struct {
317 volumeSerialNumber: windows.ULONG,314 volumeSerialNumber: windows.ULONG,
...@@ -319,55 +316,61 @@ const Os = switch (builtin.os.tag) {...@@ -319,55 +316,61 @@ const Os = switch (builtin.os.tag) {
319 };316 };
320317
321 const Directory = struct {318 const Directory = struct {
322 handle: windows.HANDLE,319 reaction_set: ReactionSet,
323 id: FileId,320 id: FileId,
324 overlapped: windows.OVERLAPPED,321 file: Io.File,
322 state: enum { idle, listening, ready },
323 iosb: windows.IO_STATUS_BLOCK,
325 // 64 KB is the packet size limit when monitoring over a network.324 // 64 KB is the packet size limit when monitoring over a network.
326 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw#remarks325 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw#remarks
327 buffer: [64 * 1024]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined,326 buffer: [64 * 1024]u8 align(@alignOf(windows.FILE.NOTIFY.INFORMATION)),
327 ready_node: std.DoublyLinkedList.Node,
328328
329 /// Start listening for events, buffer field will be overwritten eventually.329 /// Start listening for events, buffer field will be overwritten eventually.
330 fn startListening(self: *@This()) !void {330 fn startListening(dir: *Directory, w: *Watch) !void {
331 const r = windows.kernel32.ReadDirectoryChangesW(331 assert(dir.file.flags.nonblocking);
332 self.handle,332 assert(dir.state == .idle);
333 @ptrCast(&self.buffer),333 switch (windows.ntdll.NtNotifyChangeDirectoryFileEx(
334 self.buffer.len,334 dir.file.handle,
335 0,335 null,
336 &notifyApc,
337 w,
338 &dir.iosb,
339 &dir.buffer,
340 dir.buffer.len,
336 .{341 .{
337 .creation = true,342 .FILE_NAME = true,
338 .dir_name = true,343 .DIR_NAME = true,
339 .file_name = true,344 .SIZE = true,
340 .last_write = true,345 .LAST_WRITE = true,
341 .size = true,346 .CREATION = true,
342 },347 },
343 null,348 windows.FALSE,
344 &self.overlapped,349 .Notify,
345 null,350 )) {
346 );351 .SUCCESS, .PENDING => dir.state = .listening,
347 if (r == windows.FALSE) {352 .ILLEGAL_FUNCTION => return error.ReadDirectoryChangesUnsupported,
348 switch (windows.GetLastError()) {353 else => |status| return windows.unexpectedStatus(status),
349 .INVALID_FUNCTION => return error.ReadDirectoryChangesUnsupported,
350 else => |err| return windows.unexpectedError(err),
351 }
352 }354 }
353 }355 }
354356
355 fn init(gpa: Allocator, path: Cache.Path) !*@This() {357 fn notifyApc(apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows.ULONG) callconv(.winapi) void {
358 const w: *Watch = @ptrCast(@alignCast(apc_context));
359 const dir: *Directory = @fieldParentPtr("iosb", iosb);
360 assert(iosb.u.Status != .PENDING);
361 assert(dir.state == .listening);
362 w.os.ready_dirs.append(&dir.ready_node);
363 dir.state = .ready;
364 }
365
366 fn init(gpa: Allocator, path: Cache.Path) !*Directory {
356 // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW)367 // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW)
357 // It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW.368 // It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW.
358 var dir_handle: windows.HANDLE = undefined;369 var dir_handle: windows.HANDLE = undefined;
359 const root_fd = path.root_dir.handle.handle;370 const root_fd = path.root_dir.handle.handle;
360 const sub_path = path.subPathOrDot();371 const sub_path = path.subPathOrDot();
361 const sub_path_w = try std.Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call372 const sub_path_w = try Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call
362 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
363
364 var nt_name = windows.UNICODE_STRING{
365 .Length = @intCast(path_len_bytes),
366 .MaximumLength = @intCast(path_len_bytes),
367 .Buffer = @constCast(sub_path_w.span().ptr),
368 };
369 var iosb: windows.IO_STATUS_BLOCK = undefined;373 var iosb: windows.IO_STATUS_BLOCK = undefined;
370
371 switch (windows.ntdll.NtCreateFile(374 switch (windows.ntdll.NtCreateFile(
372 &dir_handle,375 &dir_handle,
373 .{376 .{
...@@ -379,7 +382,7 @@ const Os = switch (builtin.os.tag) {...@@ -379,7 +382,7 @@ const Os = switch (builtin.os.tag) {
379 },382 },
380 &.{383 &.{
381 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,384 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd,
382 .ObjectName = &nt_name,385 .ObjectName = @constCast(&sub_path_w.string()),
383 },386 },
384 &iosb,387 &iosb,
385 null,388 null,
...@@ -410,20 +413,49 @@ const Os = switch (builtin.os.tag) {...@@ -410,20 +413,49 @@ const Os = switch (builtin.os.tag) {
410413
411 const dir_id = try getFileId(dir_handle);414 const dir_id = try getFileId(dir_handle);
412415
413 const dir_ptr = try gpa.create(@This());416 const dir = try gpa.create(Directory);
414 dir_ptr.* = .{417 dir.* = .{
415 .handle = dir_handle,418 .reaction_set = .empty,
416 .id = dir_id,419 .id = dir_id,
417 .overlapped = std.mem.zeroes(windows.OVERLAPPED),420 .file = .{ .handle = dir_handle, .flags = .{ .nonblocking = true } },
421 .state = .idle,
422 .iosb = undefined,
423 .buffer = undefined,
424 .ready_node = undefined,
418 };425 };
419 return dir_ptr;426 return dir;
420 }427 }
421428
422 fn deinit(self: *@This(), gpa: Allocator) void {429 fn deinit(dir: *Directory, gpa: Allocator, w: *Watch) void {
423 _ = windows.kernel32.CancelIo(self.handle);430 state: switch (dir.state) {
424 windows.CloseHandle(self.handle);431 .idle => {},
425 gpa.destroy(self);432 .listening => {
433 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
434 _ = windows.ntdll.NtCancelIoFileEx(dir.file.handle, &dir.iosb, &cancel_iosb);
435 while (switch (dir.state) {
436 .idle => unreachable,
437 .listening => true,
438 .ready => false,
439 }) Io.Threaded.waitForApcOrAlert();
440 continue :state .ready;
441 },
442 .ready => w.os.ready_dirs.remove(&dir.ready_node),
443 }
444 windows.CloseHandle(dir.file.handle);
445 gpa.destroy(dir);
426 }446 }
447
448 /// Useful to make `*Directory` a key in `std.ArrayHashMap`.
449 const TableAdapter = struct {
450 pub fn hash(_: TableAdapter, lhs_dir: *Directory) u32 {
451 return @truncate(Hash.hash(lhs_dir.id.volumeSerialNumber, @ptrCast(&lhs_dir.id.indexNumber)));
452 }
453 pub fn eql(_: TableAdapter, lhs_dir: *Directory, rhs_dir: *Directory, rhs_index: usize) bool {
454 _ = rhs_index;
455 return lhs_dir.id.volumeSerialNumber == rhs_dir.id.volumeSerialNumber and
456 lhs_dir.id.indexNumber == rhs_dir.id.indexNumber;
457 }
458 };
427 };459 };
428460
429 fn init(cwd_path: []const u8) !Watch {461 fn init(cwd_path: []const u8) !Watch {
...@@ -433,9 +465,8 @@ const Os = switch (builtin.os.tag) {...@@ -433,9 +465,8 @@ const Os = switch (builtin.os.tag) {
433 .dir_count = 0,465 .dir_count = 0,
434 .os = switch (builtin.os.tag) {466 .os = switch (builtin.os.tag) {
435 .windows => .{467 .windows => .{
436 .handle_table = .{},468 .handle_table = .empty,
437 .dir_list = .{},469 .ready_dirs = .{},
438 .io_cp = null,
439 },470 },
440 else => {},471 else => {},
441 },472 },
...@@ -479,29 +510,22 @@ const Os = switch (builtin.os.tag) {...@@ -479,29 +510,22 @@ const Os = switch (builtin.os.tag) {
479510
480 fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool {511 fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool {
481 var any_dirty = false;512 var any_dirty = false;
482 const bytes_returned = try windows.GetOverlappedResult(dir.handle, &dir.overlapped, false);513 const bytes_returned = dir.iosb.Information;
483 if (bytes_returned == 0) {514 if (bytes_returned == 0) {
484 std.log.warn("file system watch queue overflowed; falling back to fstat", .{});515 std.log.warn("file system watch queue overflowed; falling back to fstat", .{});
485 markAllFilesDirty(w, gpa);516 markAllFilesDirty(w, gpa);
486 try dir.startListening();517 try dir.startListening(w);
487 return true;518 return true;
488 }519 }
489 var file_name_buf: [std.fs.max_path_bytes]u8 = undefined;520 var file_name_buf: [std.fs.max_path_bytes]u8 = undefined;
490 var notify: *align(1) windows.FILE_NOTIFY_INFORMATION = undefined;
491 var offset: usize = 0;521 var offset: usize = 0;
492 while (true) {522 while (true) {
493 notify = @ptrCast(&dir.buffer[offset]);523 const notify: *windows.FILE.NOTIFY.INFORMATION = @ptrCast(@alignCast(&dir.buffer[offset]));
494 const file_name_field: [*]u16 = @ptrFromInt(@intFromPtr(notify) + @sizeOf(windows.FILE_NOTIFY_INFORMATION));524 const file_name = file_name_buf[0..std.unicode.wtf16LeToWtf8(&file_name_buf, notify.fileName())];
495 const file_name_len = std.unicode.wtf16LeToWtf8(&file_name_buf, file_name_field[0 .. notify.FileNameLength / 2]);525 if (dir.reaction_set.getPtr(".")) |glob_set|
496 const file_name = file_name_buf[0..file_name_len];526 any_dirty = markStepSetDirty(gpa, glob_set, any_dirty);
497 if (w.os.handle_table.getIndex(dir.id)) |reaction_set_i| {527 if (dir.reaction_set.getPtr(file_name)) |step_set|
498 const reaction_set = w.os.handle_table.values()[reaction_set_i];528 any_dirty = markStepSetDirty(gpa, step_set, any_dirty);
499 if (reaction_set.getPtr(".")) |glob_set|
500 any_dirty = markStepSetDirty(gpa, glob_set, any_dirty);
501 if (reaction_set.getPtr(file_name)) |step_set| {
502 any_dirty = markStepSetDirty(gpa, step_set, any_dirty);
503 }
504 }
505 if (notify.NextEntryOffset == 0)529 if (notify.NextEntryOffset == 0)
506 break;530 break;
507531
...@@ -509,7 +533,7 @@ const Os = switch (builtin.os.tag) {...@@ -509,7 +533,7 @@ const Os = switch (builtin.os.tag) {
509 }533 }
510534
511 // We call this now since at this point we have finished reading dir.buffer.535 // We call this now since at this point we have finished reading dir.buffer.
512 try dir.startListening();536 try dir.startListening(w);
513 return any_dirty;537 return any_dirty;
514 }538 }
515539
...@@ -517,41 +541,32 @@ const Os = switch (builtin.os.tag) {...@@ -517,41 +541,32 @@ const Os = switch (builtin.os.tag) {
517 // Add missing marks and note persisted ones.541 // Add missing marks and note persisted ones.
518 for (steps) |step| {542 for (steps) |step| {
519 for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| {543 for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| {
520 const reaction_set = rs: {544 const dir = dir: {
521 const gop = try w.dir_table.getOrPut(gpa, path);545 const gop = try w.dir_table.getOrPut(gpa, path);
522 if (!gop.found_existing) {546 if (!gop.found_existing) {
523 const dir = try Os.Directory.init(gpa, path);547 const dir: *Directory = try .init(gpa, path);
524 errdefer dir.deinit(gpa);548 errdefer dir.deinit(gpa, w);
525 // `dir.id` may already be present in the table in549 // `dir.id` may already be present in the table in
526 // the case that we have multiple Cache.Path instances550 // the case that we have multiple Cache.Path instances
527 // that compare inequal but ultimately point to the same551 // that compare inequal but ultimately point to the same
528 // directory on the file system.552 // directory on the file system.
529 // In such case, we must revert adding this directory, but keep553 // In such case, we must revert adding this directory, but keep
530 // the additions to the step set.554 // the additions to the step set.
531 const dh_gop = try w.os.handle_table.getOrPut(gpa, dir.id);555 const dh_gop = try w.os.handle_table.getOrPut(gpa, dir);
532 if (dh_gop.found_existing) {556 if (dh_gop.found_existing) {
533 dir.deinit(gpa);557 dir.deinit(gpa, w);
534 _ = w.dir_table.pop();558 _ = w.dir_table.pop();
559 break :dir w.os.handle_table.keys()[dh_gop.index];
535 } else {560 } else {
536 assert(dh_gop.index == gop.index);561 assert(dh_gop.index == gop.index);
537 dh_gop.value_ptr.* = .{};562 try dir.startListening(w);
538 try dir.startListening();563 break :dir dir;
539 const key = w.os.counter;
540 w.os.counter +%= 1;
541 try w.os.dir_list.put(gpa, key, dir);
542 w.os.io_cp = try windows.CreateIoCompletionPort(
543 dir.handle,
544 w.os.io_cp,
545 key,
546 0,
547 );
548 }564 }
549 break :rs &w.os.handle_table.values()[dh_gop.index];
550 }565 }
551 break :rs &w.os.handle_table.values()[gop.index];566 break :dir w.os.handle_table.keys()[gop.index];
552 };567 };
553 for (files.items) |basename| {568 for (files.items) |basename| {
554 const gop = try reaction_set.getOrPut(gpa, basename);569 const gop = try dir.reaction_set.getOrPut(gpa, basename);
555 if (!gop.found_existing) gop.value_ptr.* = .{};570 if (!gop.found_existing) gop.value_ptr.* = .{};
556 try gop.value_ptr.put(gpa, step, w.generation);571 try gop.value_ptr.put(gpa, step, w.generation);
557 }572 }
...@@ -562,11 +577,11 @@ const Os = switch (builtin.os.tag) {...@@ -562,11 +577,11 @@ const Os = switch (builtin.os.tag) {
562 // Remove marks for files that are no longer inputs.577 // Remove marks for files that are no longer inputs.
563 var i: usize = 0;578 var i: usize = 0;
564 while (i < w.os.handle_table.entries.len) {579 while (i < w.os.handle_table.entries.len) {
580 const dir = w.os.handle_table.keys()[i];
565 {581 {
566 const reaction_set = &w.os.handle_table.values()[i];
567 var step_set_i: usize = 0;582 var step_set_i: usize = 0;
568 while (step_set_i < reaction_set.entries.len) {583 while (step_set_i < dir.reaction_set.entries.len) {
569 const step_set = &reaction_set.values()[step_set_i];584 const step_set = &dir.reaction_set.values()[step_set_i];
570 var dirent_i: usize = 0;585 var dirent_i: usize = 0;
571 while (dirent_i < step_set.entries.len) {586 while (dirent_i < step_set.entries.len) {
572 const generations = step_set.values();587 const generations = step_set.values();
...@@ -580,53 +595,45 @@ const Os = switch (builtin.os.tag) {...@@ -580,53 +595,45 @@ const Os = switch (builtin.os.tag) {
580 step_set_i += 1;595 step_set_i += 1;
581 continue;596 continue;
582 }597 }
583 reaction_set.swapRemoveAt(step_set_i);598 dir.reaction_set.swapRemoveAt(step_set_i);
584 }599 }
585 if (reaction_set.entries.len > 0) {600 if (dir.reaction_set.entries.len > 0) {
586 i += 1;601 i += 1;
587 continue;602 continue;
588 }603 }
589 }604 }
590605
591 w.os.dir_list.values()[i].deinit(gpa);
592 w.os.dir_list.swapRemoveAt(i);
593 w.dir_table.swapRemoveAt(i);606 w.dir_table.swapRemoveAt(i);
594 w.os.handle_table.swapRemoveAt(i);607 w.os.handle_table.swapRemoveAt(i);
608 dir.deinit(gpa, w);
595 }609 }
596 w.generation +%= 1;610 w.generation +%= 1;
597 }611 }
598 w.dir_count = w.dir_table.count();612 w.dir_count = w.dir_table.count();
599 }613 }
600614
601 fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {615 fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult {
602 var bytes_transferred: std.os.windows.DWORD = undefined;616 for (0..2) |attempt| {
603 var key: usize = undefined;617 while (w.os.ready_dirs.popFirst()) |ready_node| {
604 var overlapped_ptr: ?*std.os.windows.OVERLAPPED = undefined;618 const dir: *Directory = @fieldParentPtr("ready_node", ready_node);
605 return while (true) switch (std.os.windows.GetQueuedCompletionStatus(619 assert(dir.state == .ready);
606 w.os.io_cp.?,620 dir.state = .idle;
607 &bytes_transferred,621 switch (dir.iosb.u.Status) {
608 &key,622 .SUCCESS => return if (try markDirtySteps(w, gpa, dir)) .dirty else .clean,
609 &overlapped_ptr,623 .PENDING => unreachable,
610 @bitCast(timeout.to_i32_ms()),624 .CANCELLED => {},
611 )) {625 else => |status| return windows.unexpectedStatus(status),
612 .Normal => {626 }
613 if (bytes_transferred == 0)627 try dir.startListening(w);
614 break error.Unexpected;628 }
615629 try io.checkCancel();
616 // This 'orelse' detects a race condition that happens when we receive a630 if (attempt == 1) return .timeout;
617 // completion notification for a directory that no longer exists in our list.631 const delay_interval: windows.LARGE_INTEGER = switch (timeout) {
618 const dir = w.os.dir_list.get(key) orelse break .clean;632 .none => std.math.minInt(windows.LARGE_INTEGER),
619633 .ms => |ms| -@as(windows.LARGE_INTEGER, ms) * (std.time.ns_per_ms / 100),
620 break if (try Os.markDirtySteps(w, gpa, dir))634 };
621 .dirty635 _ = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
622 else636 } else unreachable;
623 .clean;
624 },
625 .Timeout => break .timeout,
626 // This status is issued because CancelIo was called, skip and try again.
627 .Canceled => continue,
628 else => break error.Unexpected,
629 };
630 }637 }
631 },638 },
632 .dragonfly, .freebsd, .netbsd, .openbsd, .ios, .tvos, .visionos, .watchos => struct {639 .dragonfly, .freebsd, .netbsd, .openbsd, .ios, .tvos, .visionos, .watchos => struct {
...@@ -796,7 +803,8 @@ const Os = switch (builtin.os.tag) {...@@ -796,7 +803,8 @@ const Os = switch (builtin.os.tag) {
796 w.dir_count = w.dir_table.count();803 w.dir_count = w.dir_table.count();
797 }804 }
798805
799 fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {806 fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult {
807 _ = io;
800 var timespec_buffer: posix.timespec = undefined;808 var timespec_buffer: posix.timespec = undefined;
801 var event_buffer: [100]posix.Kevent = undefined;809 var event_buffer: [100]posix.Kevent = undefined;
802 var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(&timespec_buffer));810 var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(&timespec_buffer));
...@@ -852,7 +860,8 @@ const Os = switch (builtin.os.tag) {...@@ -852,7 +860,8 @@ const Os = switch (builtin.os.tag) {
852 try w.os.fse.setPaths(gpa, steps);860 try w.os.fse.setPaths(gpa, steps);
853 w.dir_count = w.os.fse.watch_roots.len;861 w.dir_count = w.os.fse.watch_roots.len;
854 }862 }
855 fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {863 fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult {
864 _ = io;
856 return w.os.fse.wait(gpa, switch (timeout) {865 return w.os.fse.wait(gpa, switch (timeout) {
857 .none => null,866 .none => null,
858 .ms => |ms| @as(u64, ms) * std.time.ns_per_ms,867 .ms => |ms| @as(u64, ms) * std.time.ns_per_ms,
...@@ -890,10 +899,13 @@ pub const Match = struct {...@@ -890,10 +899,13 @@ pub const Match = struct {
890};899};
891900
892fn markAllFilesDirty(w: *Watch, gpa: Allocator) void {901fn markAllFilesDirty(w: *Watch, gpa: Allocator) void {
893 for (w.os.handle_table.values()) |value| {902 for (switch (builtin.os.tag) {
903 .windows => w.os.handle_table.keys(),
904 else => w.os.handle_table.values(),
905 }) |item| {
894 const reaction_set = switch (builtin.os.tag) {906 const reaction_set = switch (builtin.os.tag) {
895 .linux => value.reaction_set,907 .linux, .windows => item.reaction_set,
896 else => value,908 else => item,
897 };909 };
898 for (reaction_set.values()) |step_set| {910 for (reaction_set.values()) |step_set| {
899 for (step_set.keys()) |step| {911 for (step_set.keys()) |step| {
...@@ -951,6 +963,6 @@ pub const WaitResult = enum {...@@ -951,6 +963,6 @@ pub const WaitResult = enum {
951 clean,963 clean,
952};964};
953965
954pub fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {966pub fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult {
955 return Os.wait(w, gpa, timeout);967 return Os.wait(w, gpa, io, timeout);
956}968}
lib/std/Io/Threaded.zig+465-493
...@@ -83,7 +83,7 @@ csprng: Csprng = .{},...@@ -83,7 +83,7 @@ csprng: Csprng = .{},
83system_basic_information: SystemBasicInformation = .{},83system_basic_information: SystemBasicInformation = .{},
8484
85const SystemBasicInformation = if (!is_windows) struct {} else struct {85const SystemBasicInformation = if (!is_windows) struct {} else struct {
86 buffer: windows.SYSTEM_BASIC_INFORMATION = undefined,86 buffer: windows.SYSTEM.BASIC_INFORMATION = undefined,
87 initialized: std.atomic.Value(bool) = .{ .raw = false },87 initialized: std.atomic.Value(bool) = .{ .raw = false },
88};88};
8989
...@@ -1392,7 +1392,7 @@ const AlertableSyscall = struct {...@@ -1392,7 +1392,7 @@ const AlertableSyscall = struct {
1392 }1392 }
1393};1393};
13941394
1395fn waitForApcOrAlert() void {1395pub fn waitForApcOrAlert() void {
1396 const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);1396 const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
1397 _ = windows.ntdll.NtDelayExecution(windows.TRUE, &infinite_timeout);1397 _ = windows.ntdll.NtDelayExecution(windows.TRUE, &infinite_timeout);
1398}1398}
...@@ -2556,9 +2556,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2556,9 +2556,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2556 else => |e| e,2556 else => |e| e,
2557 },2557 },
2558 },2558 },
2559 .device_io_control => |*o| return .{2559 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },
2560 .device_io_control = try deviceIoControl(t, o),
2561 },
2562 }2560 }
2563}2561}
25642562
...@@ -2970,7 +2968,7 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren...@@ -2970,7 +2968,7 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren
2970 break :o;2968 break :o;
2971 }2969 }
2972 const buffer = o.data[data_index];2970 const buffer = o.data[data_index];
2973 const short_buffer_len = @min(std.math.maxInt(u32), buffer.len);2971 const short_buffer_len = std.math.lossyCast(u32, buffer.len);
29742972
2975 if (o.file.flags.nonblocking) {2973 if (o.file.flags.nonblocking) {
2976 context.file = o.file.handle;2974 context.file = o.file.handle;
...@@ -3259,22 +3257,11 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe...@@ -3259,22 +3257,11 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe
3259 _ = t;3257 _ = t;
3260 _ = permissions; // TODO use this value3258 _ = permissions; // TODO use this value
32613259
3262 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);3260 const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
3263 const sub_path_w = sub_path_w_array.span();3261 const attr: windows.OBJECT.ATTRIBUTES = .{
3264 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;3262 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
32653263 .Attributes = .{ .INHERIT = false },
3266 var nt_name: windows.UNICODE_STRING = .{3264 .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w.span())),
3267 .Length = path_len_bytes,
3268 .MaximumLength = path_len_bytes,
3269 .Buffer = @constCast(sub_path_w.ptr),
3270 };
3271 const attr: windows.OBJECT_ATTRIBUTES = .{
3272 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
3273 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
3274 .Attributes = .{
3275 .INHERIT = false,
3276 },
3277 .ObjectName = &nt_name,
3278 .SecurityDescriptor = null,3265 .SecurityDescriptor = null,
3279 .SecurityQualityOfService = null,3266 .SecurityQualityOfService = null,
3280 };3267 };
...@@ -3438,21 +3425,14 @@ fn dirCreateDirPathOpenWindows(...@@ -3438,21 +3425,14 @@ fn dirCreateDirPathOpenWindows(
3438 };3425 };
34393426
3440 components: while (true) {3427 components: while (true) {
3441 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, component.path);3428 const sub_path_w = try sliceToPrefixedFileW(dir.handle, component.path);
3442 const sub_path_w = sub_path_w_array.span();3429 const attr: windows.OBJECT.ATTRIBUTES = .{
3430 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
3431 .ObjectName = @constCast(&sub_path_w.string()),
3432 };
3443 const is_last = it.peekNext() == null;3433 const is_last = it.peekNext() == null;
3444 const create_disposition: w.FILE.CREATE_DISPOSITION = if (is_last) .OPEN_IF else .CREATE;
3445
3446 var result: Dir = .{ .handle = undefined };3434 var result: Dir = .{ .handle = undefined };
34473435 var iosb: w.IO_STATUS_BLOCK = undefined;
3448 const path_len_bytes: u16 = @intCast(sub_path_w.len * 2);
3449 var nt_name: w.UNICODE_STRING = .{
3450 .Length = path_len_bytes,
3451 .MaximumLength = path_len_bytes,
3452 .Buffer = @constCast(sub_path_w.ptr),
3453 };
3454 var io_status_block: w.IO_STATUS_BLOCK = undefined;
3455
3456 const syscall: Syscall = try .start();3436 const syscall: Syscall = try .start();
3457 while (true) switch (w.ntdll.NtCreateFile(3437 while (true) switch (w.ntdll.NtCreateFile(
3458 &result.handle,3438 &result.handle,
...@@ -3468,15 +3448,12 @@ fn dirCreateDirPathOpenWindows(...@@ -3468,15 +3448,12 @@ fn dirCreateDirPathOpenWindows(
3468 .SYNCHRONIZE = true,3448 .SYNCHRONIZE = true,
3469 },3449 },
3470 },3450 },
3471 &.{3451 &attr,
3472 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,3452 &iosb,
3473 .ObjectName = &nt_name,
3474 },
3475 &io_status_block,
3476 null,3453 null,
3477 .{ .NORMAL = true },3454 .{ .NORMAL = true },
3478 .VALID_FLAGS,3455 .VALID_FLAGS,
3479 create_disposition,3456 if (is_last) .OPEN_IF else .CREATE,
3480 .{3457 .{
3481 .DIRECTORY_FILE = true,3458 .DIRECTORY_FILE = true,
3482 .IO = .SYNCHRONOUS_NONALERT,3459 .IO = .SYNCHRONOUS_NONALERT,
...@@ -3944,15 +3921,15 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {...@@ -3944,15 +3921,15 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
3944 };3921 };
3945}3922}
39463923
3947fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION {3924fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM.BASIC_INFORMATION {
3948 if (!t.system_basic_information.initialized.load(.acquire)) {3925 if (!t.system_basic_information.initialized.load(.acquire)) {
3949 mutexLock(&t.mutex);3926 mutexLock(&t.mutex);
3950 defer mutexUnlock(&t.mutex);3927 defer mutexUnlock(&t.mutex);
39513928
3952 switch (windows.ntdll.NtQuerySystemInformation(3929 switch (windows.ntdll.NtQuerySystemInformation(
3953 .SystemBasicInformation,3930 .Basic,
3954 &t.system_basic_information.buffer,3931 &t.system_basic_information.buffer,
3955 @sizeOf(windows.SYSTEM_BASIC_INFORMATION),3932 @sizeOf(windows.SYSTEM.BASIC_INFORMATION),
3956 null,3933 null,
3957 )) {3934 )) {
3958 .SUCCESS => {},3935 .SUCCESS => {},
...@@ -4139,22 +4116,11 @@ fn dirAccessWindows(...@@ -4139,22 +4116,11 @@ fn dirAccessWindows(
41394116
4140 _ = options; // TODO4117 _ = options; // TODO
41414118
4142 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);4119 if (std.mem.eql(u8, sub_path, ".") or std.mem.eql(u8, sub_path, "..")) return;
4143 const sub_path_w = sub_path_w_array.span();4120 const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
41444121 const attr: windows.OBJECT.ATTRIBUTES = .{
4145 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) return;4122 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
4146 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) return;4123 .ObjectName = @constCast(&sub_path_w.string()),
4147
4148 const path_len_bytes = std.math.cast(u16, std.mem.sliceTo(sub_path_w, 0).len * 2) orelse
4149 return error.NameTooLong;
4150 var nt_name: windows.UNICODE_STRING = .{
4151 .Length = path_len_bytes,
4152 .MaximumLength = path_len_bytes,
4153 .Buffer = @constCast(sub_path_w.ptr),
4154 };
4155 const attr: windows.OBJECT_ATTRIBUTES = .{
4156 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
4157 .ObjectName = &nt_name,
4158 };4124 };
4159 var basic_info: windows.FILE.BASIC_INFORMATION = undefined;4125 var basic_info: windows.FILE.BASIC_INFORMATION = undefined;
4160 const syscall: Syscall = try .start();4126 const syscall: Syscall = try .start();
...@@ -4360,18 +4326,10 @@ fn dirCreateFileWindows(...@@ -4360,18 +4326,10 @@ fn dirCreateFileWindows(
4360 if (std.mem.eql(u8, sub_path, ".")) return error.IsDir;4326 if (std.mem.eql(u8, sub_path, ".")) return error.IsDir;
4361 if (std.mem.eql(u8, sub_path, "..")) return error.IsDir;4327 if (std.mem.eql(u8, sub_path, "..")) return error.IsDir;
43624328
4363 const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path);4329 const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
4364 const sub_path_w = sub_path_w_array.span();4330 const attr: windows.OBJECT.ATTRIBUTES = .{
4365 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;4331 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
43664332 .ObjectName = @constCast(&sub_path_w.string()),
4367 var nt_name: windows.UNICODE_STRING = .{
4368 .Length = path_len_bytes,
4369 .MaximumLength = path_len_bytes,
4370 .Buffer = @constCast(sub_path_w.ptr),
4371 };
4372 const attr: windows.OBJECT_ATTRIBUTES = .{
4373 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
4374 .ObjectName = &nt_name,
4375 };4333 };
4376 const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive)4334 const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive)
4377 .CREATE4335 .CREATE
...@@ -4966,20 +4924,14 @@ fn dirOpenFileWindows(...@@ -4966,20 +4924,14 @@ fn dirOpenFileWindows(
49664924
4967pub fn dirOpenFileWtf16(4925pub fn dirOpenFileWtf16(
4968 dir_handle: ?windows.HANDLE,4926 dir_handle: ?windows.HANDLE,
4969 sub_path_w: [:0]const u16,4927 sub_path_w: []const u16,
4970 flags: File.OpenFlags,4928 flags: File.OpenFlags,
4971) File.OpenError!File {4929) File.OpenError!File {
4972 const allow_directory = flags.allow_directory and !flags.isWrite();4930 const allow_directory = flags.allow_directory and !flags.isWrite();
4973 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;4931 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
4974 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;4932 if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
4975 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
4976 const w = windows;4933 const w = windows;
49774934
4978 var nt_name: w.UNICODE_STRING = .{
4979 .Length = path_len_bytes,
4980 .MaximumLength = path_len_bytes,
4981 .Buffer = @constCast(sub_path_w.ptr),
4982 };
4983 var io_status_block: w.IO_STATUS_BLOCK = undefined;4935 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4984 var attempt: u5 = 0;4936 var attempt: u5 = 0;
4985 var syscall: Syscall = try .start();4937 var syscall: Syscall = try .start();
...@@ -4996,7 +4948,7 @@ pub fn dirOpenFileWtf16(...@@ -4996,7 +4948,7 @@ pub fn dirOpenFileWtf16(
4996 },4948 },
4997 &.{4949 &.{
4998 .RootDirectory = dir_handle,4950 .RootDirectory = dir_handle,
4999 .ObjectName = &nt_name,4951 .ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)),
5000 },4952 },
5001 &io_status_block,4953 &io_status_block,
5002 null,4954 null,
...@@ -5329,20 +5281,19 @@ fn dirOpenDirHaiku(...@@ -5329,20 +5281,19 @@ fn dirOpenDirHaiku(
53295281
5330pub fn dirOpenDirWindows(5282pub fn dirOpenDirWindows(
5331 dir: Dir,5283 dir: Dir,
5332 sub_path_w: [:0]const u16,5284 sub_path_w: []const u16,
5333 options: Dir.OpenOptions,5285 options: Dir.OpenOptions,
5334) Dir.OpenError!Dir {5286) Dir.OpenError!Dir {
5335 const w = windows;5287 const w = windows;
53365288
5337 const path_len_bytes: u16 = @intCast(sub_path_w.len * 2);
5338 var nt_name: w.UNICODE_STRING = .{
5339 .Length = path_len_bytes,
5340 .MaximumLength = path_len_bytes,
5341 .Buffer = @constCast(sub_path_w.ptr),
5342 };
5343 var io_status_block: w.IO_STATUS_BLOCK = undefined;5289 var io_status_block: w.IO_STATUS_BLOCK = undefined;
5344 var result: Dir = .{ .handle = undefined };5290 var result: Dir = .{ .handle = undefined };
53455291
5292 const attr: w.OBJECT.ATTRIBUTES = .{
5293 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
5294 .ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)),
5295 };
5296
5346 const syscall: Syscall = try .start();5297 const syscall: Syscall = try .start();
5347 while (true) switch (w.ntdll.NtCreateFile(5298 while (true) switch (w.ntdll.NtCreateFile(
5348 &result.handle,5299 &result.handle,
...@@ -5359,10 +5310,7 @@ pub fn dirOpenDirWindows(...@@ -5359,10 +5310,7 @@ pub fn dirOpenDirWindows(
5359 .SYNCHRONIZE = true,5310 .SYNCHRONIZE = true,
5360 },5311 },
5361 },5312 },
5362 &.{5313 &attr,
5363 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
5364 .ObjectName = &nt_name,
5365 },
5366 &io_status_block,5314 &io_status_block,
5367 null,5315 null,
5368 .{ .NORMAL = true },5316 .{ .NORMAL = true },
...@@ -6194,13 +6142,15 @@ pub fn GetFinalPathNameByHandle(...@@ -6194,13 +6142,15 @@ pub fn GetFinalPathNameByHandle(
6194 input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2);6142 input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2);
6195 @memcpy(input_buf[@sizeOf(windows.MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr)));6143 @memcpy(input_buf[@sizeOf(windows.MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr)));
61966144
6197 {6145 switch ((try deviceIoControl(&.{
6198 const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_POINTS, .{ .in = &input_buf, .out = &output_buf });6146 .file = .{ .handle = mgmt_handle, .flags = .{ .nonblocking = false } },
6199 switch (rc) {6147 .code = windows.IOCTL.MOUNTMGR.QUERY_POINTS,
6200 .SUCCESS => {},6148 .in = &input_buf,
6201 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,6149 .out = &output_buf,
6202 else => return windows.unexpectedStatus(rc),6150 })).u.Status) {
6203 }6151 .SUCCESS => {},
6152 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
6153 else => |status| return windows.unexpectedStatus(status),
6204 }6154 }
6205 const mount_points_struct: *const windows.MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]);6155 const mount_points_struct: *const windows.MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]);
62066156
...@@ -6251,11 +6201,15 @@ pub fn GetFinalPathNameByHandle(...@@ -6251,11 +6201,15 @@ pub fn GetFinalPathNameByHandle(
6251 vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2);6201 vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2);
6252 @memcpy(@as([*]windows.WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink);6202 @memcpy(@as([*]windows.WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink);
62536203
6254 const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_DOS_VOLUME_PATH, .{ .in = &vol_input_buf, .out = &vol_output_buf });6204 switch ((try deviceIoControl(&.{
6255 switch (rc) {6205 .file = .{ .handle = mgmt_handle, .flags = .{ .nonblocking = true } },
6206 .code = windows.IOCTL.MOUNTMGR.QUERY_DOS_VOLUME_PATH,
6207 .in = &vol_input_buf,
6208 .out = &vol_output_buf,
6209 })).u.Status) {
6256 .SUCCESS => {},6210 .SUCCESS => {},
6257 .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume,6211 .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume,
6258 else => return windows.unexpectedStatus(rc),6212 else => |status| return windows.unexpectedStatus(status),
6259 }6213 }
6260 const volume_paths_struct: *const windows.MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]);6214 const volume_paths_struct: *const windows.MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]);
6261 const volume_path = std.mem.sliceTo(@as(6215 const volume_path = std.mem.sliceTo(@as(
...@@ -6352,20 +6306,17 @@ pub const QueryObjectNameError = error{...@@ -6352,20 +6306,17 @@ pub const QueryObjectNameError = error{
6352};6306};
63536307
6354pub fn QueryObjectName(handle: windows.HANDLE, out_buffer: []u16) QueryObjectNameError![]u16 {6308pub fn QueryObjectName(handle: windows.HANDLE, out_buffer: []u16) QueryObjectNameError![]u16 {
6355 const out_buffer_aligned = std.mem.alignInSlice(out_buffer, @alignOf(windows.OBJECT_NAME_INFORMATION)) orelse return error.NameTooLong;6309 const out_buffer_aligned = std.mem.alignInSlice(out_buffer, @alignOf(windows.OBJECT.NAME_INFORMATION)) orelse return error.NameTooLong;
63566310
6357 const info: *windows.OBJECT_NAME_INFORMATION = @ptrCast(out_buffer_aligned);6311 const info: *windows.OBJECT.NAME_INFORMATION = @ptrCast(out_buffer_aligned);
6358 // buffer size is specified in bytes6312 // buffer size is specified in bytes
6359 const out_buffer_len = std.math.cast(windows.ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(windows.ULONG);6313 const out_buffer_len = std.math.cast(windows.ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(windows.ULONG);
6360 // last argument would return the length required for full_buffer, not exposed here6314 // last argument would return the length required for full_buffer, not exposed here
6361 return switch (windows.ntdll.NtQueryObject(handle, .ObjectNameInformation, info, out_buffer_len, null)) {6315 return switch (windows.ntdll.NtQueryObject(handle, .Name, info, out_buffer_len, null)) {
6362 .SUCCESS => blk: {6316 .SUCCESS => {
6363 // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0)6317 // info.Name from ObQueryNameString is documented to be empty if the object
6364 // if the object was "unnamed", not sure if this can happen for file handles6318 // was "unnamed", not sure if this can happen for file handles
6365 if (info.Name.MaximumLength == 0) break :blk error.Unexpected;6319 return if (info.Name.isEmpty()) error.Unexpected else info.Name.slice();
6366 // resulting string length is specified in bytes
6367 const path_length_unterminated = @divExact(info.Name.Length, 2);
6368 break :blk info.Name.Buffer.?[0..path_length_unterminated];
6369 },6320 },
6370 .ACCESS_DENIED => error.AccessDenied,6321 .ACCESS_DENIED => error.AccessDenied,
6371 .INVALID_HANDLE => error.InvalidHandle,6322 .INVALID_HANDLE => error.InvalidHandle,
...@@ -6620,8 +6571,12 @@ pub const WindowsPathSpace = struct {...@@ -6620,8 +6571,12 @@ pub const WindowsPathSpace = struct {
6620 data: [windows.PATH_MAX_WIDE:0]u16,6571 data: [windows.PATH_MAX_WIDE:0]u16,
6621 len: usize,6572 len: usize,
66226573
6623 pub fn span(self: *const WindowsPathSpace) [:0]const u16 {6574 pub fn span(wps: *const WindowsPathSpace) [:0]const u16 {
6624 return self.data[0..self.len :0];6575 return wps.data[0..wps.len :0];
6576 }
6577
6578 pub fn string(wps: *const WindowsPathSpace) windows.UNICODE_STRING {
6579 return .init(wps.span());
6625 }6580 }
6626};6581};
66276582
...@@ -7076,25 +7031,19 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -7076,25 +7031,19 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
7076 _ = t;7031 _ = t;
7077 const w = windows;7032 const w = windows;
70787033
7079 const sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, sub_path);7034 if (std.mem.eql(u8, sub_path, "..")) {
7080 const sub_path_w = sub_path_w_buf.span();
7081
7082 const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));
7083 var nt_name: w.UNICODE_STRING = .{
7084 .Length = path_len_bytes,
7085 .MaximumLength = path_len_bytes,
7086 // The Windows API makes this mutable, but it will not mutate here.
7087 .Buffer = @constCast(sub_path_w.ptr),
7088 };
7089
7090 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
7091 // Windows does not recognize this, but it does work with empty string.
7092 nt_name.Length = 0;
7093 }
7094 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
7095 // Can't remove the parent directory with an open handle.7035 // Can't remove the parent directory with an open handle.
7096 return error.FileBusy;7036 return error.FileBusy;
7097 }7037 }
7038 var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
7039 if (std.mem.eql(u8, sub_path, ".")) {
7040 // Windows does not recognize this, but it does work with empty string.
7041 sub_path_w.len = 0;
7042 }
7043 const attr: w.OBJECT.ATTRIBUTES = .{
7044 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
7045 .ObjectName = @constCast(&sub_path_w.string()),
7046 };
70987047
7099 var io_status_block: w.IO_STATUS_BLOCK = undefined;7048 var io_status_block: w.IO_STATUS_BLOCK = undefined;
7100 var tmp_handle: w.HANDLE = undefined;7049 var tmp_handle: w.HANDLE = undefined;
...@@ -7106,10 +7055,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -7106,10 +7055,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
7106 .RIGHTS = .{ .DELETE = true },7055 .RIGHTS = .{ .DELETE = true },
7107 .SYNCHRONIZE = true,7056 .SYNCHRONIZE = true,
7108 } },7057 } },
7109 &.{7058 &attr,
7110 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
7111 .ObjectName = &nt_name,
7112 },
7113 &io_status_block,7059 &io_status_block,
7114 null,7060 null,
7115 .{},7061 .{},
...@@ -7741,7 +7687,7 @@ fn dirSymLinkWindows(...@@ -7741,7 +7687,7 @@ fn dirSymLinkWindows(
7741 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw7687 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
7742 var is_target_absolute = false;7688 var is_target_absolute = false;
7743 const final_target_path = target_path: {7689 const final_target_path = target_path: {
7744 if (windows.hasCommonNtPrefix(u16, target_path_w.span())) {7690 if (w.hasCommonNtPrefix(u16, target_path_w.span())) {
7745 // Already an NT path, no need to do anything to it7691 // Already an NT path, no need to do anything to it
7746 break :target_path target_path_w.span();7692 break :target_path target_path_w.span();
7747 } else {7693 } else {
...@@ -7785,13 +7731,16 @@ fn dirSymLinkWindows(...@@ -7785,13 +7731,16 @@ fn dirSymLinkWindows(
7785 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));7731 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
7786 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;7732 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
7787 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));7733 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
7788 const rc = w.DeviceIoControl(symlink_handle, .SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] });7734 switch ((try deviceIoControl(&.{
7789 switch (rc) {7735 .file = .{ .handle = symlink_handle, .flags = .{ .nonblocking = false } },
7736 .code = .SET_REPARSE_POINT,
7737 .in = buffer[0..buf_len],
7738 })).u.Status) {
7790 .SUCCESS => {},7739 .SUCCESS => {},
7791 .PRIVILEGE_NOT_HELD => return error.PermissionDenied,7740 .PRIVILEGE_NOT_HELD => return error.PermissionDenied,
7792 .ACCESS_DENIED => return error.AccessDenied,7741 .ACCESS_DENIED => return error.AccessDenied,
7793 .INVALID_DEVICE_REQUEST => return error.FileSystem,7742 .INVALID_DEVICE_REQUEST => return error.FileSystem,
7794 else => return windows.unexpectedStatus(rc),7743 else => |status| return w.unexpectedStatus(status),
7795 }7744 }
7796}7745}
77977746
...@@ -7905,17 +7854,10 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []...@@ -7905,17 +7854,10 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []
7905fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {7854fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
7906 // This gets used once for `sub_path` and then reused again temporarily7855 // This gets used once for `sub_path` and then reused again temporarily
7907 // before converting back to `buffer`.7856 // before converting back to `buffer`.
7908 var sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, sub_path);7857 var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path);
7909 const sub_path_w = sub_path_w_buf.span();7858 const attr: windows.OBJECT.ATTRIBUTES = .{
7910 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;7859 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle,
7911 var nt_name: windows.UNICODE_STRING = .{7860 .ObjectName = @constCast(&sub_path_w.string()),
7912 .Length = path_len_bytes,
7913 .MaximumLength = path_len_bytes,
7914 .Buffer = @constCast(sub_path_w.ptr),
7915 };
7916 const attr: windows.OBJECT_ATTRIBUTES = .{
7917 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
7918 .ObjectName = &nt_name,
7919 };7861 };
7920 var io_status_block: windows.IO_STATUS_BLOCK = undefined;7862 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
7921 var result_handle: windows.HANDLE = undefined;7863 var result_handle: windows.HANDLE = undefined;
...@@ -8038,14 +7980,14 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink...@@ -8038,14 +7980,14 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink
8038 const len = buf.SubstituteNameLength >> 1;7980 const len = buf.SubstituteNameLength >> 1;
8039 const path_buf = @as([*]const u16, &buf.PathBuffer);7981 const path_buf = @as([*]const u16, &buf.PathBuffer);
8040 const is_relative = buf.Flags & windows.SYMLINK_FLAG_RELATIVE != 0;7982 const is_relative = buf.Flags & windows.SYMLINK_FLAG_RELATIVE != 0;
8041 break :r try parseReadLinkPath(path_buf[offset..][0..len], is_relative, &sub_path_w_buf.data);7983 break :r try parseReadLinkPath(path_buf[offset..][0..len], is_relative, &sub_path_w.data);
8042 },7984 },
8043 @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: {7985 @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: {
8044 const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));7986 const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
8045 const offset = buf.SubstituteNameOffset >> 1;7987 const offset = buf.SubstituteNameOffset >> 1;
8046 const len = buf.SubstituteNameLength >> 1;7988 const len = buf.SubstituteNameLength >> 1;
8047 const path_buf = @as([*]const u16, &buf.PathBuffer);7989 const path_buf = @as([*]const u16, &buf.PathBuffer);
8048 break :r try parseReadLinkPath(path_buf[offset..][0..len], false, &sub_path_w_buf.data);7990 break :r try parseReadLinkPath(path_buf[offset..][0..len], false, &sub_path_w.data);
8049 },7991 },
8050 else => return error.UnsupportedReparsePointType,7992 else => return error.UnsupportedReparsePointType,
8051 };7993 };
...@@ -8541,13 +8483,14 @@ fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void {...@@ -8541,13 +8483,14 @@ fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void {
85418483
8542fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {8484fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {
8543 const t: *Threaded = @ptrCast(@alignCast(userdata));8485 const t: *Threaded = @ptrCast(@alignCast(userdata));
8544 return t.isTty(file);8486 _ = t;
8487 return isTty(file);
8545}8488}
85468489
8547fn isTty(t: *Threaded, file: File) Io.Cancelable!bool {8490fn isTty(file: File) Io.Cancelable!bool {
8548 if (is_windows) {8491 if (is_windows) {
8549 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;8492 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;
8550 switch ((try t.deviceIoControl(&.{8493 switch ((try deviceIoControl(&.{
8551 .file = .{8494 .file = .{
8552 .handle = windows.peb().ProcessParameters.ConsoleHandle,8495 .handle = windows.peb().ProcessParameters.ConsoleHandle,
8553 .flags = .{ .nonblocking = false },8496 .flags = .{ .nonblocking = false },
...@@ -8626,8 +8569,9 @@ fn isTty(t: *Threaded, file: File) Io.Cancelable!bool {...@@ -8626,8 +8569,9 @@ fn isTty(t: *Threaded, file: File) Io.Cancelable!bool {
86268569
8627fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {8570fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {
8628 const t: *Threaded = @ptrCast(@alignCast(userdata));8571 const t: *Threaded = @ptrCast(@alignCast(userdata));
8572 _ = t;
86298573
8630 if (!is_windows) return if (!try t.supportsAnsiEscapeCodes(file)) error.NotTerminalDevice;8574 if (!is_windows) return if (!try supportsAnsiEscapeCodes(file)) error.NotTerminalDevice;
86318575
8632 // For Windows Terminal, VT Sequences processing is enabled by default.8576 // For Windows Terminal, VT Sequences processing is enabled by default.
8633 const console: File = .{8577 const console: File = .{
...@@ -8635,7 +8579,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE...@@ -8635,7 +8579,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE
8635 .flags = .{ .nonblocking = false },8579 .flags = .{ .nonblocking = false },
8636 };8580 };
8637 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;8581 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;
8638 switch ((try t.deviceIoControl(&.{8582 switch ((try deviceIoControl(&.{
8639 .file = console,8583 .file = console,
8640 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,8584 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,
8641 .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})),8585 .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})),
...@@ -8661,7 +8605,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE...@@ -8661,7 +8605,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE
8661 var set_console_mode = windows.CONSOLE.USER_IO.SET_MODE(8605 var set_console_mode = windows.CONSOLE.USER_IO.SET_MODE(
8662 get_console_mode.Data | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING,8606 get_console_mode.Data | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING,
8663 );8607 );
8664 switch ((try t.deviceIoControl(&.{8608 switch ((try deviceIoControl(&.{
8665 .file = console,8609 .file = console,
8666 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,8610 .code = windows.IOCTL.CONDRV.ISSUE_USER_IO,
8667 .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})),8611 .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})),
...@@ -8673,13 +8617,14 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE...@@ -8673,13 +8617,14 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE
86738617
8674fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {8618fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {
8675 const t: *Threaded = @ptrCast(@alignCast(userdata));8619 const t: *Threaded = @ptrCast(@alignCast(userdata));
8676 return t.supportsAnsiEscapeCodes(file);8620 _ = t;
8621 return supportsAnsiEscapeCodes(file);
8677}8622}
86788623
8679fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool {8624fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool {
8680 if (is_windows) {8625 if (is_windows) {
8681 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;8626 var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE;
8682 switch ((try t.deviceIoControl(&.{8627 switch ((try deviceIoControl(&.{
8683 .file = .{8628 .file = .{
8684 .handle = windows.peb().ProcessParameters.ConsoleHandle,8629 .handle = windows.peb().ProcessParameters.ConsoleHandle,
8685 .flags = .{ .nonblocking = false },8630 .flags = .{ .nonblocking = false },
...@@ -8701,7 +8646,7 @@ fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool {...@@ -8701,7 +8646,7 @@ fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool {
8701 return false;8646 return false;
8702 }8647 }
87038648
8704 if (try t.isTty(file)) return true;8649 if (try isTty(file)) return true;
87058650
8706 return false;8651 return false;
8707}8652}
...@@ -8775,7 +8720,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool {...@@ -8775,7 +8720,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool {
8775 },8720 },
8776 };8721 };
87778722
8778 const name_info: *const windows.FILE_NAME_INFO = @ptrCast(&name_info_bytes);8723 const name_info: *const windows.FILE.NAME_INFORMATION = @ptrCast(&name_info_bytes);
8779 const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength];8724 const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength];
8780 const name_wide = std.mem.bytesAsSlice(u16, name_bytes);8725 const name_wide = std.mem.bytesAsSlice(u16, name_bytes);
8781 // The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master8726 // The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master
...@@ -9002,49 +8947,38 @@ fn fileSetTimestamps(...@@ -9002,49 +8947,38 @@ fn fileSetTimestamps(
9002 _ = t;8947 _ = t;
90038948
9004 if (is_windows) {8949 if (is_windows) {
9005 var access_time_buffer: windows.FILETIME = undefined;8950 const now_sys = if (options.access_timestamp == .now or options.modify_timestamp == .now)
9006 var modify_time_buffer: windows.FILETIME = undefined;8951 windows.ntdll.RtlGetSystemTimePrecise()
9007 var system_time_buffer: windows.LARGE_INTEGER = undefined;8952 else
90088953 undefined;
9009 if (options.access_timestamp == .now or options.modify_timestamp == .now) {8954 var iosb: windows.IO_STATUS_BLOCK = undefined;
9010 system_time_buffer = windows.ntdll.RtlGetSystemTimePrecise();8955 var info: windows.FILE.BASIC_INFORMATION = .{
9011 }8956 .CreationTime = 0,
90128957 .LastAccessTime = switch (options.access_timestamp) {
9013 const access_ptr = switch (options.access_timestamp) {8958 .unchanged => 0,
9014 .unchanged => null,8959 .now => now_sys,
9015 .now => @panic("TODO do SystemTimeToFileTime logic here"),8960 .new => |ts| windows.toSysTime(ts),
9016 .new => |ts| p: {8961 },
9017 access_time_buffer = windows.nanoSecondsToFileTime(ts);8962 .LastWriteTime = switch (options.modify_timestamp) {
9018 break :p &access_time_buffer;8963 .unchanged => 0,
9019 },8964 .now => now_sys,
8965 .new => |ts| windows.toSysTime(ts),
8966 },
8967 .ChangeTime = 0,
8968 .FileAttributes = .{},
9020 };8969 };
90218970 var syscall: Syscall = try .start();
9022 const modify_ptr = switch (options.modify_timestamp) {8971 while (true) switch (windows.ntdll.NtSetInformationFile(
9023 .unchanged => null,8972 file.handle,
9024 .now => @panic("TODO do SystemTimeToFileTime logic here"),8973 &iosb,
9025 .new => |ts| p: {8974 &info,
9026 modify_time_buffer = windows.nanoSecondsToFileTime(ts);8975 @sizeOf(windows.FILE.BASIC_INFORMATION),
9027 break :p &modify_time_buffer;8976 .Basic,
9028 },8977 )) {
8978 .SUCCESS => return syscall.finish(),
8979 .CANCELLED => try syscall.checkCancel(),
8980 else => |status| return syscall.unexpectedNtstatus(status),
9029 };8981 };
9030
9031 // https://github.com/ziglang/zig/issues/1840
9032 const syscall: Syscall = try .start();
9033 while (true) {
9034 switch (windows.kernel32.SetFileTime(file.handle, null, access_ptr, modify_ptr)) {
9035 0 => switch (windows.GetLastError()) {
9036 .OPERATION_ABORTED => {
9037 try syscall.checkCancel();
9038 continue;
9039 },
9040 else => |err| {
9041 syscall.finish();
9042 return windows.unexpectedError(err);
9043 },
9044 },
9045 else => return syscall.finish(),
9046 }
9047 }
9048 }8982 }
90498983
9050 if (native_os == .wasi and !builtin.link_libc) {8984 if (native_os == .wasi and !builtin.link_libc) {
...@@ -9636,15 +9570,43 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingErro...@@ -9636,15 +9570,43 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingErro
9636}9570}
96379571
9638fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize {9572fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize {
9573 var iosb: windows.IO_STATUS_BLOCK = undefined;
9639 var index: usize = 0;9574 var index: usize = 0;
9640 while (data.len - index != 0 and data[index].len == 0) index += 1;9575 while (data.len - index != 0 and data[index].len == 0) index += 1;
9641 if (data.len - index == 0) return 0;9576 if (data.len - index == 0) return 0;
9642 const buffer = data[index];9577 const buffer = data[index];
9643 const short_buffer_len = @min(std.math.maxInt(u32), buffer.len);9578 const short_buffer_len = std.math.lossyCast(u32, buffer.len);
96449579 if (file.flags.nonblocking) {
9645 var iosb: windows.IO_STATUS_BLOCK = undefined;9580 var done: bool = false;
96469581 switch (windows.ntdll.NtReadFile(
9647 if (!file.flags.nonblocking) {9582 file.handle,
9583 null, // event
9584 flagApc,
9585 &done, // APC context
9586 &iosb,
9587 buffer.ptr,
9588 short_buffer_len,
9589 null, // byte offset
9590 null, // key
9591 )) {
9592 // We must wait for the APC routine.
9593 .PENDING, .SUCCESS => while (!done) {
9594 // Once we get here we must not return from the function until the
9595 // operation completes, thereby releasing reference to the iosb.
9596 const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) {
9597 error.Canceled => |e| {
9598 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
9599 _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb);
9600 while (!done) waitForApcOrAlert();
9601 return e;
9602 },
9603 };
9604 waitForApcOrAlert();
9605 alertable_syscall.finish();
9606 },
9607 else => |status| iosb.u.Status = status,
9608 }
9609 } else {
9648 const syscall: Syscall = try .start();9610 const syscall: Syscall = try .start();
9649 while (true) switch (windows.ntdll.NtReadFile(9611 while (true) switch (windows.ntdll.NtReadFile(
9650 file.handle,9612 file.handle,
...@@ -9665,41 +9627,10 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr...@@ -9665,41 +9627,10 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr
9665 else => |status| {9627 else => |status| {
9666 syscall.finish();9628 syscall.finish();
9667 iosb.u.Status = status;9629 iosb.u.Status = status;
9668 return ntReadFileResult(&iosb);9630 break;
9669 },9631 },
9670 };9632 };
9671 }9633 }
9672
9673 var done: bool = false;
9674
9675 switch (windows.ntdll.NtReadFile(
9676 file.handle,
9677 null, // event
9678 flagApc,
9679 &done, // APC context
9680 &iosb,
9681 buffer.ptr,
9682 short_buffer_len,
9683 null, // byte offset
9684 null, // key
9685 )) {
9686 // We must wait for the APC routine.
9687 .PENDING, .SUCCESS => while (!done) {
9688 // Once we get here we must not return from the function until the
9689 // operation completes, thereby releasing reference to io_status_block.
9690 const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) {
9691 error.Canceled => |e| {
9692 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
9693 _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb);
9694 while (!done) waitForApcOrAlert();
9695 return e;
9696 },
9697 };
9698 waitForApcOrAlert();
9699 alertable_syscall.finish();
9700 },
9701 else => |status| iosb.u.Status = status,
9702 }
9703 return ntReadFileResult(&iosb);9634 return ntReadFileResult(&iosb);
9704}9635}
97059636
...@@ -9714,8 +9645,9 @@ fn ntReadFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {...@@ -9714,8 +9645,9 @@ fn ntReadFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {
9714 .CANCELLED => unreachable,9645 .CANCELLED => unreachable,
9715 .SUCCESS => return io_status_block.Information,9646 .SUCCESS => return io_status_block.Information,
9716 .END_OF_FILE, .PIPE_BROKEN => return error.EndOfStream,9647 .END_OF_FILE, .PIPE_BROKEN => return error.EndOfStream,
9648 .INVALID_HANDLE => return error.NotOpenForReading,
9717 .INVALID_DEVICE_REQUEST => return error.IsDir,9649 .INVALID_DEVICE_REQUEST => return error.IsDir,
9718 .LOCK_NOT_GRANTED => return error.LockViolation,9650 .FILE_LOCK_CONFLICT => return error.LockViolation,
9719 .ACCESS_DENIED => return error.AccessDenied,9651 .ACCESS_DENIED => return error.AccessDenied,
9720 else => |status| return windows.unexpectedStatus(status),9652 else => |status| return windows.unexpectedStatus(status),
9721 }9653 }
...@@ -9731,7 +9663,7 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {...@@ -9731,7 +9663,7 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {
9731 .QUOTA_EXCEEDED => return error.SystemResources,9663 .QUOTA_EXCEEDED => return error.SystemResources,
9732 .PIPE_BROKEN => return error.BrokenPipe,9664 .PIPE_BROKEN => return error.BrokenPipe,
9733 .INVALID_HANDLE => return error.NotOpenForWriting,9665 .INVALID_HANDLE => return error.NotOpenForWriting,
9734 .LOCK_NOT_GRANTED => return error.LockViolation,9666 .FILE_LOCK_CONFLICT => return error.LockViolation,
9735 .ACCESS_DENIED => return error.AccessDenied,9667 .ACCESS_DENIED => return error.AccessDenied,
9736 .WORKING_SET_QUOTA => return error.SystemResources,9668 .WORKING_SET_QUOTA => return error.SystemResources,
9737 .DISK_FULL => return error.NoSpaceLeft,9669 .DISK_FULL => return error.NoSpaceLeft,
...@@ -9740,8 +9672,6 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {...@@ -9740,8 +9672,6 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize {
9740}9672}
97419673
9742fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {9674fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
9743 if (!have_preadv) @compileError("TODO implement fileReadPositionalPosix for cursed operating systems that don't support preadv (it's only Haiku)");
9744
9745 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;9675 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
9746 var i: usize = 0;9676 var i: usize = 0;
9747 for (data) |buf| {9677 for (data) |buf| {
...@@ -9787,9 +9717,44 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea...@@ -9787,9 +9717,44 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea
9787 }9717 }
9788 }9718 }
97899719
9720 if (have_preadv) {
9721 const syscall: Syscall = try .start();
9722 while (true) {
9723 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
9724 switch (posix.errno(rc)) {
9725 .SUCCESS => {
9726 syscall.finish();
9727 return @bitCast(rc);
9728 },
9729 .INTR, .TIMEDOUT => {
9730 try syscall.checkCancel();
9731 continue;
9732 },
9733 .NXIO => return syscall.fail(error.Unseekable),
9734 .SPIPE => return syscall.fail(error.Unseekable),
9735 .OVERFLOW => return syscall.fail(error.Unseekable),
9736 .NOBUFS => return syscall.fail(error.SystemResources),
9737 .NOMEM => return syscall.fail(error.SystemResources),
9738 .AGAIN => return syscall.fail(error.WouldBlock),
9739 .IO => return syscall.fail(error.InputOutput),
9740 .ISDIR => return syscall.fail(error.IsDir),
9741 .NOTCONN => |err| return syscall.errnoBug(err), // not a socket
9742 .CONNRESET => |err| return syscall.errnoBug(err), // not a socket
9743 .INVAL => |err| return syscall.errnoBug(err),
9744 .FAULT => |err| return syscall.errnoBug(err),
9745 .BADF => {
9746 syscall.finish();
9747 if (native_os == .wasi) return error.IsDir; // File operation on directory.
9748 return error.NotOpenForReading;
9749 },
9750 else => |err| return syscall.unexpectedErrno(err),
9751 }
9752 }
9753 }
9754
9790 const syscall: Syscall = try .start();9755 const syscall: Syscall = try .start();
9791 while (true) {9756 while (true) {
9792 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));9757 const rc = posix.pread(file.handle, dest[0].ptr, @intCast(dest[0].len), @bitCast(offset));
9793 switch (posix.errno(rc)) {9758 switch (posix.errno(rc)) {
9794 .SUCCESS => {9759 .SUCCESS => {
9795 syscall.finish();9760 syscall.finish();
...@@ -9838,65 +9803,119 @@ fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.R...@@ -9838,65 +9803,119 @@ fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.R
9838}9803}
98399804
9840fn readFilePositionalWindows(file: File, buffer: []u8, offset: u64) File.ReadPositionalError!usize {9805fn readFilePositionalWindows(file: File, buffer: []u8, offset: u64) File.ReadPositionalError!usize {
9841 const DWORD = windows.DWORD;9806 var iosb: windows.IO_STATUS_BLOCK = undefined;
9842 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);9807 const short_buffer_len = std.math.lossyCast(u32, buffer.len);
9843 var overlapped: windows.OVERLAPPED = .{9808 const signed_offset: windows.LARGE_INTEGER = @intCast(offset);
9844 .Internal = 0,9809 if (file.flags.nonblocking) {
9845 .InternalHigh = 0,9810 var done: bool = false;
9846 .DUMMYUNIONNAME = .{9811 switch (windows.ntdll.NtReadFile(
9847 .DUMMYSTRUCTNAME = .{9812 file.handle,
9848 .Offset = @truncate(offset),9813 null, // event
9849 .OffsetHigh = @truncate(offset >> 32),9814 flagApc,
9815 &done, // APC context
9816 &iosb,
9817 buffer.ptr,
9818 short_buffer_len,
9819 &signed_offset,
9820 null, // key
9821 )) {
9822 // We must wait for the APC routine.
9823 .PENDING, .SUCCESS => while (!done) {
9824 // Once we get here we must not return from the function until the
9825 // operation completes, thereby releasing reference to the iosb.
9826 const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) {
9827 error.Canceled => |e| {
9828 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
9829 _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb);
9830 while (!done) waitForApcOrAlert();
9831 return e;
9832 },
9833 };
9834 waitForApcOrAlert();
9835 alertable_syscall.finish();
9850 },9836 },
9851 },9837 else => |status| iosb.u.Status = status,
9852 .hEvent = null,
9853 };
9854
9855 const syscall: Syscall = try .start();
9856 while (true) {
9857 var n: DWORD = undefined;
9858 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0) {
9859 syscall.finish();
9860 return n;
9861 }9838 }
9862 switch (windows.GetLastError()) {9839 } else {
9863 .IO_PENDING => |err| {9840 const syscall: Syscall = try .start();
9864 syscall.finish();9841 while (true) switch (windows.ntdll.NtReadFile(
9865 return windows.errorBug(err);9842 file.handle,
9866 },9843 null, // event
9867 .OPERATION_ABORTED => {9844 null, // APC routine
9868 try syscall.checkCancel();9845 null, // APC context
9869 continue;9846 &iosb,
9870 },9847 buffer.ptr,
9871 .BROKEN_PIPE, .HANDLE_EOF => {9848 short_buffer_len,
9872 syscall.finish();9849 &signed_offset,
9873 return 0;9850 null, // key
9874 },9851 )) {
9875 .NETNAME_DELETED => if (is_debug) unreachable else return error.Unexpected,9852 .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag
9876 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),9853 .CANCELLED => try syscall.checkCancel(),
9877 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),9854 else => |status| {
9878 .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected,
9879 // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing
9880 // a handle to a directory.
9881 .INVALID_FUNCTION => return syscall.fail(error.IsDir),
9882 else => |err| {
9883 syscall.finish();9855 syscall.finish();
9884 return windows.unexpectedError(err);9856 iosb.u.Status = status;
9857 break;
9885 },9858 },
9886 }9859 };
9887 }9860 }
9861 return ntReadFileResult(&iosb) catch |err| switch (err) {
9862 error.EndOfStream => 0,
9863 else => |e| e,
9864 };
9888}9865}
98899866
9890fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!void {9867fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!void {
9891 const t: *Threaded = @ptrCast(@alignCast(userdata));9868 const t: *Threaded = @ptrCast(@alignCast(userdata));
9892 _ = t;9869 _ = t;
9893 const fd = file.handle;
98949870
9895 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {9871 if (is_windows) {
9896 var result: u64 = undefined;9872 var iosb: windows.IO_STATUS_BLOCK = undefined;
9873 var info: windows.FILE.POSITION_INFORMATION = undefined;
9874 const syscall: Syscall = try .start();
9875 while (true) switch (windows.ntdll.NtQueryInformationFile(
9876 file.handle,
9877 &iosb,
9878 &info,
9879 @sizeOf(windows.FILE.POSITION_INFORMATION),
9880 .Position,
9881 )) {
9882 .SUCCESS => break,
9883 .CANCELLED => try syscall.checkCancel(),
9884 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
9885 .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable),
9886 else => |status| return syscall.unexpectedNtstatus(status),
9887 };
9888 info.CurrentByteOffset = @bitCast((if (offset >= 0) std.math.add(
9889 u64,
9890 @bitCast(info.CurrentByteOffset),
9891 @intCast(offset),
9892 ) else std.math.sub(
9893 u64,
9894 @bitCast(info.CurrentByteOffset),
9895 @intCast(-offset),
9896 )) catch |err| switch (err) {
9897 error.Overflow => return syscall.fail(error.Unseekable),
9898 });
9899 while (true) switch (windows.ntdll.NtSetInformationFile(
9900 file.handle,
9901 &iosb,
9902 &info,
9903 @sizeOf(windows.FILE.POSITION_INFORMATION),
9904 .Position,
9905 )) {
9906 .SUCCESS => return syscall.finish(),
9907 .CANCELLED => try syscall.checkCancel(),
9908 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
9909 .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable),
9910 else => |status| return syscall.unexpectedNtstatus(status),
9911 };
9912 }
9913
9914 if (native_os == .wasi and !builtin.link_libc) {
9915 var new_offset: std.os.wasi.filesize_t = undefined;
9897 const syscall: Syscall = try .start();9916 const syscall: Syscall = try .start();
9898 while (true) {9917 while (true) {
9899 switch (posix.errno(posix.system.llseek(fd, @bitCast(offset), &result, posix.SEEK.CUR))) {9918 switch (std.os.wasi.fd_seek(file.handle, offset, .CUR, &new_offset)) {
9900 .SUCCESS => {9919 .SUCCESS => {
9901 syscall.finish();9920 syscall.finish();
9902 return;9921 return;
...@@ -9913,6 +9932,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -9913,6 +9932,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
9913 .OVERFLOW => return error.Unseekable,9932 .OVERFLOW => return error.Unseekable,
9914 .SPIPE => return error.Unseekable,9933 .SPIPE => return error.Unseekable,
9915 .NXIO => return error.Unseekable,9934 .NXIO => return error.Unseekable,
9935 .NOTCAPABLE => return error.AccessDenied,
9916 else => |err| return posix.unexpectedErrno(err),9936 else => |err| return posix.unexpectedErrno(err),
9917 }9937 }
9918 },9938 },
...@@ -9920,34 +9940,13 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -9920,34 +9940,13 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
9920 }9940 }
9921 }9941 }
99229942
9923 if (is_windows) {9943 if (posix.SEEK == void) return error.Unseekable;
9924 const syscall: Syscall = try .start();
9925 while (true) {
9926 if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) {
9927 return syscall.finish();
9928 }
9929 switch (windows.GetLastError()) {
9930 .OPERATION_ABORTED => {
9931 try syscall.checkCancel();
9932 continue;
9933 },
9934 .INVALID_FUNCTION => return syscall.fail(error.Unseekable),
9935 .NEGATIVE_SEEK => return syscall.fail(error.Unseekable),
9936 .INVALID_PARAMETER => unreachable,
9937 .INVALID_HANDLE => unreachable,
9938 else => |err| {
9939 syscall.finish();
9940 return windows.unexpectedError(err);
9941 },
9942 }
9943 }
9944 }
99459944
9946 if (native_os == .wasi and !builtin.link_libc) {9945 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
9947 var new_offset: std.os.wasi.filesize_t = undefined;9946 var result: u64 = undefined;
9948 const syscall: Syscall = try .start();9947 const syscall: Syscall = try .start();
9949 while (true) {9948 while (true) {
9950 switch (std.os.wasi.fd_seek(fd, offset, .CUR, &new_offset)) {9949 switch (posix.errno(posix.system.llseek(file.handle, @bitCast(offset), &result, posix.SEEK.CUR))) {
9951 .SUCCESS => {9950 .SUCCESS => {
9952 syscall.finish();9951 syscall.finish();
9953 return;9952 return;
...@@ -9964,7 +9963,6 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -9964,7 +9963,6 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
9964 .OVERFLOW => return error.Unseekable,9963 .OVERFLOW => return error.Unseekable,
9965 .SPIPE => return error.Unseekable,9964 .SPIPE => return error.Unseekable,
9966 .NXIO => return error.Unseekable,9965 .NXIO => return error.Unseekable,
9967 .NOTCAPABLE => return error.AccessDenied,
9968 else => |err| return posix.unexpectedErrno(err),9966 else => |err| return posix.unexpectedErrno(err),
9969 }9967 }
9970 },9968 },
...@@ -9972,11 +9970,9 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -9972,11 +9970,9 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
9972 }9970 }
9973 }9971 }
99749972
9975 if (posix.SEEK == void) return error.Unseekable;
9976
9977 const syscall: Syscall = try .start();9973 const syscall: Syscall = try .start();
9978 while (true) {9974 while (true) {
9979 switch (posix.errno(lseek_sym(fd, offset, posix.SEEK.CUR))) {9975 switch (posix.errno(lseek_sym(file.handle, offset, posix.SEEK.CUR))) {
9980 .SUCCESS => {9976 .SUCCESS => {
9981 syscall.finish();9977 syscall.finish();
9982 return;9978 return;
...@@ -10003,41 +9999,31 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi...@@ -10003,41 +9999,31 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi
10003fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!void {9999fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!void {
10004 const t: *Threaded = @ptrCast(@alignCast(userdata));10000 const t: *Threaded = @ptrCast(@alignCast(userdata));
10005 _ = t;10001 _ = t;
10006 const fd = file.handle;
1000710002
10008 if (is_windows) {10003 if (is_windows) {
10009 // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]10004 var iosb: windows.IO_STATUS_BLOCK = undefined;
10010 // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."10005 var info: windows.FILE.POSITION_INFORMATION = .{ .CurrentByteOffset = @bitCast(offset) };
10011 // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex
10012 const ipos: windows.LARGE_INTEGER = @bitCast(offset);
10013
10014 const syscall: Syscall = try .start();10006 const syscall: Syscall = try .start();
10015 while (true) {10007 while (true) switch (windows.ntdll.NtSetInformationFile(
10016 if (windows.kernel32.SetFilePointerEx(fd, ipos, null, windows.FILE_BEGIN) != 0) {10008 file.handle,
10017 return syscall.finish();10009 &iosb,
10018 }10010 &info,
10019 switch (windows.GetLastError()) {10011 @sizeOf(windows.FILE.POSITION_INFORMATION),
10020 .OPERATION_ABORTED => {10012 .Position,
10021 try syscall.checkCancel();10013 )) {
10022 continue;10014 .SUCCESS => return syscall.finish(),
10023 },10015 .CANCELLED => try syscall.checkCancel(),
10024 .INVALID_FUNCTION => return syscall.fail(error.Unseekable),10016 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),
10025 .NEGATIVE_SEEK => return syscall.fail(error.Unseekable),10017 .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable),
10026 .INVALID_PARAMETER => unreachable,10018 else => |status| return syscall.unexpectedNtstatus(status),
10027 .INVALID_HANDLE => unreachable,10019 };
10028 else => |err| {
10029 syscall.finish();
10030 return windows.unexpectedError(err);
10031 },
10032 }
10033 }
10034 }10020 }
1003510021
10036 if (native_os == .wasi and !builtin.link_libc) {10022 if (native_os == .wasi and !builtin.link_libc) {
10037 const syscall: Syscall = try .start();10023 const syscall: Syscall = try .start();
10038 while (true) {10024 while (true) {
10039 var new_offset: std.os.wasi.filesize_t = undefined;10025 var new_offset: std.os.wasi.filesize_t = undefined;
10040 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {10026 switch (std.os.wasi.fd_seek(file.handle, @bitCast(offset), .SET, &new_offset)) {
10041 .SUCCESS => {10027 .SUCCESS => {
10042 syscall.finish();10028 syscall.finish();
10043 return;10029 return;
...@@ -10064,7 +10050,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi...@@ -10064,7 +10050,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi
1006410050
10065 if (posix.SEEK == void) return error.Unseekable;10051 if (posix.SEEK == void) return error.Unseekable;
1006610052
10067 return posixSeekTo(fd, offset);10053 return posixSeekTo(file.handle, offset);
10068}10054}
1006910055
10070fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void {10056fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void {
...@@ -10131,8 +10117,7 @@ fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.O...@@ -10131,8 +10117,7 @@ fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.O
10131 // If ImagePathName is a symlink, then it will contain the path of the symlink,10117 // If ImagePathName is a symlink, then it will contain the path of the symlink,
10132 // not the path that the symlink points to. However, because we are opening10118 // not the path that the symlink points to. However, because we are opening
10133 // the file, we can let the openFileW call follow the symlink for us.10119 // the file, we can let the openFileW call follow the symlink for us.
10134 const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName;10120 const image_path_name = windows.peb().ProcessParameters.ImagePathName.sliceZ();
10135 const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
10136 const prefixed_path_w = try wToPrefixedFileW(null, image_path_name);10121 const prefixed_path_w = try wToPrefixedFileW(null, image_path_name);
10137 return dirOpenFileWtf16(null, prefixed_path_w.span(), flags);10122 return dirOpenFileWtf16(null, prefixed_path_w.span(), flags);
10138 },10123 },
...@@ -10334,14 +10319,13 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut...@@ -10334,14 +10319,13 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
10334 return error.FileNotFound;10319 return error.FileNotFound;
10335 },10320 },
10336 .windows => {10321 .windows => {
10337 const w = windows;
10338 const image_path_unicode_string = &w.peb().ProcessParameters.ImagePathName;
10339 const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
10340
10341 // If ImagePathName is a symlink, then it will contain the path of the10322 // If ImagePathName is a symlink, then it will contain the path of the
10342 // symlink, not the path that the symlink points to. We want the path10323 // symlink, not the path that the symlink points to. We want the path
10343 // that the symlink points to, though, so we need to get the realpath.10324 // that the symlink points to, though, so we need to get the realpath.
10344 var path_name_w_buf = try wToPrefixedFileW(null, image_path_name);10325 var path_name_w_buf = try wToPrefixedFileW(
10326 null,
10327 windows.peb().ProcessParameters.ImagePathName.sliceZ(),
10328 );
1034510329
10346 const h_file = handle: {10330 const h_file = handle: {
10347 if (OpenFile(path_name_w_buf.span(), .{10331 if (OpenFile(path_name_w_buf.span(), .{
...@@ -10360,7 +10344,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut...@@ -10360,7 +10344,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
10360 else => |e| return e,10344 else => |e| return e,
10361 }10345 }
10362 };10346 };
10363 defer w.CloseHandle(h_file);10347 defer windows.CloseHandle(h_file);
1036410348
10365 const wide_slice = try GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data);10349 const wide_slice = try GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data);
1036610350
...@@ -10388,15 +10372,15 @@ fn fileWritePositional(...@@ -10388,15 +10372,15 @@ fn fileWritePositional(
1038810372
10389 if (is_windows) {10373 if (is_windows) {
10390 if (header.len != 0) {10374 if (header.len != 0) {
10391 return writeFilePositionalWindows(file.handle, header, offset);10375 return writeFilePositionalWindows(file, header, offset);
10392 }10376 }
10393 for (data[0 .. data.len - 1]) |buf| {10377 for (data[0 .. data.len - 1]) |buf| {
10394 if (buf.len == 0) continue;10378 if (buf.len == 0) continue;
10395 return writeFilePositionalWindows(file.handle, buf, offset);10379 return writeFilePositionalWindows(file, buf, offset);
10396 }10380 }
10397 const pattern = data[data.len - 1];10381 const pattern = data[data.len - 1];
10398 if (pattern.len == 0 or splat == 0) return 0;10382 if (pattern.len == 0 or splat == 0) return 0;
10399 return writeFilePositionalWindows(file.handle, pattern, offset);10383 return writeFilePositionalWindows(file, pattern, offset);
10400 }10384 }
1040110385
10402 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;10386 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
...@@ -10505,50 +10489,64 @@ fn fileWritePositional(...@@ -10505,50 +10489,64 @@ fn fileWritePositional(
10505 }10489 }
10506}10490}
1050710491
10508fn writeFilePositionalWindows(10492fn writeFilePositionalWindows(file: File, buffer: []const u8, offset: u64) File.WritePositionalError!usize {
10509 handle: windows.HANDLE,10493 assert(buffer.len != 0);
10510 bytes: []const u8,10494 var iosb: windows.IO_STATUS_BLOCK = undefined;
10511 offset: u64,10495 const short_buffer_len = std.math.lossyCast(u32, buffer.len);
10512) File.WritePositionalError!usize {10496 const signed_offset: windows.LARGE_INTEGER = @intCast(offset);
10513 var bytes_written: windows.DWORD = undefined;10497 if (file.flags.nonblocking) {
10514 var overlapped: windows.OVERLAPPED = .{10498 var done: bool = false;
10515 .Internal = 0,10499 switch (windows.ntdll.NtWriteFile(
10516 .InternalHigh = 0,10500 file.handle,
10517 .DUMMYUNIONNAME = .{10501 null, // event
10518 .DUMMYSTRUCTNAME = .{10502 flagApc,
10519 .Offset = @truncate(offset),10503 &done, // APC context
10520 .OffsetHigh = @truncate(offset >> 32),10504 &iosb,
10505 buffer.ptr,
10506 short_buffer_len,
10507 &signed_offset,
10508 null, // key
10509 )) {
10510 // We must wait for the APC routine.
10511 .PENDING, .SUCCESS => while (!done) {
10512 // Once we get here we must not return from the function until the
10513 // operation completes, thereby releasing reference to the iosb.
10514 const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) {
10515 error.Canceled => |e| {
10516 var cancel_iosb: windows.IO_STATUS_BLOCK = undefined;
10517 _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb);
10518 while (!done) waitForApcOrAlert();
10519 return e;
10520 },
10521 };
10522 waitForApcOrAlert();
10523 alertable_syscall.finish();
10521 },10524 },
10522 },10525 else => |status| iosb.u.Status = status,
10523 .hEvent = null,
10524 };
10525 const adjusted_len = std.math.lossyCast(u32, bytes.len);
10526 const syscall: Syscall = try .start();
10527 while (true) {
10528 if (windows.kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, &overlapped) != 0) {
10529 syscall.finish();
10530 return bytes_written;
10531 }10526 }
10532 switch (windows.GetLastError()) {10527 } else {
10533 .OPERATION_ABORTED => {10528 const syscall: Syscall = try .start();
10534 try syscall.checkCancel();10529 while (true) switch (windows.ntdll.NtWriteFile(
10535 continue;10530 file.handle,
10536 },10531 null, // event
10537 .INVALID_USER_BUFFER => return syscall.fail(error.SystemResources),10532 null, // APC routine
10538 .NOT_ENOUGH_MEMORY => return syscall.fail(error.SystemResources),10533 null, // APC context
10539 .NOT_ENOUGH_QUOTA => return syscall.fail(error.SystemResources),10534 &iosb,
10540 .NO_DATA => return syscall.fail(error.BrokenPipe),10535 buffer.ptr,
10541 .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, // use after free10536 short_buffer_len,
10542 .LOCK_VIOLATION => return syscall.fail(error.LockViolation),10537 &signed_offset,
10543 .ACCESS_DENIED => return syscall.fail(error.AccessDenied),10538 null, // key
10544 .WORKING_SET_QUOTA => return syscall.fail(error.SystemResources),10539 )) {
10545 .DISK_FULL => return syscall.fail(error.NoSpaceLeft),10540 .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag
10546 else => |err| {10541 .CANCELLED => try syscall.checkCancel(),
10542 else => |status| {
10547 syscall.finish();10543 syscall.finish();
10548 return windows.unexpectedError(err);10544 iosb.u.Status = status;
10545 return ntWriteFileResult(&iosb);
10549 },10546 },
10550 }10547 };
10551 }10548 }
10549 return ntWriteFileResult(&iosb);
10552}10550}
1055310551
10554fn fileWriteStreaming(10552fn fileWriteStreaming(
...@@ -10673,9 +10671,7 @@ fn fileWriteStreaming(...@@ -10673,9 +10671,7 @@ fn fileWriteStreaming(
1067310671
10674fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!usize {10672fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!usize {
10675 assert(buffer.len != 0);10673 assert(buffer.len != 0);
10676
10677 var iosb: windows.IO_STATUS_BLOCK = undefined;10674 var iosb: windows.IO_STATUS_BLOCK = undefined;
10678
10679 if (file.flags.nonblocking) {10675 if (file.flags.nonblocking) {
10680 var done: bool = false;10676 var done: bool = false;
10681 switch (windows.ntdll.NtWriteFile(10677 switch (windows.ntdll.NtWriteFile(
...@@ -10706,7 +10702,6 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u...@@ -10706,7 +10702,6 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u
10706 },10702 },
10707 else => |status| iosb.u.Status = status,10703 else => |status| iosb.u.Status = status,
10708 }10704 }
10709 return ntWriteFileResult(&iosb);
10710 } else {10705 } else {
10711 const syscall: Syscall = try .start();10706 const syscall: Syscall = try .start();
10712 while (true) switch (windows.ntdll.NtWriteFile(10707 while (true) switch (windows.ntdll.NtWriteFile(
...@@ -10721,17 +10716,15 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u...@@ -10721,17 +10716,15 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u
10721 null, // key10716 null, // key
10722 )) {10717 )) {
10723 .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag10718 .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag
10724 .CANCELLED => {10719 .CANCELLED => try syscall.checkCancel(),
10725 try syscall.checkCancel();
10726 continue;
10727 },
10728 else => |status| {10720 else => |status| {
10729 syscall.finish();10721 syscall.finish();
10730 iosb.u.Status = status;10722 iosb.u.Status = status;
10731 return ntWriteFileResult(&iosb);10723 break;
10732 },10724 },
10733 };10725 };
10734 }10726 }
10727 return ntWriteFileResult(&iosb);
10735}10728}
1073610729
10737fn fileWriteFileStreaming(10730fn fileWriteFileStreaming(
...@@ -11433,13 +11426,22 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {...@@ -11433,13 +11426,22 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {
11433 return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 + epoch_ns };11426 return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 + epoch_ns };
11434 },11427 },
11435 .awake, .boot => {11428 .awake, .boot => {
11436 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
11437 const qpc = windows.QueryPerformanceCounter();
11438 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA11429 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
11439 // (a read-only page of info updated and mapped by the kernel to all processes):11430 // (a read-only page of info updated and mapped by the kernel to all processes):
11440 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data11431 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
11441 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm11432 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
11442 const qpf = windows.QueryPerformanceFrequency();11433 const qpf: u64 = qpf: {
11434 var qpf: windows.LARGE_INTEGER = undefined;
11435 assert(windows.ntdll.RtlQueryPerformanceFrequency(&qpf) != windows.FALSE);
11436 break :qpf @bitCast(qpf);
11437 };
11438
11439 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
11440 const qpc: u64 = qpc: {
11441 var qpc: windows.LARGE_INTEGER = undefined;
11442 assert(windows.ntdll.RtlQueryPerformanceCounter(&qpc) != windows.FALSE);
11443 break :qpc @bitCast(qpc);
11444 };
1144311445
11444 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.11446 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
11445 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L70111447 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
...@@ -11458,7 +11460,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {...@@ -11458,7 +11460,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {
11458 // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L442-L48511460 // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L442-L485
11459 if (windows.ntdll.NtQueryInformationProcess(11461 if (windows.ntdll.NtQueryInformationProcess(
11460 handle,11462 handle,
11461 windows.PROCESSINFOCLASS.Times,11463 .Times,
11462 &times,11464 &times,
11463 @sizeOf(windows.KERNEL_USER_TIMES),11465 @sizeOf(windows.KERNEL_USER_TIMES),
11464 null,11466 null,
...@@ -11474,7 +11476,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {...@@ -11474,7 +11476,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {
11474 // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L2971-L301911476 // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L2971-L3019
11475 if (windows.ntdll.NtQueryInformationThread(11477 if (windows.ntdll.NtQueryInformationThread(
11476 handle,11478 handle,
11477 windows.THREADINFOCLASS.Times,11479 .Times,
11478 &times,11480 &times,
11479 @sizeOf(windows.KERNEL_USER_TIMES),11481 @sizeOf(windows.KERNEL_USER_TIMES),
11480 null,11482 null,
...@@ -14132,21 +14134,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr...@@ -14132,21 +14134,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr
14132}14134}
1413314135
14134fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirError!void {14136fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirError!void {
14135 if (native_os == .wasi) return error.OperationUnsupported;
14136 const t: *Threaded = @ptrCast(@alignCast(userdata));14137 const t: *Threaded = @ptrCast(@alignCast(userdata));
14137 _ = t;14138 _ = t;
1413814139
14140 if (native_os == .wasi) return error.OperationUnsupported;
14141
14139 if (is_windows) {14142 if (is_windows) {
14140 var dir_path_buffer: [windows.PATH_MAX_WIDE]u16 = undefined;14143 var dir_path_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
14141 const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buffer);14144 const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buf);
14142 const path_len_bytes = std.math.cast(u16, dir_path.len * 2) orelse return error.NameTooLong;
14143 var nt_name: windows.UNICODE_STRING = .{
14144 .Length = path_len_bytes,
14145 .MaximumLength = path_len_bytes,
14146 .Buffer = @constCast(dir_path.ptr),
14147 };
14148 const syscall: Syscall = try .start();14145 const syscall: Syscall = try .start();
14149 while (true) switch (windows.ntdll.RtlSetCurrentDirectory_U(&nt_name)) {14146 while (true) switch (windows.ntdll.RtlSetCurrentDirectory_U(&.init(dir_path))) {
14150 .SUCCESS => return syscall.finish(),14147 .SUCCESS => return syscall.finish(),
14151 .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),14148 .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName),
14152 .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),14149 .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound),
...@@ -15465,26 +15462,27 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void {...@@ -15465,26 +15462,27 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void {
15465fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT) !void {15462fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT) !void {
15466 _ = t; // TODO cancelation15463 _ = t; // TODO cancelation
15467 const handle = child.id.?;15464 const handle = child.id.?;
15468 if (windows.kernel32.TerminateProcess(handle, exit_code) == 0) {15465 _ = windows.ntdll.RtlReportSilentProcessExit(handle, @enumFromInt(exit_code));
15469 switch (windows.GetLastError()) {15466 switch (windows.ntdll.NtTerminateProcess(handle, @enumFromInt(exit_code))) {
15470 .ACCESS_DENIED => {15467 .SUCCESS => {
15471 // Usually when TerminateProcess triggers a ACCESS_DENIED error, it15468 const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
15472 // indicates that the process has already exited, but there may be15469 _ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout);
15473 // some rare edge cases where our process handle no longer has the15470 childCleanupWindows(child);
15474 // PROCESS_TERMINATE access right, so let's do another check to make15471 },
15475 // sure the process is really no longer running:15472 .ACCESS_DENIED => {
15476 const minimal_timeout: windows.LARGE_INTEGER = -1;15473 // Usually when TerminateProcess triggers a ACCESS_DENIED error, it
15477 switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) {15474 // indicates that the process has already exited, but there may be
15478 .SUCCESS => return error.AlreadyTerminated,15475 // some rare edge cases where our process handle no longer has the
15479 else => return error.AccessDenied,15476 // PROCESS_TERMINATE access right, so let's do another check to make
15480 }15477 // sure the process is really no longer running:
15481 },15478 const minimal_timeout: windows.LARGE_INTEGER = -1;
15482 else => |err| return windows.unexpectedError(err),15479 return switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) {
15483 }15480 windows.NTSTATUS.WAIT_0 => error.AlreadyTerminated,
15481 else => error.AccessDenied,
15482 };
15483 },
15484 else => |status| return windows.unexpectedStatus(status),
15484 }15485 }
15485 const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
15486 _ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout);
15487 childCleanupWindows(child);
15488}15486}
1548915487
15490fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child.Term {15488fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child.Term {
...@@ -15501,12 +15499,12 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child...@@ -15501,12 +15499,12 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child
15501 else => |status| return alertable_syscall.unexpectedNtstatus(status),15499 else => |status| return alertable_syscall.unexpectedNtstatus(status),
15502 };15500 };
1550315501
15504 var info: windows.PROCESS_BASIC_INFORMATION = undefined;15502 var info: windows.PROCESS.BASIC_INFORMATION = undefined;
15505 const term: process.Child.Term = switch (windows.ntdll.NtQueryInformationProcess(15503 const term: process.Child.Term = switch (windows.ntdll.NtQueryInformationProcess(
15506 handle,15504 handle,
15507 .BasicInformation,15505 .BasicInformation,
15508 &info,15506 &info,
15509 @sizeOf(windows.PROCESS_BASIC_INFORMATION),15507 @sizeOf(windows.PROCESS.BASIC_INFORMATION),
15510 null,15508 null,
15511 )) {15509 )) {
15512 .SUCCESS => .{ .exited = @as(u8, @truncate(@intFromEnum(info.ExitStatus))) },15510 .SUCCESS => .{ .exited = @as(u8, @truncate(@intFromEnum(info.ExitStatus))) },
...@@ -15521,12 +15519,12 @@ fn childCleanupWindows(child: *process.Child) void {...@@ -15521,12 +15519,12 @@ fn childCleanupWindows(child: *process.Child) void {
15521 const handle = child.id orelse return;15519 const handle = child.id orelse return;
1552215520
15523 if (child.request_resource_usage_statistics) {15521 if (child.request_resource_usage_statistics) {
15524 var vmc: windows.VM_COUNTERS = undefined;15522 var vmc: windows.PROCESS.VM_COUNTERS = undefined;
15525 switch (windows.ntdll.NtQueryInformationProcess(15523 switch (windows.ntdll.NtQueryInformationProcess(
15526 handle,15524 handle,
15527 .VmCounters,15525 .VmCounters,
15528 &vmc,15526 &vmc,
15529 @sizeOf(windows.VM_COUNTERS),15527 @sizeOf(windows.PROCESS.VM_COUNTERS),
15530 null,15528 null,
15531 )) {15529 )) {
15532 .SUCCESS => child.resource_usage_statistics.rusage = vmc,15530 .SUCCESS => child.resource_usage_statistics.rusage = vmc,
...@@ -15853,7 +15851,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro...@@ -15853,7 +15851,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
15853 .cbReserved2 = 0,15851 .cbReserved2 = 0,
15854 .lpReserved2 = null,15852 .lpReserved2 = null,
15855 };15853 };
15856 var piProcInfo: windows.PROCESS_INFORMATION = undefined;15854 var piProcInfo: windows.PROCESS.INFORMATION = undefined;
1585715855
15858 var arena_allocator = std.heap.ArenaAllocator.init(t.allocator);15856 var arena_allocator = std.heap.ArenaAllocator.init(t.allocator);
15859 defer arena_allocator.deinit();15857 defer arena_allocator.deinit();
...@@ -16062,7 +16060,6 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE {...@@ -16062,7 +16060,6 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE {
16062 if (t.random_file.handle) |handle| return handle;16060 if (t.random_file.handle) |handle| return handle;
16063 }16061 }
1606416062
16065 const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' };
16066 var fresh_handle: windows.HANDLE = undefined;16063 var fresh_handle: windows.HANDLE = undefined;
16067 var io_status_block: windows.IO_STATUS_BLOCK = undefined;16064 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
16068 var syscall: Syscall = try .start();16065 var syscall: Syscall = try .start();
...@@ -16072,13 +16069,9 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE {...@@ -16072,13 +16069,9 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE {
16072 .STANDARD = .{ .SYNCHRONIZE = true },16069 .STANDARD = .{ .SYNCHRONIZE = true },
16073 .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } },16070 .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } },
16074 },16071 },
16075 &.{16072 &.{ .ObjectName = @constCast(&windows.UNICODE_STRING.init(
16076 .ObjectName = @constCast(&windows.UNICODE_STRING{16073 &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' },
16077 .Length = @sizeOf(@TypeOf(device_path)),16074 )) },
16078 .MaximumLength = 0,
16079 .Buffer = @constCast(&device_path),
16080 }),
16081 },
16082 &io_status_block,16075 &io_status_block,
16083 .VALID_FLAGS,16076 .VALID_FLAGS,
16084 .{ .IO = .SYNCHRONOUS_NONALERT },16077 .{ .IO = .SYNCHRONOUS_NONALERT },
...@@ -16111,7 +16104,6 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE {...@@ -16111,7 +16104,6 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE {
16111 if (t.null_file.handle) |handle| return handle;16104 if (t.null_file.handle) |handle| return handle;
16112 }16105 }
1611316106
16114 const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' };
16115 var fresh_handle: windows.HANDLE = undefined;16107 var fresh_handle: windows.HANDLE = undefined;
16116 var io_status_block: windows.IO_STATUS_BLOCK = undefined;16108 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
16117 var syscall: Syscall = try .start();16109 var syscall: Syscall = try .start();
...@@ -16123,11 +16115,9 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE {...@@ -16123,11 +16115,9 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE {
16123 },16115 },
16124 &.{16116 &.{
16125 .Attributes = .{ .INHERIT = true },16117 .Attributes = .{ .INHERIT = true },
16126 .ObjectName = @constCast(&windows.UNICODE_STRING{16118 .ObjectName = @constCast(&windows.UNICODE_STRING.init(
16127 .Length = @sizeOf(@TypeOf(device_path)),16119 &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' },
16128 .MaximumLength = 0,16120 )),
16129 .Buffer = @constCast(&device_path),
16130 }),
16131 },16121 },
16132 &io_status_block,16122 &io_status_block,
16133 .VALID_FLAGS,16123 .VALID_FLAGS,
...@@ -16173,7 +16163,6 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE {...@@ -16173,7 +16163,6 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE {
16173 if (t.pipe_file.handle) |handle| return handle;16163 if (t.pipe_file.handle) |handle| return handle;
16174 }16164 }
1617516165
16176 const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' };
16177 var fresh_handle: windows.HANDLE = undefined;16166 var fresh_handle: windows.HANDLE = undefined;
16178 var io_status_block: windows.IO_STATUS_BLOCK = undefined;16167 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
16179 var syscall: Syscall = try .start();16168 var syscall: Syscall = try .start();
...@@ -16181,11 +16170,9 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE {...@@ -16181,11 +16170,9 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE {
16181 &fresh_handle,16170 &fresh_handle,
16182 .{ .STANDARD = .{ .SYNCHRONIZE = true } },16171 .{ .STANDARD = .{ .SYNCHRONIZE = true } },
16183 &.{16172 &.{
16184 .ObjectName = @constCast(&windows.UNICODE_STRING{16173 .ObjectName = @constCast(&windows.UNICODE_STRING.init(
16185 .Length = @sizeOf(@TypeOf(device_path)),16174 &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' },
16186 .MaximumLength = 0,16175 )),
16187 .Buffer = @constCast(&device_path),
16188 }),
16189 },16176 },
16190 &io_status_block,16177 &io_status_block,
16191 .VALID_FLAGS,16178 .VALID_FLAGS,
...@@ -16253,7 +16240,7 @@ fn windowsCreateProcessPathExt(...@@ -16253,7 +16240,7 @@ fn windowsCreateProcessPathExt(
16253 cwd_ptr: ?[*:0]u16,16240 cwd_ptr: ?[*:0]u16,
16254 flags: windows.CreateProcessFlags,16241 flags: windows.CreateProcessFlags,
16255 lpStartupInfo: *windows.STARTUPINFOW,16242 lpStartupInfo: *windows.STARTUPINFOW,
16256 lpProcessInformation: *windows.PROCESS_INFORMATION,16243 lpProcessInformation: *windows.PROCESS.INFORMATION,
16257) !void {16244) !void {
16258 const app_name_len = app_buf.items.len;16245 const app_name_len = app_buf.items.len;
16259 const dir_path_len = dir_buf.items.len;16246 const dir_path_len = dir_buf.items.len;
...@@ -16341,13 +16328,9 @@ fn windowsCreateProcessPathExt(...@@ -16341,13 +16328,9 @@ fn windowsCreateProcessPathExt(
16341 // On NTFS, `blah.exe*` will always return `blah.exe` first if it exists.16328 // On NTFS, `blah.exe*` will always return `blah.exe` first if it exists.
16342 // On FAT32, it's possible for something like `blah.exe.obj` to be returned first.16329 // On FAT32, it's possible for something like `blah.exe.obj` to be returned first.
16343 while (true) {16330 while (true) {
16344 const app_name_len_bytes = std.math.cast(u16, app_name_wildcard.len * 2) orelse return error.NameTooLong;16331 // If we get nothing with the wildcard, then we can just bail out
16345 var app_name_unicode_string = windows.UNICODE_STRING{16332 // as we know appending PATHEXT will not yield anything.
16346 .Length = app_name_len_bytes,16333 switch (windows.ntdll.NtQueryDirectoryFile(
16347 .MaximumLength = app_name_len_bytes,
16348 .Buffer = @constCast(app_name_wildcard.ptr),
16349 };
16350 const rc = windows.ntdll.NtQueryDirectoryFile(
16351 dir.handle,16334 dir.handle,
16352 null,16335 null,
16353 null,16336 null,
...@@ -16357,18 +16340,14 @@ fn windowsCreateProcessPathExt(...@@ -16357,18 +16340,14 @@ fn windowsCreateProcessPathExt(
16357 file_information_buf.len,16340 file_information_buf.len,
16358 .Directory,16341 .Directory,
16359 windows.FALSE, // single result16342 windows.FALSE, // single result
16360 &app_name_unicode_string,16343 &.init(app_name_wildcard),
16361 windows.FALSE, // restart iteration16344 windows.FALSE, // restart iteration
16362 );16345 )) {
16363
16364 // If we get nothing with the wildcard, then we can just bail out
16365 // as we know appending PATHEXT will not yield anything.
16366 switch (rc) {
16367 .SUCCESS => {},16346 .SUCCESS => {},
16368 .NO_SUCH_FILE => return error.FileNotFound,16347 .NO_SUCH_FILE => return error.FileNotFound,
16369 .NO_MORE_FILES => break,16348 .NO_MORE_FILES => break,
16370 .ACCESS_DENIED => return error.AccessDenied,16349 .ACCESS_DENIED => return error.AccessDenied,
16371 else => return windows.unexpectedStatus(rc),16350 else => |status| return windows.unexpectedStatus(status),
16372 }16351 }
1637316352
16374 // According to the docs, this can only happen if there is not enough room in the16353 // According to the docs, this can only happen if there is not enough room in the
...@@ -16514,7 +16493,7 @@ fn windowsCreateProcess(...@@ -16514,7 +16493,7 @@ fn windowsCreateProcess(
16514 cwd_ptr: ?[*:0]u16,16493 cwd_ptr: ?[*:0]u16,
16515 flags: windows.CreateProcessFlags,16494 flags: windows.CreateProcessFlags,
16516 lpStartupInfo: *windows.STARTUPINFOW,16495 lpStartupInfo: *windows.STARTUPINFOW,
16517 lpProcessInformation: *windows.PROCESS_INFORMATION,16496 lpProcessInformation: *windows.PROCESS.INFORMATION,
16518) !void {16497) !void {
16519 const syscall: Syscall = try .start();16498 const syscall: Syscall = try .start();
16520 while (true) {16499 while (true) {
...@@ -17138,7 +17117,7 @@ pub const CreatePipeOptions = struct {...@@ -17138,7 +17117,7 @@ pub const CreatePipeOptions = struct {
17138 default_timeout: windows.LARGE_INTEGER = -120 * std.time.ns_per_s / 100,17117 default_timeout: windows.LARGE_INTEGER = -120 * std.time.ns_per_s / 100,
1713917118
17140 pub const End = struct {17119 pub const End = struct {
17141 attributes: windows.OBJECT_ATTRIBUTES.ATTRIBUTES = .{},17120 attributes: windows.OBJECT.ATTRIBUTES.Flags = .{},
17142 mode: windows.FILE.MODE,17121 mode: windows.FILE.MODE,
17143 };17122 };
17144};17123};
...@@ -18373,7 +18352,7 @@ const CreateFileMapError = error{...@@ -18373,7 +18352,7 @@ const CreateFileMapError = error{
18373 OutOfMemory,18352 OutOfMemory,
18374 MappingAlreadyExists,18353 MappingAlreadyExists,
18375 Unseekable,18354 Unseekable,
18376 FileLockConflict,18355 LockViolation,
18377} || Io.Cancelable || Io.UnexpectedError;18356} || Io.Cancelable || Io.UnexpectedError;
1837818357
18379fn createFileMap(18358fn createFileMap(
...@@ -18408,7 +18387,7 @@ fn createFileMap(...@@ -18408,7 +18387,7 @@ fn createFileMap(
18408 file.handle,18387 file.handle,
18409 )) {18388 )) {
18410 .SUCCESS => {},18389 .SUCCESS => {},
18411 .FILE_LOCK_CONFLICT => return error.FileLockConflict,18390 .FILE_LOCK_CONFLICT => return error.LockViolation,
18412 .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported,18391 .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported,
18413 .ACCESS_DENIED => return error.AccessDenied,18392 .ACCESS_DENIED => return error.AccessDenied,
18414 .SECTION_TOO_BIG => return error.SectionOversize,18393 .SECTION_TOO_BIG => return error.SectionOversize,
...@@ -18724,7 +18703,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!...@@ -18724,7 +18703,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!
18724 while (true) {18703 while (true) {
18725 const buf = memory[i..];18704 const buf = memory[i..];
18726 if (buf.len == 0) break;18705 if (buf.len == 0) break;
18727 i += try writeFilePositionalWindows(file.handle, memory[i..], offset + i);18706 i += try writeFilePositionalWindows(file, memory[i..], offset + i);
18728 }18707 }
18729 } else if (native_os == .wasi and !builtin.link_libc) {18708 } else if (native_os == .wasi and !builtin.link_libc) {
18730 var i: usize = 0;18709 var i: usize = 0;
...@@ -18809,8 +18788,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!...@@ -18809,8 +18788,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError!
18809 }18788 }
18810}18789}
1881118790
18812fn deviceIoControl(t: *Threaded, o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result {18791fn deviceIoControl(o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result {
18813 _ = t;
18814 if (is_windows) {18792 if (is_windows) {
18815 const NtControlFile = switch (o.code.DeviceType) {18793 const NtControlFile = switch (o.code.DeviceType) {
18816 .FILE_SYSTEM, .NAMED_PIPE => &windows.ntdll.NtFsControlFile,18794 .FILE_SYSTEM, .NAMED_PIPE => &windows.ntdll.NtFsControlFile,
...@@ -19104,16 +19082,10 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows...@@ -19104,16 +19082,10 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
1910419082
19105 var result: windows.HANDLE = undefined;19083 var result: windows.HANDLE = undefined;
1910619084
19107 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;19085 const attr: windows.OBJECT.ATTRIBUTES = .{
19108 var nt_name: windows.UNICODE_STRING = .{
19109 .Length = path_len_bytes,
19110 .MaximumLength = path_len_bytes,
19111 .Buffer = @constCast(sub_path_w.ptr),
19112 };
19113 const attr: windows.OBJECT_ATTRIBUTES = .{
19114 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir,19086 .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir,
19115 .Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle != windows.FALSE else false },19087 .Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle != windows.FALSE else false },
19116 .ObjectName = &nt_name,19088 .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w)),
19117 .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null,19089 .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null,
19118 };19090 };
1911919091
lib/std/Io/Threaded/test.zig+1-1
...@@ -290,7 +290,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpa...@@ -290,7 +290,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpa
290 defer windows.ntdll.RtlFreeUnicodeString(&out);290 defer windows.ntdll.RtlFreeUnicodeString(&out);
291291
292 var path_space: Io.Threaded.WindowsPathSpace = undefined;292 var path_space: Io.Threaded.WindowsPathSpace = undefined;
293 const out_path = out.Buffer.?[0 .. out.Length / 2];293 const out_path = out.slice();
294 @memcpy(path_space.data[0..out_path.len], out_path);294 @memcpy(path_space.data[0..out_path.len], out_path);
295 path_space.len = out.Length / 2;295 path_space.len = out.Length / 2;
296 path_space.data[path_space.len] = 0;296 path_space.data[path_space.len] = 0;
lib/std/Thread.zig+3-13
...@@ -88,20 +88,10 @@ pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {...@@ -88,20 +88,10 @@ pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {
88 },88 },
89 .windows => {89 .windows => {
90 var buf: [max_name_len]u16 = undefined;90 var buf: [max_name_len]u16 = undefined;
91 const len = try std.unicode.wtf8ToWtf16Le(&buf, name);
92 const byte_len = math.cast(c_ushort, len * 2) orelse return error.NameTooLong;
93
94 // Note: NT allocates its own copy, no use-after-free here.
95 const unicode_string = windows.UNICODE_STRING{
96 .Length = byte_len,
97 .MaximumLength = byte_len,
98 .Buffer = &buf,
99 };
100
101 switch (windows.ntdll.NtSetInformationThread(91 switch (windows.ntdll.NtSetInformationThread(
102 self.getHandle(),92 self.getHandle(),
103 .NameInformation,93 .NameInformation,
104 &unicode_string,94 &windows.UNICODE_STRING.init(buf[0..try std.unicode.wtf8ToWtf16Le(&buf, name)]),
105 @sizeOf(windows.UNICODE_STRING),95 @sizeOf(windows.UNICODE_STRING),
106 )) {96 )) {
107 .SUCCESS => return,97 .SUCCESS => return,
...@@ -217,8 +207,8 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co...@@ -217,8 +207,8 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
217 null,207 null,
218 )) {208 )) {
219 .SUCCESS => {209 .SUCCESS => {
220 const string = @as(*const windows.UNICODE_STRING, @ptrCast(&buf));210 const string: *const windows.UNICODE_STRING = @ptrCast(&buf);
221 const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]);211 const len = std.unicode.wtf16LeToWtf8(buffer, string.slice());
222 return if (len > 0) buffer[0..len] else null;212 return if (len > 0) buffer[0..len] else null;
223 },213 },
224 .NOT_IMPLEMENTED => return error.Unsupported,214 .NOT_IMPLEMENTED => return error.Unsupported,
lib/std/debug.zig+18-27
...@@ -37,12 +37,13 @@ pub const cpu_context = @import("debug/cpu_context.zig");...@@ -37,12 +37,13 @@ pub const cpu_context = @import("debug/cpu_context.zig");
37///37///
38/// ```38/// ```
39/// pub const init: SelfInfo;39/// pub const init: SelfInfo;
40/// pub fn deinit(si: *SelfInfo, gpa: Allocator) void;40/// pub fn deinit(si: *SelfInfo, io: Io) void;
41///41///
42/// /// Returns the symbol and source location of the instruction at `address`.42/// /// Returns the symbol and source location of the instruction at `address`.
43/// pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) SelfInfoError!Symbol;43/// pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) SelfInfoError!Symbol;
44/// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`.44/// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`.
45/// pub fn getModuleName(si: *SelfInfo, gpa: Allocator, address: usize) SelfInfoError![]const u8;45/// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8;
46/// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize;
46///47///
47/// /// Whether a reliable stack unwinding strategy, such as DWARF unwinding, is available.48/// /// Whether a reliable stack unwinding strategy, such as DWARF unwinding, is available.
48/// pub const can_unwind: bool;49/// pub const can_unwind: bool;
...@@ -51,15 +52,15 @@ pub const cpu_context = @import("debug/cpu_context.zig");...@@ -51,15 +52,15 @@ pub const cpu_context = @import("debug/cpu_context.zig");
51/// /// An address representing the instruction pointer in the last frame.52/// /// An address representing the instruction pointer in the last frame.
52/// pc: usize,53/// pc: usize,
53///54///
54/// pub fn init(ctx: *cpu_context.Native, gpa: Allocator) Allocator.Error!UnwindContext;55/// pub fn init(ctx: *cpu_context.Native) Allocator.Error!UnwindContext;
55/// pub fn deinit(ctx: *UnwindContext, gpa: Allocator) void;56/// pub fn deinit(ctx: *UnwindContext) void;
56/// /// Returns the frame pointer associated with the last unwound stack frame.57/// /// Returns the frame pointer associated with the last unwound stack frame.
57/// /// If the frame pointer is unknown, 0 may be returned instead.58/// /// If the frame pointer is unknown, 0 may be returned instead.
58/// pub fn getFp(uc: *UnwindContext) usize;59/// pub fn getFp(uc: *UnwindContext) usize;
59/// };60/// };
60/// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's61/// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's
61/// /// return address, or 0 if the end of the stack has been reached.62/// /// return address, or 0 if the end of the stack has been reached.
62/// pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) SelfInfoError!usize;63/// pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) SelfInfoError!usize;
63/// ```64/// ```
64pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo"))65pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo"))
65 root.debug.SelfInfo66 root.debug.SelfInfo
...@@ -669,7 +670,6 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin...@@ -669,7 +670,6 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin
669 t.setColor(.reset) catch {};670 t.setColor(.reset) catch {};
670 return;671 return;
671 }672 }
672 const di_gpa = getDebugInfoAllocator();
673 const di = getSelfDebugInfo() catch |err| switch (err) {673 const di = getSelfDebugInfo() catch |err| switch (err) {
674 error.UnsupportedTarget => {674 error.UnsupportedTarget => {
675 t.setColor(.dim) catch {};675 t.setColor(.dim) catch {};
...@@ -696,7 +696,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin...@@ -696,7 +696,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin
696 .useless, .unsafe => {},696 .useless, .unsafe => {},
697 .safe, .ideal => continue, // no need to even warn697 .safe, .ideal => continue, // no need to even warn
698 }698 }
699 const module_name = di.getModuleName(di_gpa, io, unwind_error.address) catch "???";699 const module_name = di.getModuleName(io, unwind_error.address) catch "???";
700 const caption: []const u8 = switch (unwind_error.err) {700 const caption: []const u8 = switch (unwind_error.err) {
701 error.MissingDebugInfo => "unwind info unavailable",701 error.MissingDebugInfo => "unwind info unavailable",
702 error.InvalidDebugInfo => "unwind info invalid",702 error.InvalidDebugInfo => "unwind info invalid",
...@@ -741,7 +741,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin...@@ -741,7 +741,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin
741 }741 }
742 // `ret_addr` is the return address, which is *after* the function call.742 // `ret_addr` is the return address, which is *after* the function call.
743 // Subtract 1 to get an address *in* the function call for a better source location.743 // Subtract 1 to get an address *in* the function call for a better source location.
744 try printSourceAtAddress(di_gpa, io, di, t, ret_addr -| StackIterator.ra_call_offset);744 try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset);
745 printed_any_frame = true;745 printed_any_frame = true;
746 },746 },
747 };747 };
...@@ -788,7 +788,6 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void...@@ -788,7 +788,6 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void
788 // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace.788 // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace.
789 const n_frames = st.index;789 const n_frames = st.index;
790 if (n_frames == 0) return writer.writeAll("(empty stack trace)\n");790 if (n_frames == 0) return writer.writeAll("(empty stack trace)\n");
791 const di_gpa = getDebugInfoAllocator();
792 const di = getSelfDebugInfo() catch |err| switch (err) {791 const di = getSelfDebugInfo() catch |err| switch (err) {
793 error.UnsupportedTarget => {792 error.UnsupportedTarget => {
794 t.setColor(.dim) catch {};793 t.setColor(.dim) catch {};
...@@ -802,7 +801,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void...@@ -802,7 +801,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void
802 for (st.instruction_addresses[0..captured_frames]) |ret_addr| {801 for (st.instruction_addresses[0..captured_frames]) |ret_addr| {
803 // `ret_addr` is the return address, which is *after* the function call.802 // `ret_addr` is the return address, which is *after* the function call.
804 // Subtract 1 to get an address *in* the function call for a better source location.803 // Subtract 1 to get an address *in* the function call for a better source location.
805 try printSourceAtAddress(di_gpa, io, di, t, ret_addr -| StackIterator.ra_call_offset);804 try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset);
806 }805 }
807 if (n_frames > captured_frames) {806 if (n_frames > captured_frames) {
808 t.setColor(.bold) catch {};807 t.setColor(.bold) catch {};
...@@ -875,7 +874,7 @@ const StackIterator = union(enum) {...@@ -875,7 +874,7 @@ const StackIterator = union(enum) {
875 switch (si.*) {874 switch (si.*) {
876 .ctx_first => {},875 .ctx_first => {},
877 .fp => {},876 .fp => {},
878 .di => |*unwind_context| unwind_context.deinit(getDebugInfoAllocator()),877 .di => |*unwind_context| unwind_context.deinit(),
879 }878 }
880 }879 }
881880
...@@ -980,8 +979,7 @@ const StackIterator = union(enum) {...@@ -980,8 +979,7 @@ const StackIterator = union(enum) {
980 },979 },
981 .di => |*unwind_context| {980 .di => |*unwind_context| {
982 const di = getSelfDebugInfo() catch unreachable;981 const di = getSelfDebugInfo() catch unreachable;
983 const di_gpa = getDebugInfoAllocator();982 const ret_addr = di.unwindFrame(io, unwind_context) catch |err| {
984 const ret_addr = di.unwindFrame(di_gpa, io, unwind_context) catch |err| {
985 const pc = unwind_context.pc;983 const pc = unwind_context.pc;
986 const fp = unwind_context.getFp();984 const fp = unwind_context.getFp();
987 it.* = .{ .fp = fp };985 it.* = .{ .fp = fp };
...@@ -1109,14 +1107,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {...@@ -1109,14 +1107,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {
1109 return ptr;1107 return ptr;
1110}1108}
11111109
1112fn printSourceAtAddress(1110fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void {
1113 gpa: Allocator,1111 const symbol: Symbol = debug_info.getSymbol(io, address) catch |err| switch (err) {
1114 io: Io,
1115 debug_info: *SelfInfo,
1116 t: Io.Terminal,
1117 address: usize,
1118) Writer.Error!void {
1119 const symbol: Symbol = debug_info.getSymbol(gpa, io, address) catch |err| switch (err) {
1120 error.MissingDebugInfo,1112 error.MissingDebugInfo,
1121 error.UnsupportedDebugInfo,1113 error.UnsupportedDebugInfo,
1122 error.InvalidDebugInfo,1114 error.InvalidDebugInfo,
...@@ -1134,14 +1126,14 @@ fn printSourceAtAddress(...@@ -1134,14 +1126,14 @@ fn printSourceAtAddress(
1134 break :s .unknown;1126 break :s .unknown;
1135 },1127 },
1136 };1128 };
1137 defer if (symbol.source_location) |sl| gpa.free(sl.file_name);1129 defer if (symbol.source_location) |sl| getDebugInfoAllocator().free(sl.file_name);
1138 return printLineInfo(1130 return printLineInfo(
1139 io,1131 io,
1140 t,1132 t,
1141 symbol.source_location,1133 symbol.source_location,
1142 address,1134 address,
1143 symbol.name orelse "???",1135 symbol.name orelse "???",
1144 symbol.compile_unit_name orelse debug_info.getModuleName(gpa, io, address) catch "???",1136 symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???",
1145 );1137 );
1146}1138}
1147fn printLineInfo(1139fn printLineInfo(
...@@ -1608,14 +1600,13 @@ test "manage resources correctly" {...@@ -1608,14 +1600,13 @@ test "manage resources correctly" {
1608 return @returnAddress();1600 return @returnAddress();
1609 }1601 }
1610 };1602 };
1611 const gpa = testing.allocator;
1612 const io = testing.io;1603 const io = testing.io;
16131604
1614 var discarding: Writer.Discarding = .init(&.{});1605 var discarding: Writer.Discarding = .init(&.{});
1615 var di: SelfInfo = .init;1606 var di: SelfInfo = .init;
1616 defer di.deinit(gpa);1607 defer di.deinit(io);
1617 const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color };1608 const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color };
1618 try printSourceAtAddress(gpa, io, &di, t, S.showMyTrace());1609 try printSourceAtAddress(io, &di, t, S.showMyTrace());
1619}1610}
16201611
1621/// This API helps you track where a value originated and where it was mutated,1612/// This API helps you track where a value originated and where it was mutated,
lib/std/debug/Dwarf/SelfUnwinder.zig+2-1
...@@ -55,7 +55,8 @@ pub fn init(cpu_context: *const std.debug.cpu_context.Native) SelfUnwinder {...@@ -55,7 +55,8 @@ pub fn init(cpu_context: *const std.debug.cpu_context.Native) SelfUnwinder {
55 };55 };
56}56}
5757
58pub fn deinit(unwinder: *SelfUnwinder, gpa: Allocator) void {58pub fn deinit(unwinder: *SelfUnwinder) void {
59 const gpa = std.debug.getDebugInfoAllocator();
59 unwinder.cfi_vm.deinit(gpa);60 unwinder.cfi_vm.deinit(gpa);
60 unwinder.expr_vm.deinit(gpa);61 unwinder.expr_vm.deinit(gpa);
61 unwinder.* = undefined;62 unwinder.* = undefined;
lib/std/debug/SelfInfo/Elf.zig+11-5
...@@ -11,7 +11,9 @@ pub const init: SelfInfo = .{...@@ -11,7 +11,9 @@ pub const init: SelfInfo = .{
11 .ranges = .empty,11 .ranges = .empty,
12 .unwind_cache = null,12 .unwind_cache = null,
13};13};
14pub fn deinit(si: *SelfInfo, gpa: Allocator) void {14pub fn deinit(si: *SelfInfo, io: Io) void {
15 _ = io;
16 const gpa = std.debug.getDebugInfoAllocator();
15 for (si.modules.items) |*mod| {17 for (si.modules.items) |*mod| {
16 unwind: {18 unwind: {
17 const u = &(mod.unwind orelse break :unwind catch break :unwind);19 const u = &(mod.unwind orelse break :unwind catch break :unwind);
...@@ -28,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void {...@@ -28,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void {
28 if (si.unwind_cache) |cache| gpa.free(cache);30 if (si.unwind_cache) |cache| gpa.free(cache);
29}31}
3032
31pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol {33pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol {
34 const gpa = std.debug.getDebugInfoAllocator();
32 const module = try si.findModule(gpa, io, address, .exclusive);35 const module = try si.findModule(gpa, io, address, .exclusive);
33 defer si.rwlock.unlock(io);36 defer si.rwlock.unlock(io);
3437
...@@ -73,13 +76,15 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st...@@ -73,13 +76,15 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st
73 error.OutOfMemory => |e| return e,76 error.OutOfMemory => |e| return e,
74 };77 };
75}78}
76pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 {79pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
80 const gpa = std.debug.getDebugInfoAllocator();
77 const module = try si.findModule(gpa, io, address, .shared);81 const module = try si.findModule(gpa, io, address, .shared);
78 defer si.rwlock.unlockShared(io);82 defer si.rwlock.unlockShared(io);
79 if (module.name.len == 0) return error.MissingDebugInfo;83 if (module.name.len == 0) return error.MissingDebugInfo;
80 return module.name;84 return module.name;
81}85}
82pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize {86pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
87 const gpa = std.debug.getDebugInfoAllocator();
83 const module = try si.findModule(gpa, io, address, .shared);88 const module = try si.findModule(gpa, io, address, .shared);
84 defer si.rwlock.unlockShared(io);89 defer si.rwlock.unlockShared(io);
85 return module.load_offset;90 return module.load_offset;
...@@ -179,8 +184,9 @@ comptime {...@@ -179,8 +184,9 @@ comptime {
179 }184 }
180}185}
181pub const UnwindContext = Dwarf.SelfUnwinder;186pub const UnwindContext = Dwarf.SelfUnwinder;
182pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize {187pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize {
183 comptime assert(can_unwind);188 comptime assert(can_unwind);
189 const gpa = std.debug.getDebugInfoAllocator();
184190
185 {191 {
186 si.rwlock.lockSharedUncancelable(io);192 si.rwlock.lockSharedUncancelable(io);
lib/std/debug/SelfInfo/MachO.zig+12-8
...@@ -6,7 +6,9 @@ pub const init: SelfInfo = .{...@@ -6,7 +6,9 @@ pub const init: SelfInfo = .{
6 .mutex = .init,6 .mutex = .init,
7 .modules = .empty,7 .modules = .empty,
8};8};
9pub fn deinit(si: *SelfInfo, gpa: Allocator) void {9pub fn deinit(si: *SelfInfo, io: Io) void {
10 _ = io;
11 const gpa = std.debug.getDebugInfoAllocator();
10 for (si.modules.keys()) |*module| {12 for (si.modules.keys()) |*module| {
11 unwind: {13 unwind: {
12 const u = &(module.unwind orelse break :unwind catch break :unwind);14 const u = &(module.unwind orelse break :unwind catch break :unwind);
...@@ -20,7 +22,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void {...@@ -20,7 +22,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void {
20 si.modules.deinit(gpa);22 si.modules.deinit(gpa);
21}23}
2224
23pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol {25pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol {
26 const gpa = std.debug.getDebugInfoAllocator();
24 const module = try si.findModule(gpa, io, address);27 const module = try si.findModule(gpa, io, address);
25 defer si.mutex.unlock(io);28 defer si.mutex.unlock(io);
2629
...@@ -76,9 +79,8 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st...@@ -76,9 +79,8 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st
76 ) catch null,79 ) catch null,
77 };80 };
78}81}
79pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 {82pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
80 _ = si;83 _ = si;
81 _ = gpa;
82 _ = io;84 _ = io;
83 // This function is marked as deprecated; however, it is significantly more85 // This function is marked as deprecated; however, it is significantly more
84 // performant than `dladdr` (since the latter also does a very slow symbol86 // performant than `dladdr` (since the latter also does a very slow symbol
...@@ -87,7 +89,8 @@ pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Erro...@@ -87,7 +89,8 @@ pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Erro
87 @ptrFromInt(address),89 @ptrFromInt(address),
88 ) orelse return error.MissingDebugInfo);90 ) orelse return error.MissingDebugInfo);
89}91}
90pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize {92pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
93 const gpa = std.debug.getDebugInfoAllocator();
91 const module = try si.findModule(gpa, io, address);94 const module = try si.findModule(gpa, io, address);
92 defer si.mutex.unlock(io);95 defer si.mutex.unlock(io);
93 const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base);96 const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base);
...@@ -107,8 +110,8 @@ pub const UnwindContext = std.debug.Dwarf.SelfUnwinder;...@@ -107,8 +110,8 @@ pub const UnwindContext = std.debug.Dwarf.SelfUnwinder;
107/// Unwind a frame using MachO compact unwind info (from `__unwind_info`).110/// Unwind a frame using MachO compact unwind info (from `__unwind_info`).
108/// If the compact encoding can't encode a way to unwind a frame, it will111/// If the compact encoding can't encode a way to unwind a frame, it will
109/// defer unwinding to DWARF, in which case `__eh_frame` will be used if available.112/// defer unwinding to DWARF, in which case `__eh_frame` will be used if available.
110pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize {113pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize {
111 return unwindFrameInner(si, gpa, io, context) catch |err| switch (err) {114 return unwindFrameInner(si, io, context) catch |err| switch (err) {
112 error.InvalidDebugInfo,115 error.InvalidDebugInfo,
113 error.MissingDebugInfo,116 error.MissingDebugInfo,
114 error.UnsupportedDebugInfo,117 error.UnsupportedDebugInfo,
...@@ -134,7 +137,8 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex...@@ -134,7 +137,8 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex
134 => return error.InvalidDebugInfo,137 => return error.InvalidDebugInfo,
135 };138 };
136}139}
137fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) !usize {140fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize {
141 const gpa = std.debug.getDebugInfoAllocator();
138 const module = try si.findModule(gpa, io, context.pc);142 const module = try si.findModule(gpa, io, context.pc);
139 defer si.mutex.unlock(io);143 defer si.mutex.unlock(io);
140144
lib/std/debug/SelfInfo/Windows.zig+151-86
...@@ -1,39 +1,51 @@...@@ -1,39 +1,51 @@
1mutex: Io.Mutex,1mutex: Io.Mutex,
2ntdll_handle: ?if (load_dll_notification_procs) *anyopaque else noreturn,
3notification_cookie: ?LDR.DLL_NOTIFICATION.COOKIE,
2modules: std.ArrayList(Module),4modules: std.ArrayList(Module),
3module_name_arena: std.heap.ArenaAllocator.State,
45
5pub const init: SelfInfo = .{6pub const init: SelfInfo = .{
6 .mutex = .init,7 .mutex = .init,
8 .ntdll_handle = null,
9 .notification_cookie = null,
7 .modules = .empty,10 .modules = .empty,
8 .module_name_arena = .{},
9};11};
10pub fn deinit(si: *SelfInfo, gpa: Allocator) void {12pub fn deinit(si: *SelfInfo, io: Io) void {
11 for (si.modules.items) |*module| {13 const gpa = std.debug.getDebugInfoAllocator();
12 di: {14 if (si.notification_cookie) |cookie| unregister: {
13 const di = &(module.di orelse break :di catch break :di);15 switch ((si.getNtdllProc(.LdrUnregisterDllNotification) catch break :unregister)(cookie)) {
14 di.deinit(gpa);16 .SUCCESS => {},
17 else => |status| windows.unexpectedStatus(status) catch break :unregister,
15 }18 }
16 }19 }
20 if (si.ntdll_handle) |handle| switch (windows.ntdll.LdrUnloadDll(handle)) {
21 .SUCCESS => {},
22 else => |status| windows.unexpectedStatus(status) catch {},
23 };
24 for (si.modules.items) |*module| module.deinit(gpa, io);
17 si.modules.deinit(gpa);25 si.modules.deinit(gpa);
18
19 var module_name_arena = si.module_name_arena.promote(gpa);
20 module_name_arena.deinit();
21}26}
2227
23pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol {28pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol {
29 const gpa = std.debug.getDebugInfoAllocator();
24 try si.mutex.lock(io);30 try si.mutex.lock(io);
25 defer si.mutex.unlock(io);31 defer si.mutex.unlock(io);
26 const module = try si.findModule(gpa, address);32 const module = try si.findModule(gpa, address);
27 const di = try module.getDebugInfo(gpa, io);33 const di = try module.getDebugInfo(gpa, io);
28 return di.getSymbol(gpa, address - module.base_address);34 return di.getSymbol(gpa, address - @intFromPtr(module.entry.DllBase));
29}35}
30pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 {36pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
37 const gpa = std.debug.getDebugInfoAllocator();
31 try si.mutex.lock(io);38 try si.mutex.lock(io);
32 defer si.mutex.unlock(io);39 defer si.mutex.unlock(io);
33 const module = try si.findModule(gpa, address);40 const module = try si.findModule(gpa, address);
34 return module.name;41 return module.name orelse {
42 const name = try std.unicode.wtf16LeToWtf8Alloc(gpa, module.entry.BaseDllName.slice());
43 module.name = name;
44 return name;
45 };
35}46}
36pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize {47pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
48 const gpa = std.debug.getDebugInfoAllocator();
37 try si.mutex.lock(io);49 try si.mutex.lock(io);
38 defer si.mutex.unlock(io);50 defer si.mutex.unlock(io);
39 const module = try si.findModule(gpa, address);51 const module = try si.findModule(gpa, address);
...@@ -141,18 +153,16 @@ pub const UnwindContext = struct {...@@ -141,18 +153,16 @@ pub const UnwindContext = struct {
141 .history_table = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE),153 .history_table = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE),
142 };154 };
143 }155 }
144 pub fn deinit(ctx: *UnwindContext, gpa: Allocator) void {156 pub fn deinit(ctx: *UnwindContext) void {
145 _ = ctx;157 _ = ctx;
146 _ = gpa;
147 }158 }
148 pub fn getFp(ctx: *UnwindContext) usize {159 pub fn getFp(ctx: *UnwindContext) usize {
149 return ctx.cur.getRegs().bp;160 return ctx.cur.getRegs().bp;
150 }161 }
151};162};
152pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize {163pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize {
153 _ = si;164 _ = si;
154 _ = io;165 _ = io;
155 _ = gpa;
156166
157 const current_regs = context.cur.getRegs();167 const current_regs = context.cur.getRegs();
158 var image_base: usize = undefined;168 var image_base: usize = undefined;
...@@ -188,16 +198,12 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex...@@ -188,16 +198,12 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex
188}198}
189199
190const Module = struct {200const Module = struct {
191 base_address: usize,201 entry: *const LDR.DATA_TABLE_ENTRY,
192 size: u32,202 name: ?[]const u8,
193 name: []const u8,
194 handle: windows.HMODULE,
195
196 di: ?(Error!DebugInfo),203 di: ?(Error!DebugInfo),
197204
198 const DebugInfo = struct {205 const DebugInfo = struct {
199 arena: std.heap.ArenaAllocator.State,206 arena: std.heap.ArenaAllocator.State,
200 io: Io,
201 coff_image_base: u64,207 coff_image_base: u64,
202 mapped_file: ?MappedFile,208 mapped_file: ?MappedFile,
203 dwarf: ?Dwarf,209 dwarf: ?Dwarf,
...@@ -210,14 +216,19 @@ const Module = struct {...@@ -210,14 +216,19 @@ const Module = struct {
210 section_view: []const u8,216 section_view: []const u8,
211 fn deinit(mf: *const MappedFile, io: Io) void {217 fn deinit(mf: *const MappedFile, io: Io) void {
212 const process_handle = windows.GetCurrentProcess();218 const process_handle = windows.GetCurrentProcess();
213 assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mf.section_view.ptr)) == .SUCCESS);219 switch (windows.ntdll.NtUnmapViewOfSection(
220 process_handle,
221 @constCast(mf.section_view.ptr),
222 )) {
223 .SUCCESS => {},
224 else => |status| windows.unexpectedStatus(status) catch {},
225 }
214 windows.CloseHandle(mf.section_handle);226 windows.CloseHandle(mf.section_handle);
215 mf.file.close(io);227 mf.file.close(io);
216 }228 }
217 };229 };
218230
219 fn deinit(di: *DebugInfo, gpa: Allocator) void {231 fn deinit(di: *DebugInfo, gpa: Allocator, io: Io) void {
220 const io = di.io;
221 if (di.dwarf) |*dwarf| dwarf.deinit(gpa);232 if (di.dwarf) |*dwarf| dwarf.deinit(gpa);
222 if (di.pdb) |*pdb| {233 if (di.pdb) |*pdb| {
223 pdb.file_reader.file.close(io);234 pdb.file_reader.file.close(io);
...@@ -262,7 +273,10 @@ const Module = struct {...@@ -262,7 +273,10 @@ const Module = struct {
262 return .{273 return .{
263 .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address),274 .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address),
264 .compile_unit_name = fs.path.basename(module.obj_file_name),275 .compile_unit_name = fs.path.basename(module.obj_file_name),
265 .source_location = pdb.getLineNumberInfo(module, vaddr - coff_section.virtual_address) catch null,276 .source_location = pdb.getLineNumberInfo(
277 module,
278 vaddr - coff_section.virtual_address,
279 ) catch null,
266 };280 };
267 }281 }
268 dwarf: {282 dwarf: {
...@@ -286,13 +300,19 @@ const Module = struct {...@@ -286,13 +300,19 @@ const Module = struct {
286 }300 }
287 };301 };
288302
303 fn deinit(module: *Module, gpa: Allocator, io: Io) void {
304 if (module.name) |name| gpa.free(name);
305 if (module.di) |*di_or_err| if (di_or_err.*) |*di| di.deinit(gpa, io) else |_| {};
306 module.* = undefined;
307 }
308
289 fn getDebugInfo(module: *Module, gpa: Allocator, io: Io) Error!*DebugInfo {309 fn getDebugInfo(module: *Module, gpa: Allocator, io: Io) Error!*DebugInfo {
290 if (module.di == null) module.di = loadDebugInfo(module, gpa, io);310 if (module.di == null) module.di = loadDebugInfo(module, gpa, io);
291 return if (module.di.?) |*di| di else |err| err;311 return if (module.di.?) |*di| di else |err| err;
292 }312 }
293 fn loadDebugInfo(module: *const Module, gpa: Allocator, io: Io) Error!DebugInfo {313 fn loadDebugInfo(module: *const Module, gpa: Allocator, io: Io) Error!DebugInfo {
294 const mapped_ptr: [*]const u8 = @ptrFromInt(module.base_address);314 const mapped_ptr: [*]const u8 = @ptrCast(module.entry.DllBase);
295 const mapped = mapped_ptr[0..module.size];315 const mapped = mapped_ptr[0..module.entry.SizeOfImage];
296 var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo;316 var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo;
297317
298 var arena_instance: std.heap.ArenaAllocator = .init(gpa);318 var arena_instance: std.heap.ArenaAllocator = .init(gpa);
...@@ -304,18 +324,15 @@ const Module = struct {...@@ -304,18 +324,15 @@ const Module = struct {
304 // a binary is produced with -gdwarf, since the section names are longer than 8 bytes.324 // a binary is produced with -gdwarf, since the section names are longer than 8 bytes.
305 const mapped_file: ?DebugInfo.MappedFile = mapped: {325 const mapped_file: ?DebugInfo.MappedFile = mapped: {
306 if (!coff_obj.strtabRequired()) break :mapped null;326 if (!coff_obj.strtabRequired()) break :mapped null;
307 var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined;327 var path_buffer: [4 + windows.PATH_MAX_WIDE]u16 = undefined;
308 name_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present328 path_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present
309 const process_handle = windows.GetCurrentProcess();329 const path_slice = module.entry.FullDllName.slice();
310 const len = windows.kernel32.GetModuleFileNameExW(330 @memcpy(path_buffer[4..][0..path_slice.len], path_slice);
311 process_handle,331 const coff_file = Io.Threaded.dirOpenFileWtf16(
312 module.handle,332 null,
313 name_buffer[4..],333 path_buffer[0 .. 4 + path_slice.len],
314 windows.PATH_MAX_WIDE,334 .{},
315 );335 ) catch |err| switch (err) {
316 if (len == 0) return error.MissingDebugInfo;
317 const name_w = name_buffer[0 .. len + 4 :0];
318 const coff_file = Io.Threaded.dirOpenFileWtf16(null, name_w, .{}) catch |err| switch (err) {
319 error.Canceled => |e| return e,336 error.Canceled => |e| return e,
320 error.Unexpected => |e| return e,337 error.Unexpected => |e| return e,
321 error.FileNotFound => return error.MissingDebugInfo,338 error.FileNotFound => return error.MissingDebugInfo,
...@@ -359,7 +376,8 @@ const Module = struct {...@@ -359,7 +376,8 @@ const Module = struct {
359 null,376 null,
360 null,377 null,
361 .{ .READONLY = true },378 .{ .READONLY = true },
362 // The documentation states that if no AllocationAttribute is specified, then SEC_COMMIT is the default.379 // The documentation states that if no AllocationAttribute is specified,
380 // then SEC_COMMIT is the default.
363 // In practice, this isn't the case and specifying 0 will result in INVALID_PARAMETER_6.381 // In practice, this isn't the case and specifying 0 will result in INVALID_PARAMETER_6.
364 .{ .COMMIT = true },382 .{ .COMMIT = true },
365 coff_file.handle,383 coff_file.handle,
...@@ -368,6 +386,7 @@ const Module = struct {...@@ -368,6 +386,7 @@ const Module = struct {
368 errdefer windows.CloseHandle(section_handle);386 errdefer windows.CloseHandle(section_handle);
369 var coff_len: usize = 0;387 var coff_len: usize = 0;
370 var section_view_ptr: ?[*]const u8 = null;388 var section_view_ptr: ?[*]const u8 = null;
389 const process_handle = windows.GetCurrentProcess();
371 const map_section_rc = windows.ntdll.NtMapViewOfSection(390 const map_section_rc = windows.ntdll.NtMapViewOfSection(
372 section_handle,391 section_handle,
373 process_handle,392 process_handle,
...@@ -381,7 +400,13 @@ const Module = struct {...@@ -381,7 +400,13 @@ const Module = struct {
381 .{ .READONLY = true },400 .{ .READONLY = true },
382 );401 );
383 if (map_section_rc != .SUCCESS) return error.MissingDebugInfo;402 if (map_section_rc != .SUCCESS) return error.MissingDebugInfo;
384 errdefer assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(section_view_ptr.?)) == .SUCCESS);403 errdefer switch (windows.ntdll.NtUnmapViewOfSection(
404 process_handle,
405 @constCast(section_view_ptr.?),
406 )) {
407 .SUCCESS => {},
408 else => |status| windows.unexpectedStatus(status) catch {},
409 };
385 const section_view = section_view_ptr.?[0..coff_len];410 const section_view = section_view_ptr.?[0..coff_len];
386 coff_obj = coff.Coff.init(section_view, false) catch return error.InvalidDebugInfo;411 coff_obj = coff.Coff.init(section_view, false) catch return error.InvalidDebugInfo;
387 break :mapped .{412 break :mapped .{
...@@ -496,7 +521,6 @@ const Module = struct {...@@ -496,7 +521,6 @@ const Module = struct {
496521
497 return .{522 return .{
498 .arena = arena_instance.state,523 .arena = arena_instance.state,
499 .io = io,
500 .coff_image_base = coff_image_base,524 .coff_image_base = coff_image_base,
501 .mapped_file = mapped_file,525 .mapped_file = mapped_file,
502 .dwarf = opt_dwarf,526 .dwarf = opt_dwarf,
...@@ -509,52 +533,82 @@ const Module = struct {...@@ -509,52 +533,82 @@ const Module = struct {
509/// Assumes we already hold `si.mutex`.533/// Assumes we already hold `si.mutex`.
510fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module {534fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module {
511 for (si.modules.items) |*mod| {535 for (si.modules.items) |*mod| {
512 if (address >= mod.base_address and address < mod.base_address + mod.size) {536 const base = @intFromPtr(mod.entry.DllBase);
513 return mod;537 if (address >= base and address < base + mod.entry.SizeOfImage) return mod;
514 }
515 }538 }
516539 try si.modules.ensureUnusedCapacity(gpa, 1);
517 // A new module might have been loaded; rebuild the list.540 var entry: *LDR.DATA_TABLE_ENTRY = undefined;
518 {541 switch (windows.ntdll.LdrFindEntryForAddress(@ptrFromInt(address), &entry)) {
519 for (si.modules.items) |*mod| {542 .SUCCESS => {},
520 const di = &(mod.di orelse continue catch continue);543 .DLL_NOT_FOUND => return error.MissingDebugInfo,
521 di.deinit(gpa);544 else => |status| return windows.unexpectedStatus(status),
522 }545 }
523 si.modules.clearRetainingCapacity();546 if (si.notification_cookie == null) {
524547 var notification_cookie: LDR.DLL_NOTIFICATION.COOKIE = undefined;
525 var module_name_arena = si.module_name_arena.promote(gpa);548 switch ((try si.getNtdllProc(.LdrRegisterDllNotification))(
526 defer si.module_name_arena = module_name_arena.state;549 .{},
527 _ = module_name_arena.reset(.retain_capacity);550 &dllNotification,
528551 si,
529 const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0);552 &notification_cookie,
530 if (handle == windows.INVALID_HANDLE_VALUE) {553 )) {
531 return windows.unexpectedError(windows.GetLastError());554 .SUCCESS => si.notification_cookie = notification_cookie,
532 }555 else => |status| return windows.unexpectedStatus(status),
533 defer windows.CloseHandle(handle);
534 var entry: windows.MODULEENTRY32 = undefined;
535 entry.dwSize = @sizeOf(windows.MODULEENTRY32);
536 var result = windows.kernel32.Module32First(handle, &entry);
537 while (result != 0) : (result = windows.kernel32.Module32Next(handle, &entry)) {
538 try si.modules.append(gpa, .{
539 .base_address = @intFromPtr(entry.modBaseAddr),
540 .size = entry.modBaseSize,
541 .name = try module_name_arena.allocator().dupe(
542 u8,
543 std.mem.sliceTo(&entry.szModule, 0),
544 ),
545 .handle = entry.hModule,
546 .di = null,
547 });
548 }556 }
549 }557 }
558 const mod = si.modules.addOneAssumeCapacity();
559 mod.* = .{ .entry = entry, .name = null, .di = null };
560 return mod;
561}
550562
551 for (si.modules.items) |*mod| {563inline fn getNtdllProc(
552 if (address >= mod.base_address and address < mod.base_address + mod.size) {564 si: *SelfInfo,
553 return mod;565 comptime proc: std.meta.DeclEnum(windows.ntdll),
566) !@TypeOf(&@field(windows.ntdll, @tagName(proc))) {
567 return if (load_dll_notification_procs)
568 @ptrCast(try si.loadNtdllProc(@tagName(proc)))
569 else
570 &@field(windows.ntdll, @tagName(proc));
571}
572fn loadNtdllProc(si: *SelfInfo, name: []const u8) Io.UnexpectedError!*anyopaque {
573 const ntdll_handle = si.ntdll_handle orelse ntdll_handle: {
574 var ntdll_handle: *anyopaque = undefined;
575 switch (windows.ntdll.LdrLoadDll(null, null, &.init(
576 &.{ 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l' },
577 ), &ntdll_handle)) {
578 .SUCCESS => {},
579 else => |status| return windows.unexpectedStatus(status),
554 }580 }
581 si.ntdll_handle = ntdll_handle;
582 break :ntdll_handle ntdll_handle;
583 };
584 var proc_addr: *anyopaque = undefined;
585 switch (windows.ntdll.LdrGetProcedureAddress(ntdll_handle, &.init(name), 0, &proc_addr)) {
586 .SUCCESS => {},
587 else => |status| return windows.unexpectedStatus(status),
555 }588 }
589 return proc_addr;
590}
556591
557 return error.MissingDebugInfo;592fn dllNotification(
593 reason: LDR.DLL_NOTIFICATION.REASON,
594 data: *const LDR.DLL_NOTIFICATION.DATA,
595 context: ?*anyopaque,
596) callconv(.winapi) void {
597 const si: *SelfInfo = @ptrCast(@alignCast(context));
598 switch (reason) {
599 .LOADED => {},
600 .UNLOADED => {
601 const io = std.Options.debug_io;
602 si.mutex.lockUncancelable(io);
603 defer si.mutex.unlock(io);
604 for (si.modules.items, 0..) |*mod, mod_index| {
605 if (mod.entry.DllBase != data.Unloaded.DllBase) continue;
606 mod.deinit(std.debug.getDebugInfoAllocator(), io);
607 _ = si.modules.swapRemove(mod_index);
608 break;
609 }
610 },
611 }
558}612}
559613
560const std = @import("std");614const std = @import("std");
...@@ -563,12 +617,23 @@ const Allocator = std.mem.Allocator;...@@ -563,12 +617,23 @@ const Allocator = std.mem.Allocator;
563const Dwarf = std.debug.Dwarf;617const Dwarf = std.debug.Dwarf;
564const Pdb = std.debug.Pdb;618const Pdb = std.debug.Pdb;
565const Error = std.debug.SelfInfoError;619const Error = std.debug.SelfInfoError;
566const assert = std.debug.assert;
567const coff = std.coff;620const coff = std.coff;
568const fs = std.fs;621const fs = std.fs;
569const windows = std.os.windows;622const windows = std.os.windows;
623const LDR = windows.LDR;
570624
571const builtin = @import("builtin");625const builtin = @import("builtin");
572const native_endian = builtin.target.cpu.arch.endian();626const native_endian = builtin.target.cpu.arch.endian();
627const load_dll_notification_procs = builtin.abi == .msvc and switch (builtin.zig_backend) {
628 .stage2_c => true,
629 else => switch (builtin.output_mode) {
630 .Exe => false,
631 .Lib => switch (builtin.link_mode) {
632 .static => true,
633 .dynamic => false,
634 },
635 .Obj => true,
636 },
637};
573638
574const SelfInfo = @This();639const SelfInfo = @This();
lib/std/heap.zig+3-3
...@@ -110,11 +110,11 @@ pub fn defaultQueryPageSize() usize {...@@ -110,11 +110,11 @@ pub fn defaultQueryPageSize() usize {
110 break :size @intCast(vm_info.page_size);110 break :size @intCast(vm_info.page_size);
111 },111 },
112 .windows => {112 .windows => {
113 var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;113 var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined;
114 switch (windows.ntdll.NtQuerySystemInformation(114 switch (windows.ntdll.NtQuerySystemInformation(
115 .SystemBasicInformation,115 .Basic,
116 &sbi,116 &sbi,
117 @sizeOf(windows.SYSTEM_BASIC_INFORMATION),117 @sizeOf(windows.SYSTEM.BASIC_INFORMATION),
118 null,118 null,
119 )) {119 )) {
120 .SUCCESS => break :size sbi.PageSize,120 .SUCCESS => break :size sbi.PageSize,
lib/std/os/windows.zig+569-1126
...@@ -24,6 +24,66 @@ pub const nls = @import("windows/nls.zig");...@@ -24,6 +24,66 @@ pub const nls = @import("windows/nls.zig");
2424
25pub const current_process: HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1))));25pub const current_process: HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1))));
2626
27pub const OBJECT = struct {
28 // ref: um/winternl.h
29
30 pub const ATTRIBUTES = extern struct {
31 Length: ULONG = @sizeOf(ATTRIBUTES),
32 RootDirectory: ?HANDLE = null,
33 ObjectName: ?*UNICODE_STRING = @constCast(&UNICODE_STRING.empty),
34 Attributes: Flags = .{},
35 SecurityDescriptor: ?*anyopaque = null,
36 SecurityQualityOfService: ?*anyopaque = null,
37
38 // Valid values for the Attributes field
39 pub const Flags = packed struct(ULONG) {
40 Reserved0: u1 = 0,
41 INHERIT: bool = false,
42 Reserved2: u2 = 0,
43 PERMANENT: bool = false,
44 EXCLUSIVE: bool = false,
45 /// If name-lookup code should ignore the case of the ObjectName member rather than performing an exact-match search.
46 CASE_INSENSITIVE: bool = true,
47 OPENIF: bool = false,
48 OPENLINK: bool = false,
49 KERNEL_HANDLE: bool = false,
50 FORCE_ACCESS_CHECK: bool = false,
51 IGNORE_IMPERSONATED_DEVICEMAP: bool = false,
52 DONT_REPARSE: bool = false,
53 Reserved13: u19 = 0,
54
55 pub const VALID_ATTRIBUTES: ATTRIBUTES = .{
56 .INHERIT = true,
57 .PERMANENT = true,
58 .EXCLUSIVE = true,
59 .CASE_INSENSITIVE = true,
60 .OPENIF = true,
61 .OPENLINK = true,
62 .KERNEL_HANDLE = true,
63 .FORCE_ACCESS_CHECK = true,
64 .IGNORE_IMPERSONATED_DEVICEMAP = true,
65 .DONT_REPARSE = true,
66 };
67 };
68 };
69
70 pub const INFORMATION_CLASS = enum(c_int) {
71 Basic = 0,
72 Name = 1,
73 Type = 2,
74 Types = 3,
75 HandleFlag = 4,
76 Session = 5,
77 _,
78
79 pub const Max: @typeInfo(@This()).@"enum".tag_type = @typeInfo(@This()).@"enum".fields.len;
80 };
81
82 pub const NAME_INFORMATION = extern struct {
83 Name: UNICODE_STRING,
84 };
85};
86
27pub const FILE = struct {87pub const FILE = struct {
28 // ref: km/ntddk.h88 // ref: km/ntddk.h
2989
...@@ -73,6 +133,94 @@ pub const FILE = struct {...@@ -73,6 +133,94 @@ pub const FILE = struct {
73133
74 // ref: km/ntifs.h134 // ref: km/ntifs.h
75135
136 pub const NAME_FLAGS = packed struct(UCHAR) {
137 NTFS: bool = false,
138 DOS: bool = false,
139 Reserved2: u5 = 0,
140 UNSPECIFIED: bool = false,
141 };
142
143 pub const NOTIFY = struct {
144 pub const CHANGE = packed struct(ULONG) {
145 FILE_NAME: bool = false,
146 DIR_NAME: bool = false,
147 ATTRIBUTES: bool = false,
148 SIZE: bool = false,
149 LAST_WRITE: bool = false,
150 LAST_ACCESS: bool = false,
151 CREATION: bool = false,
152 EA: bool = false,
153 SECURITY: bool = false,
154 STREAM_NAME: bool = false,
155 STREAM_SIZE: bool = false,
156 STREAM_WRITE: bool = false,
157 Reserved12: u20 = 0,
158 };
159
160 pub const INFORMATION = extern struct {
161 NextEntryOffset: ULONG,
162 Action: ULONG,
163 FileNameLength: ULONG,
164 FileName: [0]WCHAR,
165
166 pub fn fileName(info: *INFORMATION) []WCHAR {
167 const ptr: [*]WCHAR = @ptrCast(&info.FileName);
168 return ptr[0..@divExact(info.FileNameLength, @sizeOf(WCHAR))];
169 }
170 };
171
172 pub const EXTENDED_INFORMATION = extern struct {
173 NextEntryOffset: ULONG,
174 Action: ULONG,
175 CreationTime: LARGE_INTEGER,
176 LastModificationTime: LARGE_INTEGER,
177 LastChangeTime: LARGE_INTEGER,
178 LastAccessTime: LARGE_INTEGER,
179 AllocatedLength: LARGE_INTEGER,
180 FileSize: LARGE_INTEGER,
181 FileAttributes: ATTRIBUTE,
182 u: extern union {
183 ReparsePointTag: ULONG,
184 EaSize: ULONG,
185 },
186 FileId: LARGE_INTEGER,
187 ParentFileId: LARGE_INTEGER,
188 FileNameLength: ULONG,
189 FileName: [0]WCHAR,
190
191 pub fn fileName(info: *INFORMATION) []WCHAR {
192 const ptr: [*]WCHAR = @ptrCast(&info.FileName);
193 return ptr[0..@divExact(info.FileNameLength, @sizeOf(WCHAR))];
194 }
195 };
196
197 pub const FULL_INFORMATION = extern struct {
198 NextEntryOffset: ULONG,
199 Action: ULONG,
200 CreationTime: LARGE_INTEGER,
201 LastModificationTime: LARGE_INTEGER,
202 LastChangeTime: LARGE_INTEGER,
203 LastAccessTime: LARGE_INTEGER,
204 AllocatedLength: LARGE_INTEGER,
205 FileSize: LARGE_INTEGER,
206 FileAttributes: ATTRIBUTE,
207 u: extern union {
208 ReparsePointTag: ULONG,
209 EaSize: ULONG,
210 },
211 FileId: LARGE_INTEGER,
212 ParentFileId: LARGE_INTEGER,
213 FileNameLength: ULONG,
214 FileNameFlags: NAME_FLAGS,
215 FileName: [0]WCHAR,
216
217 pub fn fileName(info: *INFORMATION) []WCHAR {
218 const ptr: [*]WCHAR = @ptrCast(&info.FileName);
219 return ptr[0..@divExact(info.FileNameLength, @sizeOf(WCHAR))];
220 }
221 };
222 };
223
76 pub const PIPE = struct {224 pub const PIPE = struct {
77 /// Define the `NamedPipeType` flags for `NtCreateNamedPipeFile`225 /// Define the `NamedPipeType` flags for `NtCreateNamedPipeFile`
78 pub const TYPE = packed struct(ULONG) {226 pub const TYPE = packed struct(ULONG) {
...@@ -357,6 +505,7 @@ pub const FILE = struct {...@@ -357,6 +505,7 @@ pub const FILE = struct {
357 IdAllExtdBothDirectory = 81,505 IdAllExtdBothDirectory = 81,
358 StreamReservation = 82,506 StreamReservation = 82,
359 MupProvider = 83,507 MupProvider = 83,
508 _,
360509
361 pub const Maximum: @typeInfo(@This()).@"enum".tag_type = 1 + @typeInfo(@This()).@"enum".fields.len;510 pub const Maximum: @typeInfo(@This()).@"enum".tag_type = 1 + @typeInfo(@This()).@"enum".fields.len;
362 };511 };
...@@ -647,6 +796,19 @@ pub const FILE = struct {...@@ -647,6 +796,19 @@ pub const FILE = struct {
647 Mode: MODE,796 Mode: MODE,
648 };797 };
649 };798 };
799
800 // ref: km/
801};
802
803pub const DIRECTORY = struct {
804 pub const NOTIFY_INFORMATION_CLASS = enum(c_int) {
805 Notify = 1,
806 NotifyExtended = 2,
807 NotifyFull = 3,
808 _,
809
810 pub const Maximum: @typeInfo(@This()).@"enum".tag_type = 1 + @typeInfo(@This()).@"enum".fields.len;
811 };
650};812};
651813
652pub const CONSOLE = struct {814pub const CONSOLE = struct {
...@@ -880,141 +1042,229 @@ pub const CONSOLE = struct {...@@ -880,141 +1042,229 @@ pub const CONSOLE = struct {
8801042
881// ref: km/ntddk.h1043// ref: km/ntddk.h
8821044
883pub const PROCESSINFOCLASS = enum(c_int) {1045pub const SYSTEM = struct {
884 BasicInformation = 0,1046 pub const INFORMATION_CLASS = enum(c_int) {
885 QuotaLimits = 1,1047 Basic = 0,
886 IoCounters = 2,1048 Performance = 2,
887 VmCounters = 3,1049 TimeOfDay = 3,
888 Times = 4,1050 Process = 5,
889 BasePriority = 5,1051 ProcessorPerformance = 8,
890 RaisePriority = 6,1052 Interrupt = 23,
891 DebugPort = 7,1053 Exception = 33,
892 ExceptionPort = 8,1054 RegistryQuota = 37,
893 AccessToken = 9,1055 Lookaside = 45,
894 LdtInformation = 10,1056 CodeIntegrity = 103,
895 LdtSize = 11,1057 Policy = 134,
896 DefaultHardErrorMode = 12,1058 _,
897 IoPortHandlers = 13,1059 };
898 PooledUsageAndLimits = 14,1060
899 WorkingSetWatch = 15,1061 pub const BASIC_INFORMATION = extern struct {
900 UserModeIOPL = 16,1062 Reserved: ULONG,
901 EnableAlignmentFaultFixup = 17,1063 TimerResolution: ULONG,
902 PriorityClass = 18,1064 PageSize: ULONG,
903 Wx86Information = 19,1065 NumberOfPhysicalPages: ULONG,
904 HandleCount = 20,1066 LowestPhysicalPageNumber: ULONG,
905 AffinityMask = 21,1067 HighestPhysicalPageNumber: ULONG,
906 PriorityBoost = 22,1068 AllocationGranularity: ULONG,
907 DeviceMap = 23,1069 MinimumUserModeAddress: ULONG_PTR,
908 SessionInformation = 24,1070 MaximumUserModeAddress: ULONG_PTR,
909 ForegroundInformation = 25,1071 ActiveProcessorsAffinityMask: KAFFINITY,
910 Wow64Information = 26,1072 NumberOfProcessors: UCHAR,
911 ImageFileName = 27,1073 };
912 LUIDDeviceMapsEnabled = 28,1074};
913 BreakOnTermination = 29,1075
914 DebugObjectHandle = 30,1076pub const PROCESS = struct {
915 DebugFlags = 31,1077 pub const INFORMATION = extern struct {
916 HandleTracing = 32,1078 hProcess: HANDLE,
917 IoPriority = 33,1079 hThread: HANDLE,
918 ExecuteFlags = 34,1080 dwProcessId: DWORD,
919 TlsInformation = 35,1081 dwThreadId: DWORD,
920 Cookie = 36,1082 };
921 ImageInformation = 37,1083
922 CycleTime = 38,1084 pub const INFOCLASS = enum(c_int) {
923 PagePriority = 39,1085 BasicInformation = 0,
924 InstrumentationCallback = 40,1086 QuotaLimits = 1,
925 ThreadStackAllocation = 41,1087 IoCounters = 2,
926 WorkingSetWatchEx = 42,1088 VmCounters = 3,
927 ImageFileNameWin32 = 43,1089 Times = 4,
928 ImageFileMapping = 44,1090 BasePriority = 5,
929 AffinityUpdateMode = 45,1091 RaisePriority = 6,
930 MemoryAllocationMode = 46,1092 DebugPort = 7,
931 GroupInformation = 47,1093 ExceptionPort = 8,
932 TokenVirtualizationEnabled = 48,1094 AccessToken = 9,
933 OwnerInformation = 49,1095 LdtInformation = 10,
934 WindowInformation = 50,1096 LdtSize = 11,
935 HandleInformation = 51,1097 DefaultHardErrorMode = 12,
936 MitigationPolicy = 52,1098 IoPortHandlers = 13,
937 DynamicFunctionTableInformation = 53,1099 PooledUsageAndLimits = 14,
938 HandleCheckingMode = 54,1100 WorkingSetWatch = 15,
939 KeepAliveCount = 55,1101 UserModeIOPL = 16,
940 RevokeFileHandles = 56,1102 EnableAlignmentFaultFixup = 17,
941 WorkingSetControl = 57,1103 PriorityClass = 18,
942 HandleTable = 58,1104 Wx86Information = 19,
943 CheckStackExtentsMode = 59,1105 HandleCount = 20,
944 CommandLineInformation = 60,1106 AffinityMask = 21,
945 ProtectionInformation = 61,1107 PriorityBoost = 22,
946 MemoryExhaustion = 62,1108 DeviceMap = 23,
947 FaultInformation = 63,1109 SessionInformation = 24,
948 TelemetryIdInformation = 64,1110 ForegroundInformation = 25,
949 CommitReleaseInformation = 65,1111 Wow64Information = 26,
950 Reserved1Information = 66,1112 ImageFileName = 27,
951 Reserved2Information = 67,1113 LUIDDeviceMapsEnabled = 28,
952 SubsystemProcess = 68,1114 BreakOnTermination = 29,
953 InPrivate = 70,1115 DebugObjectHandle = 30,
954 RaiseUMExceptionOnInvalidHandleClose = 71,1116 DebugFlags = 31,
955 SubsystemInformation = 75,1117 HandleTracing = 32,
956 Win32kSyscallFilterInformation = 79,1118 IoPriority = 33,
957 EnergyTrackingState = 82,1119 ExecuteFlags = 34,
958 NetworkIoCounters = 114,1120 TlsInformation = 35,
959 _,1121 Cookie = 36,
1122 ImageInformation = 37,
1123 CycleTime = 38,
1124 PagePriority = 39,
1125 InstrumentationCallback = 40,
1126 ThreadStackAllocation = 41,
1127 WorkingSetWatchEx = 42,
1128 ImageFileNameWin32 = 43,
1129 ImageFileMapping = 44,
1130 AffinityUpdateMode = 45,
1131 MemoryAllocationMode = 46,
1132 GroupInformation = 47,
1133 TokenVirtualizationEnabled = 48,
1134 OwnerInformation = 49,
1135 WindowInformation = 50,
1136 HandleInformation = 51,
1137 MitigationPolicy = 52,
1138 DynamicFunctionTableInformation = 53,
1139 HandleCheckingMode = 54,
1140 KeepAliveCount = 55,
1141 RevokeFileHandles = 56,
1142 WorkingSetControl = 57,
1143 HandleTable = 58,
1144 CheckStackExtentsMode = 59,
1145 CommandLineInformation = 60,
1146 ProtectionInformation = 61,
1147 MemoryExhaustion = 62,
1148 FaultInformation = 63,
1149 TelemetryIdInformation = 64,
1150 CommitReleaseInformation = 65,
1151 Reserved1Information = 66,
1152 Reserved2Information = 67,
1153 SubsystemProcess = 68,
1154 InPrivate = 70,
1155 RaiseUMExceptionOnInvalidHandleClose = 71,
1156 SubsystemInformation = 75,
1157 Win32kSyscallFilterInformation = 79,
1158 EnergyTrackingState = 82,
1159 NetworkIoCounters = 114,
1160 _,
1161
1162 pub const Max: @typeInfo(@This()).@"enum".tag_type = 117;
1163 };
1164
1165 pub const BASIC_INFORMATION = extern struct {
1166 ExitStatus: NTSTATUS,
1167 PebBaseAddress: *PEB,
1168 AffinityMask: ULONG_PTR,
1169 BasePriority: KPRIORITY,
1170 UniqueProcessId: ULONG_PTR,
1171 InheritedFromUniqueProcessId: ULONG_PTR,
1172 };
1173
1174 pub const VM_COUNTERS = extern struct {
1175 PeakVirtualSize: SIZE_T,
1176 VirtualSize: SIZE_T,
1177 PageFaultCount: ULONG,
1178 PeakWorkingSetSize: SIZE_T,
1179 WorkingSetSize: SIZE_T,
1180 QuotaPeakPagedPoolUsage: SIZE_T,
1181 QuotaPagedPoolUsage: SIZE_T,
1182 QuotaPeakNonPagedPoolUsage: SIZE_T,
1183 QuotaNonPagedPoolUsage: SIZE_T,
1184 PagefileUsage: SIZE_T,
1185 PeakPagefileUsage: SIZE_T,
1186 };
1187};
1188
1189pub const THREAD = struct {
1190 pub const INFOCLASS = enum(c_int) {
1191 BasicInformation = 0,
1192 Times = 1,
1193 Priority = 2,
1194 BasePriority = 3,
1195 AffinityMask = 4,
1196 ImpersonationToken = 5,
1197 DescriptorTableEntry = 6,
1198 EnableAlignmentFaultFixup = 7,
1199 EventPair_Reusable = 8,
1200 QuerySetWin32StartAddress = 9,
1201 ZeroTlsCell = 10,
1202 PerformanceCount = 11,
1203 AmILastThread = 12,
1204 IdealProcessor = 13,
1205 PriorityBoost = 14,
1206 SetTlsArrayAddress = 15,
1207 IsIoPending = 16,
1208 // Windows 2000+ from here
1209 HideFromDebugger = 17,
1210 // Windows XP+ from here
1211 BreakOnTermination = 18,
1212 SwitchLegacyState = 19,
1213 IsTerminated = 20,
1214 // Windows Vista+ from here
1215 LastSystemCall = 21,
1216 IoPriority = 22,
1217 CycleTime = 23,
1218 PagePriority = 24,
1219 ActualBasePriority = 25,
1220 TebInformation = 26,
1221 CSwitchMon = 27,
1222 // Windows 7+ from here
1223 CSwitchPmu = 28,
1224 Wow64Context = 29,
1225 GroupInformation = 30,
1226 UmsInformation = 31,
1227 CounterProfiling = 32,
1228 IdealProcessorEx = 33,
1229 // Windows 8+ from here
1230 CpuAccountingInformation = 34,
1231 // Windows 8.1+ from here
1232 SuspendCount = 35,
1233 // Windows 10+ from here
1234 HeterogeneousCpuPolicy = 36,
1235 ContainerId = 37,
1236 NameInformation = 38,
1237 SelectedCpuSets = 39,
1238 SystemThreadInformation = 40,
1239 ActualGroupAffinity = 41,
1240 DynamicCodePolicyInfo = 42,
1241 SubsystemInformation = 45,
1242 _,
1243
1244 pub const Max: @typeInfo(@This()).@"enum".tag_type = 60;
1245 };
9601246
961 pub const Max: @typeInfo(@This()).@"enum".tag_type = 117;1247 pub const BASIC_INFORMATION = extern struct {
1248 ExitStatus: NTSTATUS,
1249 TebBaseAddress: PVOID,
1250 ClientId: CLIENT_ID,
1251 AffinityMask: KAFFINITY,
1252 Priority: KPRIORITY,
1253 BasePriority: KPRIORITY,
1254 };
962};1255};
9631256
964pub const THREADINFOCLASS = enum(c_int) {1257pub const MEMORY = struct {
965 BasicInformation = 0,1258 pub const BASIC_INFORMATION = extern struct {
966 Times = 1,1259 BaseAddress: PVOID,
967 Priority = 2,1260 AllocationBase: PVOID,
968 BasePriority = 3,1261 AllocationProtect: DWORD,
969 AffinityMask = 4,1262 PartitionId: WORD,
970 ImpersonationToken = 5,1263 RegionSize: SIZE_T,
971 DescriptorTableEntry = 6,1264 State: DWORD,
972 EnableAlignmentFaultFixup = 7,1265 Protect: DWORD,
973 EventPair_Reusable = 8,1266 Type: DWORD,
974 QuerySetWin32StartAddress = 9,1267 };
975 ZeroTlsCell = 10,
976 PerformanceCount = 11,
977 AmILastThread = 12,
978 IdealProcessor = 13,
979 PriorityBoost = 14,
980 SetTlsArrayAddress = 15,
981 IsIoPending = 16,
982 // Windows 2000+ from here
983 HideFromDebugger = 17,
984 // Windows XP+ from here
985 BreakOnTermination = 18,
986 SwitchLegacyState = 19,
987 IsTerminated = 20,
988 // Windows Vista+ from here
989 LastSystemCall = 21,
990 IoPriority = 22,
991 CycleTime = 23,
992 PagePriority = 24,
993 ActualBasePriority = 25,
994 TebInformation = 26,
995 CSwitchMon = 27,
996 // Windows 7+ from here
997 CSwitchPmu = 28,
998 Wow64Context = 29,
999 GroupInformation = 30,
1000 UmsInformation = 31,
1001 CounterProfiling = 32,
1002 IdealProcessorEx = 33,
1003 // Windows 8+ from here
1004 CpuAccountingInformation = 34,
1005 // Windows 8.1+ from here
1006 SuspendCount = 35,
1007 // Windows 10+ from here
1008 HeterogeneousCpuPolicy = 36,
1009 ContainerId = 37,
1010 NameInformation = 38,
1011 SelectedCpuSets = 39,
1012 SystemThreadInformation = 40,
1013 ActualGroupAffinity = 41,
1014 DynamicCodePolicyInfo = 42,
1015 SubsystemInformation = 45,
1016
1017 pub const Max: @typeInfo(@This()).@"enum".tag_type = 60;
1018};1268};
10191269
1020// ref: km/ntifs.h1270// ref: km/ntifs.h
...@@ -2560,48 +2810,6 @@ pub fn GetProcessHeap() ?*HEAP {...@@ -2560,48 +2810,6 @@ pub fn GetProcessHeap() ?*HEAP {
2560 return peb().ProcessHeap;2810 return peb().ProcessHeap;
2561}2811}
25622812
2563// ref: um/winternl.h
2564
2565pub const OBJECT_ATTRIBUTES = extern struct {
2566 Length: ULONG = @sizeOf(OBJECT_ATTRIBUTES),
2567 RootDirectory: ?HANDLE = null,
2568 ObjectName: ?*UNICODE_STRING = @constCast(&UNICODE_STRING.empty),
2569 Attributes: ATTRIBUTES = .{},
2570 SecurityDescriptor: ?*anyopaque = null,
2571 SecurityQualityOfService: ?*anyopaque = null,
2572
2573 // Valid values for the Attributes field
2574 pub const ATTRIBUTES = packed struct(ULONG) {
2575 Reserved0: u1 = 0,
2576 INHERIT: bool = false,
2577 Reserved2: u2 = 0,
2578 PERMANENT: bool = false,
2579 EXCLUSIVE: bool = false,
2580 /// If name-lookup code should ignore the case of the ObjectName member rather than performing an exact-match search.
2581 CASE_INSENSITIVE: bool = true,
2582 OPENIF: bool = false,
2583 OPENLINK: bool = false,
2584 KERNEL_HANDLE: bool = false,
2585 FORCE_ACCESS_CHECK: bool = false,
2586 IGNORE_IMPERSONATED_DEVICEMAP: bool = false,
2587 DONT_REPARSE: bool = false,
2588 Reserved13: u19 = 0,
2589
2590 pub const VALID_ATTRIBUTES: ATTRIBUTES = .{
2591 .INHERIT = true,
2592 .PERMANENT = true,
2593 .EXCLUSIVE = true,
2594 .CASE_INSENSITIVE = true,
2595 .OPENIF = true,
2596 .OPENLINK = true,
2597 .KERNEL_HANDLE = true,
2598 .FORCE_ACCESS_CHECK = true,
2599 .IGNORE_IMPERSONATED_DEVICEMAP = true,
2600 .DONT_REPARSE = true,
2601 };
2602 };
2603};
2604
2605// ref none2813// ref none
26062814
2607pub fn GetCurrentProcess() HANDLE {2815pub fn GetCurrentProcess() HANDLE {
...@@ -2623,297 +2831,13 @@ pub fn GetCurrentThreadId() DWORD {...@@ -2623,297 +2831,13 @@ pub fn GetCurrentThreadId() DWORD {
2623}2831}
26242832
2625pub fn GetLastError() Win32Error {2833pub fn GetLastError() Win32Error {
2626 return @enumFromInt(teb().LastErrorValue);2834 return teb().LastErrorValue;
2627}
2628/// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls.
2629/// It implements similar behavior to `DeviceIoControl` and is meant to serve
2630/// as a direct substitute for that call.
2631/// TODO work out if we need to expose other arguments to the underlying syscalls.
2632pub fn DeviceIoControl(
2633 device: HANDLE,
2634 io_control_code: CTL_CODE,
2635 opts: struct {
2636 event: ?HANDLE = null,
2637 apc_routine: ?*const IO_APC_ROUTINE = null,
2638 apc_context: ?*anyopaque = null,
2639 io_status_block: ?*IO_STATUS_BLOCK = null,
2640 in: []const u8 = &.{},
2641 out: []u8 = &.{},
2642 },
2643) NTSTATUS {
2644 var io_status_block: IO_STATUS_BLOCK = undefined;
2645 return switch (io_control_code.DeviceType) {
2646 .FILE_SYSTEM, .NAMED_PIPE => ntdll.NtFsControlFile(
2647 device,
2648 opts.event,
2649 opts.apc_routine,
2650 opts.apc_context,
2651 opts.io_status_block orelse &io_status_block,
2652 io_control_code,
2653 if (opts.in.len > 0) opts.in.ptr else null,
2654 @intCast(opts.in.len),
2655 if (opts.out.len > 0) opts.out.ptr else null,
2656 @intCast(opts.out.len),
2657 ),
2658 else => ntdll.NtDeviceIoControlFile(
2659 device,
2660 opts.event,
2661 opts.apc_routine,
2662 opts.apc_context,
2663 opts.io_status_block orelse &io_status_block,
2664 io_control_code,
2665 if (opts.in.len > 0) opts.in.ptr else null,
2666 @intCast(opts.in.len),
2667 if (opts.out.len > 0) opts.out.ptr else null,
2668 @intCast(opts.out.len),
2669 ),
2670 };
2671}
2672
2673pub fn GetOverlappedResult(h: HANDLE, overlapped: *OVERLAPPED, wait: bool) !DWORD {
2674 var bytes: DWORD = undefined;
2675 if (kernel32.GetOverlappedResult(h, overlapped, &bytes, @intFromBool(wait)) == 0) {
2676 switch (GetLastError()) {
2677 .IO_INCOMPLETE => if (!wait) return error.WouldBlock else unreachable,
2678 else => |err| return unexpectedError(err),
2679 }
2680 }
2681 return bytes;
2682}
2683
2684pub const CreateIoCompletionPortError = error{Unexpected};
2685
2686pub fn CreateIoCompletionPort(
2687 file_handle: HANDLE,
2688 existing_completion_port: ?HANDLE,
2689 completion_key: usize,
2690 concurrent_thread_count: DWORD,
2691) CreateIoCompletionPortError!HANDLE {
2692 const handle = kernel32.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
2693 switch (GetLastError()) {
2694 .INVALID_PARAMETER => unreachable,
2695 else => |err| return unexpectedError(err),
2696 }
2697 };
2698 return handle;
2699}
2700
2701pub const PostQueuedCompletionStatusError = error{Unexpected};
2702
2703pub fn PostQueuedCompletionStatus(
2704 completion_port: HANDLE,
2705 bytes_transferred_count: DWORD,
2706 completion_key: usize,
2707 lpOverlapped: ?*OVERLAPPED,
2708) PostQueuedCompletionStatusError!void {
2709 if (kernel32.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
2710 switch (GetLastError()) {
2711 else => |err| return unexpectedError(err),
2712 }
2713 }
2714}
2715
2716pub const GetQueuedCompletionStatusResult = enum {
2717 Normal,
2718 Aborted,
2719 Canceled,
2720 EOF,
2721 Timeout,
2722};
2723
2724pub fn GetQueuedCompletionStatus(
2725 completion_port: HANDLE,
2726 bytes_transferred_count: *DWORD,
2727 lpCompletionKey: *usize,
2728 lpOverlapped: *?*OVERLAPPED,
2729 dwMilliseconds: DWORD,
2730) GetQueuedCompletionStatusResult {
2731 if (kernel32.GetQueuedCompletionStatus(
2732 completion_port,
2733 bytes_transferred_count,
2734 lpCompletionKey,
2735 lpOverlapped,
2736 dwMilliseconds,
2737 ) == FALSE) {
2738 switch (GetLastError()) {
2739 .ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted,
2740 .OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Canceled,
2741 .HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF,
2742 .WAIT_TIMEOUT => return GetQueuedCompletionStatusResult.Timeout,
2743 else => |err| {
2744 if (std.debug.runtime_safety) {
2745 @setEvalBranchQuota(2500);
2746 std.debug.panic("unexpected error: {}\n", .{err});
2747 }
2748 },
2749 }
2750 }
2751 return GetQueuedCompletionStatusResult.Normal;
2752}
2753
2754pub const GetQueuedCompletionStatusError = error{
2755 Aborted,
2756 Canceled,
2757 EOF,
2758 Timeout,
2759} || UnexpectedError;
2760
2761pub fn GetQueuedCompletionStatusEx(
2762 completion_port: HANDLE,
2763 completion_port_entries: []OVERLAPPED_ENTRY,
2764 timeout_ms: ?DWORD,
2765 alertable: bool,
2766) GetQueuedCompletionStatusError!u32 {
2767 var num_entries_removed: u32 = 0;
2768
2769 const success = kernel32.GetQueuedCompletionStatusEx(
2770 completion_port,
2771 completion_port_entries.ptr,
2772 @as(ULONG, @intCast(completion_port_entries.len)),
2773 &num_entries_removed,
2774 timeout_ms orelse INFINITE,
2775 @intFromBool(alertable),
2776 );
2777
2778 if (success == FALSE) {
2779 return switch (GetLastError()) {
2780 .ABANDONED_WAIT_0 => error.Aborted,
2781 .OPERATION_ABORTED => error.Canceled,
2782 .HANDLE_EOF => error.EOF,
2783 .WAIT_TIMEOUT => error.Timeout,
2784 else => |err| unexpectedError(err),
2785 };
2786 }
2787
2788 return num_entries_removed;
2789}2835}
27902836
2791pub fn CloseHandle(hObject: HANDLE) void {2837pub fn CloseHandle(hObject: HANDLE) void {
2792 assert(ntdll.NtClose(hObject) == .SUCCESS);2838 switch (ntdll.NtClose(hObject)) {
2793}2839 .SUCCESS => {},
27942840 else => |status| unexpectedStatus(status) catch {},
2795pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
2796 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
2797}
2798
2799pub fn sendmsg(
2800 s: ws2_32.SOCKET,
2801 msg: *ws2_32.WSAMSG_const,
2802 flags: u32,
2803) i32 {
2804 var bytes_send: DWORD = undefined;
2805 if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
2806 return ws2_32.SOCKET_ERROR;
2807 } else {
2808 return @as(i32, @as(u31, @intCast(bytes_send)));
2809 }
2810}
2811
2812pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
2813 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = @constCast(buf) };
2814 var bytes_send: DWORD = undefined;
2815 if (ws2_32.WSASendTo(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_send, flags, to, @as(i32, @intCast(to_len)), null, null) == ws2_32.SOCKET_ERROR) {
2816 return ws2_32.SOCKET_ERROR;
2817 } else {
2818 return @as(i32, @as(u31, @intCast(bytes_send)));
2819 }
2820}
2821
2822pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 {
2823 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = buf };
2824 var bytes_received: DWORD = undefined;
2825 var flags_inout = flags;
2826 if (ws2_32.WSARecvFrom(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_received, &flags_inout, from, @as(?*i32, @ptrCast(from_len)), null, null) == ws2_32.SOCKET_ERROR) {
2827 return ws2_32.SOCKET_ERROR;
2828 } else {
2829 return @as(i32, @as(u31, @intCast(bytes_received)));
2830 }
2831}
2832
2833pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 {
2834 return ws2_32.WSAPoll(fds, n, timeout);
2835}
2836
2837pub fn WSAIoctl(
2838 s: ws2_32.SOCKET,
2839 dwIoControlCode: DWORD,
2840 inBuffer: ?[]const u8,
2841 outBuffer: []u8,
2842 overlapped: ?*OVERLAPPED,
2843 completionRoutine: ?ws2_32.LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2844) !DWORD {
2845 var bytes: DWORD = undefined;
2846 switch (ws2_32.WSAIoctl(
2847 s,
2848 dwIoControlCode,
2849 if (inBuffer) |i| i.ptr else null,
2850 if (inBuffer) |i| @as(DWORD, @intCast(i.len)) else 0,
2851 outBuffer.ptr,
2852 @as(DWORD, @intCast(outBuffer.len)),
2853 &bytes,
2854 overlapped,
2855 completionRoutine,
2856 )) {
2857 0 => {},
2858 ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) {
2859 else => |err| return unexpectedWSAError(err),
2860 },
2861 else => unreachable,
2862 }
2863 return bytes;
2864}
2865
2866const GetModuleFileNameError = error{Unexpected};
2867
2868pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) GetModuleFileNameError![:0]u16 {
2869 const rc = kernel32.GetModuleFileNameW(hModule, buf_ptr, buf_len);
2870 if (rc == 0) {
2871 switch (GetLastError()) {
2872 else => |err| return unexpectedError(err),
2873 }
2874 }
2875 return buf_ptr[0..rc :0];
2876}
2877
2878pub const NtAllocateVirtualMemoryError = error{
2879 AccessDenied,
2880 InvalidParameter,
2881 NoMemory,
2882 Unexpected,
2883};
2884
2885pub fn NtAllocateVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, zero_bits: ULONG_PTR, size: ?*SIZE_T, alloc_type: ULONG, protect: ULONG) NtAllocateVirtualMemoryError!void {
2886 return switch (ntdll.NtAllocateVirtualMemory(hProcess, addr, zero_bits, size, alloc_type, protect)) {
2887 .SUCCESS => return,
2888 .ACCESS_DENIED => NtAllocateVirtualMemoryError.AccessDenied,
2889 .INVALID_PARAMETER => NtAllocateVirtualMemoryError.InvalidParameter,
2890 .NO_MEMORY => NtAllocateVirtualMemoryError.NoMemory,
2891 else => |st| unexpectedStatus(st),
2892 };
2893}
2894
2895pub const NtFreeVirtualMemoryError = error{
2896 AccessDenied,
2897 InvalidParameter,
2898 Unexpected,
2899};
2900
2901pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_type: ULONG) NtFreeVirtualMemoryError!void {
2902 // TODO: If the return value is .INVALID_PAGE_PROTECTION, call RtlFlushSecureMemoryCache and try again.
2903 return switch (ntdll.NtFreeVirtualMemory(hProcess, addr, size, free_type)) {
2904 .SUCCESS => return,
2905 .ACCESS_DENIED => NtFreeVirtualMemoryError.AccessDenied,
2906 .INVALID_PARAMETER => NtFreeVirtualMemoryError.InvalidParameter,
2907 else => NtFreeVirtualMemoryError.Unexpected,
2908 };
2909}
2910
2911pub fn SetFileCompletionNotificationModes(handle: HANDLE, flags: UCHAR) !void {
2912 const success = kernel32.SetFileCompletionNotificationModes(handle, flags);
2913 if (success == FALSE) {
2914 return switch (GetLastError()) {
2915 else => |err| unexpectedError(err),
2916 };
2917 }2841 }
2918}2842}
29192843
...@@ -2963,114 +2887,75 @@ pub const CreateProcessFlags = packed struct(u32) {...@@ -2963,114 +2887,75 @@ pub const CreateProcessFlags = packed struct(u32) {
2963 create_ignore_system_default: bool = false,2887 create_ignore_system_default: bool = false,
2964};2888};
29652889
2966pub const LoadLibraryError = error{
2967 FileNotFound,
2968 Unexpected,
2969};
2970
2971pub fn LoadLibraryW(lpLibFileName: [*:0]const u16) LoadLibraryError!HMODULE {
2972 return kernel32.LoadLibraryW(lpLibFileName) orelse {
2973 switch (GetLastError()) {
2974 .FILE_NOT_FOUND => return error.FileNotFound,
2975 .PATH_NOT_FOUND => return error.FileNotFound,
2976 .MOD_NOT_FOUND => return error.FileNotFound,
2977 else => |err| return unexpectedError(err),
2978 }
2979 };
2980}
2981
2982pub const LoadLibraryFlags = enum(DWORD) {
2983 none = 0,
2984 dont_resolve_dll_references = 0x00000001,
2985 load_ignore_code_authz_level = 0x00000010,
2986 load_library_as_datafile = 0x00000002,
2987 load_library_as_datafile_exclusive = 0x00000040,
2988 load_library_as_image_resource = 0x00000020,
2989 load_library_search_application_dir = 0x00000200,
2990 load_library_search_default_dirs = 0x00001000,
2991 load_library_search_dll_load_dir = 0x00000100,
2992 load_library_search_system32 = 0x00000800,
2993 load_library_search_user_dirs = 0x00000400,
2994 load_with_altered_search_path = 0x00000008,
2995 load_library_require_signed_target = 0x00000080,
2996 load_library_safe_current_dirs = 0x00002000,
2997};
2998
2999pub fn LoadLibraryExW(lpLibFileName: [*:0]const u16, dwFlags: LoadLibraryFlags) LoadLibraryError!HMODULE {
3000 return kernel32.LoadLibraryExW(lpLibFileName, null, @intFromEnum(dwFlags)) orelse {
3001 switch (GetLastError()) {
3002 .FILE_NOT_FOUND => return error.FileNotFound,
3003 .PATH_NOT_FOUND => return error.FileNotFound,
3004 .MOD_NOT_FOUND => return error.FileNotFound,
3005 else => |err| return unexpectedError(err),
3006 }
3007 };
3008}
3009
3010pub fn FreeLibrary(hModule: HMODULE) void {
3011 assert(kernel32.FreeLibrary(hModule) != 0);
3012}
3013
3014pub fn QueryPerformanceFrequency() u64 {
3015 // "On systems that run Windows XP or later, the function will always succeed"
3016 // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancefrequency
3017 var result: LARGE_INTEGER = undefined;
3018 assert(ntdll.RtlQueryPerformanceFrequency(&result) != 0);
3019 // The kernel treats this integer as unsigned.
3020 return @as(u64, @bitCast(result));
3021}
3022
3023pub fn QueryPerformanceCounter() u64 {
3024 // "On systems that run Windows XP or later, the function will always succeed"
3025 // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancecounter
3026 var result: LARGE_INTEGER = undefined;
3027 assert(ntdll.RtlQueryPerformanceCounter(&result) != 0);
3028 // The kernel treats this integer as unsigned.
3029 return @as(u64, @bitCast(result));
3030}
3031
3032/// This is a workaround for the C backend until zig has the ability to put
3033/// C code in inline assembly.
3034extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque;
3035extern fn zig_aarch64_windows_teb() callconv(.c) *anyopaque;
3036extern fn zig_x86_windows_teb() callconv(.c) *anyopaque;
3037extern fn zig_x86_64_windows_teb() callconv(.c) *anyopaque;
3038
3039pub fn teb() *TEB {2890pub fn teb() *TEB {
3040 return switch (native_arch) {2891 if (builtin.zig_backend == .stage2_c) return @ptrCast(@alignCast(struct {
3041 .thumb => if (builtin.zig_backend == .stage2_c)2892 /// This is a workaround for the C backend until zig has the ability to put
3042 @ptrCast(@alignCast(zig_thumb_windows_teb()))2893 /// C code in inline assembly.
3043 else2894 extern fn zig_windows_teb() callconv(.c) *anyopaque;
3044 asm (2895 }.zig_windows_teb()));
3045 \\ mrc p15, 0, %[ptr], c13, c0, 22896 switch (native_arch) {
3046 : [ptr] "=r" (-> *TEB),2897 .thumb => return asm (
3047 ),2898 \\ mrc p15, 0, %[ptr], c13, c0, 2
3048 .aarch64 => if (builtin.zig_backend == .stage2_c)2899 : [ptr] "=r" (-> *TEB),
3049 @ptrCast(@alignCast(zig_aarch64_windows_teb()))2900 ),
3050 else2901 .aarch64 => return asm (
3051 asm (2902 \\ mov %[ptr], x18
3052 \\ mov %[ptr], x182903 : [ptr] "=r" (-> *TEB),
3053 : [ptr] "=r" (-> *TEB),2904 ),
3054 ),2905 .x86 => {
3055 .x86 => if (builtin.zig_backend == .stage2_c)2906 comptime assert(
3056 @ptrCast(@alignCast(zig_x86_windows_teb()))2907 @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x18,
3057 else2908 );
3058 asm (2909 return asm (
3059 \\ movl %%fs:0x18, %[ptr]2910 \\ movl %%fs:0x18, %[ptr]
3060 : [ptr] "=r" (-> *TEB),2911 : [ptr] "=r" (-> *TEB),
3061 ),2912 );
3062 .x86_64 => if (builtin.zig_backend == .stage2_c)2913 },
3063 @ptrCast(@alignCast(zig_x86_64_windows_teb()))2914 .x86_64 => {
3064 else2915 comptime assert(
3065 asm (2916 @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x30,
2917 );
2918 return asm (
3066 \\ movq %%gs:0x30, %[ptr]2919 \\ movq %%gs:0x30, %[ptr]
3067 : [ptr] "=r" (-> *TEB),2920 : [ptr] "=r" (-> *TEB),
3068 ),2921 );
2922 },
3069 else => @compileError("unsupported arch"),2923 else => @compileError("unsupported arch"),
3070 };2924 }
3071}2925}
30722926
3073pub fn peb() *PEB {2927pub fn peb() *PEB {
2928 if (builtin.zig_backend == .stage2_c) switch (native_arch) {
2929 .x86, .x86_64 => return @ptrCast(@alignCast(struct {
2930 /// This is a workaround for the C backend until zig has the ability to put
2931 /// C code in inline assembly.
2932 extern fn zig_windows_peb() callconv(.c) *anyopaque;
2933 }.zig_windows_peb())),
2934 else => {},
2935 } else switch (native_arch) {
2936 .aarch64 => {
2937 comptime assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
2938 return asm (
2939 \\ ldr %[ptr], [x18, #0x60]
2940 : [ptr] "=r" (-> *PEB),
2941 );
2942 },
2943 .x86 => {
2944 comptime assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
2945 return asm (
2946 \\ movl %%fs:0x30, %[ptr]
2947 : [ptr] "=r" (-> *PEB),
2948 );
2949 },
2950 .x86_64 => {
2951 comptime assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
2952 return asm (
2953 \\ movq %%gs:0x60, %[ptr]
2954 : [ptr] "=r" (-> *PEB),
2955 );
2956 },
2957 else => {},
2958 }
3074 return teb().ProcessEnvironmentBlock;2959 return teb().ProcessEnvironmentBlock;
3075}2960}
30762961
...@@ -3089,20 +2974,6 @@ pub fn toSysTime(ns: Io.Timestamp) i64 {...@@ -3089,20 +2974,6 @@ pub fn toSysTime(ns: Io.Timestamp) i64 {
3089 return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100);2974 return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100);
3090}2975}
30912976
3092pub fn fileTimeToNanoSeconds(ft: FILETIME) Io.Timestamp {
3093 const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
3094 return fromSysTime(hns);
3095}
3096
3097/// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME.
3098pub fn nanoSecondsToFileTime(ns: Io.Timestamp) FILETIME {
3099 const adjusted: u64 = @bitCast(toSysTime(ns));
3100 return .{
3101 .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)),
3102 .dwLowDateTime = @as(u32, @truncate(adjusted)),
3103 };
3104}
3105
3106/// Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a2977/// Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a
3107/// redundant copy of the uppercase data.2978/// redundant copy of the uppercase data.
3108pub inline fn toUpperWtf16(c: u16) u16 {2979pub inline fn toUpperWtf16(c: u16) u16 {
...@@ -3126,7 +2997,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool {...@@ -3126,7 +2997,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool {
3126 // endianness for the uppercasing2997 // endianness for the uppercasing
3127 const a_c_native = std.mem.littleToNative(u16, a_c);2998 const a_c_native = std.mem.littleToNative(u16, a_c);
3128 const b_c_native = std.mem.littleToNative(u16, b_c);2999 const b_c_native = std.mem.littleToNative(u16, b_c);
3129 if (a_c != b_c and nls.upcaseW(a_c_native) != nls.upcaseW(b_c_native)) {3000 if (a_c != b_c and toUpperWtf16(a_c_native) != toUpperWtf16(b_c_native)) {
3130 return false;3001 return false;
3131 }3002 }
3132 }3003 }
...@@ -3134,19 +3005,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool {...@@ -3134,19 +3005,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool {
3134 }3005 }
3135 // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a3006 // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a
3136 // redundant copy of the uppercase data.3007 // redundant copy of the uppercase data.
3137 const a_bytes = @as(u16, @intCast(a.len * 2));3008 return ntdll.RtlEqualUnicodeString(&.init(a), &.init(b), TRUE) == TRUE;
3138 const a_string: UNICODE_STRING = .{
3139 .Length = a_bytes,
3140 .MaximumLength = a_bytes,
3141 .Buffer = @constCast(a.ptr),
3142 };
3143 const b_bytes = @as(u16, @intCast(b.len * 2));
3144 const b_string: UNICODE_STRING = .{
3145 .Length = b_bytes,
3146 .MaximumLength = b_bytes,
3147 .Buffer = @constCast(b.ptr),
3148 };
3149 return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
3150}3009}
31513010
3152/// Compares two WTF-8 strings using the equivalent functionality of3011/// Compares two WTF-8 strings using the equivalent functionality of
...@@ -3464,13 +3323,10 @@ pub const LONG = i32;...@@ -3464,13 +3323,10 @@ pub const LONG = i32;
3464pub const ULONG64 = u64;3323pub const ULONG64 = u64;
3465pub const ULONGLONG = u64;3324pub const ULONGLONG = u64;
3466pub const LONGLONG = i64;3325pub const LONGLONG = i64;
3467pub const HLOCAL = HANDLE;
3468pub const LANGID = c_ushort;3326pub const LANGID = c_ushort;
3469pub const COLORREF = DWORD;3327pub const COLORREF = DWORD;
34703328
3471pub const WPARAM = usize;
3472pub const LPARAM = LONG_PTR;3329pub const LPARAM = LONG_PTR;
3473pub const LRESULT = LONG_PTR;
34743330
3475pub const va_list = *opaque {};3331pub const va_list = *opaque {};
34763332
...@@ -3480,6 +3336,40 @@ pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWS...@@ -3480,6 +3336,40 @@ pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWS
3480pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead.");3336pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead.");
3481pub const PCTSTR = @compileError("Deprecated: choose between `PCSTR` or `PCWSTR` directly instead.");3337pub const PCTSTR = @compileError("Deprecated: choose between `PCSTR` or `PCWSTR` directly instead.");
34823338
3339fn STRING(comptime C: type) type {
3340 return extern struct {
3341 Length: USHORT,
3342 MaximumLength: USHORT,
3343 Buffer: ?[*]C,
3344
3345 pub const empty: @This() = .{ .Length = 0, .MaximumLength = 0, .Buffer = null };
3346
3347 pub fn init(string: []const C) @This() {
3348 const len: USHORT = @intCast(@sizeOf(C) * string.len);
3349 return .{
3350 .Length = len,
3351 .MaximumLength = len,
3352 .Buffer = @constCast(string.ptr),
3353 };
3354 }
3355
3356 pub fn isEmpty(string: *const @This()) bool {
3357 return string.Length == 0;
3358 }
3359
3360 pub fn slice(string: *const @This()) []C {
3361 return if (string.isEmpty()) &.{} else string.Buffer.?[0..@divExact(string.Length, @sizeOf(C))];
3362 }
3363
3364 pub fn sliceZ(string: *const @This()) [:0]C {
3365 assert(string.Length + @sizeOf(C) <= string.MaximumLength);
3366 return string.Buffer.?[0..@divExact(string.Length, @sizeOf(C)) :0];
3367 }
3368 };
3369}
3370pub const ANSI_STRING = STRING(CHAR);
3371pub const UNICODE_STRING = STRING(WCHAR);
3372
3483pub const TRUE = 1;3373pub const TRUE = 1;
3484pub const FALSE = 0;3374pub const FALSE = 0;
34853375
...@@ -3509,111 +3399,14 @@ pub const OVERLAPPED = extern struct {...@@ -3509,111 +3399,14 @@ pub const OVERLAPPED = extern struct {
3509 hEvent: ?HANDLE,3399 hEvent: ?HANDLE,
3510};3400};
35113401
3512pub const OVERLAPPED_ENTRY = extern struct {
3513 lpCompletionKey: ULONG_PTR,
3514 lpOverlapped: *OVERLAPPED,
3515 Internal: ULONG_PTR,
3516 dwNumberOfBytesTransferred: DWORD,
3517};
3518
3519pub const MAX_PATH = 260;3402pub const MAX_PATH = 260;
35203403
3521pub const FILE_INFO_BY_HANDLE_CLASS = enum(u32) {
3522 FileBasicInfo = 0,
3523 FileStandardInfo = 1,
3524 FileNameInfo = 2,
3525 FileRenameInfo = 3,
3526 FileDispositionInfo = 4,
3527 FileAllocationInfo = 5,
3528 FileEndOfFileInfo = 6,
3529 FileStreamInfo = 7,
3530 FileCompressionInfo = 8,
3531 FileAttributeTagInfo = 9,
3532 FileIdBothDirectoryInfo = 10,
3533 FileIdBothDirectoryRestartInfo = 11,
3534 FileIoPriorityHintInfo = 12,
3535 FileRemoteProtocolInfo = 13,
3536 FileFullDirectoryInfo = 14,
3537 FileFullDirectoryRestartInfo = 15,
3538 FileStorageInfo = 16,
3539 FileAlignmentInfo = 17,
3540 FileIdInfo = 18,
3541 FileIdExtdDirectoryInfo = 19,
3542 FileIdExtdDirectoryRestartInfo = 20,
3543};
3544
3545pub const BY_HANDLE_FILE_INFORMATION = extern struct {
3546 dwFileAttributes: DWORD,
3547 ftCreationTime: FILETIME,
3548 ftLastAccessTime: FILETIME,
3549 ftLastWriteTime: FILETIME,
3550 dwVolumeSerialNumber: DWORD,
3551 nFileSizeHigh: DWORD,
3552 nFileSizeLow: DWORD,
3553 nNumberOfLinks: DWORD,
3554 nFileIndexHigh: DWORD,
3555 nFileIndexLow: DWORD,
3556};
3557
3558pub const FILE_NAME_INFO = extern struct {
3559 FileNameLength: DWORD,
3560 FileName: [1]WCHAR,
3561};
3562
3563/// Return the normalized drive name. This is the default.
3564pub const FILE_NAME_NORMALIZED = 0x0;
3565
3566/// Return the opened file name (not normalized).
3567pub const FILE_NAME_OPENED = 0x8;
3568
3569/// Return the path with the drive letter. This is the default.
3570pub const VOLUME_NAME_DOS = 0x0;
3571
3572/// Return the path with a volume GUID path instead of the drive name.
3573pub const VOLUME_NAME_GUID = 0x1;
3574
3575/// Return the path with no drive information.
3576pub const VOLUME_NAME_NONE = 0x4;
3577
3578/// Return the path with the volume device path.
3579pub const VOLUME_NAME_NT = 0x2;
3580
3581pub const SECURITY_ATTRIBUTES = extern struct {3404pub const SECURITY_ATTRIBUTES = extern struct {
3582 nLength: DWORD,3405 nLength: DWORD,
3583 lpSecurityDescriptor: ?*anyopaque,3406 lpSecurityDescriptor: ?*anyopaque,
3584 bInheritHandle: BOOL,3407 bInheritHandle: BOOL,
3585};3408};
35863409
3587pub const PIPE_ACCESS_INBOUND = 0x00000001;
3588pub const PIPE_ACCESS_OUTBOUND = 0x00000002;
3589pub const PIPE_ACCESS_DUPLEX = 0x00000003;
3590
3591pub const PIPE_TYPE_BYTE = 0x00000000;
3592pub const PIPE_TYPE_MESSAGE = 0x00000004;
3593
3594pub const PIPE_READMODE_BYTE = 0x00000000;
3595pub const PIPE_READMODE_MESSAGE = 0x00000002;
3596
3597pub const PIPE_WAIT = 0x00000000;
3598pub const PIPE_NOWAIT = 0x00000001;
3599
3600pub const CREATE_ALWAYS = 2;
3601pub const CREATE_NEW = 1;
3602pub const OPEN_ALWAYS = 4;
3603pub const OPEN_EXISTING = 3;
3604pub const TRUNCATE_EXISTING = 5;
3605
3606// flags for CreateEvent
3607pub const CREATE_EVENT_INITIAL_SET = 0x00000002;
3608pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
3609
3610pub const PROCESS_INFORMATION = extern struct {
3611 hProcess: HANDLE,
3612 hThread: HANDLE,
3613 dwProcessId: DWORD,
3614 dwThreadId: DWORD,
3615};
3616
3617pub const STARTUPINFOW = extern struct {3410pub const STARTUPINFOW = extern struct {
3618 cb: DWORD,3411 cb: DWORD,
3619 lpReserved: ?LPWSTR,3412 lpReserved: ?LPWSTR,
...@@ -3650,50 +3443,7 @@ pub const STARTF_USESHOWWINDOW = 0x00000001;...@@ -3650,50 +3443,7 @@ pub const STARTF_USESHOWWINDOW = 0x00000001;
3650pub const STARTF_USESIZE = 0x00000002;3443pub const STARTF_USESIZE = 0x00000002;
3651pub const STARTF_USESTDHANDLES = 0x00000100;3444pub const STARTF_USESTDHANDLES = 0x00000100;
36523445
3653pub const INFINITE = 4294967295;3446pub const THREAD_START_ROUTINE = fn (LPVOID) callconv(.winapi) DWORD;
3654
3655pub const MAXIMUM_WAIT_OBJECTS = 64;
3656
3657pub const WAIT_ABANDONED = 0x00000080;
3658pub const WAIT_ABANDONED_0 = WAIT_ABANDONED + 0;
3659pub const WAIT_OBJECT_0 = 0x00000000;
3660pub const WAIT_TIMEOUT = 0x00000102;
3661pub const WAIT_FAILED = 0xFFFFFFFF;
3662
3663pub const HANDLE_FLAG_INHERIT = 0x00000001;
3664pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
3665
3666pub const MOVEFILE_COPY_ALLOWED = 2;
3667pub const MOVEFILE_CREATE_HARDLINK = 16;
3668pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
3669pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
3670pub const MOVEFILE_REPLACE_EXISTING = 1;
3671pub const MOVEFILE_WRITE_THROUGH = 8;
3672
3673pub const FILE_BEGIN = 0;
3674pub const FILE_CURRENT = 1;
3675pub const FILE_END = 2;
3676
3677pub const PTHREAD_START_ROUTINE = *const fn (LPVOID) callconv(.winapi) DWORD;
3678pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
3679
3680pub const WIN32_FIND_DATAW = extern struct {
3681 dwFileAttributes: DWORD,
3682 ftCreationTime: FILETIME,
3683 ftLastAccessTime: FILETIME,
3684 ftLastWriteTime: FILETIME,
3685 nFileSizeHigh: DWORD,
3686 nFileSizeLow: DWORD,
3687 dwReserved0: DWORD,
3688 dwReserved1: DWORD,
3689 cFileName: [260]u16,
3690 cAlternateFileName: [14]u16,
3691};
3692
3693pub const FILETIME = extern struct {
3694 dwLowDateTime: DWORD,
3695 dwHighDateTime: DWORD,
3696};
36973447
3698pub const SYSTEM_INFO = extern struct {3448pub const SYSTEM_INFO = extern struct {
3699 anon1: extern union {3449 anon1: extern union {
...@@ -3716,7 +3466,6 @@ pub const SYSTEM_INFO = extern struct {...@@ -3716,7 +3466,6 @@ pub const SYSTEM_INFO = extern struct {
37163466
3717pub const HRESULT = c_long;3467pub const HRESULT = c_long;
37183468
3719pub const KNOWNFOLDERID = GUID;
3720pub const GUID = extern struct {3469pub const GUID = extern struct {
3721 Data1: u32,3470 Data1: u32,
3722 Data2: u16,3471 Data2: u16,
...@@ -3771,75 +3520,11 @@ test GUID {...@@ -3771,75 +3520,11 @@ test GUID {
3771 );3520 );
3772}3521}
37733522
3774pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
3775
3776pub const KF_FLAG_DEFAULT = 0;
3777pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
3778pub const KF_FLAG_CREATE = 32768;
3779pub const KF_FLAG_DONT_VERIFY = 16384;
3780pub const KF_FLAG_DONT_UNEXPAND = 8192;
3781pub const KF_FLAG_NO_ALIAS = 4096;
3782pub const KF_FLAG_INIT = 2048;
3783pub const KF_FLAG_DEFAULT_PATH = 1024;
3784pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
3785pub const KF_FLAG_SIMPLE_IDLIST = 256;
3786pub const KF_FLAG_ALIAS_ONLY = -2147483648;
3787
3788pub const S_OK = 0;
3789pub const S_FALSE = 0x00000001;
3790pub const E_NOTIMPL = @as(c_long, @bitCast(@as(c_ulong, 0x80004001)));
3791pub const E_NOINTERFACE = @as(c_long, @bitCast(@as(c_ulong, 0x80004002)));
3792pub const E_POINTER = @as(c_long, @bitCast(@as(c_ulong, 0x80004003)));
3793pub const E_ABORT = @as(c_long, @bitCast(@as(c_ulong, 0x80004004)));
3794pub const E_FAIL = @as(c_long, @bitCast(@as(c_ulong, 0x80004005)));
3795pub const E_UNEXPECTED = @as(c_long, @bitCast(@as(c_ulong, 0x8000FFFF)));
3796pub const E_ACCESSDENIED = @as(c_long, @bitCast(@as(c_ulong, 0x80070005)));
3797pub const E_HANDLE = @as(c_long, @bitCast(@as(c_ulong, 0x80070006)));
3798pub const E_OUTOFMEMORY = @as(c_long, @bitCast(@as(c_ulong, 0x8007000E)));
3799pub const E_INVALIDARG = @as(c_long, @bitCast(@as(c_ulong, 0x80070057)));
3800
3801pub fn HRESULT_CODE(hr: HRESULT) Win32Error {
3802 return @enumFromInt(hr & 0xFFFF);
3803}
3804
3805pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
3806pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
3807pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
3808pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
3809pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
3810pub const FILE_FLAG_OVERLAPPED = 0x40000000;
3811pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
3812pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
3813pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
3814pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
3815pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
3816
3817pub const RECT = extern struct {
3818 left: LONG,
3819 top: LONG,
3820 right: LONG,
3821 bottom: LONG,
3822};
3823
3824pub const SMALL_RECT = extern struct {
3825 Left: SHORT,
3826 Top: SHORT,
3827 Right: SHORT,
3828 Bottom: SHORT,
3829};
3830
3831pub const POINT = extern struct {
3832 x: LONG,
3833 y: LONG,
3834};
3835
3836pub const COORD = extern struct {3523pub const COORD = extern struct {
3837 X: SHORT,3524 X: SHORT,
3838 Y: SHORT,3525 Y: SHORT,
3839};3526};
38403527
3841pub const CREATE_UNICODE_ENVIRONMENT = 1024;
3842
3843pub const TLS_OUT_OF_INDEXES = 4294967295;3528pub const TLS_OUT_OF_INDEXES = 4294967295;
3844pub const IMAGE_TLS_DIRECTORY = extern struct {3529pub const IMAGE_TLS_DIRECTORY = extern struct {
3845 StartAddressOfRawData: usize,3530 StartAddressOfRawData: usize,
...@@ -3854,8 +3539,6 @@ pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;...@@ -3854,8 +3539,6 @@ pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
38543539
3855pub const PIMAGE_TLS_CALLBACK = ?*const fn (PVOID, DWORD, PVOID) callconv(.winapi) void;3540pub const PIMAGE_TLS_CALLBACK = ?*const fn (PVOID, DWORD, PVOID) callconv(.winapi) void;
38563541
3857pub const PROV_RSA_FULL = 1;
3858
3859pub const REGSAM = ACCESS_MASK;3542pub const REGSAM = ACCESS_MASK;
3860pub const LSTATUS = LONG;3543pub const LSTATUS = LONG;
38613544
...@@ -3872,9 +3555,6 @@ pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005);...@@ -3872,9 +3555,6 @@ pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005);
3872pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006);3555pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006);
3873pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = @ptrFromInt(0x80000007);3556pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = @ptrFromInt(0x80000007);
38743557
3875/// Open symbolic link.
3876pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
3877
3878pub const RTL_QUERY_REGISTRY_TABLE = extern struct {3558pub const RTL_QUERY_REGISTRY_TABLE = extern struct {
3879 QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,3559 QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,
3880 Flags: ULONG,3560 Flags: ULONG,
...@@ -3975,38 +3655,6 @@ pub const REG = struct {...@@ -3975,38 +3655,6 @@ pub const REG = struct {
3975 pub const QWORD_LITTLE_ENDIAN: ULONG = 11;3655 pub const QWORD_LITTLE_ENDIAN: ULONG = 11;
3976};3656};
39773657
3978pub const FILE_NOTIFY_INFORMATION = extern struct {
3979 NextEntryOffset: DWORD,
3980 Action: DWORD,
3981 FileNameLength: DWORD,
3982 // Flexible array member
3983 // FileName: [1]WCHAR,
3984};
3985
3986pub const FILE_ACTION_ADDED = 0x00000001;
3987pub const FILE_ACTION_REMOVED = 0x00000002;
3988pub const FILE_ACTION_MODIFIED = 0x00000003;
3989pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
3990pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
3991
3992pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?*const fn (DWORD, DWORD, *OVERLAPPED) callconv(.winapi) void;
3993
3994pub const FileNotifyChangeFilter = packed struct(DWORD) {
3995 file_name: bool = false,
3996 dir_name: bool = false,
3997 attributes: bool = false,
3998 size: bool = false,
3999 last_write: bool = false,
4000 last_access: bool = false,
4001 creation: bool = false,
4002 ea: bool = false,
4003 security: bool = false,
4004 stream_name: bool = false,
4005 stream_size: bool = false,
4006 stream_write: bool = false,
4007 _pad: u20 = 0,
4008};
4009
4010pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;3658pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;
4011pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8;3659pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8;
40123660
...@@ -4056,26 +3704,6 @@ pub const RTL_RUN_ONCE = extern struct {...@@ -4056,26 +3704,6 @@ pub const RTL_RUN_ONCE = extern struct {
40563704
4057pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };3705pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
40583706
4059pub const COINIT = struct {
4060 pub const APARTMENTTHREADED = 2;
4061 pub const MULTITHREADED = 0;
4062 pub const DISABLE_OLE1DDE = 4;
4063 pub const SPEED_OVER_MEMORY = 8;
4064};
4065
4066pub const MEMORY_BASIC_INFORMATION = extern struct {
4067 BaseAddress: PVOID,
4068 AllocationBase: PVOID,
4069 AllocationProtect: DWORD,
4070 PartitionId: WORD,
4071 RegionSize: SIZE_T,
4072 State: DWORD,
4073 Protect: DWORD,
4074 Type: DWORD,
4075};
4076
4077pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION;
4078
4079/// > The maximum path of 32,767 characters is approximate, because the "\\?\"3707/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
4080/// > prefix may be expanded to a longer string by the system at run time, and3708/// > prefix may be expanded to a longer string by the system at run time, and
4081/// > this expansion applies to the total length.3709/// > this expansion applies to the total length.
...@@ -4544,14 +4172,6 @@ pub const UNW_FLAG_EHANDLER = 0x1;...@@ -4544,14 +4172,6 @@ pub const UNW_FLAG_EHANDLER = 0x1;
4544pub const UNW_FLAG_UHANDLER = 0x2;4172pub const UNW_FLAG_UHANDLER = 0x2;
4545pub const UNW_FLAG_CHAININFO = 0x4;4173pub const UNW_FLAG_CHAININFO = 0x4;
45464174
4547pub const UNICODE_STRING = extern struct {
4548 Length: c_ushort,
4549 MaximumLength: c_ushort,
4550 Buffer: ?[*]WCHAR,
4551
4552 pub const empty: UNICODE_STRING = .{ .Length = 0, .MaximumLength = 0, .Buffer = null };
4553};
4554
4555pub const ACTIVATION_CONTEXT_DATA = opaque {};4175pub const ACTIVATION_CONTEXT_DATA = opaque {};
4556pub const ASSEMBLY_STORAGE_MAP = opaque {};4176pub const ASSEMBLY_STORAGE_MAP = opaque {};
4557pub const FLS_CALLBACK_INFO = opaque {};4177pub const FLS_CALLBACK_INFO = opaque {};
...@@ -4564,15 +4184,6 @@ pub const CLIENT_ID = extern struct {...@@ -4564,15 +4184,6 @@ pub const CLIENT_ID = extern struct {
4564 UniqueThread: HANDLE,4184 UniqueThread: HANDLE,
4565};4185};
45664186
4567pub const THREAD_BASIC_INFORMATION = extern struct {
4568 ExitStatus: NTSTATUS,
4569 TebBaseAddress: PVOID,
4570 ClientId: CLIENT_ID,
4571 AffinityMask: KAFFINITY,
4572 Priority: KPRIORITY,
4573 BasePriority: KPRIORITY,
4574};
4575
4576pub const TEB = extern struct {4187pub const TEB = extern struct {
4577 NtTib: NT_TIB,4188 NtTib: NT_TIB,
4578 EnvironmentPointer: PVOID,4189 EnvironmentPointer: PVOID,
...@@ -4580,7 +4191,7 @@ pub const TEB = extern struct {...@@ -4580,7 +4191,7 @@ pub const TEB = extern struct {
4580 ActiveRpcHandle: PVOID,4191 ActiveRpcHandle: PVOID,
4581 ThreadLocalStoragePointer: PVOID,4192 ThreadLocalStoragePointer: PVOID,
4582 ProcessEnvironmentBlock: *PEB,4193 ProcessEnvironmentBlock: *PEB,
4583 LastErrorValue: ULONG,4194 LastErrorValue: Win32Error,
4584 Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8,4195 Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8,
4585 Reserved3: [1952]u8,4196 Reserved3: [1952]u8,
4586 TlsSlots: [64]PVOID,4197 TlsSlots: [64]PVOID,
...@@ -4793,7 +4404,7 @@ pub const PEB = extern struct {...@@ -4793,7 +4404,7 @@ pub const PEB = extern struct {
4793};4404};
47944405
4795/// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.4406/// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.
4796/// It is essentially the head of three double-linked lists of `LDR_DATA_TABLE_ENTRY` structures which each represent one loaded module.4407/// It is essentially the head of three double-linked lists of `LDR.DATA_TABLE_ENTRY` structures which each represent one loaded module.
4797///4408///
4798/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:4409/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
4799/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm4410/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm
...@@ -4825,24 +4436,89 @@ pub const PEB_LDR_DATA = extern struct {...@@ -4825,24 +4436,89 @@ pub const PEB_LDR_DATA = extern struct {
4825 ShutdownThreadId: HANDLE,4436 ShutdownThreadId: HANDLE,
4826};4437};
48274438
4828/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:4439pub const LDR = struct {
4829/// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data4440 /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
4830/// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm4441 /// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data
4831pub const LDR_DATA_TABLE_ENTRY = extern struct {4442 /// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm
4832 InLoadOrderLinks: LIST_ENTRY,4443 pub const DATA_TABLE_ENTRY = extern struct {
4833 InMemoryOrderLinks: LIST_ENTRY,4444 InLoadOrderLinks: LIST_ENTRY,
4834 InInitializationOrderLinks: LIST_ENTRY,4445 InMemoryOrderLinks: LIST_ENTRY,
4835 DllBase: PVOID,4446 InInitializationOrderLinks: LIST_ENTRY,
4836 EntryPoint: PVOID,4447 DllBase: PVOID,
4837 SizeOfImage: ULONG,4448 EntryPoint: PVOID,
4838 FullDllName: UNICODE_STRING,4449 SizeOfImage: ULONG,
4839 BaseDllName: UNICODE_STRING,4450 FullDllName: UNICODE_STRING,
4840 Reserved5: [3]PVOID,4451 BaseDllName: UNICODE_STRING,
4841 DUMMYUNIONNAME: extern union {4452 Reserved5: [3]PVOID,
4842 CheckSum: ULONG,4453 DUMMYUNIONNAME: extern union {
4843 Reserved6: PVOID,4454 CheckSum: ULONG,
4844 },4455 Reserved6: PVOID,
4845 TimeDateStamp: ULONG,4456 },
4457 TimeDateStamp: ULONG,
4458 };
4459
4460 pub const DLL_NOTIFICATION = struct {
4461 pub const REASON = enum(ULONG) { LOADED = 1, UNLOADED = 2 };
4462
4463 pub const DATA = extern union {
4464 Loaded: LOADED,
4465 Unloaded: UNLOADED,
4466
4467 pub const LOADED = extern struct {
4468 Flags: REGISTER,
4469 FullDllName: *const UNICODE_STRING,
4470 BaseDllName: *const UNICODE_STRING,
4471 DllBase: PVOID,
4472 SizeOfImage: ULONG,
4473 };
4474
4475 pub const UNLOADED = extern struct {
4476 Flags: REGISTER,
4477 FullDllName: *const UNICODE_STRING,
4478 BaseDllName: *const UNICODE_STRING,
4479 DllBase: PVOID,
4480 SizeOfImage: ULONG,
4481 };
4482 };
4483
4484 pub const COOKIE = *opaque {};
4485
4486 pub const FUNCTION = fn (
4487 NotificationReason: REASON,
4488 NotificationData: *const DATA,
4489 Context: ?PVOID,
4490 ) callconv(.winapi) void;
4491
4492 pub const REGISTER = packed struct(ULONG) {
4493 Reserved0: u32 = 0,
4494 };
4495 };
4496
4497 pub const GET_DLL_HANDLE_EX = packed struct(ULONG) {
4498 UNCHANGED_REFCOUNT: bool = false,
4499 PIN: bool = false,
4500 Reserved2: u30 = 0,
4501 };
4502
4503 pub const GET_PROCEDURE_ADDRESS = packed struct(ULONG) {
4504 DONT_RECORD_FORWARDER: bool = false,
4505 Reserved1: u31 = 0,
4506 };
4507
4508 pub const LOAD = packed struct(ULONG) {
4509 DONT_RESOLVE_DLL_REFERENCES: bool = false,
4510 LIBRARY_AS_DATAFILE: bool = false,
4511 PACKAGED_LIBRARY: bool = false,
4512 WITH_ALTERED_SEARCH_PATH: bool = false,
4513 IGNORE_CODE_AUTHZ_LEVEL: bool = false,
4514 LIBRARY_AS_IMAGE_RESOURCE: bool = false,
4515 LIBRARY_AS_DATAFILE_EXCLUSIVE: bool = false,
4516 LIBRARY_REQUERE_SIGNED_TARGET: bool = false,
4517 LIBRARY_SEARCH_DLL_LOAD_DIR: bool = false,
4518 LIBRARY_SEARCH_USER_DIRS: bool = false,
4519 LIBRARY_SEARCH_SYSTEM32: bool = false,
4520 LIBRARY_SEARCH_DEFAULT_DIRS: bool = false,
4521 };
4846};4522};
48474523
4848pub const RTL_USER_PROCESS_PARAMETERS = extern struct {4524pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
...@@ -4956,86 +4632,6 @@ pub const MODULEINFO = extern struct {...@@ -4956,86 +4632,6 @@ pub const MODULEINFO = extern struct {
4956 EntryPoint: LPVOID,4632 EntryPoint: LPVOID,
4957};4633};
49584634
4959pub const PSAPI_WS_WATCH_INFORMATION = extern struct {
4960 FaultingPc: LPVOID,
4961 FaultingVa: LPVOID,
4962};
4963
4964pub const VM_COUNTERS = extern struct {
4965 PeakVirtualSize: SIZE_T,
4966 VirtualSize: SIZE_T,
4967 PageFaultCount: ULONG,
4968 PeakWorkingSetSize: SIZE_T,
4969 WorkingSetSize: SIZE_T,
4970 QuotaPeakPagedPoolUsage: SIZE_T,
4971 QuotaPagedPoolUsage: SIZE_T,
4972 QuotaPeakNonPagedPoolUsage: SIZE_T,
4973 QuotaNonPagedPoolUsage: SIZE_T,
4974 PagefileUsage: SIZE_T,
4975 PeakPagefileUsage: SIZE_T,
4976};
4977
4978pub const PROCESS_MEMORY_COUNTERS = extern struct {
4979 cb: DWORD,
4980 PageFaultCount: DWORD,
4981 PeakWorkingSetSize: SIZE_T,
4982 WorkingSetSize: SIZE_T,
4983 QuotaPeakPagedPoolUsage: SIZE_T,
4984 QuotaPagedPoolUsage: SIZE_T,
4985 QuotaPeakNonPagedPoolUsage: SIZE_T,
4986 QuotaNonPagedPoolUsage: SIZE_T,
4987 PagefileUsage: SIZE_T,
4988 PeakPagefileUsage: SIZE_T,
4989};
4990
4991pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {
4992 cb: DWORD,
4993 PageFaultCount: DWORD,
4994 PeakWorkingSetSize: SIZE_T,
4995 WorkingSetSize: SIZE_T,
4996 QuotaPeakPagedPoolUsage: SIZE_T,
4997 QuotaPagedPoolUsage: SIZE_T,
4998 QuotaPeakNonPagedPoolUsage: SIZE_T,
4999 QuotaNonPagedPoolUsage: SIZE_T,
5000 PagefileUsage: SIZE_T,
5001 PeakPagefileUsage: SIZE_T,
5002 PrivateUsage: SIZE_T,
5003};
5004
5005pub const PERFORMANCE_INFORMATION = extern struct {
5006 cb: DWORD,
5007 CommitTotal: SIZE_T,
5008 CommitLimit: SIZE_T,
5009 CommitPeak: SIZE_T,
5010 PhysicalTotal: SIZE_T,
5011 PhysicalAvailable: SIZE_T,
5012 SystemCache: SIZE_T,
5013 KernelTotal: SIZE_T,
5014 KernelPaged: SIZE_T,
5015 KernelNonpaged: SIZE_T,
5016 PageSize: SIZE_T,
5017 HandleCount: DWORD,
5018 ProcessCount: DWORD,
5019 ThreadCount: DWORD,
5020};
5021
5022pub const ENUM_PAGE_FILE_INFORMATION = extern struct {
5023 cb: DWORD,
5024 Reserved: DWORD,
5025 TotalSize: SIZE_T,
5026 TotalInUse: SIZE_T,
5027 PeakUsage: SIZE_T,
5028};
5029
5030pub const PENUM_PAGE_FILE_CALLBACKW = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.winapi) BOOL;
5031pub const PENUM_PAGE_FILE_CALLBACKA = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.winapi) BOOL;
5032
5033pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {
5034 BasicInfo: PSAPI_WS_WATCH_INFORMATION,
5035 FaultingThreadId: ULONG_PTR,
5036 Flags: ULONG_PTR,
5037};
5038
5039pub const OSVERSIONINFOW = extern struct {4635pub const OSVERSIONINFOW = extern struct {
5040 dwOSVersionInfoSize: ULONG,4636 dwOSVersionInfoSize: ULONG,
5041 dwMajorVersion: ULONG,4637 dwMajorVersion: ULONG,
...@@ -5098,20 +4694,6 @@ pub const MOUNTMGR_VOLUME_PATHS = extern struct {...@@ -5098,20 +4694,6 @@ pub const MOUNTMGR_VOLUME_PATHS = extern struct {
5098 MultiSz: [1]WCHAR,4694 MultiSz: [1]WCHAR,
5099};4695};
51004696
5101pub const OBJECT_INFORMATION_CLASS = enum(c_int) {
5102 ObjectBasicInformation = 0,
5103 ObjectNameInformation = 1,
5104 ObjectTypeInformation = 2,
5105 ObjectTypesInformation = 3,
5106 ObjectHandleFlagInformation = 4,
5107 ObjectSessionInformation = 5,
5108 MaxObjectInfoClass,
5109};
5110
5111pub const OBJECT_NAME_INFORMATION = extern struct {
5112 Name: UNICODE_STRING,
5113};
5114
5115pub const SRWLOCK_INIT = SRWLOCK{};4697pub const SRWLOCK_INIT = SRWLOCK{};
5116pub const SRWLOCK = extern struct {4698pub const SRWLOCK = extern struct {
5117 Ptr: ?PVOID = null,4699 Ptr: ?PVOID = null,
...@@ -5122,17 +4704,6 @@ pub const CONDITION_VARIABLE = extern struct {...@@ -5122,17 +4704,6 @@ pub const CONDITION_VARIABLE = extern struct {
5122 Ptr: ?PVOID = null,4704 Ptr: ?PVOID = null,
5123};4705};
51244706
5125pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1;
5126pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2;
5127
5128pub const CTRL_C_EVENT: DWORD = 0;
5129pub const CTRL_BREAK_EVENT: DWORD = 1;
5130pub const CTRL_CLOSE_EVENT: DWORD = 2;
5131pub const CTRL_LOGOFF_EVENT: DWORD = 5;
5132pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
5133
5134pub const HANDLER_ROUTINE = *const fn (dwCtrlType: DWORD) callconv(.winapi) BOOL;
5135
5136/// Processor feature enumeration.4707/// Processor feature enumeration.
5137pub const PF = enum(DWORD) {4708pub const PF = enum(DWORD) {
5138 /// On a Pentium, a floating-point precision error can occur in rare circumstances.4709 /// On a Pentium, a floating-point precision error can occur in rare circumstances.
...@@ -5431,72 +5002,13 @@ pub const KUSER_SHARED_DATA = extern struct {...@@ -5431,72 +5002,13 @@ pub const KUSER_SHARED_DATA = extern struct {
5431/// Read-only user-mode address for the shared data.5002/// Read-only user-mode address for the shared data.
5432/// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm5003/// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
5433/// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/5004/// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/
5434pub const SharedUserData: *const KUSER_SHARED_DATA = @as(*const KUSER_SHARED_DATA, @ptrFromInt(0x7FFE0000));5005pub const SharedUserData: *const KUSER_SHARED_DATA = @ptrFromInt(0x7FFE0000);
54355006
5436pub fn IsProcessorFeaturePresent(feature: PF) bool {5007pub fn IsProcessorFeaturePresent(feature: PF) bool {
5437 if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false;5008 if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false;
5438 return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1;5009 return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1;
5439}5010}
54405011
5441pub const TH32CS_SNAPHEAPLIST = 0x00000001;
5442pub const TH32CS_SNAPPROCESS = 0x00000002;
5443pub const TH32CS_SNAPTHREAD = 0x00000004;
5444pub const TH32CS_SNAPMODULE = 0x00000008;
5445pub const TH32CS_SNAPMODULE32 = 0x00000010;
5446pub const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE;
5447pub const TH32CS_INHERIT = 0x80000000;
5448
5449pub const MAX_MODULE_NAME32 = 255;
5450pub const MODULEENTRY32 = extern struct {
5451 dwSize: DWORD,
5452 th32ModuleID: DWORD,
5453 th32ProcessID: DWORD,
5454 GlblcntUsage: DWORD,
5455 ProccntUsage: DWORD,
5456 modBaseAddr: *BYTE,
5457 modBaseSize: DWORD,
5458 hModule: HMODULE,
5459 szModule: [MAX_MODULE_NAME32 + 1]CHAR,
5460 szExePath: [MAX_PATH]CHAR,
5461};
5462
5463pub const SYSTEM_INFORMATION_CLASS = enum(c_int) {
5464 SystemBasicInformation = 0,
5465 SystemPerformanceInformation = 2,
5466 SystemTimeOfDayInformation = 3,
5467 SystemProcessInformation = 5,
5468 SystemProcessorPerformanceInformation = 8,
5469 SystemInterruptInformation = 23,
5470 SystemExceptionInformation = 33,
5471 SystemRegistryQuotaInformation = 37,
5472 SystemLookasideInformation = 45,
5473 SystemCodeIntegrityInformation = 103,
5474 SystemPolicyInformation = 134,
5475};
5476
5477pub const SYSTEM_BASIC_INFORMATION = extern struct {
5478 Reserved: ULONG,
5479 TimerResolution: ULONG,
5480 PageSize: ULONG,
5481 NumberOfPhysicalPages: ULONG,
5482 LowestPhysicalPageNumber: ULONG,
5483 HighestPhysicalPageNumber: ULONG,
5484 AllocationGranularity: ULONG,
5485 MinimumUserModeAddress: ULONG_PTR,
5486 MaximumUserModeAddress: ULONG_PTR,
5487 ActiveProcessorsAffinityMask: KAFFINITY,
5488 NumberOfProcessors: UCHAR,
5489};
5490
5491pub const PROCESS_BASIC_INFORMATION = extern struct {
5492 ExitStatus: NTSTATUS,
5493 PebBaseAddress: *PEB,
5494 AffinityMask: ULONG_PTR,
5495 BasePriority: KPRIORITY,
5496 UniqueProcessId: ULONG_PTR,
5497 InheritedFromUniqueProcessId: ULONG_PTR,
5498};
5499
5500// https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L9835012// https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L983
5501pub const KERNEL_USER_TIMES = extern struct {5013pub const KERNEL_USER_TIMES = extern struct {
5502 CreationTime: LARGE_INTEGER,5014 CreationTime: LARGE_INTEGER,
...@@ -5505,75 +5017,6 @@ pub const KERNEL_USER_TIMES = extern struct {...@@ -5505,75 +5017,6 @@ pub const KERNEL_USER_TIMES = extern struct {
5505 UserTime: LARGE_INTEGER,5017 UserTime: LARGE_INTEGER,
5506};5018};
55075019
5508pub const ReadMemoryError = error{
5509 Unexpected,
5510};
5511
5512pub fn ReadProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []u8) ReadMemoryError![]u8 {
5513 var nread: usize = 0;
5514 switch (ntdll.NtReadVirtualMemory(
5515 handle,
5516 addr,
5517 buffer.ptr,
5518 buffer.len,
5519 &nread,
5520 )) {
5521 .SUCCESS => return buffer[0..nread],
5522 // TODO: map errors
5523 else => |rc| return unexpectedStatus(rc),
5524 }
5525}
5526
5527pub const WriteMemoryError = error{
5528 Unexpected,
5529};
5530
5531pub fn WriteProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []const u8) WriteMemoryError!usize {
5532 var nwritten: usize = 0;
5533 switch (ntdll.NtWriteVirtualMemory(
5534 handle,
5535 addr,
5536 buffer.ptr,
5537 buffer.len,
5538 &nwritten,
5539 )) {
5540 .SUCCESS => return nwritten,
5541 // TODO: map errors
5542 else => |rc| return unexpectedStatus(rc),
5543 }
5544}
5545
5546pub const ProcessBaseAddressError = error{
5547 AccessDenied,
5548 InvalidHandle,
5549 Unexpected,
5550} || ReadMemoryError;
5551
5552/// Returns the base address of the process loaded into memory.
5553pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
5554 var info: PROCESS_BASIC_INFORMATION = undefined;
5555 var nread: DWORD = 0;
5556 const rc = ntdll.NtQueryInformationProcess(
5557 handle,
5558 .BasicInformation,
5559 &info,
5560 @sizeOf(PROCESS_BASIC_INFORMATION),
5561 &nread,
5562 );
5563 switch (rc) {
5564 .SUCCESS => {},
5565 .ACCESS_DENIED => return error.AccessDenied,
5566 .INVALID_HANDLE => return error.InvalidHandle,
5567 .INVALID_PARAMETER => unreachable,
5568 else => return unexpectedStatus(rc),
5569 }
5570
5571 var peb_buf: [@sizeOf(PEB)]u8 align(@alignOf(PEB)) = undefined;
5572 const peb_out = try ReadProcessMemory(handle, info.PebBaseAddress, &peb_buf);
5573 const ppeb: *const PEB = @ptrCast(@alignCast(peb_out.ptr));
5574 return ppeb.ImageBaseAddress;
5575}
5576
5577pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize {5020pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize {
5578 // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE.5021 // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE.
5579 if (wtf16le.len < wtf8.len) {5022 if (wtf16le.len < wtf8.len) {
lib/std/os/windows/kernel32.zig+4-197
...@@ -1,154 +1,29 @@...@@ -1,154 +1,29 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const windows = std.os.windows;2const windows = std.os.windows;
33
4const ACCESS_MASK = windows.ACCESS_MASK;
5const BOOL = windows.BOOL;4const BOOL = windows.BOOL;
6const CONDITION_VARIABLE = windows.CONDITION_VARIABLE;
7const COORD = windows.COORD;
8const DWORD = windows.DWORD;5const DWORD = windows.DWORD;
9const FARPROC = windows.FARPROC;
10const FILETIME = windows.FILETIME;
11const HANDLE = windows.HANDLE;6const HANDLE = windows.HANDLE;
12const HANDLER_ROUTINE = windows.HANDLER_ROUTINE;
13const HMODULE = windows.HMODULE;
14const LARGE_INTEGER = windows.LARGE_INTEGER;
15const LPCSTR = windows.LPCSTR;
16const LPCVOID = windows.LPCVOID;7const LPCVOID = windows.LPCVOID;
17const LPCWSTR = windows.LPCWSTR;8const LPCWSTR = windows.LPCWSTR;
18const LPTHREAD_START_ROUTINE = windows.LPTHREAD_START_ROUTINE;
19const LPVOID = windows.LPVOID;9const LPVOID = windows.LPVOID;
20const LPWSTR = windows.LPWSTR;10const LPWSTR = windows.LPWSTR;
21const MODULEENTRY32 = windows.MODULEENTRY32;11const PROCESS = windows.PROCESS;
22const OVERLAPPED = windows.OVERLAPPED;12const THREAD_START_ROUTINE = windows.THREAD_START_ROUTINE;
23const OVERLAPPED_ENTRY = windows.OVERLAPPED_ENTRY;
24const PROCESS_INFORMATION = windows.PROCESS_INFORMATION;
25const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;13const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
26const SIZE_T = windows.SIZE_T;14const SIZE_T = windows.SIZE_T;
27const SRWLOCK = windows.SRWLOCK;
28const STARTUPINFOW = windows.STARTUPINFOW;15const STARTUPINFOW = windows.STARTUPINFOW;
29const SYSTEM_INFO = windows.SYSTEM_INFO;
30const UCHAR = windows.UCHAR;
31const UINT = windows.UINT;16const UINT = windows.UINT;
32const ULONG = windows.ULONG;
33const ULONG_PTR = windows.ULONG_PTR;
34const va_list = windows.va_list;17const va_list = windows.va_list;
35const WCHAR = windows.WCHAR;
36const Win32Error = windows.Win32Error;18const Win32Error = windows.Win32Error;
37const WORD = windows.WORD;
3819
39// I/O - Filesystem20// I/O - Filesystem
4021
41pub extern "kernel32" fn ReadDirectoryChangesW(
42 hDirectory: HANDLE,
43 lpBuffer: [*]align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) u8,
44 nBufferLength: DWORD,
45 bWatchSubtree: BOOL,
46 dwNotifyFilter: windows.FileNotifyChangeFilter,
47 lpBytesReturned: ?*DWORD,
48 lpOverlapped: ?*OVERLAPPED,
49 lpCompletionRoutine: windows.LPOVERLAPPED_COMPLETION_ROUTINE,
50) callconv(.winapi) BOOL;
51
52// TODO: Wrapper around NtCancelIoFile.
53pub extern "kernel32" fn CancelIo(
54 hFile: HANDLE,
55) callconv(.winapi) BOOL;
56
57// TODO: Wrapper around NtSetInformationFile + `FILE_POSITION_INFORMATION`.
58// `FILE_STANDARD_INFORMATION` is also used if dwMoveMethod is `FILE_END`
59pub extern "kernel32" fn SetFilePointerEx(
60 hFile: HANDLE,
61 liDistanceToMove: LARGE_INTEGER,
62 lpNewFilePointer: ?*LARGE_INTEGER,
63 dwMoveMethod: DWORD,
64) callconv(.winapi) BOOL;
65
66// TODO: Wrapper around NtSetInformationFile + `FILE_BASIC_INFORMATION`
67pub extern "kernel32" fn SetFileTime(
68 hFile: HANDLE,
69 lpCreationTime: ?*const FILETIME,
70 lpLastAccessTime: ?*const FILETIME,
71 lpLastWriteTime: ?*const FILETIME,
72) callconv(.winapi) BOOL;
73
74pub extern "kernel32" fn WriteFile(
75 in_hFile: HANDLE,
76 in_lpBuffer: [*]const u8,
77 in_nNumberOfBytesToWrite: DWORD,
78 out_lpNumberOfBytesWritten: ?*DWORD,
79 in_out_lpOverlapped: ?*OVERLAPPED,
80) callconv(.winapi) BOOL;
81
82// TODO: Wrapper around NtSetInformationFile + `FILE_IO_COMPLETION_NOTIFICATION_INFORMATION`.
83pub extern "kernel32" fn SetFileCompletionNotificationModes(
84 FileHandle: HANDLE,
85 Flags: UCHAR,
86) callconv(.winapi) BOOL;
87
88pub extern "kernel32" fn ReadFile(
89 hFile: HANDLE,
90 lpBuffer: LPVOID,
91 nNumberOfBytesToRead: DWORD,
92 lpNumberOfBytesRead: ?*DWORD,
93 lpOverlapped: ?*OVERLAPPED,
94) callconv(.winapi) BOOL;
95
96pub extern "kernel32" fn GetSystemDirectoryW(22pub extern "kernel32" fn GetSystemDirectoryW(
97 lpBuffer: LPWSTR,23 lpBuffer: LPWSTR,
98 uSize: UINT,24 uSize: UINT,
99) callconv(.winapi) UINT;25) callconv(.winapi) UINT;
10026
101// I/O - Kernel Objects
102
103// TODO: Wrapper around NtRemoveIoCompletion.
104pub extern "kernel32" fn GetQueuedCompletionStatus(
105 CompletionPort: HANDLE,
106 lpNumberOfBytesTransferred: *DWORD,
107 lpCompletionKey: *ULONG_PTR,
108 lpOverlapped: *?*OVERLAPPED,
109 dwMilliseconds: DWORD,
110) callconv(.winapi) BOOL;
111
112// TODO: Wrapper around NtRemoveIoCompletionEx.
113pub extern "kernel32" fn GetQueuedCompletionStatusEx(
114 CompletionPort: HANDLE,
115 lpCompletionPortEntries: [*]OVERLAPPED_ENTRY,
116 ulCount: ULONG,
117 ulNumEntriesRemoved: *ULONG,
118 dwMilliseconds: DWORD,
119 fAlertable: BOOL,
120) callconv(.winapi) BOOL;
121
122// TODO: Wrapper around NtSetIoCompletion with `IoStatus = .SUCCESS`.
123pub extern "kernel32" fn PostQueuedCompletionStatus(
124 CompletionPort: HANDLE,
125 dwNumberOfBytesTransferred: DWORD,
126 dwCompletionKey: ULONG_PTR,
127 lpOverlapped: ?*OVERLAPPED,
128) callconv(.winapi) BOOL;
129
130pub extern "kernel32" fn GetOverlappedResult(
131 hFile: HANDLE,
132 lpOverlapped: *OVERLAPPED,
133 lpNumberOfBytesTransferred: *DWORD,
134 bWait: BOOL,
135) callconv(.winapi) BOOL;
136
137// TODO: Wrapper around NtCreateIoCompletion + NtSetInformationFile with FILE_COMPLETION_INFORMATION.
138// This would be better splitting into two functions.
139pub extern "kernel32" fn CreateIoCompletionPort(
140 FileHandle: HANDLE,
141 ExistingCompletionPort: ?HANDLE,
142 CompletionKey: ULONG_PTR,
143 NumberOfConcurrentThreads: DWORD,
144) callconv(.winapi) ?HANDLE;
145
146// TODO: Wrapper around RtlReportSilentProcessExit + NtTerminateProcess.
147pub extern "kernel32" fn TerminateProcess(
148 hProcess: HANDLE,
149 uExitCode: UINT,
150) callconv(.winapi) BOOL;
151
152// Process Management27// Process Management
15328
154pub extern "kernel32" fn CreateProcessW(29pub extern "kernel32" fn CreateProcessW(
...@@ -161,86 +36,21 @@ pub extern "kernel32" fn CreateProcessW(...@@ -161,86 +36,21 @@ pub extern "kernel32" fn CreateProcessW(
161 lpEnvironment: ?[*:0]const u16,36 lpEnvironment: ?[*:0]const u16,
162 lpCurrentDirectory: ?LPCWSTR,37 lpCurrentDirectory: ?LPCWSTR,
163 lpStartupInfo: *STARTUPINFOW,38 lpStartupInfo: *STARTUPINFOW,
164 lpProcessInformation: *PROCESS_INFORMATION,39 lpProcessInformation: *PROCESS.INFORMATION,
165) callconv(.winapi) BOOL;
166
167// TODO: Wrapper around NtQueryInformationProcess with `PROCESS_BASIC_INFORMATION`.
168pub extern "kernel32" fn GetExitCodeProcess(
169 hProcess: HANDLE,
170 lpExitCode: *DWORD,
171) callconv(.winapi) BOOL;40) callconv(.winapi) BOOL;
17241
173pub extern "kernel32" fn CreateToolhelp32Snapshot(
174 dwFlags: DWORD,
175 th32ProcessID: DWORD,
176) callconv(.winapi) HANDLE;
177
178// Threading42// Threading
17943
180// TODO: Already a wrapper for this, see `windows.GetCurrentThreadId`.
181pub extern "kernel32" fn GetCurrentThreadId() callconv(.winapi) DWORD;
182
183// TODO: CreateRemoteThread with hProcess=NtCurrentProcess().44// TODO: CreateRemoteThread with hProcess=NtCurrentProcess().
184pub extern "kernel32" fn CreateThread(45pub extern "kernel32" fn CreateThread(
185 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,46 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
186 dwStackSize: SIZE_T,47 dwStackSize: SIZE_T,
187 lpStartAddress: LPTHREAD_START_ROUTINE,48 lpStartAddress: *const THREAD_START_ROUTINE,
188 lpParameter: ?LPVOID,49 lpParameter: ?LPVOID,
189 dwCreationFlags: DWORD,50 dwCreationFlags: DWORD,
190 lpThreadId: ?*DWORD,51 lpThreadId: ?*DWORD,
191) callconv(.winapi) ?HANDLE;52) callconv(.winapi) ?HANDLE;
19253
193// Code Libraries/Modules
194
195// TODO: Wrapper around LdrGetDllFullName.
196pub extern "kernel32" fn GetModuleFileNameW(
197 hModule: ?HMODULE,
198 lpFilename: [*]WCHAR,
199 nSize: DWORD,
200) callconv(.winapi) DWORD;
201
202extern "kernel32" fn K32GetModuleFileNameExW(
203 hProcess: HANDLE,
204 hModule: ?HMODULE,
205 lpFilename: LPWSTR,
206 nSize: DWORD,
207) callconv(.winapi) DWORD;
208pub const GetModuleFileNameExW = K32GetModuleFileNameExW;
209
210// TODO: Wrapper around ntdll.LdrGetDllHandle, which is a wrapper around LdrGetDllHandleEx
211pub extern "kernel32" fn GetModuleHandleW(
212 lpModuleName: ?LPCWSTR,
213) callconv(.winapi) ?HMODULE;
214
215pub extern "kernel32" fn Module32First(
216 hSnapshot: HANDLE,
217 lpme: *MODULEENTRY32,
218) callconv(.winapi) BOOL;
219
220pub extern "kernel32" fn Module32Next(
221 hSnapshot: HANDLE,
222 lpme: *MODULEENTRY32,
223) callconv(.winapi) BOOL;
224
225pub extern "kernel32" fn LoadLibraryW(
226 lpLibFileName: LPCWSTR,
227) callconv(.winapi) ?HMODULE;
228
229pub extern "kernel32" fn LoadLibraryExW(
230 lpLibFileName: LPCWSTR,
231 hFile: ?HANDLE,
232 dwFlags: DWORD,
233) callconv(.winapi) ?HMODULE;
234
235pub extern "kernel32" fn GetProcAddress(
236 hModule: HMODULE,
237 lpProcName: LPCSTR,
238) callconv(.winapi) ?FARPROC;
239
240pub extern "kernel32" fn FreeLibrary(
241 hModule: HMODULE,
242) callconv(.winapi) BOOL;
243
244// Error Management54// Error Management
24555
246pub extern "kernel32" fn FormatMessageW(56pub extern "kernel32" fn FormatMessageW(
...@@ -252,6 +62,3 @@ pub extern "kernel32" fn FormatMessageW(...@@ -252,6 +62,3 @@ pub extern "kernel32" fn FormatMessageW(
252 nSize: DWORD,62 nSize: DWORD,
253 Arguments: ?*va_list,63 Arguments: ?*va_list,
254) callconv(.winapi) DWORD;64) callconv(.winapi) DWORD;
255
256// TODO: Getter for teb().LastErrorValue.
257pub extern "kernel32" fn GetLastError() callconv(.winapi) Win32Error;
lib/std/os/windows/ntdll.zig+175-72
...@@ -2,6 +2,7 @@ const std = @import("../../std.zig");...@@ -2,6 +2,7 @@ const std = @import("../../std.zig");
2const windows = std.os.windows;2const windows = std.os.windows;
33
4const ACCESS_MASK = windows.ACCESS_MASK;4const ACCESS_MASK = windows.ACCESS_MASK;
5const ANSI_STRING = windows.ANSI_STRING;
5const BOOL = windows.BOOL;6const BOOL = windows.BOOL;
6const BOOLEAN = windows.BOOLEAN;7const BOOLEAN = windows.BOOLEAN;
7const CONDITION_VARIABLE = windows.CONDITION_VARIABLE;8const CONDITION_VARIABLE = windows.CONDITION_VARIABLE;
...@@ -9,6 +10,7 @@ const CONTEXT = windows.CONTEXT;...@@ -9,6 +10,7 @@ const CONTEXT = windows.CONTEXT;
9const CRITICAL_SECTION = windows.CRITICAL_SECTION;10const CRITICAL_SECTION = windows.CRITICAL_SECTION;
10const CTL_CODE = windows.CTL_CODE;11const CTL_CODE = windows.CTL_CODE;
11const CURDIR = windows.CURDIR;12const CURDIR = windows.CURDIR;
13const DIRECTORY = windows.DIRECTORY;
12const DWORD = windows.DWORD;14const DWORD = windows.DWORD;
13const DWORD64 = windows.DWORD64;15const DWORD64 = windows.DWORD64;
14const ERESOURCE = windows.ERESOURCE;16const ERESOURCE = windows.ERESOURCE;
...@@ -22,18 +24,19 @@ const IO_APC_ROUTINE = windows.IO_APC_ROUTINE;...@@ -22,18 +24,19 @@ const IO_APC_ROUTINE = windows.IO_APC_ROUTINE;
22const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK;24const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK;
23const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;25const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
24const LARGE_INTEGER = windows.LARGE_INTEGER;26const LARGE_INTEGER = windows.LARGE_INTEGER;
27const LDR = windows.LDR;
25const LOGICAL = windows.LOGICAL;28const LOGICAL = windows.LOGICAL;
26const LONG = windows.LONG;29const LONG = windows.LONG;
27const LPCVOID = windows.LPCVOID;30const LPCVOID = windows.LPCVOID;
28const LPVOID = windows.LPVOID;31const LPVOID = windows.LPVOID;
29const MEM = windows.MEM;32const MEM = windows.MEM;
30const NTSTATUS = windows.NTSTATUS;33const NTSTATUS = windows.NTSTATUS;
31const OBJECT_ATTRIBUTES = windows.OBJECT_ATTRIBUTES;34const OBJECT = windows.OBJECT;
32const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS;
33const PAGE = windows.PAGE;35const PAGE = windows.PAGE;
34const PCWSTR = windows.PCWSTR;36const PCWSTR = windows.PCWSTR;
35const PROCESSINFOCLASS = windows.PROCESSINFOCLASS;37const PROCESS = windows.PROCESS;
36const PVOID = windows.PVOID;38const PVOID = windows.PVOID;
39const PWSTR = windows.PWSTR;
37const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;40const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
38const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;41const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;
39const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;42const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
...@@ -41,8 +44,8 @@ const SEC = windows.SEC;...@@ -41,8 +44,8 @@ const SEC = windows.SEC;
41const SECTION_INHERIT = windows.SECTION_INHERIT;44const SECTION_INHERIT = windows.SECTION_INHERIT;
42const SIZE_T = windows.SIZE_T;45const SIZE_T = windows.SIZE_T;
43const SRWLOCK = windows.SRWLOCK;46const SRWLOCK = windows.SRWLOCK;
44const SYSTEM_INFORMATION_CLASS = windows.SYSTEM_INFORMATION_CLASS;47const SYSTEM = windows.SYSTEM;
45const THREADINFOCLASS = windows.THREADINFOCLASS;48const THREAD = windows.THREAD;
46const ULONG = windows.ULONG;49const ULONG = windows.ULONG;
47const ULONG_PTR = windows.ULONG_PTR;50const ULONG_PTR = windows.ULONG_PTR;
48const UNICODE_STRING = windows.UNICODE_STRING;51const UNICODE_STRING = windows.UNICODE_STRING;
...@@ -91,7 +94,7 @@ pub extern "ntdll" fn RtlCaptureContext(...@@ -91,7 +94,7 @@ pub extern "ntdll" fn RtlCaptureContext(
9194
92pub extern "ntdll" fn NtSetInformationThread(95pub extern "ntdll" fn NtSetInformationThread(
93 ThreadHandle: HANDLE,96 ThreadHandle: HANDLE,
94 ThreadInformationClass: THREADINFOCLASS,97 ThreadInformationClass: THREAD.INFOCLASS,
95 ThreadInformation: *const anyopaque,98 ThreadInformation: *const anyopaque,
96 ThreadInformationLength: ULONG,99 ThreadInformationLength: ULONG,
97) callconv(.winapi) NTSTATUS;100) callconv(.winapi) NTSTATUS;
...@@ -99,7 +102,7 @@ pub extern "ntdll" fn NtSetInformationThread(...@@ -99,7 +102,7 @@ pub extern "ntdll" fn NtSetInformationThread(
99pub extern "ntdll" fn NtCreateFile(102pub extern "ntdll" fn NtCreateFile(
100 FileHandle: *HANDLE,103 FileHandle: *HANDLE,
101 DesiredAccess: ACCESS_MASK,104 DesiredAccess: ACCESS_MASK,
102 ObjectAttributes: *const OBJECT_ATTRIBUTES,105 ObjectAttributes: *const OBJECT.ATTRIBUTES,
103 IoStatusBlock: *IO_STATUS_BLOCK,106 IoStatusBlock: *IO_STATUS_BLOCK,
104 AllocationSize: ?*const LARGE_INTEGER,107 AllocationSize: ?*const LARGE_INTEGER,
105 FileAttributes: FILE.ATTRIBUTE,108 FileAttributes: FILE.ATTRIBUTE,
...@@ -152,7 +155,7 @@ pub extern "ntdll" fn NtLockFile(...@@ -152,7 +155,7 @@ pub extern "ntdll" fn NtLockFile(
152pub extern "ntdll" fn NtOpenFile(155pub extern "ntdll" fn NtOpenFile(
153 FileHandle: *HANDLE,156 FileHandle: *HANDLE,
154 DesiredAccess: ACCESS_MASK,157 DesiredAccess: ACCESS_MASK,
155 ObjectAttributes: *const OBJECT_ATTRIBUTES,158 ObjectAttributes: *const OBJECT.ATTRIBUTES,
156 IoStatusBlock: *IO_STATUS_BLOCK,159 IoStatusBlock: *IO_STATUS_BLOCK,
157 ShareAccess: FILE.SHARE,160 ShareAccess: FILE.SHARE,
158 OpenOptions: FILE.MODE,161 OpenOptions: FILE.MODE,
...@@ -233,7 +236,7 @@ pub extern "ntdll" fn NtUnlockFile(...@@ -233,7 +236,7 @@ pub extern "ntdll" fn NtUnlockFile(
233236
234pub extern "ntdll" fn NtQueryObject(237pub extern "ntdll" fn NtQueryObject(
235 Handle: HANDLE,238 Handle: HANDLE,
236 ObjectInformationClass: OBJECT_INFORMATION_CLASS,239 ObjectInformationClass: OBJECT.INFORMATION_CLASS,
237 ObjectInformation: ?PVOID,240 ObjectInformation: ?PVOID,
238 ObjectInformationLength: ULONG,241 ObjectInformationLength: ULONG,
239 ReturnLength: ?*ULONG,242 ReturnLength: ?*ULONG,
...@@ -246,7 +249,7 @@ pub extern "ntdll" fn NtClose(...@@ -246,7 +249,7 @@ pub extern "ntdll" fn NtClose(
246pub extern "ntdll" fn NtCreateSection(249pub extern "ntdll" fn NtCreateSection(
247 SectionHandle: *HANDLE,250 SectionHandle: *HANDLE,
248 DesiredAccess: ACCESS_MASK,251 DesiredAccess: ACCESS_MASK,
249 ObjectAttributes: ?*const OBJECT_ATTRIBUTES,252 ObjectAttributes: ?*const OBJECT.ATTRIBUTES,
250 MaximumSize: ?*const LARGE_INTEGER,253 MaximumSize: ?*const LARGE_INTEGER,
251 SectionPageProtection: PAGE,254 SectionPageProtection: PAGE,
252 AllocationAttributes: SEC,255 AllocationAttributes: SEC,
...@@ -331,7 +334,7 @@ pub extern "ntdll" fn NtWaitForSingleObject(...@@ -331,7 +334,7 @@ pub extern "ntdll" fn NtWaitForSingleObject(
331334
332pub extern "ntdll" fn NtQueryInformationProcess(335pub extern "ntdll" fn NtQueryInformationProcess(
333 ProcessHandle: HANDLE,336 ProcessHandle: HANDLE,
334 ProcessInformationClass: PROCESSINFOCLASS,337 ProcessInformationClass: PROCESS.INFOCLASS,
335 ProcessInformation: *anyopaque,338 ProcessInformation: *anyopaque,
336 ProcessInformationLength: ULONG,339 ProcessInformationLength: ULONG,
337 ReturnLength: ?*ULONG,340 ReturnLength: ?*ULONG,
...@@ -339,14 +342,14 @@ pub extern "ntdll" fn NtQueryInformationProcess(...@@ -339,14 +342,14 @@ pub extern "ntdll" fn NtQueryInformationProcess(
339342
340pub extern "ntdll" fn NtQueryInformationThread(343pub extern "ntdll" fn NtQueryInformationThread(
341 ThreadHandle: HANDLE,344 ThreadHandle: HANDLE,
342 ThreadInformationClass: THREADINFOCLASS,345 ThreadInformationClass: THREAD.INFOCLASS,
343 ThreadInformation: *anyopaque,346 ThreadInformation: *anyopaque,
344 ThreadInformationLength: ULONG,347 ThreadInformationLength: ULONG,
345 ReturnLength: ?*ULONG,348 ReturnLength: ?*ULONG,
346) callconv(.winapi) NTSTATUS;349) callconv(.winapi) NTSTATUS;
347350
348pub extern "ntdll" fn NtQuerySystemInformation(351pub extern "ntdll" fn NtQuerySystemInformation(
349 SystemInformationClass: SYSTEM_INFORMATION_CLASS,352 SystemInformationClass: SYSTEM.INFORMATION_CLASS,
350 SystemInformation: PVOID,353 SystemInformation: PVOID,
351 SystemInformationLength: ULONG,354 SystemInformationLength: ULONG,
352 ReturnLength: ?*ULONG,355 ReturnLength: ?*ULONG,
...@@ -354,15 +357,99 @@ pub extern "ntdll" fn NtQuerySystemInformation(...@@ -354,15 +357,99 @@ pub extern "ntdll" fn NtQuerySystemInformation(
354357
355// ref none358// ref none
356359
360pub extern "ntdll" fn LdrAddRefDll(
361 Flags: ULONG,
362 DllHandle: PVOID,
363) callconv(.winapi) NTSTATUS;
364pub extern "ntdll" fn LdrLoadDll(
365 DllPath: ?PCWSTR,
366 DllCharacteristics: ?*const ULONG,
367 DllName: *const UNICODE_STRING,
368 DllHandle: *PVOID,
369) callconv(.winapi) NTSTATUS;
370pub extern "ntdll" fn LdrUnloadDll(
371 DllHandle: PVOID,
372) callconv(.winapi) NTSTATUS;
373
374pub extern "ntdll" fn LdrFindEntryForAddress(
375 DllHandle: PVOID,
376 Entry: **LDR.DATA_TABLE_ENTRY,
377) callconv(.winapi) NTSTATUS;
378pub extern "ntdll" fn LdrGetDllFullName(
379 DllHandle: ?PVOID,
380 FullDllName: *UNICODE_STRING,
381) callconv(.winapi) NTSTATUS;
382pub extern "ntdll" fn LdrGetDllPath(
383 DllName: PCWSTR,
384 Flags: LDR.LOAD,
385 DllPath: *PWSTR,
386 SearchPaths: *PWSTR,
387) callconv(.winapi) NTSTATUS;
388
389pub extern "ntdll" fn LdrGetDllHandle(
390 DllPath: ?PCWSTR,
391 DllCharacteristics: ?*const ULONG,
392 DllName: *const UNICODE_STRING,
393 DllHandle: *PVOID,
394) callconv(.winapi) NTSTATUS;
395pub extern "ntdll" fn LdrGetDllHandleByMapping(
396 BaseAddress: PVOID,
397 DllHandle: *PVOID,
398) callconv(.winapi) NTSTATUS;
399pub extern "ntdll" fn LdrGetDllHandleByName(
400 BaseDllName: *const UNICODE_STRING,
401 FullDllName: *const UNICODE_STRING,
402 DllHandle: *PVOID,
403) callconv(.winapi) NTSTATUS;
404pub extern "ntdll" fn LdrGetDllHandleEx(
405 Flags: LDR.GET_DLL_HANDLE_EX,
406 DllPath: ?PCWSTR,
407 DllCharacteristics: ?*const ULONG,
408 DllName: *const UNICODE_STRING,
409 DllHandle: *PVOID,
410) callconv(.winapi) NTSTATUS;
411
412pub extern "ntdll" fn LdrGetProcedureAddress(
413 DllHandle: PVOID,
414 ProcedureName: *const ANSI_STRING,
415 ProcedureNumber: ULONG,
416 ProcedureAddress: *PVOID,
417) callconv(.winapi) NTSTATUS;
418pub extern "ntdll" fn LdrGetProcedureAddressEx(
419 DllHandle: PVOID,
420 ProcedureName: *const ANSI_STRING,
421 ProcedureNumber: ULONG,
422 ProcedureAddress: *PVOID,
423 Flags: LDR.GET_PROCEDURE_ADDRESS,
424) callconv(.winapi) NTSTATUS;
425pub extern "ntdll" fn LdrGetProcedureAddressForCaller(
426 DllHandle: PVOID,
427 ProcedureName: *const ANSI_STRING,
428 ProcedureNumber: ULONG,
429 ProcedureAddress: *PVOID,
430 Flags: LDR.GET_PROCEDURE_ADDRESS,
431 CallerAddress: PVOID,
432) callconv(.winapi) NTSTATUS;
433
434pub extern "ntdll" fn LdrRegisterDllNotification(
435 Flags: LDR.DLL_NOTIFICATION.REGISTER,
436 NotificationFunction: *const LDR.DLL_NOTIFICATION.FUNCTION,
437 Context: ?PVOID,
438 Cookie: *LDR.DLL_NOTIFICATION.COOKIE,
439) callconv(.winapi) NTSTATUS;
440pub extern "ntdll" fn LdrUnregisterDllNotification(
441 Cookie: LDR.DLL_NOTIFICATION.COOKIE,
442) callconv(.winapi) NTSTATUS;
443
357pub extern "ntdll" fn NtQueryAttributesFile(444pub extern "ntdll" fn NtQueryAttributesFile(
358 ObjectAttributes: *const OBJECT_ATTRIBUTES,445 ObjectAttributes: *const OBJECT.ATTRIBUTES,
359 FileAttributes: *FILE.BASIC_INFORMATION,446 FileAttributes: *FILE.BASIC_INFORMATION,
360) callconv(.winapi) NTSTATUS;447) callconv(.winapi) NTSTATUS;
361448
362pub extern "ntdll" fn NtCreateEvent(449pub extern "ntdll" fn NtCreateEvent(
363 EventHandle: *HANDLE,450 EventHandle: *HANDLE,
364 DesiredAccess: ACCESS_MASK,451 DesiredAccess: ACCESS_MASK,
365 ObjectAttributes: ?*const OBJECT_ATTRIBUTES,452 ObjectAttributes: ?*const OBJECT.ATTRIBUTES,
366 EventType: EVENT_TYPE,453 EventType: EVENT_TYPE,
367 InitialState: BOOLEAN,454 InitialState: BOOLEAN,
368) callconv(.winapi) NTSTATUS;455) callconv(.winapi) NTSTATUS;
...@@ -374,7 +461,7 @@ pub extern "ntdll" fn NtSetEvent(...@@ -374,7 +461,7 @@ pub extern "ntdll" fn NtSetEvent(
374pub extern "ntdll" fn NtCreateKeyedEvent(461pub extern "ntdll" fn NtCreateKeyedEvent(
375 KeyedEventHandle: *HANDLE,462 KeyedEventHandle: *HANDLE,
376 DesiredAccess: ACCESS_MASK,463 DesiredAccess: ACCESS_MASK,
377 ObjectAttributes: ?*const OBJECT_ATTRIBUTES,464 ObjectAttributes: ?*const OBJECT.ATTRIBUTES,
378 Flags: ULONG,465 Flags: ULONG,
379) callconv(.winapi) NTSTATUS;466) callconv(.winapi) NTSTATUS;
380pub extern "ntdll" fn NtReleaseKeyedEvent(467pub extern "ntdll" fn NtReleaseKeyedEvent(
...@@ -390,10 +477,57 @@ pub extern "ntdll" fn NtWaitForKeyedEvent(...@@ -390,10 +477,57 @@ pub extern "ntdll" fn NtWaitForKeyedEvent(
390 Timeout: ?*const LARGE_INTEGER,477 Timeout: ?*const LARGE_INTEGER,
391) callconv(.winapi) NTSTATUS;478) callconv(.winapi) NTSTATUS;
392479
480pub extern "ntdll" fn NtCancelSynchronousIoFile(
481 ThreadHandle: HANDLE,
482 IoRequestToCancel: ?*IO_STATUS_BLOCK,
483 IoStatusBlock: *IO_STATUS_BLOCK,
484) callconv(.winapi) NTSTATUS;
485pub extern "ntdll" fn NtCancelIoFile(
486 FileHandle: HANDLE,
487 IoStatusBlock: *IO_STATUS_BLOCK,
488) callconv(.winapi) NTSTATUS;
489pub extern "ntdll" fn NtCancelIoFileEx(
490 FileHandle: HANDLE,
491 IoRequestToCancel: *const IO_STATUS_BLOCK,
492 IoStatusBlock: *IO_STATUS_BLOCK,
493) callconv(.winapi) NTSTATUS;
494
495/// This function has been observed to return SUCCESS on timeout on Windows 10
496/// and TIMEOUT on Wine 10.0.
497///
498/// This function has been observed on Windows 11 such that positive interval
499/// is real time, which can cause waits to be interrupted by changing system
500/// time, however negative intervals are not affected by changes to system
501/// time.
502pub extern "ntdll" fn NtDelayExecution(
503 Alertable: BOOLEAN,
504 DelayInterval: *const LARGE_INTEGER,
505) callconv(.winapi) NTSTATUS;
506
507pub extern "ntdll" fn NtNotifyChangeDirectoryFileEx(
508 FileHandle: HANDLE,
509 Event: ?HANDLE,
510 ApcRoutine: ?*const IO_APC_ROUTINE,
511 ApcContext: ?*anyopaque,
512 IoStatusBlock: *IO_STATUS_BLOCK,
513 Buffer: *anyopaque,
514 Length: ULONG,
515 CompletionFilter: FILE.NOTIFY.CHANGE,
516 WatchTree: BOOLEAN,
517 DirectoryNotifyInformationClass: DIRECTORY.NOTIFY_INFORMATION_CLASS,
518) callconv(.winapi) NTSTATUS;
519
520pub extern "ntdll" fn NtOpenThread(
521 ThreadHandle: *HANDLE,
522 DesiredAccess: ACCESS_MASK,
523 ObjectAttributes: *const OBJECT.ATTRIBUTES,
524 ClientId: *const windows.CLIENT_ID,
525) callconv(.winapi) NTSTATUS;
526
393pub extern "ntdll" fn NtCreateNamedPipeFile(527pub extern "ntdll" fn NtCreateNamedPipeFile(
394 FileHandle: *HANDLE,528 FileHandle: *HANDLE,
395 DesiredAccess: ACCESS_MASK,529 DesiredAccess: ACCESS_MASK,
396 ObjectAttributes: *const OBJECT_ATTRIBUTES,530 ObjectAttributes: *const OBJECT.ATTRIBUTES,
397 IoStatusBlock: *IO_STATUS_BLOCK,531 IoStatusBlock: *IO_STATUS_BLOCK,
398 ShareAccess: FILE.SHARE,532 ShareAccess: FILE.SHARE,
399 CreateDisposition: FILE.CREATE_DISPOSITION,533 CreateDisposition: FILE.CREATE_DISPOSITION,
...@@ -437,7 +571,7 @@ pub extern "ntdll" fn NtUnmapViewOfSectionEx(...@@ -437,7 +571,7 @@ pub extern "ntdll" fn NtUnmapViewOfSectionEx(
437pub extern "ntdll" fn NtOpenKey(571pub extern "ntdll" fn NtOpenKey(
438 KeyHandle: *HANDLE,572 KeyHandle: *HANDLE,
439 DesiredAccess: ACCESS_MASK,573 DesiredAccess: ACCESS_MASK,
440 ObjectAttributes: *const OBJECT_ATTRIBUTES,574 ObjectAttributes: *const OBJECT.ATTRIBUTES,
441) callconv(.winapi) NTSTATUS;575) callconv(.winapi) NTSTATUS;
442576
443pub extern "ntdll" fn NtQueueApcThread(577pub extern "ntdll" fn NtQueueApcThread(
...@@ -470,6 +604,19 @@ pub extern "ntdll" fn NtProtectVirtualMemory(...@@ -470,6 +604,19 @@ pub extern "ntdll" fn NtProtectVirtualMemory(
470 OldAccessProtection: *PAGE,604 OldAccessProtection: *PAGE,
471) callconv(.winapi) NTSTATUS;605) callconv(.winapi) NTSTATUS;
472606
607pub extern "ntdll" fn NtWaitForAlertByThreadId(
608 Address: ?*const anyopaque,
609 Timeout: ?*const LARGE_INTEGER,
610) callconv(.winapi) NTSTATUS;
611pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS;
612pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS;
613pub extern "ntdll" fn NtAlertMultipleThreadByThreadId(
614 ThreadIds: [*]const ULONG_PTR,
615 ThreadCount: ULONG,
616 Unknown1: ?*const anyopaque,
617 Unknown2: ?*const anyopaque,
618) callconv(.winapi) NTSTATUS;
619
473pub extern "ntdll" fn NtYieldExecution() callconv(.winapi) NTSTATUS;620pub extern "ntdll" fn NtYieldExecution() callconv(.winapi) NTSTATUS;
474621
475pub extern "ntdll" fn RtlAddVectoredExceptionHandler(622pub extern "ntdll" fn RtlAddVectoredExceptionHandler(
...@@ -527,10 +674,6 @@ pub extern "ntdll" fn RtlQueryPerformanceCounter(...@@ -527,10 +674,6 @@ pub extern "ntdll" fn RtlQueryPerformanceCounter(
527pub extern "ntdll" fn RtlQueryPerformanceFrequency(674pub extern "ntdll" fn RtlQueryPerformanceFrequency(
528 PerformanceFrequency: *LARGE_INTEGER,675 PerformanceFrequency: *LARGE_INTEGER,
529) callconv(.winapi) BOOL;676) callconv(.winapi) BOOL;
530pub extern "ntdll" fn NtQueryPerformanceCounter(
531 PerformanceCounter: *LARGE_INTEGER,
532 PerformanceFrequency: ?*LARGE_INTEGER,
533) callconv(.winapi) NTSTATUS;
534677
535pub extern "ntdll" fn RtlReAllocateHeap(678pub extern "ntdll" fn RtlReAllocateHeap(
536 HeapHandle: *HEAP,679 HeapHandle: *HEAP,
...@@ -539,8 +682,17 @@ pub extern "ntdll" fn RtlReAllocateHeap(...@@ -539,8 +682,17 @@ pub extern "ntdll" fn RtlReAllocateHeap(
539 Size: SIZE_T,682 Size: SIZE_T,
540) callconv(.winapi) ?PVOID;683) callconv(.winapi) ?PVOID;
541684
685pub extern "ntdll" fn RtlReportSilentProcessExit(
686 ProcessHandle: HANDLE,
687 ExitStatus: NTSTATUS,
688) callconv(.winapi) NTSTATUS;
689pub extern "ntdll" fn NtTerminateProcess(
690 ProcessHandle: ?HANDLE,
691 ExitStatus: NTSTATUS,
692) callconv(.winapi) NTSTATUS;
693
542pub extern "ntdll" fn RtlSetCurrentDirectory_U(694pub extern "ntdll" fn RtlSetCurrentDirectory_U(
543 PathName: *UNICODE_STRING,695 PathName: *const UNICODE_STRING,
544) callconv(.winapi) NTSTATUS;696) callconv(.winapi) NTSTATUS;
545697
546pub extern "ntdll" fn RtlTryAcquireSRWLockExclusive(698pub extern "ntdll" fn RtlTryAcquireSRWLockExclusive(
...@@ -572,52 +724,3 @@ pub extern "ntdll" fn RtlWakeConditionVariable(...@@ -572,52 +724,3 @@ pub extern "ntdll" fn RtlWakeConditionVariable(
572pub extern "ntdll" fn RtlWakeAllConditionVariable(724pub extern "ntdll" fn RtlWakeAllConditionVariable(
573 ConditionVariable: *CONDITION_VARIABLE,725 ConditionVariable: *CONDITION_VARIABLE,
574) callconv(.winapi) void;726) callconv(.winapi) void;
575
576pub extern "ntdll" fn NtWaitForAlertByThreadId(
577 Address: ?*const anyopaque,
578 Timeout: ?*const LARGE_INTEGER,
579) callconv(.winapi) NTSTATUS;
580pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS;
581pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS;
582pub extern "ntdll" fn NtAlertMultipleThreadByThreadId(
583 ThreadIds: [*]const ULONG_PTR,
584 ThreadCount: ULONG,
585 Unknown1: ?*const anyopaque,
586 Unknown2: ?*const anyopaque,
587) callconv(.winapi) NTSTATUS;
588
589pub extern "ntdll" fn NtOpenThread(
590 ThreadHandle: *HANDLE,
591 DesiredAccess: ACCESS_MASK,
592 ObjectAttributes: *const OBJECT_ATTRIBUTES,
593 ClientId: *const windows.CLIENT_ID,
594) callconv(.winapi) NTSTATUS;
595
596pub extern "ntdll" fn NtCancelSynchronousIoFile(
597 ThreadHandle: HANDLE,
598 IoRequestToCancel: ?*IO_STATUS_BLOCK,
599 IoStatusBlock: *IO_STATUS_BLOCK,
600) callconv(.winapi) NTSTATUS;
601
602/// This function has been observed to return SUCCESS on timeout on Windows 10
603/// and TIMEOUT on Wine 10.0.
604///
605/// This function has been observed on Windows 11 such that positive interval
606/// is real time, which can cause waits to be interrupted by changing system
607/// time, however negative intervals are not affected by changes to system
608/// time.
609pub extern "ntdll" fn NtDelayExecution(
610 Alertable: BOOLEAN,
611 DelayInterval: *const LARGE_INTEGER,
612) callconv(.winapi) NTSTATUS;
613
614pub extern "ntdll" fn NtCancelIoFile(
615 FileHandle: HANDLE,
616 IoStatusBlock: *IO_STATUS_BLOCK,
617) callconv(.winapi) NTSTATUS;
618
619pub extern "ntdll" fn NtCancelIoFileEx(
620 FileHandle: HANDLE,
621 IoRequestToCancel: *const IO_STATUS_BLOCK,
622 IoStatusBlock: *IO_STATUS_BLOCK,
623) callconv(.winapi) NTSTATUS;
lib/std/os/windows/win32error.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1/// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d1/// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
2pub const Win32Error = enum(u16) {2pub const Win32Error = enum(u32) {
3 /// The operation completed successfully.3 /// The operation completed successfully.
4 SUCCESS = 0,4 SUCCESS = 0,
5 /// Incorrect function.5 /// Incorrect function.
lib/std/process.zig+4-4
...@@ -243,7 +243,7 @@ pub fn getBaseAddress() usize {...@@ -243,7 +243,7 @@ pub fn getBaseAddress() usize {
243 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {243 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {
244 return @intFromPtr(&std.c._mh_execute_header);244 return @intFromPtr(&std.c._mh_execute_header);
245 },245 },
246 .windows => return @intFromPtr(windows.kernel32.GetModuleHandleW(null)),246 .windows => return @intFromPtr(windows.peb().ImageBaseAddress),
247 else => @compileError("Unsupported OS"),247 else => @compileError("Unsupported OS"),
248 }248 }
249}249}
...@@ -606,11 +606,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {...@@ -606,11 +606,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
606 return @as(u64, @bitCast(physmem));606 return @as(u64, @bitCast(physmem));
607 },607 },
608 .windows => {608 .windows => {
609 var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;609 var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined;
610 const rc = windows.ntdll.NtQuerySystemInformation(610 const rc = windows.ntdll.NtQuerySystemInformation(
611 .SystemBasicInformation,611 .Basic,
612 &sbi,612 &sbi,
613 @sizeOf(windows.SYSTEM_BASIC_INFORMATION),613 @sizeOf(windows.SYSTEM.BASIC_INFORMATION),
614 null,614 null,
615 );615 );
616 if (rc != .SUCCESS) {616 if (rc != .SUCCESS) {
lib/std/process/Child.zig+1-1
...@@ -86,7 +86,7 @@ pub const ResourceUsageStatistics = struct {...@@ -86,7 +86,7 @@ pub const ResourceUsageStatistics = struct {
86 .visionos,86 .visionos,
87 .watchos,87 .watchos,
88 => @as(?std.posix.rusage, null),88 => @as(?std.posix.rusage, null),
89 .windows => @as(?std.os.windows.VM_COUNTERS, null),89 .windows => @as(?std.os.windows.PROCESS.VM_COUNTERS, null),
90 else => {},90 else => {},
91 };91 };
92};92};
lib/std/start.zig+5-9
...@@ -473,10 +473,9 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn {...@@ -473,10 +473,9 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn {
473 std.Thread.maybeAttachSignalStack();473 std.Thread.maybeAttachSignalStack();
474 std.debug.maybeEnableSegfaultHandler();474 std.debug.maybeEnableSegfaultHandler();
475475
476 const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine;476 std.os.windows.ntdll.RtlExitUserProcess(
477 const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)];477 callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global),
478478 );
479 std.os.windows.ntdll.RtlExitUserProcess(callMain(cmd_line_w, .global));
480}479}
481480
482fn wWinMainCRTStartup() callconv(.withStackAlign(.c, 1)) noreturn {481fn wWinMainCRTStartup() callconv(.withStackAlign(.c, 1)) noreturn {
...@@ -647,9 +646,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal...@@ -647,9 +646,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
647 // values in their intended encoding from the PEB instead.646 // values in their intended encoding from the PEB instead.
648 std.Thread.maybeAttachSignalStack();647 std.Thread.maybeAttachSignalStack();
649 std.debug.maybeEnableSegfaultHandler();648 std.debug.maybeEnableSegfaultHandler();
650 const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine;649 return callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global);
651 const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)];
652 return callMain(cmd_line_w, .global);
653 },650 },
654 else => {},651 else => {},
655 }652 }
...@@ -776,8 +773,7 @@ fn call_wWinMain() std.os.windows.INT {...@@ -776,8 +773,7 @@ fn call_wWinMain() std.os.windows.INT {
776 // - With STARTF_USESHOWWINDOW unset:773 // - With STARTF_USESHOWWINDOW unset:
777 // - nShowCmd is always SW_SHOWDEFAULT774 // - nShowCmd is always SW_SHOWDEFAULT
778 const SW_SHOWDEFAULT = 10;775 const SW_SHOWDEFAULT = 10;
779 const STARTF_USESHOWWINDOW = 1;776 if (peb.ProcessParameters.dwFlags & std.os.windows.STARTF_USESHOWWINDOW != 0) {
780 if (peb.ProcessParameters.dwFlags & STARTF_USESHOWWINDOW != 0) {
781 break :nShowCmd @truncate(peb.ProcessParameters.dwShowWindow);777 break :nShowCmd @truncate(peb.ProcessParameters.dwShowWindow);
782 }778 }
783 break :nShowCmd SW_SHOWDEFAULT;779 break :nShowCmd SW_SHOWDEFAULT;
lib/std/zig/system/windows.zig+5-5
...@@ -100,11 +100,11 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {...@@ -100,11 +100,11 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {
100 REG.MULTI_SZ,100 REG.MULTI_SZ,
101 => {101 => {
102 comptime assert(@sizeOf(std.os.windows.UNICODE_STRING) % 2 == 0);102 comptime assert(@sizeOf(std.os.windows.UNICODE_STRING) % 2 == 0);
103 const unicode = @as(*std.os.windows.UNICODE_STRING, @ptrCast(&tmp_bufs[i]));103 const unicode: *std.os.windows.UNICODE_STRING = @ptrCast(&tmp_bufs[i]);
104 unicode.* = .{104 unicode.* = .{
105 .Length = 0,105 .Length = 0,
106 .MaximumLength = max_value_len - @sizeOf(std.os.windows.UNICODE_STRING),106 .MaximumLength = max_value_len - @sizeOf(std.os.windows.UNICODE_STRING),
107 .Buffer = @as([*]u16, @ptrCast(tmp_bufs[i][@sizeOf(std.os.windows.UNICODE_STRING)..])),107 .Buffer = @ptrCast(tmp_bufs[i][@sizeOf(std.os.windows.UNICODE_STRING)..]),
108 };108 };
109 break :blk unicode;109 break :blk unicode;
110 },110 },
...@@ -159,8 +159,8 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {...@@ -159,8 +159,8 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {
159 REG.MULTI_SZ,159 REG.MULTI_SZ,
160 => {160 => {
161 var buf = @field(args, field.name).value_buf;161 var buf = @field(args, field.name).value_buf;
162 const entry = @as(*align(1) const std.os.windows.UNICODE_STRING, @ptrCast(table[i + 1].EntryContext));162 const entry: *const std.os.windows.UNICODE_STRING = @ptrCast(table[i + 1].EntryContext);
163 const len = try std.unicode.utf16LeToUtf8(buf, entry.Buffer.?[0 .. entry.Length / 2]);163 const len = try std.unicode.utf16LeToUtf8(buf, entry.slice());
164 buf[len] = 0;164 buf[len] = 0;
165 },165 },
166166
...@@ -168,7 +168,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {...@@ -168,7 +168,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {
168 REG.DWORD_BIG_ENDIAN,168 REG.DWORD_BIG_ENDIAN,
169 REG.QWORD,169 REG.QWORD,
170 => {170 => {
171 const entry = @as([*]align(1) const u8, @ptrCast(table[i + 1].EntryContext));171 const entry: [*]const u8 = @ptrCast(table[i + 1].EntryContext);
172 switch (@field(args, field.name).value_type) {172 switch (@field(args, field.name).value_type) {
173 REG.DWORD, REG.DWORD_BIG_ENDIAN => {173 REG.DWORD, REG.DWORD_BIG_ENDIAN => {
174 @memcpy(@field(args, field.name).value_buf[0..4], entry[0..4]);174 @memcpy(@field(args, field.name).value_buf[0..4], entry[0..4]);
lib/zig.h+24-4
...@@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a...@@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a
41484148
4149#if defined(zig_thumb)4149#if defined(zig_thumb)
41504150
4151static inline void* zig_thumb_windows_teb(void) {4151static inline void* zig_windows_teb(void) {
4152 void* teb = 0;4152 void* teb = 0;
4153#if defined(zig_msvc)4153#if defined(zig_msvc)
4154 teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2);4154 teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2);
...@@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) {...@@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) {
41604160
4161#elif defined(zig_aarch64)4161#elif defined(zig_aarch64)
41624162
4163static inline void* zig_aarch64_windows_teb(void) {4163static inline void* zig_windows_teb(void) {
4164 void* teb = 0;4164 void* teb = 0;
4165#if defined(zig_msvc)4165#if defined(zig_msvc)
4166 teb = (void*)__readx18qword(0x0);4166 teb = (void*)__readx18qword(0x0);
...@@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) {...@@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) {
41724172
4173#elif defined(zig_x86_32)4173#elif defined(zig_x86_32)
41744174
4175static inline void* zig_x86_windows_teb(void) {4175static inline void* zig_windows_teb(void) {
4176 void* teb = 0;4176 void* teb = 0;
4177#if defined(zig_msvc)4177#if defined(zig_msvc)
4178 teb = (void*)__readfsdword(0x18);4178 teb = (void*)__readfsdword(0x18);
...@@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) {...@@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) {
4182 return teb;4182 return teb;
4183}4183}
41844184
4185static inline void* zig_windows_peb(void) {
4186 void* peb = 0;
4187#if defined(zig_msvc)
4188 peb = (void*)__readfsdword(0x30);
4189#elif defined(zig_gnuc_asm)
4190 __asm__ ("movl %%fs:0x30, %[ptr]" : [ptr] "=r" (peb));
4191#endif
4192 return peb;
4193}
4194
4185#elif defined(zig_x86_64)4195#elif defined(zig_x86_64)
41864196
4187static inline void* zig_x86_64_windows_teb(void) {4197static inline void* zig_windows_teb(void) {
4188 void* teb = 0;4198 void* teb = 0;
4189#if defined(zig_msvc)4199#if defined(zig_msvc)
4190 teb = (void*)__readgsqword(0x30);4200 teb = (void*)__readgsqword(0x30);
...@@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) {...@@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) {
4194 return teb;4204 return teb;
4195}4205}
41964206
4207static inline void* zig_windows_peb(void) {
4208 void* peb = 0;
4209#if defined(zig_msvc)
4210 peb = (void*)__readgsqword(0x60);
4211#elif defined(zig_gnuc_asm)
4212 __asm__ ("movq %%gs:0x60, %[ptr]" : [ptr] "=r" (peb));
4213#endif
4214 return peb;
4215}
4216
4197#endif4217#endif
41984218
4199#if defined(zig_loongarch)4219#if defined(zig_loongarch)
stage1/zig.h+24-4
...@@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a...@@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a
41484148
4149#if defined(zig_thumb)4149#if defined(zig_thumb)
41504150
4151static inline void* zig_thumb_windows_teb(void) {4151static inline void* zig_windows_teb(void) {
4152 void* teb = 0;4152 void* teb = 0;
4153#if defined(zig_msvc)4153#if defined(zig_msvc)
4154 teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2);4154 teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2);
...@@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) {...@@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) {
41604160
4161#elif defined(zig_aarch64)4161#elif defined(zig_aarch64)
41624162
4163static inline void* zig_aarch64_windows_teb(void) {4163static inline void* zig_windows_teb(void) {
4164 void* teb = 0;4164 void* teb = 0;
4165#if defined(zig_msvc)4165#if defined(zig_msvc)
4166 teb = (void*)__readx18qword(0x0);4166 teb = (void*)__readx18qword(0x0);
...@@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) {...@@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) {
41724172
4173#elif defined(zig_x86_32)4173#elif defined(zig_x86_32)
41744174
4175static inline void* zig_x86_windows_teb(void) {4175static inline void* zig_windows_teb(void) {
4176 void* teb = 0;4176 void* teb = 0;
4177#if defined(zig_msvc)4177#if defined(zig_msvc)
4178 teb = (void*)__readfsdword(0x18);4178 teb = (void*)__readfsdword(0x18);
...@@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) {...@@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) {
4182 return teb;4182 return teb;
4183}4183}
41844184
4185static inline void* zig_windows_peb(void) {
4186 void* peb = 0;
4187#if defined(zig_msvc)
4188 peb = (void*)__readfsdword(0x30);
4189#elif defined(zig_gnuc_asm)
4190 __asm__ ("movl %%fs:0x30, %[ptr]" : [ptr] "=r" (peb));
4191#endif
4192 return peb;
4193}
4194
4185#elif defined(zig_x86_64)4195#elif defined(zig_x86_64)
41864196
4187static inline void* zig_x86_64_windows_teb(void) {4197static inline void* zig_windows_teb(void) {
4188 void* teb = 0;4198 void* teb = 0;
4189#if defined(zig_msvc)4199#if defined(zig_msvc)
4190 teb = (void*)__readgsqword(0x30);4200 teb = (void*)__readgsqword(0x30);
...@@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) {...@@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) {
4194 return teb;4204 return teb;
4195}4205}
41964206
4207static inline void* zig_windows_peb(void) {
4208 void* peb = 0;
4209#if defined(zig_msvc)
4210 peb = (void*)__readgsqword(0x60);
4211#elif defined(zig_gnuc_asm)
4212 __asm__ ("movq %%gs:0x60, %[ptr]" : [ptr] "=r" (peb));
4213#endif
4214 return peb;
4215}
4216
4197#endif4217#endif
41984218
4199#if defined(zig_loongarch)4219#if defined(zig_loongarch)
test/standalone/coff_dwarf/main.zig+3-4
...@@ -4,17 +4,16 @@ const fatal = std.process.fatal;...@@ -4,17 +4,16 @@ const fatal = std.process.fatal;
4extern fn add(a: u32, b: u32, addr: *usize) u32;4extern fn add(a: u32, b: u32, addr: *usize) u32;
55
6pub fn main(init: std.process.Init) void {6pub fn main(init: std.process.Init) void {
7 const gpa = init.gpa;
8 const io = init.io;7 const io = init.io;
98
10 var di: std.debug.SelfInfo = .init;9 var di: std.debug.SelfInfo = .init;
11 defer di.deinit(gpa);10 defer di.deinit(io);
1211
13 var add_addr: usize = undefined;12 var add_addr: usize = undefined;
14 _ = add(1, 2, &add_addr);13 _ = add(1, 2, &add_addr);
1514
16 const symbol = di.getSymbol(gpa, io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err});15 const symbol = di.getSymbol(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err});
17 defer if (symbol.source_location) |sl| gpa.free(sl.file_name);16 defer if (symbol.source_location) |sl| std.debug.getDebugInfoAllocator().free(sl.file_name);
1817
19 if (symbol.name == null) fatal("failed to resolve symbol name", .{});18 if (symbol.name == null) fatal("failed to resolve symbol name", .{});
20 if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{});19 if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{});
test/standalone/windows_argv/fuzz.zig+12-6
...@@ -127,7 +127,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO...@@ -127,7 +127,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
127 .hStdOutput = null,127 .hStdOutput = null,
128 .hStdError = windows.peb().ProcessParameters.hStdError,128 .hStdError = windows.peb().ProcessParameters.hStdError,
129 };129 };
130 var proc_info: windows.PROCESS_INFORMATION = undefined;130 var proc_info: windows.PROCESS.INFORMATION = undefined;
131131
132 if (windows.kernel32.CreateProcessW(132 if (windows.kernel32.CreateProcessW(
133 @constCast(verify_path.ptr),133 @constCast(verify_path.ptr),
...@@ -141,7 +141,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO...@@ -141,7 +141,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
141 &startup_info,141 &startup_info,
142 &proc_info,142 &proc_info,
143 ) == 0) {143 ) == 0) {
144 std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.kernel32.GetLastError()});144 std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.GetLastError()});
145 }145 }
146146
147 windows.CloseHandle(proc_info.hThread);147 windows.CloseHandle(proc_info.hThread);
...@@ -156,9 +156,15 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO...@@ -156,9 +156,15 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
156 else => |status| return windows.unexpectedStatus(status),156 else => |status| return windows.unexpectedStatus(status),
157 }157 }
158158
159 var exit_code: windows.DWORD = undefined;159 var info: windows.PROCESS.BASIC_INFORMATION = undefined;
160 if (windows.kernel32.GetExitCodeProcess(child_proc, &exit_code) == 0) {160 switch (windows.ntdll.NtQueryInformationProcess(
161 return error.UnableToGetExitCode;161 child_proc,
162 .BasicInformation,
163 &info,
164 @sizeOf(windows.PROCESS.BASIC_INFORMATION),
165 null,
166 )) {
167 .SUCCESS => return @intFromEnum(info.ExitStatus),
168 else => return error.UnableToGetExitCode,
162 }169 }
163 return exit_code;
164}170}
test/standalone/windows_argv/lib.zig+3-3
...@@ -16,9 +16,9 @@ fn testArgv(expected_args: []const [*:0]const u16) !void {...@@ -16,9 +16,9 @@ fn testArgv(expected_args: []const [*:0]const u16) !void {
16 defer arena_state.deinit();16 defer arena_state.deinit();
17 const allocator = arena_state.allocator();17 const allocator = arena_state.allocator();
1818
19 const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine;19 const raw_args: std.process.Args = .{
20 const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)];20 .vector = std.os.windows.peb().ProcessParameters.CommandLine.slice(),
21 const raw_args: std.process.Args = .{ .vector = cmd_line_w };21 };
22 const args = try raw_args.toSlice(allocator);22 const args = try raw_args.toSlice(allocator);
23 var wtf8_buf = std.array_list.Managed(u8).init(allocator);23 var wtf8_buf = std.array_list.Managed(u8).init(allocator);
2424