| author | |
| committer | |
| log | b5bd4946067d3796855e0b4b12219dfc28e15e8f |
| tree | 5fc2b5e02c308f0b9123c24e8c7c88925899d180 |
| parent | 12cb5b92851f601c44d48deadea9934146edcffa |
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 | 35 | |
| 36 | 36 | # CMake gives a syntax error when file paths with backward slashes are used. |
| 37 | 37 | # Here, we use forward slashes only to work around this. |
| 38 | & cmake .. ` | |
| 38 | cmake .. ` | |
| 39 | 39 | -GNinja ` |
| 40 | 40 | -DCMAKE_INSTALL_PREFIX="stage3-debug" ` |
| 41 | 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` |
| ... | ... | @@ -54,7 +54,7 @@ ninja install |
| 54 | 54 | CheckLastExitCode |
| 55 | 55 | |
| 56 | 56 | Write-Output "Main test suite..." |
| 57 | & "stage3-debug\bin\zig.exe" build test docs ` | |
| 57 | stage3-debug\bin\zig build test docs ` | |
| 58 | 58 | --maxrss $ZSF_MAX_RSS ` |
| 59 | 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 60 | 60 | --search-prefix "$PREFIX_PATH" ` |
| ... | ... | @@ -66,26 +66,25 @@ Write-Output "Main test suite..." |
| 66 | 66 | CheckLastExitCode |
| 67 | 67 | |
| 68 | 68 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." |
| 69 | & "stage3-debug\bin\zig.exe" test ` | |
| 70 | ..\test\behavior.zig ` | |
| 69 | stage3-debug\bin\zig build-obj ` | |
| 71 | 70 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 72 | 71 | -ofmt=c ` |
| 73 | -femit-bin="test-x86_64-windows-msvc.c" ` | |
| 74 | --test-no-exec ` | |
| 72 | -OReleaseSmall ` | |
| 73 | --name compiler_rt ` | |
| 74 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | |
| 75 | 75 | -target x86_64-windows-msvc ` |
| 76 | -lc | |
| 76 | -lc ` | |
| 77 | ..\lib\compiler_rt.zig | |
| 77 | 78 | CheckLastExitCode |
| 78 | 79 | |
| 79 | & "stage3-debug\bin\zig.exe" build-obj ` | |
| 80 | stage3-debug\bin\zig test ` | |
| 80 | 81 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 81 | 82 | -ofmt=c ` |
| 82 | -OReleaseSmall ` | |
| 83 | --name compiler_rt ` | |
| 84 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | |
| 85 | --dep build_options ` | |
| 83 | -femit-bin="behavior-x86_64-windows-msvc.c" ` | |
| 84 | --test-no-exec ` | |
| 86 | 85 | -target x86_64-windows-msvc ` |
| 87 | -Mroot="..\lib\compiler_rt.zig" ` | |
| 88 | -Mbuild_options="config.zig" | |
| 86 | -lc ` | |
| 87 | ..\test\behavior.zig | |
| 89 | 88 | CheckLastExitCode |
| 90 | 89 | |
| 91 | 90 | Import-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 | 96 | CheckLastExitCode |
| 98 | 97 | |
| 99 | 98 | Write-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.lib | |
| 99 | cl /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 | |
| 101 | 100 | CheckLastExitCode |
| 102 | 101 | |
| 103 | & .\test-x86_64-windows-msvc.exe | |
| 102 | .\behavior-x86_64-windows-msvc | |
| 104 | 103 | CheckLastExitCode |
ci/x86_64-windows-release.ps1+16-17| ... | ... | @@ -35,7 +35,7 @@ Set-Location -Path 'build-release' |
| 35 | 35 | |
| 36 | 36 | # CMake gives a syntax error when file paths with backward slashes are used. |
| 37 | 37 | # Here, we use forward slashes only to work around this. |
| 38 | & cmake .. ` | |
| 38 | cmake .. ` | |
| 39 | 39 | -GNinja ` |
| 40 | 40 | -DCMAKE_INSTALL_PREFIX="stage3-release" ` |
| 41 | 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` |
| ... | ... | @@ -54,7 +54,7 @@ ninja install |
| 54 | 54 | CheckLastExitCode |
| 55 | 55 | |
| 56 | 56 | Write-Output "Main test suite..." |
| 57 | & "stage3-release\bin\zig.exe" build test docs ` | |
| 57 | stage3-release\bin\zig.exe build test docs ` | |
| 58 | 58 | --maxrss $ZSF_MAX_RSS ` |
| 59 | 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 60 | 60 | --search-prefix "$PREFIX_PATH" ` |
| ... | ... | @@ -67,7 +67,7 @@ CheckLastExitCode |
| 67 | 67 | |
| 68 | 68 | # Ensure that stage3 and stage4 are byte-for-byte identical. |
| 69 | 69 | Write-Output "Build and compare stage4..." |
| 70 | & "stage3-release\bin\zig.exe" build ` | |
| 70 | stage3-release\bin\zig.exe build ` | |
| 71 | 71 | --prefix stage4-release ` |
| 72 | 72 | -Denable-llvm ` |
| 73 | 73 | -Dno-lib ` |
| ... | ... | @@ -85,26 +85,25 @@ Compare-Object (Get-Content stage3-release\bin\zig.exe) (Get-Content stage4-rele |
| 85 | 85 | CheckLastExitCode |
| 86 | 86 | |
| 87 | 87 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." |
| 88 | & "stage3-release\bin\zig.exe" test ` | |
| 89 | ..\test\behavior.zig ` | |
| 88 | stage3-release\bin\zig.exe build-obj ` | |
| 90 | 89 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 91 | 90 | -ofmt=c ` |
| 92 | -femit-bin="test-x86_64-windows-msvc.c" ` | |
| 93 | --test-no-exec ` | |
| 91 | -OReleaseSmall ` | |
| 92 | --name compiler_rt ` | |
| 93 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | |
| 94 | 94 | -target x86_64-windows-msvc ` |
| 95 | -lc | |
| 95 | -lc ` | |
| 96 | ..\lib\compiler_rt.zig | |
| 96 | 97 | CheckLastExitCode |
| 97 | 98 | |
| 98 | & "stage3-release\bin\zig.exe" build-obj ` | |
| 99 | stage3-release\bin\zig.exe test ` | |
| 99 | 100 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 100 | 101 | -ofmt=c ` |
| 101 | -OReleaseSmall ` | |
| 102 | --name compiler_rt ` | |
| 103 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | |
| 104 | --dep build_options ` | |
| 102 | -femit-bin="behavior-x86_64-windows-msvc.c" ` | |
| 103 | --test-no-exec ` | |
| 105 | 104 | -target x86_64-windows-msvc ` |
| 106 | -Mroot="..\lib\compiler_rt.zig" ` | |
| 107 | -Mbuild_options="config.zig" | |
| 105 | -lc ` | |
| 106 | ..\test\behavior.zig | |
| 108 | 107 | CheckLastExitCode |
| 109 | 108 | |
| 110 | 109 | Import-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 | 115 | CheckLastExitCode |
| 117 | 116 | |
| 118 | 117 | Write-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.lib | |
| 118 | cl /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 | |
| 120 | 119 | CheckLastExitCode |
| 121 | 120 | |
| 122 | & .\test-x86_64-windows-msvc.exe | |
| 121 | .\behavior-x86_64-windows-msvc | |
| 123 | 122 | CheckLastExitCode |
lib/compiler/build_runner.zig+1-1| ... | ... | @@ -621,7 +621,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 621 | 621 | }) catch &caption_buf; |
| 622 | 622 | var debouncing_node = main_progress_node.start(caption, 0); |
| 623 | 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 | 625 | .timeout => { |
| 626 | 626 | assert(in_debounce); |
| 627 | 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 | 632 | |
| 633 | 633 | export fn fuzzer_unslide_address(addr: usize) usize { |
| 634 | 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 | 636 | std.debug.panic("failed to find virtual address slide: {t}", .{err}); |
| 637 | 637 | }; |
| 638 | 638 | return addr - slide; |
lib/std/Build/Watch.zig+145-133| ... | ... | @@ -180,7 +180,7 @@ const Os = switch (builtin.os.tag) { |
| 180 | 180 | const gop = try w.dir_table.getOrPut(gpa, path); |
| 181 | 181 | if (!gop.found_existing) { |
| 182 | 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 | 184 | error.FileNotFound => { |
| 185 | 185 | std.debug.assert(w.dir_table.swapRemove(path)); |
| 186 | 186 | continue; |
| ... | ... | @@ -291,12 +291,13 @@ const Os = switch (builtin.os.tag) { |
| 291 | 291 | w.dir_count = w.dir_table.count(); |
| 292 | 292 | } |
| 293 | 293 | |
| 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 | 296 | const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms()); |
| 296 | 297 | if (events_len == 0) |
| 297 | 298 | return .timeout; |
| 298 | 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 | 301 | return .dirty; |
| 301 | 302 | } |
| 302 | 303 | return .clean; |
| ... | ... | @@ -306,12 +307,8 @@ const Os = switch (builtin.os.tag) { |
| 306 | 307 | const windows = std.os.windows; |
| 307 | 308 | |
| 308 | 309 | /// Keyed differently but indexes correspond 1:1 with `dir_table`. |
| 309 | handle_table: HandleTable, | |
| 310 | dir_list: std.AutoArrayHashMapUnmanaged(usize, *Directory), | |
| 311 | io_cp: ?windows.HANDLE, | |
| 312 | counter: usize = 0, | |
| 313 | ||
| 314 | const HandleTable = std.AutoArrayHashMapUnmanaged(FileId, ReactionSet); | |
| 310 | handle_table: std.ArrayHashMapUnmanaged(*Directory, void, Directory.TableAdapter, false), | |
| 311 | ready_dirs: std.DoublyLinkedList, | |
| 315 | 312 | |
| 316 | 313 | const FileId = struct { |
| 317 | 314 | volumeSerialNumber: windows.ULONG, |
| ... | ... | @@ -319,55 +316,61 @@ const Os = switch (builtin.os.tag) { |
| 319 | 316 | }; |
| 320 | 317 | |
| 321 | 318 | const Directory = struct { |
| 322 | handle: windows.HANDLE, | |
| 319 | reaction_set: ReactionSet, | |
| 323 | 320 | id: FileId, |
| 324 | overlapped: windows.OVERLAPPED, | |
| 321 | file: Io.File, | |
| 322 | state: enum { idle, listening, ready }, | |
| 323 | iosb: windows.IO_STATUS_BLOCK, | |
| 325 | 324 | // 64 KB is the packet size limit when monitoring over a network. |
| 326 | 325 | // 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, | |
| 328 | 328 | |
| 329 | 329 | /// Start listening for events, buffer field will be overwritten eventually. |
| 330 | fn startListening(self: *@This()) !void { | |
| 331 | const r = windows.kernel32.ReadDirectoryChangesW( | |
| 332 | self.handle, | |
| 333 | @ptrCast(&self.buffer), | |
| 334 | self.buffer.len, | |
| 335 | 0, | |
| 330 | fn startListening(dir: *Directory, w: *Watch) !void { | |
| 331 | assert(dir.file.flags.nonblocking); | |
| 332 | assert(dir.state == .idle); | |
| 333 | switch (windows.ntdll.NtNotifyChangeDirectoryFileEx( | |
| 334 | dir.file.handle, | |
| 335 | null, | |
| 336 | &notifyApc, | |
| 337 | w, | |
| 338 | &dir.iosb, | |
| 339 | &dir.buffer, | |
| 340 | dir.buffer.len, | |
| 336 | 341 | .{ |
| 337 | .creation = true, | |
| 338 | .dir_name = true, | |
| 339 | .file_name = true, | |
| 340 | .last_write = true, | |
| 341 | .size = true, | |
| 342 | .FILE_NAME = true, | |
| 343 | .DIR_NAME = true, | |
| 344 | .SIZE = true, | |
| 345 | .LAST_WRITE = true, | |
| 346 | .CREATION = true, | |
| 342 | 347 | }, |
| 343 | null, | |
| 344 | &self.overlapped, | |
| 345 | null, | |
| 346 | ); | |
| 347 | if (r == windows.FALSE) { | |
| 348 | switch (windows.GetLastError()) { | |
| 349 | .INVALID_FUNCTION => return error.ReadDirectoryChangesUnsupported, | |
| 350 | else => |err| return windows.unexpectedError(err), | |
| 351 | } | |
| 348 | windows.FALSE, | |
| 349 | .Notify, | |
| 350 | )) { | |
| 351 | .SUCCESS, .PENDING => dir.state = .listening, | |
| 352 | .ILLEGAL_FUNCTION => return error.ReadDirectoryChangesUnsupported, | |
| 353 | else => |status| return windows.unexpectedStatus(status), | |
| 352 | 354 | } |
| 353 | 355 | } |
| 354 | 356 | |
| 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 | 367 | // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW) |
| 357 | 368 | // It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW. |
| 358 | 369 | var dir_handle: windows.HANDLE = undefined; |
| 359 | 370 | const root_fd = path.root_dir.handle.handle; |
| 360 | 371 | const sub_path = path.subPathOrDot(); |
| 361 | const sub_path_w = try std.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 | }; | |
| 372 | const sub_path_w = try Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call | |
| 369 | 373 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 370 | ||
| 371 | 374 | switch (windows.ntdll.NtCreateFile( |
| 372 | 375 | &dir_handle, |
| 373 | 376 | .{ |
| ... | ... | @@ -379,7 +382,7 @@ const Os = switch (builtin.os.tag) { |
| 379 | 382 | }, |
| 380 | 383 | &.{ |
| 381 | 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 | 387 | &iosb, |
| 385 | 388 | null, |
| ... | ... | @@ -410,20 +413,49 @@ const Os = switch (builtin.os.tag) { |
| 410 | 413 | |
| 411 | 414 | const dir_id = try getFileId(dir_handle); |
| 412 | 415 | |
| 413 | const dir_ptr = try gpa.create(@This()); | |
| 414 | dir_ptr.* = .{ | |
| 415 | .handle = dir_handle, | |
| 416 | const dir = try gpa.create(Directory); | |
| 417 | dir.* = .{ | |
| 418 | .reaction_set = .empty, | |
| 416 | 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 | } |
| 421 | 428 | |
| 422 | fn deinit(self: *@This(), gpa: Allocator) void { | |
| 423 | _ = windows.kernel32.CancelIo(self.handle); | |
| 424 | windows.CloseHandle(self.handle); | |
| 425 | gpa.destroy(self); | |
| 429 | fn deinit(dir: *Directory, gpa: Allocator, w: *Watch) void { | |
| 430 | state: switch (dir.state) { | |
| 431 | .idle => {}, | |
| 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 | }; |
| 428 | 460 | |
| 429 | 461 | fn init(cwd_path: []const u8) !Watch { |
| ... | ... | @@ -433,9 +465,8 @@ const Os = switch (builtin.os.tag) { |
| 433 | 465 | .dir_count = 0, |
| 434 | 466 | .os = switch (builtin.os.tag) { |
| 435 | 467 | .windows => .{ |
| 436 | .handle_table = .{}, | |
| 437 | .dir_list = .{}, | |
| 438 | .io_cp = null, | |
| 468 | .handle_table = .empty, | |
| 469 | .ready_dirs = .{}, | |
| 439 | 470 | }, |
| 440 | 471 | else => {}, |
| 441 | 472 | }, |
| ... | ... | @@ -479,29 +510,22 @@ const Os = switch (builtin.os.tag) { |
| 479 | 510 | |
| 480 | 511 | fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool { |
| 481 | 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 | 514 | if (bytes_returned == 0) { |
| 484 | 515 | std.log.warn("file system watch queue overflowed; falling back to fstat", .{}); |
| 485 | 516 | markAllFilesDirty(w, gpa); |
| 486 | try dir.startListening(); | |
| 517 | try dir.startListening(w); | |
| 487 | 518 | return true; |
| 488 | 519 | } |
| 489 | 520 | var file_name_buf: [std.fs.max_path_bytes]u8 = undefined; |
| 490 | var notify: *align(1) windows.FILE_NOTIFY_INFORMATION = undefined; | |
| 491 | 521 | var offset: usize = 0; |
| 492 | 522 | while (true) { |
| 493 | notify = @ptrCast(&dir.buffer[offset]); | |
| 494 | const file_name_field: [*]u16 = @ptrFromInt(@intFromPtr(notify) + @sizeOf(windows.FILE_NOTIFY_INFORMATION)); | |
| 495 | const file_name_len = std.unicode.wtf16LeToWtf8(&file_name_buf, file_name_field[0 .. notify.FileNameLength / 2]); | |
| 496 | const file_name = file_name_buf[0..file_name_len]; | |
| 497 | if (w.os.handle_table.getIndex(dir.id)) |reaction_set_i| { | |
| 498 | const reaction_set = w.os.handle_table.values()[reaction_set_i]; | |
| 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 | } | |
| 523 | const notify: *windows.FILE.NOTIFY.INFORMATION = @ptrCast(@alignCast(&dir.buffer[offset])); | |
| 524 | const file_name = file_name_buf[0..std.unicode.wtf16LeToWtf8(&file_name_buf, notify.fileName())]; | |
| 525 | if (dir.reaction_set.getPtr(".")) |glob_set| | |
| 526 | any_dirty = markStepSetDirty(gpa, glob_set, any_dirty); | |
| 527 | if (dir.reaction_set.getPtr(file_name)) |step_set| | |
| 528 | any_dirty = markStepSetDirty(gpa, step_set, any_dirty); | |
| 505 | 529 | if (notify.NextEntryOffset == 0) |
| 506 | 530 | break; |
| 507 | 531 | |
| ... | ... | @@ -509,7 +533,7 @@ const Os = switch (builtin.os.tag) { |
| 509 | 533 | } |
| 510 | 534 | |
| 511 | 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 | 537 | return any_dirty; |
| 514 | 538 | } |
| 515 | 539 | |
| ... | ... | @@ -517,41 +541,32 @@ const Os = switch (builtin.os.tag) { |
| 517 | 541 | // Add missing marks and note persisted ones. |
| 518 | 542 | for (steps) |step| { |
| 519 | 543 | for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| { |
| 520 | const reaction_set = rs: { | |
| 544 | const dir = dir: { | |
| 521 | 545 | const gop = try w.dir_table.getOrPut(gpa, path); |
| 522 | 546 | if (!gop.found_existing) { |
| 523 | const dir = try Os.Directory.init(gpa, path); | |
| 524 | errdefer dir.deinit(gpa); | |
| 547 | const dir: *Directory = try .init(gpa, path); | |
| 548 | errdefer dir.deinit(gpa, w); | |
| 525 | 549 | // `dir.id` may already be present in the table in |
| 526 | 550 | // the case that we have multiple Cache.Path instances |
| 527 | 551 | // that compare inequal but ultimately point to the same |
| 528 | 552 | // directory on the file system. |
| 529 | 553 | // In such case, we must revert adding this directory, but keep |
| 530 | 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 | 556 | if (dh_gop.found_existing) { |
| 533 | dir.deinit(gpa); | |
| 557 | dir.deinit(gpa, w); | |
| 534 | 558 | _ = w.dir_table.pop(); |
| 559 | break :dir w.os.handle_table.keys()[dh_gop.index]; | |
| 535 | 560 | } else { |
| 536 | 561 | assert(dh_gop.index == gop.index); |
| 537 | dh_gop.value_ptr.* = .{}; | |
| 538 | try dir.startListening(); | |
| 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 | ); | |
| 562 | try dir.startListening(w); | |
| 563 | break :dir dir; | |
| 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 | 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 | 570 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 556 | 571 | try gop.value_ptr.put(gpa, step, w.generation); |
| 557 | 572 | } |
| ... | ... | @@ -562,11 +577,11 @@ const Os = switch (builtin.os.tag) { |
| 562 | 577 | // Remove marks for files that are no longer inputs. |
| 563 | 578 | var i: usize = 0; |
| 564 | 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 | 582 | var step_set_i: usize = 0; |
| 568 | while (step_set_i < reaction_set.entries.len) { | |
| 569 | const step_set = &reaction_set.values()[step_set_i]; | |
| 583 | while (step_set_i < dir.reaction_set.entries.len) { | |
| 584 | const step_set = &dir.reaction_set.values()[step_set_i]; | |
| 570 | 585 | var dirent_i: usize = 0; |
| 571 | 586 | while (dirent_i < step_set.entries.len) { |
| 572 | 587 | const generations = step_set.values(); |
| ... | ... | @@ -580,53 +595,45 @@ const Os = switch (builtin.os.tag) { |
| 580 | 595 | step_set_i += 1; |
| 581 | 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 | 601 | i += 1; |
| 587 | 602 | continue; |
| 588 | 603 | } |
| 589 | 604 | } |
| 590 | 605 | |
| 591 | w.os.dir_list.values()[i].deinit(gpa); | |
| 592 | w.os.dir_list.swapRemoveAt(i); | |
| 593 | 606 | w.dir_table.swapRemoveAt(i); |
| 594 | 607 | w.os.handle_table.swapRemoveAt(i); |
| 608 | dir.deinit(gpa, w); | |
| 595 | 609 | } |
| 596 | 610 | w.generation +%= 1; |
| 597 | 611 | } |
| 598 | 612 | w.dir_count = w.dir_table.count(); |
| 599 | 613 | } |
| 600 | 614 | |
| 601 | fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult { | |
| 602 | var bytes_transferred: std.os.windows.DWORD = undefined; | |
| 603 | var key: usize = undefined; | |
| 604 | var overlapped_ptr: ?*std.os.windows.OVERLAPPED = undefined; | |
| 605 | return while (true) switch (std.os.windows.GetQueuedCompletionStatus( | |
| 606 | w.os.io_cp.?, | |
| 607 | &bytes_transferred, | |
| 608 | &key, | |
| 609 | &overlapped_ptr, | |
| 610 | @bitCast(timeout.to_i32_ms()), | |
| 611 | )) { | |
| 612 | .Normal => { | |
| 613 | if (bytes_transferred == 0) | |
| 614 | break error.Unexpected; | |
| 615 | ||
| 616 | // This 'orelse' detects a race condition that happens when we receive a | |
| 617 | // completion notification for a directory that no longer exists in our list. | |
| 618 | const dir = w.os.dir_list.get(key) orelse break .clean; | |
| 619 | ||
| 620 | break if (try Os.markDirtySteps(w, gpa, dir)) | |
| 621 | .dirty | |
| 622 | else | |
| 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 | }; | |
| 615 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 616 | for (0..2) |attempt| { | |
| 617 | while (w.os.ready_dirs.popFirst()) |ready_node| { | |
| 618 | const dir: *Directory = @fieldParentPtr("ready_node", ready_node); | |
| 619 | assert(dir.state == .ready); | |
| 620 | dir.state = .idle; | |
| 621 | switch (dir.iosb.u.Status) { | |
| 622 | .SUCCESS => return if (try markDirtySteps(w, gpa, dir)) .dirty else .clean, | |
| 623 | .PENDING => unreachable, | |
| 624 | .CANCELLED => {}, | |
| 625 | else => |status| return windows.unexpectedStatus(status), | |
| 626 | } | |
| 627 | try dir.startListening(w); | |
| 628 | } | |
| 629 | try io.checkCancel(); | |
| 630 | if (attempt == 1) return .timeout; | |
| 631 | const delay_interval: windows.LARGE_INTEGER = switch (timeout) { | |
| 632 | .none => std.math.minInt(windows.LARGE_INTEGER), | |
| 633 | .ms => |ms| -@as(windows.LARGE_INTEGER, ms) * (std.time.ns_per_ms / 100), | |
| 634 | }; | |
| 635 | _ = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval); | |
| 636 | } else unreachable; | |
| 630 | 637 | } |
| 631 | 638 | }, |
| 632 | 639 | .dragonfly, .freebsd, .netbsd, .openbsd, .ios, .tvos, .visionos, .watchos => struct { |
| ... | ... | @@ -796,7 +803,8 @@ const Os = switch (builtin.os.tag) { |
| 796 | 803 | w.dir_count = w.dir_table.count(); |
| 797 | 804 | } |
| 798 | 805 | |
| 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 | 808 | var timespec_buffer: posix.timespec = undefined; |
| 801 | 809 | var event_buffer: [100]posix.Kevent = undefined; |
| 802 | 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 | 860 | try w.os.fse.setPaths(gpa, steps); |
| 853 | 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 | 865 | return w.os.fse.wait(gpa, switch (timeout) { |
| 857 | 866 | .none => null, |
| 858 | 867 | .ms => |ms| @as(u64, ms) * std.time.ns_per_ms, |
| ... | ... | @@ -890,10 +899,13 @@ pub const Match = struct { |
| 890 | 899 | }; |
| 891 | 900 | |
| 892 | 901 | fn 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 | 906 | const reaction_set = switch (builtin.os.tag) { |
| 895 | .linux => value.reaction_set, | |
| 896 | else => value, | |
| 907 | .linux, .windows => item.reaction_set, | |
| 908 | else => item, | |
| 897 | 909 | }; |
| 898 | 910 | for (reaction_set.values()) |step_set| { |
| 899 | 911 | for (step_set.keys()) |step| { |
| ... | ... | @@ -951,6 +963,6 @@ pub const WaitResult = enum { |
| 951 | 963 | clean, |
| 952 | 964 | }; |
| 953 | 965 | |
| 954 | pub fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult { | |
| 955 | return Os.wait(w, gpa, timeout); | |
| 966 | pub fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 967 | return Os.wait(w, gpa, io, timeout); | |
| 956 | 968 | } |
lib/std/Io/Threaded.zig+465-493| ... | ... | @@ -83,7 +83,7 @@ csprng: Csprng = .{}, |
| 83 | 83 | system_basic_information: SystemBasicInformation = .{}, |
| 84 | 84 | |
| 85 | 85 | const SystemBasicInformation = if (!is_windows) struct {} else struct { |
| 86 | buffer: windows.SYSTEM_BASIC_INFORMATION = undefined, | |
| 86 | buffer: windows.SYSTEM.BASIC_INFORMATION = undefined, | |
| 87 | 87 | initialized: std.atomic.Value(bool) = .{ .raw = false }, |
| 88 | 88 | }; |
| 89 | 89 | |
| ... | ... | @@ -1392,7 +1392,7 @@ const AlertableSyscall = struct { |
| 1392 | 1392 | } |
| 1393 | 1393 | }; |
| 1394 | 1394 | |
| 1395 | fn waitForApcOrAlert() void { | |
| 1395 | pub fn waitForApcOrAlert() void { | |
| 1396 | 1396 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); |
| 1397 | 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 | 2556 | else => |e| e, |
| 2557 | 2557 | }, |
| 2558 | 2558 | }, |
| 2559 | .device_io_control => |*o| return .{ | |
| 2560 | .device_io_control = try deviceIoControl(t, o), | |
| 2561 | }, | |
| 2559 | .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) }, | |
| 2562 | 2560 | } |
| 2563 | 2561 | } |
| 2564 | 2562 | |
| ... | ... | @@ -2970,7 +2968,7 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren |
| 2970 | 2968 | break :o; |
| 2971 | 2969 | } |
| 2972 | 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); | |
| 2974 | 2972 | |
| 2975 | 2973 | if (o.file.flags.nonblocking) { |
| 2976 | 2974 | context.file = o.file.handle; |
| ... | ... | @@ -3259,22 +3257,11 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe |
| 3259 | 3257 | _ = t; |
| 3260 | 3258 | _ = permissions; // TODO use this value |
| 3261 | 3259 | |
| 3262 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 3263 | const sub_path_w = sub_path_w_array.span(); | |
| 3264 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | |
| 3265 | ||
| 3266 | var nt_name: windows.UNICODE_STRING = .{ | |
| 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, | |
| 3260 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 3261 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 3262 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | |
| 3263 | .Attributes = .{ .INHERIT = false }, | |
| 3264 | .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w.span())), | |
| 3278 | 3265 | .SecurityDescriptor = null, |
| 3279 | 3266 | .SecurityQualityOfService = null, |
| 3280 | 3267 | }; |
| ... | ... | @@ -3438,21 +3425,14 @@ fn dirCreateDirPathOpenWindows( |
| 3438 | 3425 | }; |
| 3439 | 3426 | |
| 3440 | 3427 | components: while (true) { |
| 3441 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, component.path); | |
| 3442 | const sub_path_w = sub_path_w_array.span(); | |
| 3428 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, component.path); | |
| 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 | 3433 | const is_last = it.peekNext() == null; |
| 3444 | const create_disposition: w.FILE.CREATE_DISPOSITION = if (is_last) .OPEN_IF else .CREATE; | |
| 3445 | ||
| 3446 | 3434 | var result: Dir = .{ .handle = undefined }; |
| 3447 | ||
| 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 | ||
| 3435 | var iosb: w.IO_STATUS_BLOCK = undefined; | |
| 3456 | 3436 | const syscall: Syscall = try .start(); |
| 3457 | 3437 | while (true) switch (w.ntdll.NtCreateFile( |
| 3458 | 3438 | &result.handle, |
| ... | ... | @@ -3468,15 +3448,12 @@ fn dirCreateDirPathOpenWindows( |
| 3468 | 3448 | .SYNCHRONIZE = true, |
| 3469 | 3449 | }, |
| 3470 | 3450 | }, |
| 3471 | &.{ | |
| 3472 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | |
| 3473 | .ObjectName = &nt_name, | |
| 3474 | }, | |
| 3475 | &io_status_block, | |
| 3451 | &attr, | |
| 3452 | &iosb, | |
| 3476 | 3453 | null, |
| 3477 | 3454 | .{ .NORMAL = true }, |
| 3478 | 3455 | .VALID_FLAGS, |
| 3479 | create_disposition, | |
| 3456 | if (is_last) .OPEN_IF else .CREATE, | |
| 3480 | 3457 | .{ |
| 3481 | 3458 | .DIRECTORY_FILE = true, |
| 3482 | 3459 | .IO = .SYNCHRONOUS_NONALERT, |
| ... | ... | @@ -3944,15 +3921,15 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 3944 | 3921 | }; |
| 3945 | 3922 | } |
| 3946 | 3923 | |
| 3947 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION { | |
| 3924 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM.BASIC_INFORMATION { | |
| 3948 | 3925 | if (!t.system_basic_information.initialized.load(.acquire)) { |
| 3949 | 3926 | mutexLock(&t.mutex); |
| 3950 | 3927 | defer mutexUnlock(&t.mutex); |
| 3951 | 3928 | |
| 3952 | 3929 | switch (windows.ntdll.NtQuerySystemInformation( |
| 3953 | .SystemBasicInformation, | |
| 3930 | .Basic, | |
| 3954 | 3931 | &t.system_basic_information.buffer, |
| 3955 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | |
| 3932 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), | |
| 3956 | 3933 | null, |
| 3957 | 3934 | )) { |
| 3958 | 3935 | .SUCCESS => {}, |
| ... | ... | @@ -4139,22 +4116,11 @@ fn dirAccessWindows( |
| 4139 | 4116 | |
| 4140 | 4117 | _ = options; // TODO |
| 4141 | 4118 | |
| 4142 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 4143 | const sub_path_w = sub_path_w_array.span(); | |
| 4144 | ||
| 4145 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) return; | |
| 4146 | if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) return; | |
| 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, | |
| 4119 | if (std.mem.eql(u8, sub_path, ".") or std.mem.eql(u8, sub_path, "..")) return; | |
| 4120 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 4121 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 4122 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | |
| 4123 | .ObjectName = @constCast(&sub_path_w.string()), | |
| 4158 | 4124 | }; |
| 4159 | 4125 | var basic_info: windows.FILE.BASIC_INFORMATION = undefined; |
| 4160 | 4126 | const syscall: Syscall = try .start(); |
| ... | ... | @@ -4360,18 +4326,10 @@ fn dirCreateFileWindows( |
| 4360 | 4326 | if (std.mem.eql(u8, sub_path, ".")) return error.IsDir; |
| 4361 | 4327 | if (std.mem.eql(u8, sub_path, "..")) return error.IsDir; |
| 4362 | 4328 | |
| 4363 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 4364 | const sub_path_w = sub_path_w_array.span(); | |
| 4365 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | |
| 4366 | ||
| 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, | |
| 4329 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 4330 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 4331 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | |
| 4332 | .ObjectName = @constCast(&sub_path_w.string()), | |
| 4375 | 4333 | }; |
| 4376 | 4334 | const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive) |
| 4377 | 4335 | .CREATE |
| ... | ... | @@ -4966,20 +4924,14 @@ fn dirOpenFileWindows( |
| 4966 | 4924 | |
| 4967 | 4925 | pub fn dirOpenFileWtf16( |
| 4968 | 4926 | dir_handle: ?windows.HANDLE, |
| 4969 | sub_path_w: [:0]const u16, | |
| 4927 | sub_path_w: []const u16, | |
| 4970 | 4928 | flags: File.OpenFlags, |
| 4971 | 4929 | ) File.OpenError!File { |
| 4972 | 4930 | const allow_directory = flags.allow_directory and !flags.isWrite(); |
| 4973 | 4931 | if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir; |
| 4974 | 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 | 4933 | const w = windows; |
| 4977 | 4934 | |
| 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 | 4935 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 4984 | 4936 | var attempt: u5 = 0; |
| 4985 | 4937 | var syscall: Syscall = try .start(); |
| ... | ... | @@ -4996,7 +4948,7 @@ pub fn dirOpenFileWtf16( |
| 4996 | 4948 | }, |
| 4997 | 4949 | &.{ |
| 4998 | 4950 | .RootDirectory = dir_handle, |
| 4999 | .ObjectName = &nt_name, | |
| 4951 | .ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)), | |
| 5000 | 4952 | }, |
| 5001 | 4953 | &io_status_block, |
| 5002 | 4954 | null, |
| ... | ... | @@ -5329,20 +5281,19 @@ fn dirOpenDirHaiku( |
| 5329 | 5281 | |
| 5330 | 5282 | pub fn dirOpenDirWindows( |
| 5331 | 5283 | dir: Dir, |
| 5332 | sub_path_w: [:0]const u16, | |
| 5284 | sub_path_w: []const u16, | |
| 5333 | 5285 | options: Dir.OpenOptions, |
| 5334 | 5286 | ) Dir.OpenError!Dir { |
| 5335 | 5287 | const w = windows; |
| 5336 | 5288 | |
| 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 | 5289 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 5344 | 5290 | var result: Dir = .{ .handle = undefined }; |
| 5345 | 5291 | |
| 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 | 5297 | const syscall: Syscall = try .start(); |
| 5347 | 5298 | while (true) switch (w.ntdll.NtCreateFile( |
| 5348 | 5299 | &result.handle, |
| ... | ... | @@ -5359,10 +5310,7 @@ pub fn dirOpenDirWindows( |
| 5359 | 5310 | .SYNCHRONIZE = true, |
| 5360 | 5311 | }, |
| 5361 | 5312 | }, |
| 5362 | &.{ | |
| 5363 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | |
| 5364 | .ObjectName = &nt_name, | |
| 5365 | }, | |
| 5313 | &attr, | |
| 5366 | 5314 | &io_status_block, |
| 5367 | 5315 | null, |
| 5368 | 5316 | .{ .NORMAL = true }, |
| ... | ... | @@ -6194,13 +6142,15 @@ pub fn GetFinalPathNameByHandle( |
| 6194 | 6142 | input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2); |
| 6195 | 6143 | @memcpy(input_buf[@sizeOf(windows.MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr))); |
| 6196 | 6144 | |
| 6197 | { | |
| 6198 | const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_POINTS, .{ .in = &input_buf, .out = &output_buf }); | |
| 6199 | switch (rc) { | |
| 6200 | .SUCCESS => {}, | |
| 6201 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | |
| 6202 | else => return windows.unexpectedStatus(rc), | |
| 6203 | } | |
| 6145 | switch ((try deviceIoControl(&.{ | |
| 6146 | .file = .{ .handle = mgmt_handle, .flags = .{ .nonblocking = false } }, | |
| 6147 | .code = windows.IOCTL.MOUNTMGR.QUERY_POINTS, | |
| 6148 | .in = &input_buf, | |
| 6149 | .out = &output_buf, | |
| 6150 | })).u.Status) { | |
| 6151 | .SUCCESS => {}, | |
| 6152 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | |
| 6153 | else => |status| return windows.unexpectedStatus(status), | |
| 6204 | 6154 | } |
| 6205 | 6155 | const mount_points_struct: *const windows.MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]); |
| 6206 | 6156 | |
| ... | ... | @@ -6251,11 +6201,15 @@ pub fn GetFinalPathNameByHandle( |
| 6251 | 6201 | vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2); |
| 6252 | 6202 | @memcpy(@as([*]windows.WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink); |
| 6253 | 6203 | |
| 6254 | const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_DOS_VOLUME_PATH, .{ .in = &vol_input_buf, .out = &vol_output_buf }); | |
| 6255 | switch (rc) { | |
| 6204 | switch ((try deviceIoControl(&.{ | |
| 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 | 6210 | .SUCCESS => {}, |
| 6257 | 6211 | .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume, |
| 6258 | else => return windows.unexpectedStatus(rc), | |
| 6212 | else => |status| return windows.unexpectedStatus(status), | |
| 6259 | 6213 | } |
| 6260 | 6214 | const volume_paths_struct: *const windows.MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]); |
| 6261 | 6215 | const volume_path = std.mem.sliceTo(@as( |
| ... | ... | @@ -6352,20 +6306,17 @@ pub const QueryObjectNameError = error{ |
| 6352 | 6306 | }; |
| 6353 | 6307 | |
| 6354 | 6308 | pub 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; | |
| 6356 | 6310 | |
| 6357 | const info: *windows.OBJECT_NAME_INFORMATION = @ptrCast(out_buffer_aligned); | |
| 6311 | const info: *windows.OBJECT.NAME_INFORMATION = @ptrCast(out_buffer_aligned); | |
| 6358 | 6312 | // buffer size is specified in bytes |
| 6359 | 6313 | const out_buffer_len = std.math.cast(windows.ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(windows.ULONG); |
| 6360 | 6314 | // 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)) { | |
| 6362 | .SUCCESS => blk: { | |
| 6363 | // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0) | |
| 6364 | // if the object was "unnamed", not sure if this can happen for file handles | |
| 6365 | if (info.Name.MaximumLength == 0) break :blk error.Unexpected; | |
| 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]; | |
| 6315 | return switch (windows.ntdll.NtQueryObject(handle, .Name, info, out_buffer_len, null)) { | |
| 6316 | .SUCCESS => { | |
| 6317 | // info.Name from ObQueryNameString is documented to be empty if the object | |
| 6318 | // was "unnamed", not sure if this can happen for file handles | |
| 6319 | return if (info.Name.isEmpty()) error.Unexpected else info.Name.slice(); | |
| 6369 | 6320 | }, |
| 6370 | 6321 | .ACCESS_DENIED => error.AccessDenied, |
| 6371 | 6322 | .INVALID_HANDLE => error.InvalidHandle, |
| ... | ... | @@ -6620,8 +6571,12 @@ pub const WindowsPathSpace = struct { |
| 6620 | 6571 | data: [windows.PATH_MAX_WIDE:0]u16, |
| 6621 | 6572 | len: usize, |
| 6622 | 6573 | |
| 6623 | pub fn span(self: *const WindowsPathSpace) [:0]const u16 { | |
| 6624 | return self.data[0..self.len :0]; | |
| 6574 | pub fn span(wps: *const WindowsPathSpace) [:0]const u16 { | |
| 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 | }; |
| 6627 | 6582 | |
| ... | ... | @@ -7076,25 +7031,19 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov |
| 7076 | 7031 | _ = t; |
| 7077 | 7032 | const w = windows; |
| 7078 | 7033 | |
| 7079 | const sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, 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) { | |
| 7034 | if (std.mem.eql(u8, sub_path, "..")) { | |
| 7095 | 7035 | // Can't remove the parent directory with an open handle. |
| 7096 | 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 | }; | |
| 7098 | 7047 | |
| 7099 | 7048 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 7100 | 7049 | var tmp_handle: w.HANDLE = undefined; |
| ... | ... | @@ -7106,10 +7055,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov |
| 7106 | 7055 | .RIGHTS = .{ .DELETE = true }, |
| 7107 | 7056 | .SYNCHRONIZE = true, |
| 7108 | 7057 | } }, |
| 7109 | &.{ | |
| 7110 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | |
| 7111 | .ObjectName = &nt_name, | |
| 7112 | }, | |
| 7058 | &attr, | |
| 7113 | 7059 | &io_status_block, |
| 7114 | 7060 | null, |
| 7115 | 7061 | .{}, |
| ... | ... | @@ -7741,7 +7687,7 @@ fn dirSymLinkWindows( |
| 7741 | 7687 | // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw |
| 7742 | 7688 | var is_target_absolute = false; |
| 7743 | 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 | 7691 | // Already an NT path, no need to do anything to it |
| 7746 | 7692 | break :target_path target_path_w.span(); |
| 7747 | 7693 | } else { |
| ... | ... | @@ -7785,13 +7731,16 @@ fn dirSymLinkWindows( |
| 7785 | 7731 | @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); |
| 7786 | 7732 | const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2; |
| 7787 | 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] }); | |
| 7789 | switch (rc) { | |
| 7734 | switch ((try deviceIoControl(&.{ | |
| 7735 | .file = .{ .handle = symlink_handle, .flags = .{ .nonblocking = false } }, | |
| 7736 | .code = .SET_REPARSE_POINT, | |
| 7737 | .in = buffer[0..buf_len], | |
| 7738 | })).u.Status) { | |
| 7790 | 7739 | .SUCCESS => {}, |
| 7791 | 7740 | .PRIVILEGE_NOT_HELD => return error.PermissionDenied, |
| 7792 | 7741 | .ACCESS_DENIED => return error.AccessDenied, |
| 7793 | 7742 | .INVALID_DEVICE_REQUEST => return error.FileSystem, |
| 7794 | else => return windows.unexpectedStatus(rc), | |
| 7743 | else => |status| return w.unexpectedStatus(status), | |
| 7795 | 7744 | } |
| 7796 | 7745 | } |
| 7797 | 7746 | |
| ... | ... | @@ -7905,17 +7854,10 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: [] |
| 7905 | 7854 | fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize { |
| 7906 | 7855 | // This gets used once for `sub_path` and then reused again temporarily |
| 7907 | 7856 | // before converting back to `buffer`. |
| 7908 | var sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 7909 | const sub_path_w = sub_path_w_buf.span(); | |
| 7910 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | |
| 7911 | var nt_name: windows.UNICODE_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, | |
| 7857 | var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); | |
| 7858 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 7859 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | |
| 7860 | .ObjectName = @constCast(&sub_path_w.string()), | |
| 7919 | 7861 | }; |
| 7920 | 7862 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 7921 | 7863 | var result_handle: windows.HANDLE = undefined; |
| ... | ... | @@ -8038,14 +7980,14 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink |
| 8038 | 7980 | const len = buf.SubstituteNameLength >> 1; |
| 8039 | 7981 | const path_buf = @as([*]const u16, &buf.PathBuffer); |
| 8040 | 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 | 7985 | @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: { |
| 8044 | 7986 | const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0])); |
| 8045 | 7987 | const offset = buf.SubstituteNameOffset >> 1; |
| 8046 | 7988 | const len = buf.SubstituteNameLength >> 1; |
| 8047 | 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 | 7992 | else => return error.UnsupportedReparsePointType, |
| 8051 | 7993 | }; |
| ... | ... | @@ -8541,13 +8483,14 @@ fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 8541 | 8483 | |
| 8542 | 8484 | fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 8543 | 8485 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8544 | return t.isTty(file); | |
| 8486 | _ = t; | |
| 8487 | return isTty(file); | |
| 8545 | 8488 | } |
| 8546 | 8489 | |
| 8547 | fn isTty(t: *Threaded, file: File) Io.Cancelable!bool { | |
| 8490 | fn isTty(file: File) Io.Cancelable!bool { | |
| 8548 | 8491 | if (is_windows) { |
| 8549 | 8492 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8550 | switch ((try t.deviceIoControl(&.{ | |
| 8493 | switch ((try deviceIoControl(&.{ | |
| 8551 | 8494 | .file = .{ |
| 8552 | 8495 | .handle = windows.peb().ProcessParameters.ConsoleHandle, |
| 8553 | 8496 | .flags = .{ .nonblocking = false }, |
| ... | ... | @@ -8626,8 +8569,9 @@ fn isTty(t: *Threaded, file: File) Io.Cancelable!bool { |
| 8626 | 8569 | |
| 8627 | 8570 | fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void { |
| 8628 | 8571 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8572 | _ = t; | |
| 8629 | 8573 | |
| 8630 | if (!is_windows) return if (!try t.supportsAnsiEscapeCodes(file)) error.NotTerminalDevice; | |
| 8574 | if (!is_windows) return if (!try supportsAnsiEscapeCodes(file)) error.NotTerminalDevice; | |
| 8631 | 8575 | |
| 8632 | 8576 | // For Windows Terminal, VT Sequences processing is enabled by default. |
| 8633 | 8577 | const console: File = .{ |
| ... | ... | @@ -8635,7 +8579,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8635 | 8579 | .flags = .{ .nonblocking = false }, |
| 8636 | 8580 | }; |
| 8637 | 8581 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8638 | switch ((try t.deviceIoControl(&.{ | |
| 8582 | switch ((try deviceIoControl(&.{ | |
| 8639 | 8583 | .file = console, |
| 8640 | 8584 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, |
| 8641 | 8585 | .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), |
| ... | ... | @@ -8661,7 +8605,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8661 | 8605 | var set_console_mode = windows.CONSOLE.USER_IO.SET_MODE( |
| 8662 | 8606 | get_console_mode.Data | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING, |
| 8663 | 8607 | ); |
| 8664 | switch ((try t.deviceIoControl(&.{ | |
| 8608 | switch ((try deviceIoControl(&.{ | |
| 8665 | 8609 | .file = console, |
| 8666 | 8610 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, |
| 8667 | 8611 | .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})), |
| ... | ... | @@ -8673,13 +8617,14 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8673 | 8617 | |
| 8674 | 8618 | fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 8675 | 8619 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8676 | return t.supportsAnsiEscapeCodes(file); | |
| 8620 | _ = t; | |
| 8621 | return supportsAnsiEscapeCodes(file); | |
| 8677 | 8622 | } |
| 8678 | 8623 | |
| 8679 | fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { | |
| 8624 | fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool { | |
| 8680 | 8625 | if (is_windows) { |
| 8681 | 8626 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8682 | switch ((try t.deviceIoControl(&.{ | |
| 8627 | switch ((try deviceIoControl(&.{ | |
| 8683 | 8628 | .file = .{ |
| 8684 | 8629 | .handle = windows.peb().ProcessParameters.ConsoleHandle, |
| 8685 | 8630 | .flags = .{ .nonblocking = false }, |
| ... | ... | @@ -8701,7 +8646,7 @@ fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { |
| 8701 | 8646 | return false; |
| 8702 | 8647 | } |
| 8703 | 8648 | |
| 8704 | if (try t.isTty(file)) return true; | |
| 8649 | if (try isTty(file)) return true; | |
| 8705 | 8650 | |
| 8706 | 8651 | return false; |
| 8707 | 8652 | } |
| ... | ... | @@ -8775,7 +8720,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool { |
| 8775 | 8720 | }, |
| 8776 | 8721 | }; |
| 8777 | 8722 | |
| 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 | 8724 | const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength]; |
| 8780 | 8725 | const name_wide = std.mem.bytesAsSlice(u16, name_bytes); |
| 8781 | 8726 | // 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 | 8947 | _ = t; |
| 9003 | 8948 | |
| 9004 | 8949 | if (is_windows) { |
| 9005 | var access_time_buffer: windows.FILETIME = undefined; | |
| 9006 | var modify_time_buffer: windows.FILETIME = undefined; | |
| 9007 | var system_time_buffer: windows.LARGE_INTEGER = undefined; | |
| 9008 | ||
| 9009 | if (options.access_timestamp == .now or options.modify_timestamp == .now) { | |
| 9010 | system_time_buffer = windows.ntdll.RtlGetSystemTimePrecise(); | |
| 9011 | } | |
| 9012 | ||
| 9013 | const access_ptr = switch (options.access_timestamp) { | |
| 9014 | .unchanged => null, | |
| 9015 | .now => @panic("TODO do SystemTimeToFileTime logic here"), | |
| 9016 | .new => |ts| p: { | |
| 9017 | access_time_buffer = windows.nanoSecondsToFileTime(ts); | |
| 9018 | break :p &access_time_buffer; | |
| 9019 | }, | |
| 8950 | const now_sys = if (options.access_timestamp == .now or options.modify_timestamp == .now) | |
| 8951 | windows.ntdll.RtlGetSystemTimePrecise() | |
| 8952 | else | |
| 8953 | undefined; | |
| 8954 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 8955 | var info: windows.FILE.BASIC_INFORMATION = .{ | |
| 8956 | .CreationTime = 0, | |
| 8957 | .LastAccessTime = switch (options.access_timestamp) { | |
| 8958 | .unchanged => 0, | |
| 8959 | .now => now_sys, | |
| 8960 | .new => |ts| windows.toSysTime(ts), | |
| 8961 | }, | |
| 8962 | .LastWriteTime = switch (options.modify_timestamp) { | |
| 8963 | .unchanged => 0, | |
| 8964 | .now => now_sys, | |
| 8965 | .new => |ts| windows.toSysTime(ts), | |
| 8966 | }, | |
| 8967 | .ChangeTime = 0, | |
| 8968 | .FileAttributes = .{}, | |
| 9020 | 8969 | }; |
| 9021 | ||
| 9022 | const modify_ptr = switch (options.modify_timestamp) { | |
| 9023 | .unchanged => null, | |
| 9024 | .now => @panic("TODO do SystemTimeToFileTime logic here"), | |
| 9025 | .new => |ts| p: { | |
| 9026 | modify_time_buffer = windows.nanoSecondsToFileTime(ts); | |
| 9027 | break :p &modify_time_buffer; | |
| 9028 | }, | |
| 8970 | var syscall: Syscall = try .start(); | |
| 8971 | while (true) switch (windows.ntdll.NtSetInformationFile( | |
| 8972 | file.handle, | |
| 8973 | &iosb, | |
| 8974 | &info, | |
| 8975 | @sizeOf(windows.FILE.BASIC_INFORMATION), | |
| 8976 | .Basic, | |
| 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 | } |
| 9049 | 8983 | |
| 9050 | 8984 | if (native_os == .wasi and !builtin.link_libc) { |
| ... | ... | @@ -9636,15 +9570,43 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingErro |
| 9636 | 9570 | } |
| 9637 | 9571 | |
| 9638 | 9572 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize { |
| 9573 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 9639 | 9574 | var index: usize = 0; |
| 9640 | 9575 | while (data.len - index != 0 and data[index].len == 0) index += 1; |
| 9641 | 9576 | if (data.len - index == 0) return 0; |
| 9642 | 9577 | const buffer = data[index]; |
| 9643 | const short_buffer_len = @min(std.math.maxInt(u32), buffer.len); | |
| 9644 | ||
| 9645 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 9646 | ||
| 9647 | if (!file.flags.nonblocking) { | |
| 9578 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); | |
| 9579 | if (file.flags.nonblocking) { | |
| 9580 | var done: bool = false; | |
| 9581 | switch (windows.ntdll.NtReadFile( | |
| 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 | 9610 | const syscall: Syscall = try .start(); |
| 9649 | 9611 | while (true) switch (windows.ntdll.NtReadFile( |
| 9650 | 9612 | file.handle, |
| ... | ... | @@ -9665,41 +9627,10 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr |
| 9665 | 9627 | else => |status| { |
| 9666 | 9628 | syscall.finish(); |
| 9667 | 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 | 9634 | return ntReadFileResult(&iosb); |
| 9704 | 9635 | } |
| 9705 | 9636 | |
| ... | ... | @@ -9714,8 +9645,9 @@ fn ntReadFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { |
| 9714 | 9645 | .CANCELLED => unreachable, |
| 9715 | 9646 | .SUCCESS => return io_status_block.Information, |
| 9716 | 9647 | .END_OF_FILE, .PIPE_BROKEN => return error.EndOfStream, |
| 9648 | .INVALID_HANDLE => return error.NotOpenForReading, | |
| 9717 | 9649 | .INVALID_DEVICE_REQUEST => return error.IsDir, |
| 9718 | .LOCK_NOT_GRANTED => return error.LockViolation, | |
| 9650 | .FILE_LOCK_CONFLICT => return error.LockViolation, | |
| 9719 | 9651 | .ACCESS_DENIED => return error.AccessDenied, |
| 9720 | 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 | 9663 | .QUOTA_EXCEEDED => return error.SystemResources, |
| 9732 | 9664 | .PIPE_BROKEN => return error.BrokenPipe, |
| 9733 | 9665 | .INVALID_HANDLE => return error.NotOpenForWriting, |
| 9734 | .LOCK_NOT_GRANTED => return error.LockViolation, | |
| 9666 | .FILE_LOCK_CONFLICT => return error.LockViolation, | |
| 9735 | 9667 | .ACCESS_DENIED => return error.AccessDenied, |
| 9736 | 9668 | .WORKING_SET_QUOTA => return error.SystemResources, |
| 9737 | 9669 | .DISK_FULL => return error.NoSpaceLeft, |
| ... | ... | @@ -9740,8 +9672,6 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { |
| 9740 | 9672 | } |
| 9741 | 9673 | |
| 9742 | 9674 | fn 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 | 9675 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| 9746 | 9676 | var i: usize = 0; |
| 9747 | 9677 | for (data) |buf| { |
| ... | ... | @@ -9787,9 +9717,44 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea |
| 9787 | 9717 | } |
| 9788 | 9718 | } |
| 9789 | 9719 | |
| 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 | 9755 | const syscall: Syscall = try .start(); |
| 9791 | 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 | 9758 | switch (posix.errno(rc)) { |
| 9794 | 9759 | .SUCCESS => { |
| 9795 | 9760 | syscall.finish(); |
| ... | ... | @@ -9838,65 +9803,119 @@ fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.R |
| 9838 | 9803 | } |
| 9839 | 9804 | |
| 9840 | 9805 | fn readFilePositionalWindows(file: File, buffer: []u8, offset: u64) File.ReadPositionalError!usize { |
| 9841 | const DWORD = windows.DWORD; | |
| 9842 | const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len); | |
| 9843 | var overlapped: windows.OVERLAPPED = .{ | |
| 9844 | .Internal = 0, | |
| 9845 | .InternalHigh = 0, | |
| 9846 | .DUMMYUNIONNAME = .{ | |
| 9847 | .DUMMYSTRUCTNAME = .{ | |
| 9848 | .Offset = @truncate(offset), | |
| 9849 | .OffsetHigh = @truncate(offset >> 32), | |
| 9806 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 9807 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); | |
| 9808 | const signed_offset: windows.LARGE_INTEGER = @intCast(offset); | |
| 9809 | if (file.flags.nonblocking) { | |
| 9810 | var done: bool = false; | |
| 9811 | switch (windows.ntdll.NtReadFile( | |
| 9812 | file.handle, | |
| 9813 | null, // event | |
| 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 | }, | |
| 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; | |
| 9837 | else => |status| iosb.u.Status = status, | |
| 9861 | 9838 | } |
| 9862 | switch (windows.GetLastError()) { | |
| 9863 | .IO_PENDING => |err| { | |
| 9864 | syscall.finish(); | |
| 9865 | return windows.errorBug(err); | |
| 9866 | }, | |
| 9867 | .OPERATION_ABORTED => { | |
| 9868 | try syscall.checkCancel(); | |
| 9869 | continue; | |
| 9870 | }, | |
| 9871 | .BROKEN_PIPE, .HANDLE_EOF => { | |
| 9872 | syscall.finish(); | |
| 9873 | return 0; | |
| 9874 | }, | |
| 9875 | .NETNAME_DELETED => if (is_debug) unreachable else return error.Unexpected, | |
| 9876 | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), | |
| 9877 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | |
| 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| { | |
| 9839 | } else { | |
| 9840 | const syscall: Syscall = try .start(); | |
| 9841 | while (true) switch (windows.ntdll.NtReadFile( | |
| 9842 | file.handle, | |
| 9843 | null, // event | |
| 9844 | null, // APC routine | |
| 9845 | null, // APC context | |
| 9846 | &iosb, | |
| 9847 | buffer.ptr, | |
| 9848 | short_buffer_len, | |
| 9849 | &signed_offset, | |
| 9850 | null, // key | |
| 9851 | )) { | |
| 9852 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag | |
| 9853 | .CANCELLED => try syscall.checkCancel(), | |
| 9854 | else => |status| { | |
| 9883 | 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 | } |
| 9889 | 9866 | |
| 9890 | 9867 | fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!void { |
| 9891 | 9868 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 9892 | 9869 | _ = t; |
| 9893 | const fd = file.handle; | |
| 9894 | 9870 | |
| 9895 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 9896 | var result: u64 = undefined; | |
| 9871 | if (is_windows) { | |
| 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 | 9916 | const syscall: Syscall = try .start(); |
| 9898 | 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 | 9919 | .SUCCESS => { |
| 9901 | 9920 | syscall.finish(); |
| 9902 | 9921 | return; |
| ... | ... | @@ -9913,6 +9932,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9913 | 9932 | .OVERFLOW => return error.Unseekable, |
| 9914 | 9933 | .SPIPE => return error.Unseekable, |
| 9915 | 9934 | .NXIO => return error.Unseekable, |
| 9935 | .NOTCAPABLE => return error.AccessDenied, | |
| 9916 | 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 | 9940 | } |
| 9921 | 9941 | } |
| 9922 | 9942 | |
| 9923 | if (is_windows) { | |
| 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 | } | |
| 9943 | if (posix.SEEK == void) return error.Unseekable; | |
| 9945 | 9944 | |
| 9946 | if (native_os == .wasi and !builtin.link_libc) { | |
| 9947 | var new_offset: std.os.wasi.filesize_t = undefined; | |
| 9945 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 9946 | var result: u64 = undefined; | |
| 9948 | 9947 | const syscall: Syscall = try .start(); |
| 9949 | 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 | 9950 | .SUCCESS => { |
| 9952 | 9951 | syscall.finish(); |
| 9953 | 9952 | return; |
| ... | ... | @@ -9964,7 +9963,6 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9964 | 9963 | .OVERFLOW => return error.Unseekable, |
| 9965 | 9964 | .SPIPE => return error.Unseekable, |
| 9966 | 9965 | .NXIO => return error.Unseekable, |
| 9967 | .NOTCAPABLE => return error.AccessDenied, | |
| 9968 | 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 | 9970 | } |
| 9973 | 9971 | } |
| 9974 | 9972 | |
| 9975 | if (posix.SEEK == void) return error.Unseekable; | |
| 9976 | ||
| 9977 | 9973 | const syscall: Syscall = try .start(); |
| 9978 | 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 | 9976 | .SUCCESS => { |
| 9981 | 9977 | syscall.finish(); |
| 9982 | 9978 | return; |
| ... | ... | @@ -10003,41 +9999,31 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 10003 | 9999 | fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!void { |
| 10004 | 10000 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 10005 | 10001 | _ = t; |
| 10006 | const fd = file.handle; | |
| 10007 | 10002 | |
| 10008 | 10003 | if (is_windows) { |
| 10009 | // "The starting point is zero or the beginning of the file. If [FILE_BEGIN] | |
| 10010 | // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value." | |
| 10011 | // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex | |
| 10012 | const ipos: windows.LARGE_INTEGER = @bitCast(offset); | |
| 10013 | ||
| 10004 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 10005 | var info: windows.FILE.POSITION_INFORMATION = .{ .CurrentByteOffset = @bitCast(offset) }; | |
| 10014 | 10006 | const syscall: Syscall = try .start(); |
| 10015 | while (true) { | |
| 10016 | if (windows.kernel32.SetFilePointerEx(fd, ipos, null, windows.FILE_BEGIN) != 0) { | |
| 10017 | return syscall.finish(); | |
| 10018 | } | |
| 10019 | switch (windows.GetLastError()) { | |
| 10020 | .OPERATION_ABORTED => { | |
| 10021 | try syscall.checkCancel(); | |
| 10022 | continue; | |
| 10023 | }, | |
| 10024 | .INVALID_FUNCTION => return syscall.fail(error.Unseekable), | |
| 10025 | .NEGATIVE_SEEK => return syscall.fail(error.Unseekable), | |
| 10026 | .INVALID_PARAMETER => unreachable, | |
| 10027 | .INVALID_HANDLE => unreachable, | |
| 10028 | else => |err| { | |
| 10029 | syscall.finish(); | |
| 10030 | return windows.unexpectedError(err); | |
| 10031 | }, | |
| 10032 | } | |
| 10033 | } | |
| 10007 | while (true) switch (windows.ntdll.NtSetInformationFile( | |
| 10008 | file.handle, | |
| 10009 | &iosb, | |
| 10010 | &info, | |
| 10011 | @sizeOf(windows.FILE.POSITION_INFORMATION), | |
| 10012 | .Position, | |
| 10013 | )) { | |
| 10014 | .SUCCESS => return syscall.finish(), | |
| 10015 | .CANCELLED => try syscall.checkCancel(), | |
| 10016 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | |
| 10017 | .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable), | |
| 10018 | else => |status| return syscall.unexpectedNtstatus(status), | |
| 10019 | }; | |
| 10034 | 10020 | } |
| 10035 | 10021 | |
| 10036 | 10022 | if (native_os == .wasi and !builtin.link_libc) { |
| 10037 | 10023 | const syscall: Syscall = try .start(); |
| 10038 | 10024 | while (true) { |
| 10039 | 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 | 10027 | .SUCCESS => { |
| 10042 | 10028 | syscall.finish(); |
| 10043 | 10029 | return; |
| ... | ... | @@ -10064,7 +10050,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 10064 | 10050 | |
| 10065 | 10051 | if (posix.SEEK == void) return error.Unseekable; |
| 10066 | 10052 | |
| 10067 | return posixSeekTo(fd, offset); | |
| 10053 | return posixSeekTo(file.handle, offset); | |
| 10068 | 10054 | } |
| 10069 | 10055 | |
| 10070 | 10056 | fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void { |
| ... | ... | @@ -10131,8 +10117,7 @@ fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.O |
| 10131 | 10117 | // If ImagePathName is a symlink, then it will contain the path of the symlink, |
| 10132 | 10118 | // not the path that the symlink points to. However, because we are opening |
| 10133 | 10119 | // the file, we can let the openFileW call follow the symlink for us. |
| 10134 | const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName; | |
| 10135 | const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0]; | |
| 10120 | const image_path_name = windows.peb().ProcessParameters.ImagePathName.sliceZ(); | |
| 10136 | 10121 | const prefixed_path_w = try wToPrefixedFileW(null, image_path_name); |
| 10137 | 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 | 10319 | return error.FileNotFound; |
| 10335 | 10320 | }, |
| 10336 | 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 | 10322 | // If ImagePathName is a symlink, then it will contain the path of the |
| 10342 | 10323 | // symlink, not the path that the symlink points to. We want the path |
| 10343 | 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 | ); | |
| 10345 | 10329 | |
| 10346 | 10330 | const h_file = handle: { |
| 10347 | 10331 | if (OpenFile(path_name_w_buf.span(), .{ |
| ... | ... | @@ -10360,7 +10344,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut |
| 10360 | 10344 | else => |e| return e, |
| 10361 | 10345 | } |
| 10362 | 10346 | }; |
| 10363 | defer w.CloseHandle(h_file); | |
| 10347 | defer windows.CloseHandle(h_file); | |
| 10364 | 10348 | |
| 10365 | 10349 | const wide_slice = try GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data); |
| 10366 | 10350 | |
| ... | ... | @@ -10388,15 +10372,15 @@ fn fileWritePositional( |
| 10388 | 10372 | |
| 10389 | 10373 | if (is_windows) { |
| 10390 | 10374 | if (header.len != 0) { |
| 10391 | return writeFilePositionalWindows(file.handle, header, offset); | |
| 10375 | return writeFilePositionalWindows(file, header, offset); | |
| 10392 | 10376 | } |
| 10393 | 10377 | for (data[0 .. data.len - 1]) |buf| { |
| 10394 | 10378 | if (buf.len == 0) continue; |
| 10395 | return writeFilePositionalWindows(file.handle, buf, offset); | |
| 10379 | return writeFilePositionalWindows(file, buf, offset); | |
| 10396 | 10380 | } |
| 10397 | 10381 | const pattern = data[data.len - 1]; |
| 10398 | 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 | } |
| 10401 | 10385 | |
| 10402 | 10386 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| ... | ... | @@ -10505,50 +10489,64 @@ fn fileWritePositional( |
| 10505 | 10489 | } |
| 10506 | 10490 | } |
| 10507 | 10491 | |
| 10508 | fn writeFilePositionalWindows( | |
| 10509 | handle: windows.HANDLE, | |
| 10510 | bytes: []const u8, | |
| 10511 | offset: u64, | |
| 10512 | ) File.WritePositionalError!usize { | |
| 10513 | var bytes_written: windows.DWORD = undefined; | |
| 10514 | var overlapped: windows.OVERLAPPED = .{ | |
| 10515 | .Internal = 0, | |
| 10516 | .InternalHigh = 0, | |
| 10517 | .DUMMYUNIONNAME = .{ | |
| 10518 | .DUMMYSTRUCTNAME = .{ | |
| 10519 | .Offset = @truncate(offset), | |
| 10520 | .OffsetHigh = @truncate(offset >> 32), | |
| 10492 | fn writeFilePositionalWindows(file: File, buffer: []const u8, offset: u64) File.WritePositionalError!usize { | |
| 10493 | assert(buffer.len != 0); | |
| 10494 | var iosb: windows.IO_STATUS_BLOCK = undefined; | |
| 10495 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); | |
| 10496 | const signed_offset: windows.LARGE_INTEGER = @intCast(offset); | |
| 10497 | if (file.flags.nonblocking) { | |
| 10498 | var done: bool = false; | |
| 10499 | switch (windows.ntdll.NtWriteFile( | |
| 10500 | file.handle, | |
| 10501 | null, // event | |
| 10502 | flagApc, | |
| 10503 | &done, // APC context | |
| 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 | }, | |
| 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; | |
| 10525 | else => |status| iosb.u.Status = status, | |
| 10531 | 10526 | } |
| 10532 | switch (windows.GetLastError()) { | |
| 10533 | .OPERATION_ABORTED => { | |
| 10534 | try syscall.checkCancel(); | |
| 10535 | continue; | |
| 10536 | }, | |
| 10537 | .INVALID_USER_BUFFER => return syscall.fail(error.SystemResources), | |
| 10538 | .NOT_ENOUGH_MEMORY => return syscall.fail(error.SystemResources), | |
| 10539 | .NOT_ENOUGH_QUOTA => return syscall.fail(error.SystemResources), | |
| 10540 | .NO_DATA => return syscall.fail(error.BrokenPipe), | |
| 10541 | .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, // use after free | |
| 10542 | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), | |
| 10543 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | |
| 10544 | .WORKING_SET_QUOTA => return syscall.fail(error.SystemResources), | |
| 10545 | .DISK_FULL => return syscall.fail(error.NoSpaceLeft), | |
| 10546 | else => |err| { | |
| 10527 | } else { | |
| 10528 | const syscall: Syscall = try .start(); | |
| 10529 | while (true) switch (windows.ntdll.NtWriteFile( | |
| 10530 | file.handle, | |
| 10531 | null, // event | |
| 10532 | null, // APC routine | |
| 10533 | null, // APC context | |
| 10534 | &iosb, | |
| 10535 | buffer.ptr, | |
| 10536 | short_buffer_len, | |
| 10537 | &signed_offset, | |
| 10538 | null, // key | |
| 10539 | )) { | |
| 10540 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag | |
| 10541 | .CANCELLED => try syscall.checkCancel(), | |
| 10542 | else => |status| { | |
| 10547 | 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 | } |
| 10553 | 10551 | |
| 10554 | 10552 | fn fileWriteStreaming( |
| ... | ... | @@ -10673,9 +10671,7 @@ fn fileWriteStreaming( |
| 10673 | 10671 | |
| 10674 | 10672 | fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!usize { |
| 10675 | 10673 | assert(buffer.len != 0); |
| 10676 | ||
| 10677 | 10674 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 10678 | ||
| 10679 | 10675 | if (file.flags.nonblocking) { |
| 10680 | 10676 | var done: bool = false; |
| 10681 | 10677 | switch (windows.ntdll.NtWriteFile( |
| ... | ... | @@ -10706,7 +10702,6 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u |
| 10706 | 10702 | }, |
| 10707 | 10703 | else => |status| iosb.u.Status = status, |
| 10708 | 10704 | } |
| 10709 | return ntWriteFileResult(&iosb); | |
| 10710 | 10705 | } else { |
| 10711 | 10706 | const syscall: Syscall = try .start(); |
| 10712 | 10707 | while (true) switch (windows.ntdll.NtWriteFile( |
| ... | ... | @@ -10721,17 +10716,15 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u |
| 10721 | 10716 | null, // key |
| 10722 | 10717 | )) { |
| 10723 | 10718 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag |
| 10724 | .CANCELLED => { | |
| 10725 | try syscall.checkCancel(); | |
| 10726 | continue; | |
| 10727 | }, | |
| 10719 | .CANCELLED => try syscall.checkCancel(), | |
| 10728 | 10720 | else => |status| { |
| 10729 | 10721 | syscall.finish(); |
| 10730 | 10722 | iosb.u.Status = status; |
| 10731 | return ntWriteFileResult(&iosb); | |
| 10723 | break; | |
| 10732 | 10724 | }, |
| 10733 | 10725 | }; |
| 10734 | 10726 | } |
| 10727 | return ntWriteFileResult(&iosb); | |
| 10735 | 10728 | } |
| 10736 | 10729 | |
| 10737 | 10730 | fn fileWriteFileStreaming( |
| ... | ... | @@ -11433,13 +11426,22 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11433 | 11426 | return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 + epoch_ns }; |
| 11434 | 11427 | }, |
| 11435 | 11428 | .awake, .boot => { |
| 11436 | // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. | |
| 11437 | const qpc = windows.QueryPerformanceCounter(); | |
| 11438 | 11429 | // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA |
| 11439 | 11430 | // (a read-only page of info updated and mapped by the kernel to all processes): |
| 11440 | 11431 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data |
| 11441 | 11432 | // 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 | }; | |
| 11443 | 11445 | |
| 11444 | 11446 | // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. |
| 11445 | 11447 | // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 |
| ... | ... | @@ -11458,7 +11460,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11458 | 11460 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L442-L485 |
| 11459 | 11461 | if (windows.ntdll.NtQueryInformationProcess( |
| 11460 | 11462 | handle, |
| 11461 | windows.PROCESSINFOCLASS.Times, | |
| 11463 | .Times, | |
| 11462 | 11464 | &times, |
| 11463 | 11465 | @sizeOf(windows.KERNEL_USER_TIMES), |
| 11464 | 11466 | null, |
| ... | ... | @@ -11474,7 +11476,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11474 | 11476 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L2971-L3019 |
| 11475 | 11477 | if (windows.ntdll.NtQueryInformationThread( |
| 11476 | 11478 | handle, |
| 11477 | windows.THREADINFOCLASS.Times, | |
| 11479 | .Times, | |
| 11478 | 11480 | &times, |
| 11479 | 11481 | @sizeOf(windows.KERNEL_USER_TIMES), |
| 11480 | 11482 | null, |
| ... | ... | @@ -14132,21 +14134,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr |
| 14132 | 14134 | } |
| 14133 | 14135 | |
| 14134 | 14136 | fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirError!void { |
| 14135 | if (native_os == .wasi) return error.OperationUnsupported; | |
| 14136 | 14137 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 14137 | 14138 | _ = t; |
| 14138 | 14139 | |
| 14140 | if (native_os == .wasi) return error.OperationUnsupported; | |
| 14141 | ||
| 14139 | 14142 | if (is_windows) { |
| 14140 | var dir_path_buffer: [windows.PATH_MAX_WIDE]u16 = undefined; | |
| 14141 | const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buffer); | |
| 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 | }; | |
| 14143 | var dir_path_buf: [windows.PATH_MAX_WIDE]u16 = undefined; | |
| 14144 | const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buf); | |
| 14148 | 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 | 14147 | .SUCCESS => return syscall.finish(), |
| 14151 | 14148 | .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName), |
| 14152 | 14149 | .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound), |
| ... | ... | @@ -15465,26 +15462,27 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 15465 | 15462 | fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT) !void { |
| 15466 | 15463 | _ = t; // TODO cancelation |
| 15467 | 15464 | const handle = child.id.?; |
| 15468 | if (windows.kernel32.TerminateProcess(handle, exit_code) == 0) { | |
| 15469 | switch (windows.GetLastError()) { | |
| 15470 | .ACCESS_DENIED => { | |
| 15471 | // Usually when TerminateProcess triggers a ACCESS_DENIED error, it | |
| 15472 | // indicates that the process has already exited, but there may be | |
| 15473 | // some rare edge cases where our process handle no longer has the | |
| 15474 | // PROCESS_TERMINATE access right, so let's do another check to make | |
| 15475 | // sure the process is really no longer running: | |
| 15476 | const minimal_timeout: windows.LARGE_INTEGER = -1; | |
| 15477 | switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) { | |
| 15478 | .SUCCESS => return error.AlreadyTerminated, | |
| 15479 | else => return error.AccessDenied, | |
| 15480 | } | |
| 15481 | }, | |
| 15482 | else => |err| return windows.unexpectedError(err), | |
| 15483 | } | |
| 15465 | _ = windows.ntdll.RtlReportSilentProcessExit(handle, @enumFromInt(exit_code)); | |
| 15466 | switch (windows.ntdll.NtTerminateProcess(handle, @enumFromInt(exit_code))) { | |
| 15467 | .SUCCESS => { | |
| 15468 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); | |
| 15469 | _ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout); | |
| 15470 | childCleanupWindows(child); | |
| 15471 | }, | |
| 15472 | .ACCESS_DENIED => { | |
| 15473 | // Usually when TerminateProcess triggers a ACCESS_DENIED error, it | |
| 15474 | // indicates that the process has already exited, but there may be | |
| 15475 | // some rare edge cases where our process handle no longer has the | |
| 15476 | // PROCESS_TERMINATE access right, so let's do another check to make | |
| 15477 | // sure the process is really no longer running: | |
| 15478 | const minimal_timeout: windows.LARGE_INTEGER = -1; | |
| 15479 | return switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) { | |
| 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 | } |
| 15489 | 15487 | |
| 15490 | 15488 | fn 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 | 15499 | else => |status| return alertable_syscall.unexpectedNtstatus(status), |
| 15502 | 15500 | }; |
| 15503 | 15501 | |
| 15504 | var info: windows.PROCESS_BASIC_INFORMATION = undefined; | |
| 15502 | var info: windows.PROCESS.BASIC_INFORMATION = undefined; | |
| 15505 | 15503 | const term: process.Child.Term = switch (windows.ntdll.NtQueryInformationProcess( |
| 15506 | 15504 | handle, |
| 15507 | 15505 | .BasicInformation, |
| 15508 | 15506 | &info, |
| 15509 | @sizeOf(windows.PROCESS_BASIC_INFORMATION), | |
| 15507 | @sizeOf(windows.PROCESS.BASIC_INFORMATION), | |
| 15510 | 15508 | null, |
| 15511 | 15509 | )) { |
| 15512 | 15510 | .SUCCESS => .{ .exited = @as(u8, @truncate(@intFromEnum(info.ExitStatus))) }, |
| ... | ... | @@ -15521,12 +15519,12 @@ fn childCleanupWindows(child: *process.Child) void { |
| 15521 | 15519 | const handle = child.id orelse return; |
| 15522 | 15520 | |
| 15523 | 15521 | if (child.request_resource_usage_statistics) { |
| 15524 | var vmc: windows.VM_COUNTERS = undefined; | |
| 15522 | var vmc: windows.PROCESS.VM_COUNTERS = undefined; | |
| 15525 | 15523 | switch (windows.ntdll.NtQueryInformationProcess( |
| 15526 | 15524 | handle, |
| 15527 | 15525 | .VmCounters, |
| 15528 | 15526 | &vmc, |
| 15529 | @sizeOf(windows.VM_COUNTERS), | |
| 15527 | @sizeOf(windows.PROCESS.VM_COUNTERS), | |
| 15530 | 15528 | null, |
| 15531 | 15529 | )) { |
| 15532 | 15530 | .SUCCESS => child.resource_usage_statistics.rusage = vmc, |
| ... | ... | @@ -15853,7 +15851,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 15853 | 15851 | .cbReserved2 = 0, |
| 15854 | 15852 | .lpReserved2 = null, |
| 15855 | 15853 | }; |
| 15856 | var piProcInfo: windows.PROCESS_INFORMATION = undefined; | |
| 15854 | var piProcInfo: windows.PROCESS.INFORMATION = undefined; | |
| 15857 | 15855 | |
| 15858 | 15856 | var arena_allocator = std.heap.ArenaAllocator.init(t.allocator); |
| 15859 | 15857 | defer arena_allocator.deinit(); |
| ... | ... | @@ -16062,7 +16060,6 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 16062 | 16060 | if (t.random_file.handle) |handle| return handle; |
| 16063 | 16061 | } |
| 16064 | 16062 | |
| 16065 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' }; | |
| 16066 | 16063 | var fresh_handle: windows.HANDLE = undefined; |
| 16067 | 16064 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16068 | 16065 | var syscall: Syscall = try .start(); |
| ... | ... | @@ -16072,13 +16069,9 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 16072 | 16069 | .STANDARD = .{ .SYNCHRONIZE = true }, |
| 16073 | 16070 | .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } }, |
| 16074 | 16071 | }, |
| 16075 | &.{ | |
| 16076 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | |
| 16077 | .Length = @sizeOf(@TypeOf(device_path)), | |
| 16078 | .MaximumLength = 0, | |
| 16079 | .Buffer = @constCast(&device_path), | |
| 16080 | }), | |
| 16081 | }, | |
| 16072 | &.{ .ObjectName = @constCast(&windows.UNICODE_STRING.init( | |
| 16073 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' }, | |
| 16074 | )) }, | |
| 16082 | 16075 | &io_status_block, |
| 16083 | 16076 | .VALID_FLAGS, |
| 16084 | 16077 | .{ .IO = .SYNCHRONOUS_NONALERT }, |
| ... | ... | @@ -16111,7 +16104,6 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { |
| 16111 | 16104 | if (t.null_file.handle) |handle| return handle; |
| 16112 | 16105 | } |
| 16113 | 16106 | |
| 16114 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' }; | |
| 16115 | 16107 | var fresh_handle: windows.HANDLE = undefined; |
| 16116 | 16108 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16117 | 16109 | var syscall: Syscall = try .start(); |
| ... | ... | @@ -16123,11 +16115,9 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { |
| 16123 | 16115 | }, |
| 16124 | 16116 | &.{ |
| 16125 | 16117 | .Attributes = .{ .INHERIT = true }, |
| 16126 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | |
| 16127 | .Length = @sizeOf(@TypeOf(device_path)), | |
| 16128 | .MaximumLength = 0, | |
| 16129 | .Buffer = @constCast(&device_path), | |
| 16130 | }), | |
| 16118 | .ObjectName = @constCast(&windows.UNICODE_STRING.init( | |
| 16119 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' }, | |
| 16120 | )), | |
| 16131 | 16121 | }, |
| 16132 | 16122 | &io_status_block, |
| 16133 | 16123 | .VALID_FLAGS, |
| ... | ... | @@ -16173,7 +16163,6 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { |
| 16173 | 16163 | if (t.pipe_file.handle) |handle| return handle; |
| 16174 | 16164 | } |
| 16175 | 16165 | |
| 16176 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' }; | |
| 16177 | 16166 | var fresh_handle: windows.HANDLE = undefined; |
| 16178 | 16167 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16179 | 16168 | var syscall: Syscall = try .start(); |
| ... | ... | @@ -16181,11 +16170,9 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { |
| 16181 | 16170 | &fresh_handle, |
| 16182 | 16171 | .{ .STANDARD = .{ .SYNCHRONIZE = true } }, |
| 16183 | 16172 | &.{ |
| 16184 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | |
| 16185 | .Length = @sizeOf(@TypeOf(device_path)), | |
| 16186 | .MaximumLength = 0, | |
| 16187 | .Buffer = @constCast(&device_path), | |
| 16188 | }), | |
| 16173 | .ObjectName = @constCast(&windows.UNICODE_STRING.init( | |
| 16174 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' }, | |
| 16175 | )), | |
| 16189 | 16176 | }, |
| 16190 | 16177 | &io_status_block, |
| 16191 | 16178 | .VALID_FLAGS, |
| ... | ... | @@ -16253,7 +16240,7 @@ fn windowsCreateProcessPathExt( |
| 16253 | 16240 | cwd_ptr: ?[*:0]u16, |
| 16254 | 16241 | flags: windows.CreateProcessFlags, |
| 16255 | 16242 | lpStartupInfo: *windows.STARTUPINFOW, |
| 16256 | lpProcessInformation: *windows.PROCESS_INFORMATION, | |
| 16243 | lpProcessInformation: *windows.PROCESS.INFORMATION, | |
| 16257 | 16244 | ) !void { |
| 16258 | 16245 | const app_name_len = app_buf.items.len; |
| 16259 | 16246 | const dir_path_len = dir_buf.items.len; |
| ... | ... | @@ -16341,13 +16328,9 @@ fn windowsCreateProcessPathExt( |
| 16341 | 16328 | // On NTFS, `blah.exe*` will always return `blah.exe` first if it exists. |
| 16342 | 16329 | // On FAT32, it's possible for something like `blah.exe.obj` to be returned first. |
| 16343 | 16330 | while (true) { |
| 16344 | const app_name_len_bytes = std.math.cast(u16, app_name_wildcard.len * 2) orelse return error.NameTooLong; | |
| 16345 | var app_name_unicode_string = windows.UNICODE_STRING{ | |
| 16346 | .Length = app_name_len_bytes, | |
| 16347 | .MaximumLength = app_name_len_bytes, | |
| 16348 | .Buffer = @constCast(app_name_wildcard.ptr), | |
| 16349 | }; | |
| 16350 | const rc = windows.ntdll.NtQueryDirectoryFile( | |
| 16331 | // If we get nothing with the wildcard, then we can just bail out | |
| 16332 | // as we know appending PATHEXT will not yield anything. | |
| 16333 | switch (windows.ntdll.NtQueryDirectoryFile( | |
| 16351 | 16334 | dir.handle, |
| 16352 | 16335 | null, |
| 16353 | 16336 | null, |
| ... | ... | @@ -16357,18 +16340,14 @@ fn windowsCreateProcessPathExt( |
| 16357 | 16340 | file_information_buf.len, |
| 16358 | 16341 | .Directory, |
| 16359 | 16342 | windows.FALSE, // single result |
| 16360 | &app_name_unicode_string, | |
| 16343 | &.init(app_name_wildcard), | |
| 16361 | 16344 | windows.FALSE, // restart iteration |
| 16362 | ); | |
| 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) { | |
| 16345 | )) { | |
| 16367 | 16346 | .SUCCESS => {}, |
| 16368 | 16347 | .NO_SUCH_FILE => return error.FileNotFound, |
| 16369 | 16348 | .NO_MORE_FILES => break, |
| 16370 | 16349 | .ACCESS_DENIED => return error.AccessDenied, |
| 16371 | else => return windows.unexpectedStatus(rc), | |
| 16350 | else => |status| return windows.unexpectedStatus(status), | |
| 16372 | 16351 | } |
| 16373 | 16352 | |
| 16374 | 16353 | // According to the docs, this can only happen if there is not enough room in the |
| ... | ... | @@ -16514,7 +16493,7 @@ fn windowsCreateProcess( |
| 16514 | 16493 | cwd_ptr: ?[*:0]u16, |
| 16515 | 16494 | flags: windows.CreateProcessFlags, |
| 16516 | 16495 | lpStartupInfo: *windows.STARTUPINFOW, |
| 16517 | lpProcessInformation: *windows.PROCESS_INFORMATION, | |
| 16496 | lpProcessInformation: *windows.PROCESS.INFORMATION, | |
| 16518 | 16497 | ) !void { |
| 16519 | 16498 | const syscall: Syscall = try .start(); |
| 16520 | 16499 | while (true) { |
| ... | ... | @@ -17138,7 +17117,7 @@ pub const CreatePipeOptions = struct { |
| 17138 | 17117 | default_timeout: windows.LARGE_INTEGER = -120 * std.time.ns_per_s / 100, |
| 17139 | 17118 | |
| 17140 | 17119 | pub const End = struct { |
| 17141 | attributes: windows.OBJECT_ATTRIBUTES.ATTRIBUTES = .{}, | |
| 17120 | attributes: windows.OBJECT.ATTRIBUTES.Flags = .{}, | |
| 17142 | 17121 | mode: windows.FILE.MODE, |
| 17143 | 17122 | }; |
| 17144 | 17123 | }; |
| ... | ... | @@ -18373,7 +18352,7 @@ const CreateFileMapError = error{ |
| 18373 | 18352 | OutOfMemory, |
| 18374 | 18353 | MappingAlreadyExists, |
| 18375 | 18354 | Unseekable, |
| 18376 | FileLockConflict, | |
| 18355 | LockViolation, | |
| 18377 | 18356 | } || Io.Cancelable || Io.UnexpectedError; |
| 18378 | 18357 | |
| 18379 | 18358 | fn createFileMap( |
| ... | ... | @@ -18408,7 +18387,7 @@ fn createFileMap( |
| 18408 | 18387 | file.handle, |
| 18409 | 18388 | )) { |
| 18410 | 18389 | .SUCCESS => {}, |
| 18411 | .FILE_LOCK_CONFLICT => return error.FileLockConflict, | |
| 18390 | .FILE_LOCK_CONFLICT => return error.LockViolation, | |
| 18412 | 18391 | .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported, |
| 18413 | 18392 | .ACCESS_DENIED => return error.AccessDenied, |
| 18414 | 18393 | .SECTION_TOO_BIG => return error.SectionOversize, |
| ... | ... | @@ -18724,7 +18703,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! |
| 18724 | 18703 | while (true) { |
| 18725 | 18704 | const buf = memory[i..]; |
| 18726 | 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 | 18708 | } else if (native_os == .wasi and !builtin.link_libc) { |
| 18730 | 18709 | var i: usize = 0; |
| ... | ... | @@ -18809,8 +18788,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! |
| 18809 | 18788 | } |
| 18810 | 18789 | } |
| 18811 | 18790 | |
| 18812 | fn deviceIoControl(t: *Threaded, o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result { | |
| 18813 | _ = t; | |
| 18791 | fn deviceIoControl(o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result { | |
| 18814 | 18792 | if (is_windows) { |
| 18815 | 18793 | const NtControlFile = switch (o.code.DeviceType) { |
| 18816 | 18794 | .FILE_SYSTEM, .NAMED_PIPE => &windows.ntdll.NtFsControlFile, |
| ... | ... | @@ -19104,16 +19082,10 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows |
| 19104 | 19082 | |
| 19105 | 19083 | var result: windows.HANDLE = undefined; |
| 19106 | 19084 | |
| 19107 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | |
| 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 = .{ | |
| 19085 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 19114 | 19086 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir, |
| 19115 | 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 | 19089 | .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null, |
| 19118 | 19090 | }; |
| 19119 | 19091 |
lib/std/Io/Threaded/test.zig+1-1| ... | ... | @@ -290,7 +290,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpa |
| 290 | 290 | defer windows.ntdll.RtlFreeUnicodeString(&out); |
| 291 | 291 | |
| 292 | 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 | 294 | @memcpy(path_space.data[0..out_path.len], out_path); |
| 295 | 295 | path_space.len = out.Length / 2; |
| 296 | 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 | 88 | }, |
| 89 | 89 | .windows => { |
| 90 | 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 | 91 | switch (windows.ntdll.NtSetInformationThread( |
| 102 | 92 | self.getHandle(), |
| 103 | 93 | .NameInformation, |
| 104 | &unicode_string, | |
| 94 | &windows.UNICODE_STRING.init(buf[0..try std.unicode.wtf8ToWtf16Le(&buf, name)]), | |
| 105 | 95 | @sizeOf(windows.UNICODE_STRING), |
| 106 | 96 | )) { |
| 107 | 97 | .SUCCESS => return, |
| ... | ... | @@ -217,8 +207,8 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co |
| 217 | 207 | null, |
| 218 | 208 | )) { |
| 219 | 209 | .SUCCESS => { |
| 220 | const string = @as(*const windows.UNICODE_STRING, @ptrCast(&buf)); | |
| 221 | const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]); | |
| 210 | const string: *const windows.UNICODE_STRING = @ptrCast(&buf); | |
| 211 | const len = std.unicode.wtf16LeToWtf8(buffer, string.slice()); | |
| 222 | 212 | return if (len > 0) buffer[0..len] else null; |
| 223 | 213 | }, |
| 224 | 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 | 37 | /// |
| 38 | 38 | /// ``` |
| 39 | 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 | 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 | 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 | 48 | /// /// Whether a reliable stack unwinding strategy, such as DWARF unwinding, is available. |
| 48 | 49 | /// pub const can_unwind: bool; |
| ... | ... | @@ -51,15 +52,15 @@ pub const cpu_context = @import("debug/cpu_context.zig"); |
| 51 | 52 | /// /// An address representing the instruction pointer in the last frame. |
| 52 | 53 | /// pc: usize, |
| 53 | 54 | /// |
| 54 | /// pub fn init(ctx: *cpu_context.Native, gpa: Allocator) Allocator.Error!UnwindContext; | |
| 55 | /// pub fn deinit(ctx: *UnwindContext, gpa: Allocator) void; | |
| 55 | /// pub fn init(ctx: *cpu_context.Native) Allocator.Error!UnwindContext; | |
| 56 | /// pub fn deinit(ctx: *UnwindContext) void; | |
| 56 | 57 | /// /// Returns the frame pointer associated with the last unwound stack frame. |
| 57 | 58 | /// /// If the frame pointer is unknown, 0 may be returned instead. |
| 58 | 59 | /// pub fn getFp(uc: *UnwindContext) usize; |
| 59 | 60 | /// }; |
| 60 | 61 | /// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's |
| 61 | 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 | /// ``` |
| 64 | 65 | pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) |
| 65 | 66 | root.debug.SelfInfo |
| ... | ... | @@ -669,7 +670,6 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 669 | 670 | t.setColor(.reset) catch {}; |
| 670 | 671 | return; |
| 671 | 672 | } |
| 672 | const di_gpa = getDebugInfoAllocator(); | |
| 673 | 673 | const di = getSelfDebugInfo() catch |err| switch (err) { |
| 674 | 674 | error.UnsupportedTarget => { |
| 675 | 675 | t.setColor(.dim) catch {}; |
| ... | ... | @@ -696,7 +696,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 696 | 696 | .useless, .unsafe => {}, |
| 697 | 697 | .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 | 700 | const caption: []const u8 = switch (unwind_error.err) { |
| 701 | 701 | error.MissingDebugInfo => "unwind info unavailable", |
| 702 | 702 | error.InvalidDebugInfo => "unwind info invalid", |
| ... | ... | @@ -741,7 +741,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 741 | 741 | } |
| 742 | 742 | // `ret_addr` is the return address, which is *after* the function call. |
| 743 | 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 | 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 | 788 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. |
| 789 | 789 | const n_frames = st.index; |
| 790 | 790 | if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); |
| 791 | const di_gpa = getDebugInfoAllocator(); | |
| 792 | 791 | const di = getSelfDebugInfo() catch |err| switch (err) { |
| 793 | 792 | error.UnsupportedTarget => { |
| 794 | 793 | t.setColor(.dim) catch {}; |
| ... | ... | @@ -802,7 +801,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void |
| 802 | 801 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { |
| 803 | 802 | // `ret_addr` is the return address, which is *after* the function call. |
| 804 | 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 | 806 | if (n_frames > captured_frames) { |
| 808 | 807 | t.setColor(.bold) catch {}; |
| ... | ... | @@ -875,7 +874,7 @@ const StackIterator = union(enum) { |
| 875 | 874 | switch (si.*) { |
| 876 | 875 | .ctx_first => {}, |
| 877 | 876 | .fp => {}, |
| 878 | .di => |*unwind_context| unwind_context.deinit(getDebugInfoAllocator()), | |
| 877 | .di => |*unwind_context| unwind_context.deinit(), | |
| 879 | 878 | } |
| 880 | 879 | } |
| 881 | 880 | |
| ... | ... | @@ -980,8 +979,7 @@ const StackIterator = union(enum) { |
| 980 | 979 | }, |
| 981 | 980 | .di => |*unwind_context| { |
| 982 | 981 | const di = getSelfDebugInfo() catch unreachable; |
| 983 | const di_gpa = getDebugInfoAllocator(); | |
| 984 | const ret_addr = di.unwindFrame(di_gpa, io, unwind_context) catch |err| { | |
| 982 | const ret_addr = di.unwindFrame(io, unwind_context) catch |err| { | |
| 985 | 983 | const pc = unwind_context.pc; |
| 986 | 984 | const fp = unwind_context.getFp(); |
| 987 | 985 | it.* = .{ .fp = fp }; |
| ... | ... | @@ -1109,14 +1107,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { |
| 1109 | 1107 | return ptr; |
| 1110 | 1108 | } |
| 1111 | 1109 | |
| 1112 | fn printSourceAtAddress( | |
| 1113 | gpa: Allocator, | |
| 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) { | |
| 1110 | fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void { | |
| 1111 | const symbol: Symbol = debug_info.getSymbol(io, address) catch |err| switch (err) { | |
| 1120 | 1112 | error.MissingDebugInfo, |
| 1121 | 1113 | error.UnsupportedDebugInfo, |
| 1122 | 1114 | error.InvalidDebugInfo, |
| ... | ... | @@ -1134,14 +1126,14 @@ fn printSourceAtAddress( |
| 1134 | 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 | 1130 | return printLineInfo( |
| 1139 | 1131 | io, |
| 1140 | 1132 | t, |
| 1141 | 1133 | symbol.source_location, |
| 1142 | 1134 | address, |
| 1143 | 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 | } |
| 1147 | 1139 | fn printLineInfo( |
| ... | ... | @@ -1608,14 +1600,13 @@ test "manage resources correctly" { |
| 1608 | 1600 | return @returnAddress(); |
| 1609 | 1601 | } |
| 1610 | 1602 | }; |
| 1611 | const gpa = testing.allocator; | |
| 1612 | 1603 | const io = testing.io; |
| 1613 | 1604 | |
| 1614 | 1605 | var discarding: Writer.Discarding = .init(&.{}); |
| 1615 | 1606 | var di: SelfInfo = .init; |
| 1616 | defer di.deinit(gpa); | |
| 1607 | defer di.deinit(io); | |
| 1617 | 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 | } |
| 1620 | 1611 | |
| 1621 | 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 | 55 | }; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | pub fn deinit(unwinder: *SelfUnwinder, gpa: Allocator) void { | |
| 58 | pub fn deinit(unwinder: *SelfUnwinder) void { | |
| 59 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 59 | 60 | unwinder.cfi_vm.deinit(gpa); |
| 60 | 61 | unwinder.expr_vm.deinit(gpa); |
| 61 | 62 | unwinder.* = undefined; |
lib/std/debug/SelfInfo/Elf.zig+11-5| ... | ... | @@ -11,7 +11,9 @@ pub const init: SelfInfo = .{ |
| 11 | 11 | .ranges = .empty, |
| 12 | 12 | .unwind_cache = null, |
| 13 | 13 | }; |
| 14 | pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | |
| 14 | pub fn deinit(si: *SelfInfo, io: Io) void { | |
| 15 | _ = io; | |
| 16 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 15 | 17 | for (si.modules.items) |*mod| { |
| 16 | 18 | unwind: { |
| 17 | 19 | const u = &(mod.unwind orelse break :unwind catch break :unwind); |
| ... | ... | @@ -28,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 28 | 30 | if (si.unwind_cache) |cache| gpa.free(cache); |
| 29 | 31 | } |
| 30 | 32 | |
| 31 | pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol { | |
| 33 | pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { | |
| 34 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 32 | 35 | const module = try si.findModule(gpa, io, address, .exclusive); |
| 33 | 36 | defer si.rwlock.unlock(io); |
| 34 | 37 | |
| ... | ... | @@ -73,13 +76,15 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st |
| 73 | 76 | error.OutOfMemory => |e| return e, |
| 74 | 77 | }; |
| 75 | 78 | } |
| 76 | pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 { | |
| 79 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { | |
| 80 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 77 | 81 | const module = try si.findModule(gpa, io, address, .shared); |
| 78 | 82 | defer si.rwlock.unlockShared(io); |
| 79 | 83 | if (module.name.len == 0) return error.MissingDebugInfo; |
| 80 | 84 | return module.name; |
| 81 | 85 | } |
| 82 | pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize { | |
| 86 | pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { | |
| 87 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 83 | 88 | const module = try si.findModule(gpa, io, address, .shared); |
| 84 | 89 | defer si.rwlock.unlockShared(io); |
| 85 | 90 | return module.load_offset; |
| ... | ... | @@ -179,8 +184,9 @@ comptime { |
| 179 | 184 | } |
| 180 | 185 | } |
| 181 | 186 | pub const UnwindContext = Dwarf.SelfUnwinder; |
| 182 | pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize { | |
| 187 | pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize { | |
| 183 | 188 | comptime assert(can_unwind); |
| 189 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 184 | 190 | |
| 185 | 191 | { |
| 186 | 192 | si.rwlock.lockSharedUncancelable(io); |
lib/std/debug/SelfInfo/MachO.zig+12-8| ... | ... | @@ -6,7 +6,9 @@ pub const init: SelfInfo = .{ |
| 6 | 6 | .mutex = .init, |
| 7 | 7 | .modules = .empty, |
| 8 | 8 | }; |
| 9 | pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | |
| 9 | pub fn deinit(si: *SelfInfo, io: Io) void { | |
| 10 | _ = io; | |
| 11 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 10 | 12 | for (si.modules.keys()) |*module| { |
| 11 | 13 | unwind: { |
| 12 | 14 | const u = &(module.unwind orelse break :unwind catch break :unwind); |
| ... | ... | @@ -20,7 +22,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 20 | 22 | si.modules.deinit(gpa); |
| 21 | 23 | } |
| 22 | 24 | |
| 23 | pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol { | |
| 25 | pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { | |
| 26 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 24 | 27 | const module = try si.findModule(gpa, io, address); |
| 25 | 28 | defer si.mutex.unlock(io); |
| 26 | 29 | |
| ... | ... | @@ -76,9 +79,8 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st |
| 76 | 79 | ) catch null, |
| 77 | 80 | }; |
| 78 | 81 | } |
| 79 | pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 { | |
| 82 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { | |
| 80 | 83 | _ = si; |
| 81 | _ = gpa; | |
| 82 | 84 | _ = io; |
| 83 | 85 | // This function is marked as deprecated; however, it is significantly more |
| 84 | 86 | // 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 | 89 | @ptrFromInt(address), |
| 88 | 90 | ) orelse return error.MissingDebugInfo); |
| 89 | 91 | } |
| 90 | pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize { | |
| 92 | pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { | |
| 93 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 91 | 94 | const module = try si.findModule(gpa, io, address); |
| 92 | 95 | defer si.mutex.unlock(io); |
| 93 | 96 | const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base); |
| ... | ... | @@ -107,8 +110,8 @@ pub const UnwindContext = std.debug.Dwarf.SelfUnwinder; |
| 107 | 110 | /// Unwind a frame using MachO compact unwind info (from `__unwind_info`). |
| 108 | 111 | /// If the compact encoding can't encode a way to unwind a frame, it will |
| 109 | 112 | /// defer unwinding to DWARF, in which case `__eh_frame` will be used if available. |
| 110 | pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize { | |
| 111 | return unwindFrameInner(si, gpa, io, context) catch |err| switch (err) { | |
| 113 | pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize { | |
| 114 | return unwindFrameInner(si, io, context) catch |err| switch (err) { | |
| 112 | 115 | error.InvalidDebugInfo, |
| 113 | 116 | error.MissingDebugInfo, |
| 114 | 117 | error.UnsupportedDebugInfo, |
| ... | ... | @@ -134,7 +137,8 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex |
| 134 | 137 | => return error.InvalidDebugInfo, |
| 135 | 138 | }; |
| 136 | 139 | } |
| 137 | fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) !usize { | |
| 140 | fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize { | |
| 141 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 138 | 142 | const module = try si.findModule(gpa, io, context.pc); |
| 139 | 143 | defer si.mutex.unlock(io); |
| 140 | 144 |
lib/std/debug/SelfInfo/Windows.zig+151-86| ... | ... | @@ -1,39 +1,51 @@ |
| 1 | 1 | mutex: Io.Mutex, |
| 2 | ntdll_handle: ?if (load_dll_notification_procs) *anyopaque else noreturn, | |
| 3 | notification_cookie: ?LDR.DLL_NOTIFICATION.COOKIE, | |
| 2 | 4 | modules: std.ArrayList(Module), |
| 3 | module_name_arena: std.heap.ArenaAllocator.State, | |
| 4 | 5 | |
| 5 | 6 | pub const init: SelfInfo = .{ |
| 6 | 7 | .mutex = .init, |
| 8 | .ntdll_handle = null, | |
| 9 | .notification_cookie = null, | |
| 7 | 10 | .modules = .empty, |
| 8 | .module_name_arena = .{}, | |
| 9 | 11 | }; |
| 10 | pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | |
| 11 | for (si.modules.items) |*module| { | |
| 12 | di: { | |
| 13 | const di = &(module.di orelse break :di catch break :di); | |
| 14 | di.deinit(gpa); | |
| 12 | pub fn deinit(si: *SelfInfo, io: Io) void { | |
| 13 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 14 | if (si.notification_cookie) |cookie| unregister: { | |
| 15 | switch ((si.getNtdllProc(.LdrUnregisterDllNotification) catch break :unregister)(cookie)) { | |
| 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 | 25 | si.modules.deinit(gpa); |
| 18 | ||
| 19 | var module_name_arena = si.module_name_arena.promote(gpa); | |
| 20 | module_name_arena.deinit(); | |
| 21 | 26 | } |
| 22 | 27 | |
| 23 | pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol { | |
| 28 | pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { | |
| 29 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 24 | 30 | try si.mutex.lock(io); |
| 25 | 31 | defer si.mutex.unlock(io); |
| 26 | 32 | const module = try si.findModule(gpa, address); |
| 27 | 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 | } |
| 30 | pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error![]const u8 { | |
| 36 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { | |
| 37 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 31 | 38 | try si.mutex.lock(io); |
| 32 | 39 | defer si.mutex.unlock(io); |
| 33 | 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 | } |
| 36 | pub fn getModuleSlide(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!usize { | |
| 47 | pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { | |
| 48 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 37 | 49 | try si.mutex.lock(io); |
| 38 | 50 | defer si.mutex.unlock(io); |
| 39 | 51 | const module = try si.findModule(gpa, address); |
| ... | ... | @@ -141,18 +153,16 @@ pub const UnwindContext = struct { |
| 141 | 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 | 157 | _ = ctx; |
| 146 | _ = gpa; | |
| 147 | 158 | } |
| 148 | 159 | pub fn getFp(ctx: *UnwindContext) usize { |
| 149 | 160 | return ctx.cur.getRegs().bp; |
| 150 | 161 | } |
| 151 | 162 | }; |
| 152 | pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize { | |
| 163 | pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize { | |
| 153 | 164 | _ = si; |
| 154 | 165 | _ = io; |
| 155 | _ = gpa; | |
| 156 | 166 | |
| 157 | 167 | const current_regs = context.cur.getRegs(); |
| 158 | 168 | var image_base: usize = undefined; |
| ... | ... | @@ -188,16 +198,12 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex |
| 188 | 198 | } |
| 189 | 199 | |
| 190 | 200 | const Module = struct { |
| 191 | base_address: usize, | |
| 192 | size: u32, | |
| 193 | name: []const u8, | |
| 194 | handle: windows.HMODULE, | |
| 195 | ||
| 201 | entry: *const LDR.DATA_TABLE_ENTRY, | |
| 202 | name: ?[]const u8, | |
| 196 | 203 | di: ?(Error!DebugInfo), |
| 197 | 204 | |
| 198 | 205 | const DebugInfo = struct { |
| 199 | 206 | arena: std.heap.ArenaAllocator.State, |
| 200 | io: Io, | |
| 201 | 207 | coff_image_base: u64, |
| 202 | 208 | mapped_file: ?MappedFile, |
| 203 | 209 | dwarf: ?Dwarf, |
| ... | ... | @@ -210,14 +216,19 @@ const Module = struct { |
| 210 | 216 | section_view: []const u8, |
| 211 | 217 | fn deinit(mf: *const MappedFile, io: Io) void { |
| 212 | 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 | 226 | windows.CloseHandle(mf.section_handle); |
| 215 | 227 | mf.file.close(io); |
| 216 | 228 | } |
| 217 | 229 | }; |
| 218 | 230 | |
| 219 | fn deinit(di: *DebugInfo, gpa: Allocator) void { | |
| 220 | const io = di.io; | |
| 231 | fn deinit(di: *DebugInfo, gpa: Allocator, io: Io) void { | |
| 221 | 232 | if (di.dwarf) |*dwarf| dwarf.deinit(gpa); |
| 222 | 233 | if (di.pdb) |*pdb| { |
| 223 | 234 | pdb.file_reader.file.close(io); |
| ... | ... | @@ -262,7 +273,10 @@ const Module = struct { |
| 262 | 273 | return .{ |
| 263 | 274 | .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address), |
| 264 | 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 | 282 | dwarf: { |
| ... | ... | @@ -286,13 +300,19 @@ const Module = struct { |
| 286 | 300 | } |
| 287 | 301 | }; |
| 288 | 302 | |
| 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 | 309 | fn getDebugInfo(module: *Module, gpa: Allocator, io: Io) Error!*DebugInfo { |
| 290 | 310 | if (module.di == null) module.di = loadDebugInfo(module, gpa, io); |
| 291 | 311 | return if (module.di.?) |*di| di else |err| err; |
| 292 | 312 | } |
| 293 | 313 | fn loadDebugInfo(module: *const Module, gpa: Allocator, io: Io) Error!DebugInfo { |
| 294 | const mapped_ptr: [*]const u8 = @ptrFromInt(module.base_address); | |
| 295 | const mapped = mapped_ptr[0..module.size]; | |
| 314 | const mapped_ptr: [*]const u8 = @ptrCast(module.entry.DllBase); | |
| 315 | const mapped = mapped_ptr[0..module.entry.SizeOfImage]; | |
| 296 | 316 | var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo; |
| 297 | 317 | |
| 298 | 318 | var arena_instance: std.heap.ArenaAllocator = .init(gpa); |
| ... | ... | @@ -304,18 +324,15 @@ const Module = struct { |
| 304 | 324 | // a binary is produced with -gdwarf, since the section names are longer than 8 bytes. |
| 305 | 325 | const mapped_file: ?DebugInfo.MappedFile = mapped: { |
| 306 | 326 | if (!coff_obj.strtabRequired()) break :mapped null; |
| 307 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; | |
| 308 | name_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present | |
| 309 | const process_handle = windows.GetCurrentProcess(); | |
| 310 | const len = windows.kernel32.GetModuleFileNameExW( | |
| 311 | process_handle, | |
| 312 | module.handle, | |
| 313 | name_buffer[4..], | |
| 314 | windows.PATH_MAX_WIDE, | |
| 315 | ); | |
| 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) { | |
| 327 | var path_buffer: [4 + windows.PATH_MAX_WIDE]u16 = undefined; | |
| 328 | path_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present | |
| 329 | const path_slice = module.entry.FullDllName.slice(); | |
| 330 | @memcpy(path_buffer[4..][0..path_slice.len], path_slice); | |
| 331 | const coff_file = Io.Threaded.dirOpenFileWtf16( | |
| 332 | null, | |
| 333 | path_buffer[0 .. 4 + path_slice.len], | |
| 334 | .{}, | |
| 335 | ) catch |err| switch (err) { | |
| 319 | 336 | error.Canceled => |e| return e, |
| 320 | 337 | error.Unexpected => |e| return e, |
| 321 | 338 | error.FileNotFound => return error.MissingDebugInfo, |
| ... | ... | @@ -359,7 +376,8 @@ const Module = struct { |
| 359 | 376 | null, |
| 360 | 377 | null, |
| 361 | 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 | 381 | // In practice, this isn't the case and specifying 0 will result in INVALID_PARAMETER_6. |
| 364 | 382 | .{ .COMMIT = true }, |
| 365 | 383 | coff_file.handle, |
| ... | ... | @@ -368,6 +386,7 @@ const Module = struct { |
| 368 | 386 | errdefer windows.CloseHandle(section_handle); |
| 369 | 387 | var coff_len: usize = 0; |
| 370 | 388 | var section_view_ptr: ?[*]const u8 = null; |
| 389 | const process_handle = windows.GetCurrentProcess(); | |
| 371 | 390 | const map_section_rc = windows.ntdll.NtMapViewOfSection( |
| 372 | 391 | section_handle, |
| 373 | 392 | process_handle, |
| ... | ... | @@ -381,7 +400,13 @@ const Module = struct { |
| 381 | 400 | .{ .READONLY = true }, |
| 382 | 401 | ); |
| 383 | 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 | 410 | const section_view = section_view_ptr.?[0..coff_len]; |
| 386 | 411 | coff_obj = coff.Coff.init(section_view, false) catch return error.InvalidDebugInfo; |
| 387 | 412 | break :mapped .{ |
| ... | ... | @@ -496,7 +521,6 @@ const Module = struct { |
| 496 | 521 | |
| 497 | 522 | return .{ |
| 498 | 523 | .arena = arena_instance.state, |
| 499 | .io = io, | |
| 500 | 524 | .coff_image_base = coff_image_base, |
| 501 | 525 | .mapped_file = mapped_file, |
| 502 | 526 | .dwarf = opt_dwarf, |
| ... | ... | @@ -509,52 +533,82 @@ const Module = struct { |
| 509 | 533 | /// Assumes we already hold `si.mutex`. |
| 510 | 534 | fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module { |
| 511 | 535 | for (si.modules.items) |*mod| { |
| 512 | if (address >= mod.base_address and address < mod.base_address + mod.size) { | |
| 513 | return mod; | |
| 514 | } | |
| 536 | const base = @intFromPtr(mod.entry.DllBase); | |
| 537 | if (address >= base and address < base + mod.entry.SizeOfImage) return mod; | |
| 515 | 538 | } |
| 516 | ||
| 517 | // A new module might have been loaded; rebuild the list. | |
| 518 | { | |
| 519 | for (si.modules.items) |*mod| { | |
| 520 | const di = &(mod.di orelse continue catch continue); | |
| 521 | di.deinit(gpa); | |
| 522 | } | |
| 523 | si.modules.clearRetainingCapacity(); | |
| 524 | ||
| 525 | var module_name_arena = si.module_name_arena.promote(gpa); | |
| 526 | defer si.module_name_arena = module_name_arena.state; | |
| 527 | _ = module_name_arena.reset(.retain_capacity); | |
| 528 | ||
| 529 | const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0); | |
| 530 | if (handle == windows.INVALID_HANDLE_VALUE) { | |
| 531 | return windows.unexpectedError(windows.GetLastError()); | |
| 532 | } | |
| 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 | }); | |
| 539 | try si.modules.ensureUnusedCapacity(gpa, 1); | |
| 540 | var entry: *LDR.DATA_TABLE_ENTRY = undefined; | |
| 541 | switch (windows.ntdll.LdrFindEntryForAddress(@ptrFromInt(address), &entry)) { | |
| 542 | .SUCCESS => {}, | |
| 543 | .DLL_NOT_FOUND => return error.MissingDebugInfo, | |
| 544 | else => |status| return windows.unexpectedStatus(status), | |
| 545 | } | |
| 546 | if (si.notification_cookie == null) { | |
| 547 | var notification_cookie: LDR.DLL_NOTIFICATION.COOKIE = undefined; | |
| 548 | switch ((try si.getNtdllProc(.LdrRegisterDllNotification))( | |
| 549 | .{}, | |
| 550 | &dllNotification, | |
| 551 | si, | |
| 552 | &notification_cookie, | |
| 553 | )) { | |
| 554 | .SUCCESS => si.notification_cookie = notification_cookie, | |
| 555 | else => |status| return windows.unexpectedStatus(status), | |
| 548 | 556 | } |
| 549 | 557 | } |
| 558 | const mod = si.modules.addOneAssumeCapacity(); | |
| 559 | mod.* = .{ .entry = entry, .name = null, .di = null }; | |
| 560 | return mod; | |
| 561 | } | |
| 550 | 562 | |
| 551 | for (si.modules.items) |*mod| { | |
| 552 | if (address >= mod.base_address and address < mod.base_address + mod.size) { | |
| 553 | return mod; | |
| 563 | inline fn getNtdllProc( | |
| 564 | si: *SelfInfo, | |
| 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 | } | |
| 572 | fn 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 | } | |
| 556 | 591 | |
| 557 | return error.MissingDebugInfo; | |
| 592 | fn 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 | } |
| 559 | 613 | |
| 560 | 614 | const std = @import("std"); |
| ... | ... | @@ -563,12 +617,23 @@ const Allocator = std.mem.Allocator; |
| 563 | 617 | const Dwarf = std.debug.Dwarf; |
| 564 | 618 | const Pdb = std.debug.Pdb; |
| 565 | 619 | const Error = std.debug.SelfInfoError; |
| 566 | const assert = std.debug.assert; | |
| 567 | 620 | const coff = std.coff; |
| 568 | 621 | const fs = std.fs; |
| 569 | 622 | const windows = std.os.windows; |
| 623 | const LDR = windows.LDR; | |
| 570 | 624 | |
| 571 | 625 | const builtin = @import("builtin"); |
| 572 | 626 | const native_endian = builtin.target.cpu.arch.endian(); |
| 627 | const 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 | }; | |
| 573 | 638 | |
| 574 | 639 | const SelfInfo = @This(); |
lib/std/heap.zig+3-3| ... | ... | @@ -110,11 +110,11 @@ pub fn defaultQueryPageSize() usize { |
| 110 | 110 | break :size @intCast(vm_info.page_size); |
| 111 | 111 | }, |
| 112 | 112 | .windows => { |
| 113 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | |
| 113 | var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined; | |
| 114 | 114 | switch (windows.ntdll.NtQuerySystemInformation( |
| 115 | .SystemBasicInformation, | |
| 115 | .Basic, | |
| 116 | 116 | &sbi, |
| 117 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | |
| 117 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), | |
| 118 | 118 | null, |
| 119 | 119 | )) { |
| 120 | 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 | 24 | |
| 25 | 25 | pub const current_process: HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))); |
| 26 | 26 | |
| 27 | pub 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 | ||
| 27 | 87 | pub const FILE = struct { |
| 28 | 88 | // ref: km/ntddk.h |
| 29 | 89 | |
| ... | ... | @@ -73,6 +133,94 @@ pub const FILE = struct { |
| 73 | 133 | |
| 74 | 134 | // ref: km/ntifs.h |
| 75 | 135 | |
| 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 | 224 | pub const PIPE = struct { |
| 77 | 225 | /// Define the `NamedPipeType` flags for `NtCreateNamedPipeFile` |
| 78 | 226 | pub const TYPE = packed struct(ULONG) { |
| ... | ... | @@ -357,6 +505,7 @@ pub const FILE = struct { |
| 357 | 505 | IdAllExtdBothDirectory = 81, |
| 358 | 506 | StreamReservation = 82, |
| 359 | 507 | MupProvider = 83, |
| 508 | _, | |
| 360 | 509 | |
| 361 | 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 | 796 | Mode: MODE, |
| 648 | 797 | }; |
| 649 | 798 | }; |
| 799 | ||
| 800 | // ref: km/ | |
| 801 | }; | |
| 802 | ||
| 803 | pub 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 | }; |
| 651 | 813 | |
| 652 | 814 | pub const CONSOLE = struct { |
| ... | ... | @@ -880,141 +1042,229 @@ pub const CONSOLE = struct { |
| 880 | 1042 | |
| 881 | 1043 | // ref: km/ntddk.h |
| 882 | 1044 | |
| 883 | pub const PROCESSINFOCLASS = enum(c_int) { | |
| 884 | BasicInformation = 0, | |
| 885 | QuotaLimits = 1, | |
| 886 | IoCounters = 2, | |
| 887 | VmCounters = 3, | |
| 888 | Times = 4, | |
| 889 | BasePriority = 5, | |
| 890 | RaisePriority = 6, | |
| 891 | DebugPort = 7, | |
| 892 | ExceptionPort = 8, | |
| 893 | AccessToken = 9, | |
| 894 | LdtInformation = 10, | |
| 895 | LdtSize = 11, | |
| 896 | DefaultHardErrorMode = 12, | |
| 897 | IoPortHandlers = 13, | |
| 898 | PooledUsageAndLimits = 14, | |
| 899 | WorkingSetWatch = 15, | |
| 900 | UserModeIOPL = 16, | |
| 901 | EnableAlignmentFaultFixup = 17, | |
| 902 | PriorityClass = 18, | |
| 903 | Wx86Information = 19, | |
| 904 | HandleCount = 20, | |
| 905 | AffinityMask = 21, | |
| 906 | PriorityBoost = 22, | |
| 907 | DeviceMap = 23, | |
| 908 | SessionInformation = 24, | |
| 909 | ForegroundInformation = 25, | |
| 910 | Wow64Information = 26, | |
| 911 | ImageFileName = 27, | |
| 912 | LUIDDeviceMapsEnabled = 28, | |
| 913 | BreakOnTermination = 29, | |
| 914 | DebugObjectHandle = 30, | |
| 915 | DebugFlags = 31, | |
| 916 | HandleTracing = 32, | |
| 917 | IoPriority = 33, | |
| 918 | ExecuteFlags = 34, | |
| 919 | TlsInformation = 35, | |
| 920 | Cookie = 36, | |
| 921 | ImageInformation = 37, | |
| 922 | CycleTime = 38, | |
| 923 | PagePriority = 39, | |
| 924 | InstrumentationCallback = 40, | |
| 925 | ThreadStackAllocation = 41, | |
| 926 | WorkingSetWatchEx = 42, | |
| 927 | ImageFileNameWin32 = 43, | |
| 928 | ImageFileMapping = 44, | |
| 929 | AffinityUpdateMode = 45, | |
| 930 | MemoryAllocationMode = 46, | |
| 931 | GroupInformation = 47, | |
| 932 | TokenVirtualizationEnabled = 48, | |
| 933 | OwnerInformation = 49, | |
| 934 | WindowInformation = 50, | |
| 935 | HandleInformation = 51, | |
| 936 | MitigationPolicy = 52, | |
| 937 | DynamicFunctionTableInformation = 53, | |
| 938 | HandleCheckingMode = 54, | |
| 939 | KeepAliveCount = 55, | |
| 940 | RevokeFileHandles = 56, | |
| 941 | WorkingSetControl = 57, | |
| 942 | HandleTable = 58, | |
| 943 | CheckStackExtentsMode = 59, | |
| 944 | CommandLineInformation = 60, | |
| 945 | ProtectionInformation = 61, | |
| 946 | MemoryExhaustion = 62, | |
| 947 | FaultInformation = 63, | |
| 948 | TelemetryIdInformation = 64, | |
| 949 | CommitReleaseInformation = 65, | |
| 950 | Reserved1Information = 66, | |
| 951 | Reserved2Information = 67, | |
| 952 | SubsystemProcess = 68, | |
| 953 | InPrivate = 70, | |
| 954 | RaiseUMExceptionOnInvalidHandleClose = 71, | |
| 955 | SubsystemInformation = 75, | |
| 956 | Win32kSyscallFilterInformation = 79, | |
| 957 | EnergyTrackingState = 82, | |
| 958 | NetworkIoCounters = 114, | |
| 959 | _, | |
| 1045 | pub const SYSTEM = struct { | |
| 1046 | pub const INFORMATION_CLASS = enum(c_int) { | |
| 1047 | Basic = 0, | |
| 1048 | Performance = 2, | |
| 1049 | TimeOfDay = 3, | |
| 1050 | Process = 5, | |
| 1051 | ProcessorPerformance = 8, | |
| 1052 | Interrupt = 23, | |
| 1053 | Exception = 33, | |
| 1054 | RegistryQuota = 37, | |
| 1055 | Lookaside = 45, | |
| 1056 | CodeIntegrity = 103, | |
| 1057 | Policy = 134, | |
| 1058 | _, | |
| 1059 | }; | |
| 1060 | ||
| 1061 | pub const BASIC_INFORMATION = extern struct { | |
| 1062 | Reserved: ULONG, | |
| 1063 | TimerResolution: ULONG, | |
| 1064 | PageSize: ULONG, | |
| 1065 | NumberOfPhysicalPages: ULONG, | |
| 1066 | LowestPhysicalPageNumber: ULONG, | |
| 1067 | HighestPhysicalPageNumber: ULONG, | |
| 1068 | AllocationGranularity: ULONG, | |
| 1069 | MinimumUserModeAddress: ULONG_PTR, | |
| 1070 | MaximumUserModeAddress: ULONG_PTR, | |
| 1071 | ActiveProcessorsAffinityMask: KAFFINITY, | |
| 1072 | NumberOfProcessors: UCHAR, | |
| 1073 | }; | |
| 1074 | }; | |
| 1075 | ||
| 1076 | pub const PROCESS = struct { | |
| 1077 | pub const INFORMATION = extern struct { | |
| 1078 | hProcess: HANDLE, | |
| 1079 | hThread: HANDLE, | |
| 1080 | dwProcessId: DWORD, | |
| 1081 | dwThreadId: DWORD, | |
| 1082 | }; | |
| 1083 | ||
| 1084 | pub const INFOCLASS = enum(c_int) { | |
| 1085 | BasicInformation = 0, | |
| 1086 | QuotaLimits = 1, | |
| 1087 | IoCounters = 2, | |
| 1088 | VmCounters = 3, | |
| 1089 | Times = 4, | |
| 1090 | BasePriority = 5, | |
| 1091 | RaisePriority = 6, | |
| 1092 | DebugPort = 7, | |
| 1093 | ExceptionPort = 8, | |
| 1094 | AccessToken = 9, | |
| 1095 | LdtInformation = 10, | |
| 1096 | LdtSize = 11, | |
| 1097 | DefaultHardErrorMode = 12, | |
| 1098 | IoPortHandlers = 13, | |
| 1099 | PooledUsageAndLimits = 14, | |
| 1100 | WorkingSetWatch = 15, | |
| 1101 | UserModeIOPL = 16, | |
| 1102 | EnableAlignmentFaultFixup = 17, | |
| 1103 | PriorityClass = 18, | |
| 1104 | Wx86Information = 19, | |
| 1105 | HandleCount = 20, | |
| 1106 | AffinityMask = 21, | |
| 1107 | PriorityBoost = 22, | |
| 1108 | DeviceMap = 23, | |
| 1109 | SessionInformation = 24, | |
| 1110 | ForegroundInformation = 25, | |
| 1111 | Wow64Information = 26, | |
| 1112 | ImageFileName = 27, | |
| 1113 | LUIDDeviceMapsEnabled = 28, | |
| 1114 | BreakOnTermination = 29, | |
| 1115 | DebugObjectHandle = 30, | |
| 1116 | DebugFlags = 31, | |
| 1117 | HandleTracing = 32, | |
| 1118 | IoPriority = 33, | |
| 1119 | ExecuteFlags = 34, | |
| 1120 | TlsInformation = 35, | |
| 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 | ||
| 1189 | pub 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 | }; | |
| 960 | 1246 | |
| 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 | }; |
| 963 | 1256 | |
| 964 | pub const THREADINFOCLASS = enum(c_int) { | |
| 965 | BasicInformation = 0, | |
| 966 | Times = 1, | |
| 967 | Priority = 2, | |
| 968 | BasePriority = 3, | |
| 969 | AffinityMask = 4, | |
| 970 | ImpersonationToken = 5, | |
| 971 | DescriptorTableEntry = 6, | |
| 972 | EnableAlignmentFaultFixup = 7, | |
| 973 | EventPair_Reusable = 8, | |
| 974 | QuerySetWin32StartAddress = 9, | |
| 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; | |
| 1257 | pub const MEMORY = struct { | |
| 1258 | pub const BASIC_INFORMATION = extern struct { | |
| 1259 | BaseAddress: PVOID, | |
| 1260 | AllocationBase: PVOID, | |
| 1261 | AllocationProtect: DWORD, | |
| 1262 | PartitionId: WORD, | |
| 1263 | RegionSize: SIZE_T, | |
| 1264 | State: DWORD, | |
| 1265 | Protect: DWORD, | |
| 1266 | Type: DWORD, | |
| 1267 | }; | |
| 1018 | 1268 | }; |
| 1019 | 1269 | |
| 1020 | 1270 | // ref: km/ntifs.h |
| ... | ... | @@ -2560,48 +2810,6 @@ pub fn GetProcessHeap() ?*HEAP { |
| 2560 | 2810 | return peb().ProcessHeap; |
| 2561 | 2811 | } |
| 2562 | 2812 | |
| 2563 | // ref: um/winternl.h | |
| 2564 | ||
| 2565 | pub 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 | 2813 | // ref none |
| 2606 | 2814 | |
| 2607 | 2815 | pub fn GetCurrentProcess() HANDLE { |
| ... | ... | @@ -2623,297 +2831,13 @@ pub fn GetCurrentThreadId() DWORD { |
| 2623 | 2831 | } |
| 2624 | 2832 | |
| 2625 | 2833 | pub fn GetLastError() Win32Error { |
| 2626 | return @enumFromInt(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. | |
| 2632 | pub 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 | ||
| 2673 | pub 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 | ||
| 2684 | pub const CreateIoCompletionPortError = error{Unexpected}; | |
| 2685 | ||
| 2686 | pub 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 | ||
| 2701 | pub const PostQueuedCompletionStatusError = error{Unexpected}; | |
| 2702 | ||
| 2703 | pub 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 | ||
| 2716 | pub const GetQueuedCompletionStatusResult = enum { | |
| 2717 | Normal, | |
| 2718 | Aborted, | |
| 2719 | Canceled, | |
| 2720 | EOF, | |
| 2721 | Timeout, | |
| 2722 | }; | |
| 2723 | ||
| 2724 | pub 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 | ||
| 2754 | pub const GetQueuedCompletionStatusError = error{ | |
| 2755 | Aborted, | |
| 2756 | Canceled, | |
| 2757 | EOF, | |
| 2758 | Timeout, | |
| 2759 | } || UnexpectedError; | |
| 2760 | ||
| 2761 | pub 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; | |
| 2834 | return teb().LastErrorValue; | |
| 2789 | 2835 | } |
| 2790 | 2836 | |
| 2791 | 2837 | pub fn CloseHandle(hObject: HANDLE) void { |
| 2792 | assert(ntdll.NtClose(hObject) == .SUCCESS); | |
| 2793 | } | |
| 2794 | ||
| 2795 | pub 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 | ||
| 2799 | pub 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 | ||
| 2812 | pub 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 | ||
| 2822 | pub 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 | ||
| 2833 | pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 { | |
| 2834 | return ws2_32.WSAPoll(fds, n, timeout); | |
| 2835 | } | |
| 2836 | ||
| 2837 | pub 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 | ||
| 2866 | const GetModuleFileNameError = error{Unexpected}; | |
| 2867 | ||
| 2868 | pub 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 | ||
| 2878 | pub const NtAllocateVirtualMemoryError = error{ | |
| 2879 | AccessDenied, | |
| 2880 | InvalidParameter, | |
| 2881 | NoMemory, | |
| 2882 | Unexpected, | |
| 2883 | }; | |
| 2884 | ||
| 2885 | pub 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 | ||
| 2895 | pub const NtFreeVirtualMemoryError = error{ | |
| 2896 | AccessDenied, | |
| 2897 | InvalidParameter, | |
| 2898 | Unexpected, | |
| 2899 | }; | |
| 2900 | ||
| 2901 | pub 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 | ||
| 2911 | pub 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 | }; | |
| 2838 | switch (ntdll.NtClose(hObject)) { | |
| 2839 | .SUCCESS => {}, | |
| 2840 | else => |status| unexpectedStatus(status) catch {}, | |
| 2917 | 2841 | } |
| 2918 | 2842 | } |
| 2919 | 2843 | |
| ... | ... | @@ -2963,114 +2887,75 @@ pub const CreateProcessFlags = packed struct(u32) { |
| 2963 | 2887 | create_ignore_system_default: bool = false, |
| 2964 | 2888 | }; |
| 2965 | 2889 | |
| 2966 | pub const LoadLibraryError = error{ | |
| 2967 | FileNotFound, | |
| 2968 | Unexpected, | |
| 2969 | }; | |
| 2970 | ||
| 2971 | pub 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 | ||
| 2982 | pub 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 | ||
| 2999 | pub 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 | ||
| 3010 | pub fn FreeLibrary(hModule: HMODULE) void { | |
| 3011 | assert(kernel32.FreeLibrary(hModule) != 0); | |
| 3012 | } | |
| 3013 | ||
| 3014 | pub 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 | ||
| 3023 | pub 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. | |
| 3034 | extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque; | |
| 3035 | extern fn zig_aarch64_windows_teb() callconv(.c) *anyopaque; | |
| 3036 | extern fn zig_x86_windows_teb() callconv(.c) *anyopaque; | |
| 3037 | extern fn zig_x86_64_windows_teb() callconv(.c) *anyopaque; | |
| 3038 | ||
| 3039 | 2890 | pub fn teb() *TEB { |
| 3040 | return switch (native_arch) { | |
| 3041 | .thumb => if (builtin.zig_backend == .stage2_c) | |
| 3042 | @ptrCast(@alignCast(zig_thumb_windows_teb())) | |
| 3043 | else | |
| 3044 | asm ( | |
| 3045 | \\ mrc p15, 0, %[ptr], c13, c0, 2 | |
| 3046 | : [ptr] "=r" (-> *TEB), | |
| 3047 | ), | |
| 3048 | .aarch64 => if (builtin.zig_backend == .stage2_c) | |
| 3049 | @ptrCast(@alignCast(zig_aarch64_windows_teb())) | |
| 3050 | else | |
| 3051 | asm ( | |
| 3052 | \\ mov %[ptr], x18 | |
| 3053 | : [ptr] "=r" (-> *TEB), | |
| 3054 | ), | |
| 3055 | .x86 => if (builtin.zig_backend == .stage2_c) | |
| 3056 | @ptrCast(@alignCast(zig_x86_windows_teb())) | |
| 3057 | else | |
| 3058 | asm ( | |
| 2891 | if (builtin.zig_backend == .stage2_c) return @ptrCast(@alignCast(struct { | |
| 2892 | /// This is a workaround for the C backend until zig has the ability to put | |
| 2893 | /// C code in inline assembly. | |
| 2894 | extern fn zig_windows_teb() callconv(.c) *anyopaque; | |
| 2895 | }.zig_windows_teb())); | |
| 2896 | switch (native_arch) { | |
| 2897 | .thumb => return asm ( | |
| 2898 | \\ mrc p15, 0, %[ptr], c13, c0, 2 | |
| 2899 | : [ptr] "=r" (-> *TEB), | |
| 2900 | ), | |
| 2901 | .aarch64 => return asm ( | |
| 2902 | \\ mov %[ptr], x18 | |
| 2903 | : [ptr] "=r" (-> *TEB), | |
| 2904 | ), | |
| 2905 | .x86 => { | |
| 2906 | comptime assert( | |
| 2907 | @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x18, | |
| 2908 | ); | |
| 2909 | return asm ( | |
| 3059 | 2910 | \\ movl %%fs:0x18, %[ptr] |
| 3060 | 2911 | : [ptr] "=r" (-> *TEB), |
| 3061 | ), | |
| 3062 | .x86_64 => if (builtin.zig_backend == .stage2_c) | |
| 3063 | @ptrCast(@alignCast(zig_x86_64_windows_teb())) | |
| 3064 | else | |
| 3065 | asm ( | |
| 2912 | ); | |
| 2913 | }, | |
| 2914 | .x86_64 => { | |
| 2915 | comptime assert( | |
| 2916 | @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x30, | |
| 2917 | ); | |
| 2918 | return asm ( | |
| 3066 | 2919 | \\ movq %%gs:0x30, %[ptr] |
| 3067 | 2920 | : [ptr] "=r" (-> *TEB), |
| 3068 | ), | |
| 2921 | ); | |
| 2922 | }, | |
| 3069 | 2923 | else => @compileError("unsupported arch"), |
| 3070 | }; | |
| 2924 | } | |
| 3071 | 2925 | } |
| 3072 | 2926 | |
| 3073 | 2927 | pub 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 | 2959 | return teb().ProcessEnvironmentBlock; |
| 3075 | 2960 | } |
| 3076 | 2961 | |
| ... | ... | @@ -3089,20 +2974,6 @@ pub fn toSysTime(ns: Io.Timestamp) i64 { |
| 3089 | 2974 | return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100); |
| 3090 | 2975 | } |
| 3091 | 2976 | |
| 3092 | pub 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. | |
| 3098 | pub 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 | 2977 | /// Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a |
| 3107 | 2978 | /// redundant copy of the uppercase data. |
| 3108 | 2979 | pub inline fn toUpperWtf16(c: u16) u16 { |
| ... | ... | @@ -3126,7 +2997,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { |
| 3126 | 2997 | // endianness for the uppercasing |
| 3127 | 2998 | const a_c_native = std.mem.littleToNative(u16, a_c); |
| 3128 | 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 | 3001 | return false; |
| 3131 | 3002 | } |
| 3132 | 3003 | } |
| ... | ... | @@ -3134,19 +3005,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { |
| 3134 | 3005 | } |
| 3135 | 3006 | // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a |
| 3136 | 3007 | // redundant copy of the uppercase data. |
| 3137 | const a_bytes = @as(u16, @intCast(a.len * 2)); | |
| 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; | |
| 3008 | return ntdll.RtlEqualUnicodeString(&.init(a), &.init(b), TRUE) == TRUE; | |
| 3150 | 3009 | } |
| 3151 | 3010 | |
| 3152 | 3011 | /// Compares two WTF-8 strings using the equivalent functionality of |
| ... | ... | @@ -3464,13 +3323,10 @@ pub const LONG = i32; |
| 3464 | 3323 | pub const ULONG64 = u64; |
| 3465 | 3324 | pub const ULONGLONG = u64; |
| 3466 | 3325 | pub const LONGLONG = i64; |
| 3467 | pub const HLOCAL = HANDLE; | |
| 3468 | 3326 | pub const LANGID = c_ushort; |
| 3469 | 3327 | pub const COLORREF = DWORD; |
| 3470 | 3328 | |
| 3471 | pub const WPARAM = usize; | |
| 3472 | 3329 | pub const LPARAM = LONG_PTR; |
| 3473 | pub const LRESULT = LONG_PTR; | |
| 3474 | 3330 | |
| 3475 | 3331 | pub const va_list = *opaque {}; |
| 3476 | 3332 | |
| ... | ... | @@ -3480,6 +3336,40 @@ pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWS |
| 3480 | 3336 | pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead."); |
| 3481 | 3337 | pub const PCTSTR = @compileError("Deprecated: choose between `PCSTR` or `PCWSTR` directly instead."); |
| 3482 | 3338 | |
| 3339 | fn 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 | } | |
| 3370 | pub const ANSI_STRING = STRING(CHAR); | |
| 3371 | pub const UNICODE_STRING = STRING(WCHAR); | |
| 3372 | ||
| 3483 | 3373 | pub const TRUE = 1; |
| 3484 | 3374 | pub const FALSE = 0; |
| 3485 | 3375 | |
| ... | ... | @@ -3509,111 +3399,14 @@ pub const OVERLAPPED = extern struct { |
| 3509 | 3399 | hEvent: ?HANDLE, |
| 3510 | 3400 | }; |
| 3511 | 3401 | |
| 3512 | pub const OVERLAPPED_ENTRY = extern struct { | |
| 3513 | lpCompletionKey: ULONG_PTR, | |
| 3514 | lpOverlapped: *OVERLAPPED, | |
| 3515 | Internal: ULONG_PTR, | |
| 3516 | dwNumberOfBytesTransferred: DWORD, | |
| 3517 | }; | |
| 3518 | ||
| 3519 | 3402 | pub const MAX_PATH = 260; |
| 3520 | 3403 | |
| 3521 | pub 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 | ||
| 3545 | pub 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 | ||
| 3558 | pub 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. | |
| 3564 | pub const FILE_NAME_NORMALIZED = 0x0; | |
| 3565 | ||
| 3566 | /// Return the opened file name (not normalized). | |
| 3567 | pub const FILE_NAME_OPENED = 0x8; | |
| 3568 | ||
| 3569 | /// Return the path with the drive letter. This is the default. | |
| 3570 | pub const VOLUME_NAME_DOS = 0x0; | |
| 3571 | ||
| 3572 | /// Return the path with a volume GUID path instead of the drive name. | |
| 3573 | pub const VOLUME_NAME_GUID = 0x1; | |
| 3574 | ||
| 3575 | /// Return the path with no drive information. | |
| 3576 | pub const VOLUME_NAME_NONE = 0x4; | |
| 3577 | ||
| 3578 | /// Return the path with the volume device path. | |
| 3579 | pub const VOLUME_NAME_NT = 0x2; | |
| 3580 | ||
| 3581 | 3404 | pub const SECURITY_ATTRIBUTES = extern struct { |
| 3582 | 3405 | nLength: DWORD, |
| 3583 | 3406 | lpSecurityDescriptor: ?*anyopaque, |
| 3584 | 3407 | bInheritHandle: BOOL, |
| 3585 | 3408 | }; |
| 3586 | 3409 | |
| 3587 | pub const PIPE_ACCESS_INBOUND = 0x00000001; | |
| 3588 | pub const PIPE_ACCESS_OUTBOUND = 0x00000002; | |
| 3589 | pub const PIPE_ACCESS_DUPLEX = 0x00000003; | |
| 3590 | ||
| 3591 | pub const PIPE_TYPE_BYTE = 0x00000000; | |
| 3592 | pub const PIPE_TYPE_MESSAGE = 0x00000004; | |
| 3593 | ||
| 3594 | pub const PIPE_READMODE_BYTE = 0x00000000; | |
| 3595 | pub const PIPE_READMODE_MESSAGE = 0x00000002; | |
| 3596 | ||
| 3597 | pub const PIPE_WAIT = 0x00000000; | |
| 3598 | pub const PIPE_NOWAIT = 0x00000001; | |
| 3599 | ||
| 3600 | pub const CREATE_ALWAYS = 2; | |
| 3601 | pub const CREATE_NEW = 1; | |
| 3602 | pub const OPEN_ALWAYS = 4; | |
| 3603 | pub const OPEN_EXISTING = 3; | |
| 3604 | pub const TRUNCATE_EXISTING = 5; | |
| 3605 | ||
| 3606 | // flags for CreateEvent | |
| 3607 | pub const CREATE_EVENT_INITIAL_SET = 0x00000002; | |
| 3608 | pub const CREATE_EVENT_MANUAL_RESET = 0x00000001; | |
| 3609 | ||
| 3610 | pub const PROCESS_INFORMATION = extern struct { | |
| 3611 | hProcess: HANDLE, | |
| 3612 | hThread: HANDLE, | |
| 3613 | dwProcessId: DWORD, | |
| 3614 | dwThreadId: DWORD, | |
| 3615 | }; | |
| 3616 | ||
| 3617 | 3410 | pub const STARTUPINFOW = extern struct { |
| 3618 | 3411 | cb: DWORD, |
| 3619 | 3412 | lpReserved: ?LPWSTR, |
| ... | ... | @@ -3650,50 +3443,7 @@ pub const STARTF_USESHOWWINDOW = 0x00000001; |
| 3650 | 3443 | pub const STARTF_USESIZE = 0x00000002; |
| 3651 | 3444 | pub const STARTF_USESTDHANDLES = 0x00000100; |
| 3652 | 3445 | |
| 3653 | pub const INFINITE = 4294967295; | |
| 3654 | ||
| 3655 | pub const MAXIMUM_WAIT_OBJECTS = 64; | |
| 3656 | ||
| 3657 | pub const WAIT_ABANDONED = 0x00000080; | |
| 3658 | pub const WAIT_ABANDONED_0 = WAIT_ABANDONED + 0; | |
| 3659 | pub const WAIT_OBJECT_0 = 0x00000000; | |
| 3660 | pub const WAIT_TIMEOUT = 0x00000102; | |
| 3661 | pub const WAIT_FAILED = 0xFFFFFFFF; | |
| 3662 | ||
| 3663 | pub const HANDLE_FLAG_INHERIT = 0x00000001; | |
| 3664 | pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002; | |
| 3665 | ||
| 3666 | pub const MOVEFILE_COPY_ALLOWED = 2; | |
| 3667 | pub const MOVEFILE_CREATE_HARDLINK = 16; | |
| 3668 | pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4; | |
| 3669 | pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32; | |
| 3670 | pub const MOVEFILE_REPLACE_EXISTING = 1; | |
| 3671 | pub const MOVEFILE_WRITE_THROUGH = 8; | |
| 3672 | ||
| 3673 | pub const FILE_BEGIN = 0; | |
| 3674 | pub const FILE_CURRENT = 1; | |
| 3675 | pub const FILE_END = 2; | |
| 3676 | ||
| 3677 | pub const PTHREAD_START_ROUTINE = *const fn (LPVOID) callconv(.winapi) DWORD; | |
| 3678 | pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; | |
| 3679 | ||
| 3680 | pub 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 | ||
| 3693 | pub const FILETIME = extern struct { | |
| 3694 | dwLowDateTime: DWORD, | |
| 3695 | dwHighDateTime: DWORD, | |
| 3696 | }; | |
| 3446 | pub const THREAD_START_ROUTINE = fn (LPVOID) callconv(.winapi) DWORD; | |
| 3697 | 3447 | |
| 3698 | 3448 | pub const SYSTEM_INFO = extern struct { |
| 3699 | 3449 | anon1: extern union { |
| ... | ... | @@ -3716,7 +3466,6 @@ pub const SYSTEM_INFO = extern struct { |
| 3716 | 3466 | |
| 3717 | 3467 | pub const HRESULT = c_long; |
| 3718 | 3468 | |
| 3719 | pub const KNOWNFOLDERID = GUID; | |
| 3720 | 3469 | pub const GUID = extern struct { |
| 3721 | 3470 | Data1: u32, |
| 3722 | 3471 | Data2: u16, |
| ... | ... | @@ -3771,75 +3520,11 @@ test GUID { |
| 3771 | 3520 | ); |
| 3772 | 3521 | } |
| 3773 | 3522 | |
| 3774 | pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"); | |
| 3775 | ||
| 3776 | pub const KF_FLAG_DEFAULT = 0; | |
| 3777 | pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536; | |
| 3778 | pub const KF_FLAG_CREATE = 32768; | |
| 3779 | pub const KF_FLAG_DONT_VERIFY = 16384; | |
| 3780 | pub const KF_FLAG_DONT_UNEXPAND = 8192; | |
| 3781 | pub const KF_FLAG_NO_ALIAS = 4096; | |
| 3782 | pub const KF_FLAG_INIT = 2048; | |
| 3783 | pub const KF_FLAG_DEFAULT_PATH = 1024; | |
| 3784 | pub const KF_FLAG_NOT_PARENT_RELATIVE = 512; | |
| 3785 | pub const KF_FLAG_SIMPLE_IDLIST = 256; | |
| 3786 | pub const KF_FLAG_ALIAS_ONLY = -2147483648; | |
| 3787 | ||
| 3788 | pub const S_OK = 0; | |
| 3789 | pub const S_FALSE = 0x00000001; | |
| 3790 | pub const E_NOTIMPL = @as(c_long, @bitCast(@as(c_ulong, 0x80004001))); | |
| 3791 | pub const E_NOINTERFACE = @as(c_long, @bitCast(@as(c_ulong, 0x80004002))); | |
| 3792 | pub const E_POINTER = @as(c_long, @bitCast(@as(c_ulong, 0x80004003))); | |
| 3793 | pub const E_ABORT = @as(c_long, @bitCast(@as(c_ulong, 0x80004004))); | |
| 3794 | pub const E_FAIL = @as(c_long, @bitCast(@as(c_ulong, 0x80004005))); | |
| 3795 | pub const E_UNEXPECTED = @as(c_long, @bitCast(@as(c_ulong, 0x8000FFFF))); | |
| 3796 | pub const E_ACCESSDENIED = @as(c_long, @bitCast(@as(c_ulong, 0x80070005))); | |
| 3797 | pub const E_HANDLE = @as(c_long, @bitCast(@as(c_ulong, 0x80070006))); | |
| 3798 | pub const E_OUTOFMEMORY = @as(c_long, @bitCast(@as(c_ulong, 0x8007000E))); | |
| 3799 | pub const E_INVALIDARG = @as(c_long, @bitCast(@as(c_ulong, 0x80070057))); | |
| 3800 | ||
| 3801 | pub fn HRESULT_CODE(hr: HRESULT) Win32Error { | |
| 3802 | return @enumFromInt(hr & 0xFFFF); | |
| 3803 | } | |
| 3804 | ||
| 3805 | pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; | |
| 3806 | pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; | |
| 3807 | pub const FILE_FLAG_NO_BUFFERING = 0x20000000; | |
| 3808 | pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000; | |
| 3809 | pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; | |
| 3810 | pub const FILE_FLAG_OVERLAPPED = 0x40000000; | |
| 3811 | pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000; | |
| 3812 | pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000; | |
| 3813 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; | |
| 3814 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; | |
| 3815 | pub const FILE_FLAG_WRITE_THROUGH = 0x80000000; | |
| 3816 | ||
| 3817 | pub const RECT = extern struct { | |
| 3818 | left: LONG, | |
| 3819 | top: LONG, | |
| 3820 | right: LONG, | |
| 3821 | bottom: LONG, | |
| 3822 | }; | |
| 3823 | ||
| 3824 | pub const SMALL_RECT = extern struct { | |
| 3825 | Left: SHORT, | |
| 3826 | Top: SHORT, | |
| 3827 | Right: SHORT, | |
| 3828 | Bottom: SHORT, | |
| 3829 | }; | |
| 3830 | ||
| 3831 | pub const POINT = extern struct { | |
| 3832 | x: LONG, | |
| 3833 | y: LONG, | |
| 3834 | }; | |
| 3835 | ||
| 3836 | 3523 | pub const COORD = extern struct { |
| 3837 | 3524 | X: SHORT, |
| 3838 | 3525 | Y: SHORT, |
| 3839 | 3526 | }; |
| 3840 | 3527 | |
| 3841 | pub const CREATE_UNICODE_ENVIRONMENT = 1024; | |
| 3842 | ||
| 3843 | 3528 | pub const TLS_OUT_OF_INDEXES = 4294967295; |
| 3844 | 3529 | pub const IMAGE_TLS_DIRECTORY = extern struct { |
| 3845 | 3530 | StartAddressOfRawData: usize, |
| ... | ... | @@ -3854,8 +3539,6 @@ pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; |
| 3854 | 3539 | |
| 3855 | 3540 | pub const PIMAGE_TLS_CALLBACK = ?*const fn (PVOID, DWORD, PVOID) callconv(.winapi) void; |
| 3856 | 3541 | |
| 3857 | pub const PROV_RSA_FULL = 1; | |
| 3858 | ||
| 3859 | 3542 | pub const REGSAM = ACCESS_MASK; |
| 3860 | 3543 | pub const LSTATUS = LONG; |
| 3861 | 3544 | |
| ... | ... | @@ -3872,9 +3555,6 @@ pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005); |
| 3872 | 3555 | pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006); |
| 3873 | 3556 | pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = @ptrFromInt(0x80000007); |
| 3874 | 3557 | |
| 3875 | /// Open symbolic link. | |
| 3876 | pub const REG_OPTION_OPEN_LINK: DWORD = 0x8; | |
| 3877 | ||
| 3878 | 3558 | pub const RTL_QUERY_REGISTRY_TABLE = extern struct { |
| 3879 | 3559 | QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE, |
| 3880 | 3560 | Flags: ULONG, |
| ... | ... | @@ -3975,38 +3655,6 @@ pub const REG = struct { |
| 3975 | 3655 | pub const QWORD_LITTLE_ENDIAN: ULONG = 11; |
| 3976 | 3656 | }; |
| 3977 | 3657 | |
| 3978 | pub 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 | ||
| 3986 | pub const FILE_ACTION_ADDED = 0x00000001; | |
| 3987 | pub const FILE_ACTION_REMOVED = 0x00000002; | |
| 3988 | pub const FILE_ACTION_MODIFIED = 0x00000003; | |
| 3989 | pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; | |
| 3990 | pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; | |
| 3991 | ||
| 3992 | pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?*const fn (DWORD, DWORD, *OVERLAPPED) callconv(.winapi) void; | |
| 3993 | ||
| 3994 | pub 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 | ||
| 4010 | 3658 | pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4; |
| 4011 | 3659 | pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8; |
| 4012 | 3660 | |
| ... | ... | @@ -4056,26 +3704,6 @@ pub const RTL_RUN_ONCE = extern struct { |
| 4056 | 3704 | |
| 4057 | 3705 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null }; |
| 4058 | 3706 | |
| 4059 | pub 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 | ||
| 4066 | pub 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 | ||
| 4077 | pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION; | |
| 4078 | ||
| 4079 | 3707 | /// > The maximum path of 32,767 characters is approximate, because the "\\?\" |
| 4080 | 3708 | /// > prefix may be expanded to a longer string by the system at run time, and |
| 4081 | 3709 | /// > this expansion applies to the total length. |
| ... | ... | @@ -4544,14 +4172,6 @@ pub const UNW_FLAG_EHANDLER = 0x1; |
| 4544 | 4172 | pub const UNW_FLAG_UHANDLER = 0x2; |
| 4545 | 4173 | pub const UNW_FLAG_CHAININFO = 0x4; |
| 4546 | 4174 | |
| 4547 | pub 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 | ||
| 4555 | 4175 | pub const ACTIVATION_CONTEXT_DATA = opaque {}; |
| 4556 | 4176 | pub const ASSEMBLY_STORAGE_MAP = opaque {}; |
| 4557 | 4177 | pub const FLS_CALLBACK_INFO = opaque {}; |
| ... | ... | @@ -4564,15 +4184,6 @@ pub const CLIENT_ID = extern struct { |
| 4564 | 4184 | UniqueThread: HANDLE, |
| 4565 | 4185 | }; |
| 4566 | 4186 | |
| 4567 | pub 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 | ||
| 4576 | 4187 | pub const TEB = extern struct { |
| 4577 | 4188 | NtTib: NT_TIB, |
| 4578 | 4189 | EnvironmentPointer: PVOID, |
| ... | ... | @@ -4580,7 +4191,7 @@ pub const TEB = extern struct { |
| 4580 | 4191 | ActiveRpcHandle: PVOID, |
| 4581 | 4192 | ThreadLocalStoragePointer: PVOID, |
| 4582 | 4193 | ProcessEnvironmentBlock: *PEB, |
| 4583 | LastErrorValue: ULONG, | |
| 4194 | LastErrorValue: Win32Error, | |
| 4584 | 4195 | Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8, |
| 4585 | 4196 | Reserved3: [1952]u8, |
| 4586 | 4197 | TlsSlots: [64]PVOID, |
| ... | ... | @@ -4793,7 +4404,7 @@ pub const PEB = extern struct { |
| 4793 | 4404 | }; |
| 4794 | 4405 | |
| 4795 | 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 | 4409 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: |
| 4799 | 4410 | /// - 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 | 4436 | ShutdownThreadId: HANDLE, |
| 4826 | 4437 | }; |
| 4827 | 4438 | |
| 4828 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: | |
| 4829 | /// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data | |
| 4830 | /// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm | |
| 4831 | pub const LDR_DATA_TABLE_ENTRY = extern struct { | |
| 4832 | InLoadOrderLinks: LIST_ENTRY, | |
| 4833 | InMemoryOrderLinks: LIST_ENTRY, | |
| 4834 | InInitializationOrderLinks: LIST_ENTRY, | |
| 4835 | DllBase: PVOID, | |
| 4836 | EntryPoint: PVOID, | |
| 4837 | SizeOfImage: ULONG, | |
| 4838 | FullDllName: UNICODE_STRING, | |
| 4839 | BaseDllName: UNICODE_STRING, | |
| 4840 | Reserved5: [3]PVOID, | |
| 4841 | DUMMYUNIONNAME: extern union { | |
| 4842 | CheckSum: ULONG, | |
| 4843 | Reserved6: PVOID, | |
| 4844 | }, | |
| 4845 | TimeDateStamp: ULONG, | |
| 4439 | pub const LDR = struct { | |
| 4440 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: | |
| 4441 | /// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data | |
| 4442 | /// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm | |
| 4443 | pub const DATA_TABLE_ENTRY = extern struct { | |
| 4444 | InLoadOrderLinks: LIST_ENTRY, | |
| 4445 | InMemoryOrderLinks: LIST_ENTRY, | |
| 4446 | InInitializationOrderLinks: LIST_ENTRY, | |
| 4447 | DllBase: PVOID, | |
| 4448 | EntryPoint: PVOID, | |
| 4449 | SizeOfImage: ULONG, | |
| 4450 | FullDllName: UNICODE_STRING, | |
| 4451 | BaseDllName: UNICODE_STRING, | |
| 4452 | Reserved5: [3]PVOID, | |
| 4453 | DUMMYUNIONNAME: extern union { | |
| 4454 | CheckSum: ULONG, | |
| 4455 | Reserved6: PVOID, | |
| 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 | }; |
| 4847 | 4523 | |
| 4848 | 4524 | pub const RTL_USER_PROCESS_PARAMETERS = extern struct { |
| ... | ... | @@ -4956,86 +4632,6 @@ pub const MODULEINFO = extern struct { |
| 4956 | 4632 | EntryPoint: LPVOID, |
| 4957 | 4633 | }; |
| 4958 | 4634 | |
| 4959 | pub const PSAPI_WS_WATCH_INFORMATION = extern struct { | |
| 4960 | FaultingPc: LPVOID, | |
| 4961 | FaultingVa: LPVOID, | |
| 4962 | }; | |
| 4963 | ||
| 4964 | pub 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 | ||
| 4978 | pub 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 | ||
| 4991 | pub 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 | ||
| 5005 | pub 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 | ||
| 5022 | pub 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 | ||
| 5030 | pub const PENUM_PAGE_FILE_CALLBACKW = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.winapi) BOOL; | |
| 5031 | pub const PENUM_PAGE_FILE_CALLBACKA = ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.winapi) BOOL; | |
| 5032 | ||
| 5033 | pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct { | |
| 5034 | BasicInfo: PSAPI_WS_WATCH_INFORMATION, | |
| 5035 | FaultingThreadId: ULONG_PTR, | |
| 5036 | Flags: ULONG_PTR, | |
| 5037 | }; | |
| 5038 | ||
| 5039 | 4635 | pub const OSVERSIONINFOW = extern struct { |
| 5040 | 4636 | dwOSVersionInfoSize: ULONG, |
| 5041 | 4637 | dwMajorVersion: ULONG, |
| ... | ... | @@ -5098,20 +4694,6 @@ pub const MOUNTMGR_VOLUME_PATHS = extern struct { |
| 5098 | 4694 | MultiSz: [1]WCHAR, |
| 5099 | 4695 | }; |
| 5100 | 4696 | |
| 5101 | pub 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 | ||
| 5111 | pub const OBJECT_NAME_INFORMATION = extern struct { | |
| 5112 | Name: UNICODE_STRING, | |
| 5113 | }; | |
| 5114 | ||
| 5115 | 4697 | pub const SRWLOCK_INIT = SRWLOCK{}; |
| 5116 | 4698 | pub const SRWLOCK = extern struct { |
| 5117 | 4699 | Ptr: ?PVOID = null, |
| ... | ... | @@ -5122,17 +4704,6 @@ pub const CONDITION_VARIABLE = extern struct { |
| 5122 | 4704 | Ptr: ?PVOID = null, |
| 5123 | 4705 | }; |
| 5124 | 4706 | |
| 5125 | pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1; | |
| 5126 | pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2; | |
| 5127 | ||
| 5128 | pub const CTRL_C_EVENT: DWORD = 0; | |
| 5129 | pub const CTRL_BREAK_EVENT: DWORD = 1; | |
| 5130 | pub const CTRL_CLOSE_EVENT: DWORD = 2; | |
| 5131 | pub const CTRL_LOGOFF_EVENT: DWORD = 5; | |
| 5132 | pub const CTRL_SHUTDOWN_EVENT: DWORD = 6; | |
| 5133 | ||
| 5134 | pub const HANDLER_ROUTINE = *const fn (dwCtrlType: DWORD) callconv(.winapi) BOOL; | |
| 5135 | ||
| 5136 | 4707 | /// Processor feature enumeration. |
| 5137 | 4708 | pub const PF = enum(DWORD) { |
| 5138 | 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 | 5002 | /// Read-only user-mode address for the shared data. |
| 5432 | 5003 | /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm |
| 5433 | 5004 | /// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/ |
| 5434 | pub const SharedUserData: *const KUSER_SHARED_DATA = @as(*const KUSER_SHARED_DATA, @ptrFromInt(0x7FFE0000)); | |
| 5005 | pub const SharedUserData: *const KUSER_SHARED_DATA = @ptrFromInt(0x7FFE0000); | |
| 5435 | 5006 | |
| 5436 | 5007 | pub fn IsProcessorFeaturePresent(feature: PF) bool { |
| 5437 | 5008 | if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false; |
| 5438 | 5009 | return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1; |
| 5439 | 5010 | } |
| 5440 | 5011 | |
| 5441 | pub const TH32CS_SNAPHEAPLIST = 0x00000001; | |
| 5442 | pub const TH32CS_SNAPPROCESS = 0x00000002; | |
| 5443 | pub const TH32CS_SNAPTHREAD = 0x00000004; | |
| 5444 | pub const TH32CS_SNAPMODULE = 0x00000008; | |
| 5445 | pub const TH32CS_SNAPMODULE32 = 0x00000010; | |
| 5446 | pub const TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE; | |
| 5447 | pub const TH32CS_INHERIT = 0x80000000; | |
| 5448 | ||
| 5449 | pub const MAX_MODULE_NAME32 = 255; | |
| 5450 | pub 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 | ||
| 5463 | pub 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 | ||
| 5477 | pub 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 | ||
| 5491 | pub 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 | 5012 | // https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L983 |
| 5501 | 5013 | pub const KERNEL_USER_TIMES = extern struct { |
| 5502 | 5014 | CreationTime: LARGE_INTEGER, |
| ... | ... | @@ -5505,75 +5017,6 @@ pub const KERNEL_USER_TIMES = extern struct { |
| 5505 | 5017 | UserTime: LARGE_INTEGER, |
| 5506 | 5018 | }; |
| 5507 | 5019 | |
| 5508 | pub const ReadMemoryError = error{ | |
| 5509 | Unexpected, | |
| 5510 | }; | |
| 5511 | ||
| 5512 | pub 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 | ||
| 5527 | pub const WriteMemoryError = error{ | |
| 5528 | Unexpected, | |
| 5529 | }; | |
| 5530 | ||
| 5531 | pub 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 | ||
| 5546 | pub const ProcessBaseAddressError = error{ | |
| 5547 | AccessDenied, | |
| 5548 | InvalidHandle, | |
| 5549 | Unexpected, | |
| 5550 | } || ReadMemoryError; | |
| 5551 | ||
| 5552 | /// Returns the base address of the process loaded into memory. | |
| 5553 | pub 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 | ||
| 5577 | 5020 | pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize { |
| 5578 | 5021 | // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE. |
| 5579 | 5022 | if (wtf16le.len < wtf8.len) { |
lib/std/os/windows/kernel32.zig+4-197| ... | ... | @@ -1,154 +1,29 @@ |
| 1 | 1 | const std = @import("../../std.zig"); |
| 2 | 2 | const windows = std.os.windows; |
| 3 | 3 | |
| 4 | const ACCESS_MASK = windows.ACCESS_MASK; | |
| 5 | 4 | const BOOL = windows.BOOL; |
| 6 | const CONDITION_VARIABLE = windows.CONDITION_VARIABLE; | |
| 7 | const COORD = windows.COORD; | |
| 8 | 5 | const DWORD = windows.DWORD; |
| 9 | const FARPROC = windows.FARPROC; | |
| 10 | const FILETIME = windows.FILETIME; | |
| 11 | 6 | const HANDLE = windows.HANDLE; |
| 12 | const HANDLER_ROUTINE = windows.HANDLER_ROUTINE; | |
| 13 | const HMODULE = windows.HMODULE; | |
| 14 | const LARGE_INTEGER = windows.LARGE_INTEGER; | |
| 15 | const LPCSTR = windows.LPCSTR; | |
| 16 | 7 | const LPCVOID = windows.LPCVOID; |
| 17 | 8 | const LPCWSTR = windows.LPCWSTR; |
| 18 | const LPTHREAD_START_ROUTINE = windows.LPTHREAD_START_ROUTINE; | |
| 19 | 9 | const LPVOID = windows.LPVOID; |
| 20 | 10 | const LPWSTR = windows.LPWSTR; |
| 21 | const MODULEENTRY32 = windows.MODULEENTRY32; | |
| 22 | const OVERLAPPED = windows.OVERLAPPED; | |
| 23 | const OVERLAPPED_ENTRY = windows.OVERLAPPED_ENTRY; | |
| 24 | const PROCESS_INFORMATION = windows.PROCESS_INFORMATION; | |
| 11 | const PROCESS = windows.PROCESS; | |
| 12 | const THREAD_START_ROUTINE = windows.THREAD_START_ROUTINE; | |
| 25 | 13 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; |
| 26 | 14 | const SIZE_T = windows.SIZE_T; |
| 27 | const SRWLOCK = windows.SRWLOCK; | |
| 28 | 15 | const STARTUPINFOW = windows.STARTUPINFOW; |
| 29 | const SYSTEM_INFO = windows.SYSTEM_INFO; | |
| 30 | const UCHAR = windows.UCHAR; | |
| 31 | 16 | const UINT = windows.UINT; |
| 32 | const ULONG = windows.ULONG; | |
| 33 | const ULONG_PTR = windows.ULONG_PTR; | |
| 34 | 17 | const va_list = windows.va_list; |
| 35 | const WCHAR = windows.WCHAR; | |
| 36 | 18 | const Win32Error = windows.Win32Error; |
| 37 | const WORD = windows.WORD; | |
| 38 | 19 | |
| 39 | 20 | // I/O - Filesystem |
| 40 | 21 | |
| 41 | pub 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. | |
| 53 | pub 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` | |
| 59 | pub 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` | |
| 67 | pub extern "kernel32" fn SetFileTime( | |
| 68 | hFile: HANDLE, | |
| 69 | lpCreationTime: ?*const FILETIME, | |
| 70 | lpLastAccessTime: ?*const FILETIME, | |
| 71 | lpLastWriteTime: ?*const FILETIME, | |
| 72 | ) callconv(.winapi) BOOL; | |
| 73 | ||
| 74 | pub 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`. | |
| 83 | pub extern "kernel32" fn SetFileCompletionNotificationModes( | |
| 84 | FileHandle: HANDLE, | |
| 85 | Flags: UCHAR, | |
| 86 | ) callconv(.winapi) BOOL; | |
| 87 | ||
| 88 | pub extern "kernel32" fn ReadFile( | |
| 89 | hFile: HANDLE, | |
| 90 | lpBuffer: LPVOID, | |
| 91 | nNumberOfBytesToRead: DWORD, | |
| 92 | lpNumberOfBytesRead: ?*DWORD, | |
| 93 | lpOverlapped: ?*OVERLAPPED, | |
| 94 | ) callconv(.winapi) BOOL; | |
| 95 | ||
| 96 | 22 | pub extern "kernel32" fn GetSystemDirectoryW( |
| 97 | 23 | lpBuffer: LPWSTR, |
| 98 | 24 | uSize: UINT, |
| 99 | 25 | ) callconv(.winapi) UINT; |
| 100 | 26 | |
| 101 | // I/O - Kernel Objects | |
| 102 | ||
| 103 | // TODO: Wrapper around NtRemoveIoCompletion. | |
| 104 | pub 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. | |
| 113 | pub 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`. | |
| 123 | pub extern "kernel32" fn PostQueuedCompletionStatus( | |
| 124 | CompletionPort: HANDLE, | |
| 125 | dwNumberOfBytesTransferred: DWORD, | |
| 126 | dwCompletionKey: ULONG_PTR, | |
| 127 | lpOverlapped: ?*OVERLAPPED, | |
| 128 | ) callconv(.winapi) BOOL; | |
| 129 | ||
| 130 | pub 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. | |
| 139 | pub 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. | |
| 147 | pub extern "kernel32" fn TerminateProcess( | |
| 148 | hProcess: HANDLE, | |
| 149 | uExitCode: UINT, | |
| 150 | ) callconv(.winapi) BOOL; | |
| 151 | ||
| 152 | 27 | // Process Management |
| 153 | 28 | |
| 154 | 29 | pub extern "kernel32" fn CreateProcessW( |
| ... | ... | @@ -161,86 +36,21 @@ pub extern "kernel32" fn CreateProcessW( |
| 161 | 36 | lpEnvironment: ?[*:0]const u16, |
| 162 | 37 | lpCurrentDirectory: ?LPCWSTR, |
| 163 | 38 | lpStartupInfo: *STARTUPINFOW, |
| 164 | lpProcessInformation: *PROCESS_INFORMATION, | |
| 165 | ) callconv(.winapi) BOOL; | |
| 166 | ||
| 167 | // TODO: Wrapper around NtQueryInformationProcess with `PROCESS_BASIC_INFORMATION`. | |
| 168 | pub extern "kernel32" fn GetExitCodeProcess( | |
| 169 | hProcess: HANDLE, | |
| 170 | lpExitCode: *DWORD, | |
| 39 | lpProcessInformation: *PROCESS.INFORMATION, | |
| 171 | 40 | ) callconv(.winapi) BOOL; |
| 172 | 41 | |
| 173 | pub extern "kernel32" fn CreateToolhelp32Snapshot( | |
| 174 | dwFlags: DWORD, | |
| 175 | th32ProcessID: DWORD, | |
| 176 | ) callconv(.winapi) HANDLE; | |
| 177 | ||
| 178 | 42 | // Threading |
| 179 | 43 | |
| 180 | // TODO: Already a wrapper for this, see `windows.GetCurrentThreadId`. | |
| 181 | pub extern "kernel32" fn GetCurrentThreadId() callconv(.winapi) DWORD; | |
| 182 | ||
| 183 | 44 | // TODO: CreateRemoteThread with hProcess=NtCurrentProcess(). |
| 184 | 45 | pub extern "kernel32" fn CreateThread( |
| 185 | 46 | lpThreadAttributes: ?*SECURITY_ATTRIBUTES, |
| 186 | 47 | dwStackSize: SIZE_T, |
| 187 | lpStartAddress: LPTHREAD_START_ROUTINE, | |
| 48 | lpStartAddress: *const THREAD_START_ROUTINE, | |
| 188 | 49 | lpParameter: ?LPVOID, |
| 189 | 50 | dwCreationFlags: DWORD, |
| 190 | 51 | lpThreadId: ?*DWORD, |
| 191 | 52 | ) callconv(.winapi) ?HANDLE; |
| 192 | 53 | |
| 193 | // Code Libraries/Modules | |
| 194 | ||
| 195 | // TODO: Wrapper around LdrGetDllFullName. | |
| 196 | pub extern "kernel32" fn GetModuleFileNameW( | |
| 197 | hModule: ?HMODULE, | |
| 198 | lpFilename: [*]WCHAR, | |
| 199 | nSize: DWORD, | |
| 200 | ) callconv(.winapi) DWORD; | |
| 201 | ||
| 202 | extern "kernel32" fn K32GetModuleFileNameExW( | |
| 203 | hProcess: HANDLE, | |
| 204 | hModule: ?HMODULE, | |
| 205 | lpFilename: LPWSTR, | |
| 206 | nSize: DWORD, | |
| 207 | ) callconv(.winapi) DWORD; | |
| 208 | pub const GetModuleFileNameExW = K32GetModuleFileNameExW; | |
| 209 | ||
| 210 | // TODO: Wrapper around ntdll.LdrGetDllHandle, which is a wrapper around LdrGetDllHandleEx | |
| 211 | pub extern "kernel32" fn GetModuleHandleW( | |
| 212 | lpModuleName: ?LPCWSTR, | |
| 213 | ) callconv(.winapi) ?HMODULE; | |
| 214 | ||
| 215 | pub extern "kernel32" fn Module32First( | |
| 216 | hSnapshot: HANDLE, | |
| 217 | lpme: *MODULEENTRY32, | |
| 218 | ) callconv(.winapi) BOOL; | |
| 219 | ||
| 220 | pub extern "kernel32" fn Module32Next( | |
| 221 | hSnapshot: HANDLE, | |
| 222 | lpme: *MODULEENTRY32, | |
| 223 | ) callconv(.winapi) BOOL; | |
| 224 | ||
| 225 | pub extern "kernel32" fn LoadLibraryW( | |
| 226 | lpLibFileName: LPCWSTR, | |
| 227 | ) callconv(.winapi) ?HMODULE; | |
| 228 | ||
| 229 | pub extern "kernel32" fn LoadLibraryExW( | |
| 230 | lpLibFileName: LPCWSTR, | |
| 231 | hFile: ?HANDLE, | |
| 232 | dwFlags: DWORD, | |
| 233 | ) callconv(.winapi) ?HMODULE; | |
| 234 | ||
| 235 | pub extern "kernel32" fn GetProcAddress( | |
| 236 | hModule: HMODULE, | |
| 237 | lpProcName: LPCSTR, | |
| 238 | ) callconv(.winapi) ?FARPROC; | |
| 239 | ||
| 240 | pub extern "kernel32" fn FreeLibrary( | |
| 241 | hModule: HMODULE, | |
| 242 | ) callconv(.winapi) BOOL; | |
| 243 | ||
| 244 | 54 | // Error Management |
| 245 | 55 | |
| 246 | 56 | pub extern "kernel32" fn FormatMessageW( |
| ... | ... | @@ -252,6 +62,3 @@ pub extern "kernel32" fn FormatMessageW( |
| 252 | 62 | nSize: DWORD, |
| 253 | 63 | Arguments: ?*va_list, |
| 254 | 64 | ) callconv(.winapi) DWORD; |
| 255 | ||
| 256 | // TODO: Getter for teb().LastErrorValue. | |
| 257 | pub 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 | 2 | const windows = std.os.windows; |
| 3 | 3 | |
| 4 | 4 | const ACCESS_MASK = windows.ACCESS_MASK; |
| 5 | const ANSI_STRING = windows.ANSI_STRING; | |
| 5 | 6 | const BOOL = windows.BOOL; |
| 6 | 7 | const BOOLEAN = windows.BOOLEAN; |
| 7 | 8 | const CONDITION_VARIABLE = windows.CONDITION_VARIABLE; |
| ... | ... | @@ -9,6 +10,7 @@ const CONTEXT = windows.CONTEXT; |
| 9 | 10 | const CRITICAL_SECTION = windows.CRITICAL_SECTION; |
| 10 | 11 | const CTL_CODE = windows.CTL_CODE; |
| 11 | 12 | const CURDIR = windows.CURDIR; |
| 13 | const DIRECTORY = windows.DIRECTORY; | |
| 12 | 14 | const DWORD = windows.DWORD; |
| 13 | 15 | const DWORD64 = windows.DWORD64; |
| 14 | 16 | const ERESOURCE = windows.ERESOURCE; |
| ... | ... | @@ -22,18 +24,19 @@ const IO_APC_ROUTINE = windows.IO_APC_ROUTINE; |
| 22 | 24 | const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK; |
| 23 | 25 | const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS; |
| 24 | 26 | const LARGE_INTEGER = windows.LARGE_INTEGER; |
| 27 | const LDR = windows.LDR; | |
| 25 | 28 | const LOGICAL = windows.LOGICAL; |
| 26 | 29 | const LONG = windows.LONG; |
| 27 | 30 | const LPCVOID = windows.LPCVOID; |
| 28 | 31 | const LPVOID = windows.LPVOID; |
| 29 | 32 | const MEM = windows.MEM; |
| 30 | 33 | const NTSTATUS = windows.NTSTATUS; |
| 31 | const OBJECT_ATTRIBUTES = windows.OBJECT_ATTRIBUTES; | |
| 32 | const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS; | |
| 34 | const OBJECT = windows.OBJECT; | |
| 33 | 35 | const PAGE = windows.PAGE; |
| 34 | 36 | const PCWSTR = windows.PCWSTR; |
| 35 | const PROCESSINFOCLASS = windows.PROCESSINFOCLASS; | |
| 37 | const PROCESS = windows.PROCESS; | |
| 36 | 38 | const PVOID = windows.PVOID; |
| 39 | const PWSTR = windows.PWSTR; | |
| 37 | 40 | const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW; |
| 38 | 41 | const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE; |
| 39 | 42 | const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION; |
| ... | ... | @@ -41,8 +44,8 @@ const SEC = windows.SEC; |
| 41 | 44 | const SECTION_INHERIT = windows.SECTION_INHERIT; |
| 42 | 45 | const SIZE_T = windows.SIZE_T; |
| 43 | 46 | const SRWLOCK = windows.SRWLOCK; |
| 44 | const SYSTEM_INFORMATION_CLASS = windows.SYSTEM_INFORMATION_CLASS; | |
| 45 | const THREADINFOCLASS = windows.THREADINFOCLASS; | |
| 47 | const SYSTEM = windows.SYSTEM; | |
| 48 | const THREAD = windows.THREAD; | |
| 46 | 49 | const ULONG = windows.ULONG; |
| 47 | 50 | const ULONG_PTR = windows.ULONG_PTR; |
| 48 | 51 | const UNICODE_STRING = windows.UNICODE_STRING; |
| ... | ... | @@ -91,7 +94,7 @@ pub extern "ntdll" fn RtlCaptureContext( |
| 91 | 94 | |
| 92 | 95 | pub extern "ntdll" fn NtSetInformationThread( |
| 93 | 96 | ThreadHandle: HANDLE, |
| 94 | ThreadInformationClass: THREADINFOCLASS, | |
| 97 | ThreadInformationClass: THREAD.INFOCLASS, | |
| 95 | 98 | ThreadInformation: *const anyopaque, |
| 96 | 99 | ThreadInformationLength: ULONG, |
| 97 | 100 | ) callconv(.winapi) NTSTATUS; |
| ... | ... | @@ -99,7 +102,7 @@ pub extern "ntdll" fn NtSetInformationThread( |
| 99 | 102 | pub extern "ntdll" fn NtCreateFile( |
| 100 | 103 | FileHandle: *HANDLE, |
| 101 | 104 | DesiredAccess: ACCESS_MASK, |
| 102 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | |
| 105 | ObjectAttributes: *const OBJECT.ATTRIBUTES, | |
| 103 | 106 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 104 | 107 | AllocationSize: ?*const LARGE_INTEGER, |
| 105 | 108 | FileAttributes: FILE.ATTRIBUTE, |
| ... | ... | @@ -152,7 +155,7 @@ pub extern "ntdll" fn NtLockFile( |
| 152 | 155 | pub extern "ntdll" fn NtOpenFile( |
| 153 | 156 | FileHandle: *HANDLE, |
| 154 | 157 | DesiredAccess: ACCESS_MASK, |
| 155 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | |
| 158 | ObjectAttributes: *const OBJECT.ATTRIBUTES, | |
| 156 | 159 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 157 | 160 | ShareAccess: FILE.SHARE, |
| 158 | 161 | OpenOptions: FILE.MODE, |
| ... | ... | @@ -233,7 +236,7 @@ pub extern "ntdll" fn NtUnlockFile( |
| 233 | 236 | |
| 234 | 237 | pub extern "ntdll" fn NtQueryObject( |
| 235 | 238 | Handle: HANDLE, |
| 236 | ObjectInformationClass: OBJECT_INFORMATION_CLASS, | |
| 239 | ObjectInformationClass: OBJECT.INFORMATION_CLASS, | |
| 237 | 240 | ObjectInformation: ?PVOID, |
| 238 | 241 | ObjectInformationLength: ULONG, |
| 239 | 242 | ReturnLength: ?*ULONG, |
| ... | ... | @@ -246,7 +249,7 @@ pub extern "ntdll" fn NtClose( |
| 246 | 249 | pub extern "ntdll" fn NtCreateSection( |
| 247 | 250 | SectionHandle: *HANDLE, |
| 248 | 251 | DesiredAccess: ACCESS_MASK, |
| 249 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | |
| 252 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, | |
| 250 | 253 | MaximumSize: ?*const LARGE_INTEGER, |
| 251 | 254 | SectionPageProtection: PAGE, |
| 252 | 255 | AllocationAttributes: SEC, |
| ... | ... | @@ -331,7 +334,7 @@ pub extern "ntdll" fn NtWaitForSingleObject( |
| 331 | 334 | |
| 332 | 335 | pub extern "ntdll" fn NtQueryInformationProcess( |
| 333 | 336 | ProcessHandle: HANDLE, |
| 334 | ProcessInformationClass: PROCESSINFOCLASS, | |
| 337 | ProcessInformationClass: PROCESS.INFOCLASS, | |
| 335 | 338 | ProcessInformation: *anyopaque, |
| 336 | 339 | ProcessInformationLength: ULONG, |
| 337 | 340 | ReturnLength: ?*ULONG, |
| ... | ... | @@ -339,14 +342,14 @@ pub extern "ntdll" fn NtQueryInformationProcess( |
| 339 | 342 | |
| 340 | 343 | pub extern "ntdll" fn NtQueryInformationThread( |
| 341 | 344 | ThreadHandle: HANDLE, |
| 342 | ThreadInformationClass: THREADINFOCLASS, | |
| 345 | ThreadInformationClass: THREAD.INFOCLASS, | |
| 343 | 346 | ThreadInformation: *anyopaque, |
| 344 | 347 | ThreadInformationLength: ULONG, |
| 345 | 348 | ReturnLength: ?*ULONG, |
| 346 | 349 | ) callconv(.winapi) NTSTATUS; |
| 347 | 350 | |
| 348 | 351 | pub extern "ntdll" fn NtQuerySystemInformation( |
| 349 | SystemInformationClass: SYSTEM_INFORMATION_CLASS, | |
| 352 | SystemInformationClass: SYSTEM.INFORMATION_CLASS, | |
| 350 | 353 | SystemInformation: PVOID, |
| 351 | 354 | SystemInformationLength: ULONG, |
| 352 | 355 | ReturnLength: ?*ULONG, |
| ... | ... | @@ -354,15 +357,99 @@ pub extern "ntdll" fn NtQuerySystemInformation( |
| 354 | 357 | |
| 355 | 358 | // ref none |
| 356 | 359 | |
| 360 | pub extern "ntdll" fn LdrAddRefDll( | |
| 361 | Flags: ULONG, | |
| 362 | DllHandle: PVOID, | |
| 363 | ) callconv(.winapi) NTSTATUS; | |
| 364 | pub extern "ntdll" fn LdrLoadDll( | |
| 365 | DllPath: ?PCWSTR, | |
| 366 | DllCharacteristics: ?*const ULONG, | |
| 367 | DllName: *const UNICODE_STRING, | |
| 368 | DllHandle: *PVOID, | |
| 369 | ) callconv(.winapi) NTSTATUS; | |
| 370 | pub extern "ntdll" fn LdrUnloadDll( | |
| 371 | DllHandle: PVOID, | |
| 372 | ) callconv(.winapi) NTSTATUS; | |
| 373 | ||
| 374 | pub extern "ntdll" fn LdrFindEntryForAddress( | |
| 375 | DllHandle: PVOID, | |
| 376 | Entry: **LDR.DATA_TABLE_ENTRY, | |
| 377 | ) callconv(.winapi) NTSTATUS; | |
| 378 | pub extern "ntdll" fn LdrGetDllFullName( | |
| 379 | DllHandle: ?PVOID, | |
| 380 | FullDllName: *UNICODE_STRING, | |
| 381 | ) callconv(.winapi) NTSTATUS; | |
| 382 | pub extern "ntdll" fn LdrGetDllPath( | |
| 383 | DllName: PCWSTR, | |
| 384 | Flags: LDR.LOAD, | |
| 385 | DllPath: *PWSTR, | |
| 386 | SearchPaths: *PWSTR, | |
| 387 | ) callconv(.winapi) NTSTATUS; | |
| 388 | ||
| 389 | pub extern "ntdll" fn LdrGetDllHandle( | |
| 390 | DllPath: ?PCWSTR, | |
| 391 | DllCharacteristics: ?*const ULONG, | |
| 392 | DllName: *const UNICODE_STRING, | |
| 393 | DllHandle: *PVOID, | |
| 394 | ) callconv(.winapi) NTSTATUS; | |
| 395 | pub extern "ntdll" fn LdrGetDllHandleByMapping( | |
| 396 | BaseAddress: PVOID, | |
| 397 | DllHandle: *PVOID, | |
| 398 | ) callconv(.winapi) NTSTATUS; | |
| 399 | pub extern "ntdll" fn LdrGetDllHandleByName( | |
| 400 | BaseDllName: *const UNICODE_STRING, | |
| 401 | FullDllName: *const UNICODE_STRING, | |
| 402 | DllHandle: *PVOID, | |
| 403 | ) callconv(.winapi) NTSTATUS; | |
| 404 | pub 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 | ||
| 412 | pub extern "ntdll" fn LdrGetProcedureAddress( | |
| 413 | DllHandle: PVOID, | |
| 414 | ProcedureName: *const ANSI_STRING, | |
| 415 | ProcedureNumber: ULONG, | |
| 416 | ProcedureAddress: *PVOID, | |
| 417 | ) callconv(.winapi) NTSTATUS; | |
| 418 | pub 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; | |
| 425 | pub 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 | ||
| 434 | pub 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; | |
| 440 | pub extern "ntdll" fn LdrUnregisterDllNotification( | |
| 441 | Cookie: LDR.DLL_NOTIFICATION.COOKIE, | |
| 442 | ) callconv(.winapi) NTSTATUS; | |
| 443 | ||
| 357 | 444 | pub extern "ntdll" fn NtQueryAttributesFile( |
| 358 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | |
| 445 | ObjectAttributes: *const OBJECT.ATTRIBUTES, | |
| 359 | 446 | FileAttributes: *FILE.BASIC_INFORMATION, |
| 360 | 447 | ) callconv(.winapi) NTSTATUS; |
| 361 | 448 | |
| 362 | 449 | pub extern "ntdll" fn NtCreateEvent( |
| 363 | 450 | EventHandle: *HANDLE, |
| 364 | 451 | DesiredAccess: ACCESS_MASK, |
| 365 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | |
| 452 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, | |
| 366 | 453 | EventType: EVENT_TYPE, |
| 367 | 454 | InitialState: BOOLEAN, |
| 368 | 455 | ) callconv(.winapi) NTSTATUS; |
| ... | ... | @@ -374,7 +461,7 @@ pub extern "ntdll" fn NtSetEvent( |
| 374 | 461 | pub extern "ntdll" fn NtCreateKeyedEvent( |
| 375 | 462 | KeyedEventHandle: *HANDLE, |
| 376 | 463 | DesiredAccess: ACCESS_MASK, |
| 377 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | |
| 464 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, | |
| 378 | 465 | Flags: ULONG, |
| 379 | 466 | ) callconv(.winapi) NTSTATUS; |
| 380 | 467 | pub extern "ntdll" fn NtReleaseKeyedEvent( |
| ... | ... | @@ -390,10 +477,57 @@ pub extern "ntdll" fn NtWaitForKeyedEvent( |
| 390 | 477 | Timeout: ?*const LARGE_INTEGER, |
| 391 | 478 | ) callconv(.winapi) NTSTATUS; |
| 392 | 479 | |
| 480 | pub extern "ntdll" fn NtCancelSynchronousIoFile( | |
| 481 | ThreadHandle: HANDLE, | |
| 482 | IoRequestToCancel: ?*IO_STATUS_BLOCK, | |
| 483 | IoStatusBlock: *IO_STATUS_BLOCK, | |
| 484 | ) callconv(.winapi) NTSTATUS; | |
| 485 | pub extern "ntdll" fn NtCancelIoFile( | |
| 486 | FileHandle: HANDLE, | |
| 487 | IoStatusBlock: *IO_STATUS_BLOCK, | |
| 488 | ) callconv(.winapi) NTSTATUS; | |
| 489 | pub 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. | |
| 502 | pub extern "ntdll" fn NtDelayExecution( | |
| 503 | Alertable: BOOLEAN, | |
| 504 | DelayInterval: *const LARGE_INTEGER, | |
| 505 | ) callconv(.winapi) NTSTATUS; | |
| 506 | ||
| 507 | pub 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 | ||
| 520 | pub 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 | ||
| 393 | 527 | pub extern "ntdll" fn NtCreateNamedPipeFile( |
| 394 | 528 | FileHandle: *HANDLE, |
| 395 | 529 | DesiredAccess: ACCESS_MASK, |
| 396 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | |
| 530 | ObjectAttributes: *const OBJECT.ATTRIBUTES, | |
| 397 | 531 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 398 | 532 | ShareAccess: FILE.SHARE, |
| 399 | 533 | CreateDisposition: FILE.CREATE_DISPOSITION, |
| ... | ... | @@ -437,7 +571,7 @@ pub extern "ntdll" fn NtUnmapViewOfSectionEx( |
| 437 | 571 | pub extern "ntdll" fn NtOpenKey( |
| 438 | 572 | KeyHandle: *HANDLE, |
| 439 | 573 | DesiredAccess: ACCESS_MASK, |
| 440 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | |
| 574 | ObjectAttributes: *const OBJECT.ATTRIBUTES, | |
| 441 | 575 | ) callconv(.winapi) NTSTATUS; |
| 442 | 576 | |
| 443 | 577 | pub extern "ntdll" fn NtQueueApcThread( |
| ... | ... | @@ -470,6 +604,19 @@ pub extern "ntdll" fn NtProtectVirtualMemory( |
| 470 | 604 | OldAccessProtection: *PAGE, |
| 471 | 605 | ) callconv(.winapi) NTSTATUS; |
| 472 | 606 | |
| 607 | pub extern "ntdll" fn NtWaitForAlertByThreadId( | |
| 608 | Address: ?*const anyopaque, | |
| 609 | Timeout: ?*const LARGE_INTEGER, | |
| 610 | ) callconv(.winapi) NTSTATUS; | |
| 611 | pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS; | |
| 612 | pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS; | |
| 613 | pub 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 | ||
| 473 | 620 | pub extern "ntdll" fn NtYieldExecution() callconv(.winapi) NTSTATUS; |
| 474 | 621 | |
| 475 | 622 | pub extern "ntdll" fn RtlAddVectoredExceptionHandler( |
| ... | ... | @@ -527,10 +674,6 @@ pub extern "ntdll" fn RtlQueryPerformanceCounter( |
| 527 | 674 | pub extern "ntdll" fn RtlQueryPerformanceFrequency( |
| 528 | 675 | PerformanceFrequency: *LARGE_INTEGER, |
| 529 | 676 | ) callconv(.winapi) BOOL; |
| 530 | pub extern "ntdll" fn NtQueryPerformanceCounter( | |
| 531 | PerformanceCounter: *LARGE_INTEGER, | |
| 532 | PerformanceFrequency: ?*LARGE_INTEGER, | |
| 533 | ) callconv(.winapi) NTSTATUS; | |
| 534 | 677 | |
| 535 | 678 | pub extern "ntdll" fn RtlReAllocateHeap( |
| 536 | 679 | HeapHandle: *HEAP, |
| ... | ... | @@ -539,8 +682,17 @@ pub extern "ntdll" fn RtlReAllocateHeap( |
| 539 | 682 | Size: SIZE_T, |
| 540 | 683 | ) callconv(.winapi) ?PVOID; |
| 541 | 684 | |
| 685 | pub extern "ntdll" fn RtlReportSilentProcessExit( | |
| 686 | ProcessHandle: HANDLE, | |
| 687 | ExitStatus: NTSTATUS, | |
| 688 | ) callconv(.winapi) NTSTATUS; | |
| 689 | pub extern "ntdll" fn NtTerminateProcess( | |
| 690 | ProcessHandle: ?HANDLE, | |
| 691 | ExitStatus: NTSTATUS, | |
| 692 | ) callconv(.winapi) NTSTATUS; | |
| 693 | ||
| 542 | 694 | pub extern "ntdll" fn RtlSetCurrentDirectory_U( |
| 543 | PathName: *UNICODE_STRING, | |
| 695 | PathName: *const UNICODE_STRING, | |
| 544 | 696 | ) callconv(.winapi) NTSTATUS; |
| 545 | 697 | |
| 546 | 698 | pub extern "ntdll" fn RtlTryAcquireSRWLockExclusive( |
| ... | ... | @@ -572,52 +724,3 @@ pub extern "ntdll" fn RtlWakeConditionVariable( |
| 572 | 724 | pub extern "ntdll" fn RtlWakeAllConditionVariable( |
| 573 | 725 | ConditionVariable: *CONDITION_VARIABLE, |
| 574 | 726 | ) callconv(.winapi) void; |
| 575 | ||
| 576 | pub extern "ntdll" fn NtWaitForAlertByThreadId( | |
| 577 | Address: ?*const anyopaque, | |
| 578 | Timeout: ?*const LARGE_INTEGER, | |
| 579 | ) callconv(.winapi) NTSTATUS; | |
| 580 | pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS; | |
| 581 | pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS; | |
| 582 | pub 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 | ||
| 589 | pub 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 | ||
| 596 | pub 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. | |
| 609 | pub extern "ntdll" fn NtDelayExecution( | |
| 610 | Alertable: BOOLEAN, | |
| 611 | DelayInterval: *const LARGE_INTEGER, | |
| 612 | ) callconv(.winapi) NTSTATUS; | |
| 613 | ||
| 614 | pub extern "ntdll" fn NtCancelIoFile( | |
| 615 | FileHandle: HANDLE, | |
| 616 | IoStatusBlock: *IO_STATUS_BLOCK, | |
| 617 | ) callconv(.winapi) NTSTATUS; | |
| 618 | ||
| 619 | pub 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 | 1 | /// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d |
| 2 | pub const Win32Error = enum(u16) { | |
| 2 | pub const Win32Error = enum(u32) { | |
| 3 | 3 | /// The operation completed successfully. |
| 4 | 4 | SUCCESS = 0, |
| 5 | 5 | /// Incorrect function. |
lib/std/process.zig+4-4| ... | ... | @@ -243,7 +243,7 @@ pub fn getBaseAddress() usize { |
| 243 | 243 | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { |
| 244 | 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 | 247 | else => @compileError("Unsupported OS"), |
| 248 | 248 | } |
| 249 | 249 | } |
| ... | ... | @@ -606,11 +606,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { |
| 606 | 606 | return @as(u64, @bitCast(physmem)); |
| 607 | 607 | }, |
| 608 | 608 | .windows => { |
| 609 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | |
| 609 | var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined; | |
| 610 | 610 | const rc = windows.ntdll.NtQuerySystemInformation( |
| 611 | .SystemBasicInformation, | |
| 611 | .Basic, | |
| 612 | 612 | &sbi, |
| 613 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | |
| 613 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), | |
| 614 | 614 | null, |
| 615 | 615 | ); |
| 616 | 616 | if (rc != .SUCCESS) { |
lib/std/process/Child.zig+1-1| ... | ... | @@ -86,7 +86,7 @@ pub const ResourceUsageStatistics = struct { |
| 86 | 86 | .visionos, |
| 87 | 87 | .watchos, |
| 88 | 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 | 90 | else => {}, |
| 91 | 91 | }; |
| 92 | 92 | }; |
lib/std/start.zig+5-9| ... | ... | @@ -473,10 +473,9 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn { |
| 473 | 473 | std.Thread.maybeAttachSignalStack(); |
| 474 | 474 | std.debug.maybeEnableSegfaultHandler(); |
| 475 | 475 | |
| 476 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | |
| 477 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | |
| 478 | ||
| 479 | std.os.windows.ntdll.RtlExitUserProcess(callMain(cmd_line_w, .global)); | |
| 476 | std.os.windows.ntdll.RtlExitUserProcess( | |
| 477 | callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global), | |
| 478 | ); | |
| 480 | 479 | } |
| 481 | 480 | |
| 482 | 481 | fn 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 | 646 | // values in their intended encoding from the PEB instead. |
| 648 | 647 | std.Thread.maybeAttachSignalStack(); |
| 649 | 648 | std.debug.maybeEnableSegfaultHandler(); |
| 650 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | |
| 651 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | |
| 652 | return callMain(cmd_line_w, .global); | |
| 649 | return callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global); | |
| 653 | 650 | }, |
| 654 | 651 | else => {}, |
| 655 | 652 | } |
| ... | ... | @@ -776,8 +773,7 @@ fn call_wWinMain() std.os.windows.INT { |
| 776 | 773 | // - With STARTF_USESHOWWINDOW unset: |
| 777 | 774 | // - nShowCmd is always SW_SHOWDEFAULT |
| 778 | 775 | const SW_SHOWDEFAULT = 10; |
| 779 | const STARTF_USESHOWWINDOW = 1; | |
| 780 | if (peb.ProcessParameters.dwFlags & STARTF_USESHOWWINDOW != 0) { | |
| 776 | if (peb.ProcessParameters.dwFlags & std.os.windows.STARTF_USESHOWWINDOW != 0) { | |
| 781 | 777 | break :nShowCmd @truncate(peb.ProcessParameters.dwShowWindow); |
| 782 | 778 | } |
| 783 | 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 | 100 | REG.MULTI_SZ, |
| 101 | 101 | => { |
| 102 | 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 | 104 | unicode.* = .{ |
| 105 | 105 | .Length = 0, |
| 106 | 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 | 109 | break :blk unicode; |
| 110 | 110 | }, |
| ... | ... | @@ -159,8 +159,8 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { |
| 159 | 159 | REG.MULTI_SZ, |
| 160 | 160 | => { |
| 161 | 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)); | |
| 163 | const len = try std.unicode.utf16LeToUtf8(buf, entry.Buffer.?[0 .. entry.Length / 2]); | |
| 162 | const entry: *const std.os.windows.UNICODE_STRING = @ptrCast(table[i + 1].EntryContext); | |
| 163 | const len = try std.unicode.utf16LeToUtf8(buf, entry.slice()); | |
| 164 | 164 | buf[len] = 0; |
| 165 | 165 | }, |
| 166 | 166 | |
| ... | ... | @@ -168,7 +168,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { |
| 168 | 168 | REG.DWORD_BIG_ENDIAN, |
| 169 | 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 | 172 | switch (@field(args, field.name).value_type) { |
| 173 | 173 | REG.DWORD, REG.DWORD_BIG_ENDIAN => { |
| 174 | 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 | 4148 | |
| 4149 | 4149 | #if defined(zig_thumb) |
| 4150 | 4150 | |
| 4151 | static inline void* zig_thumb_windows_teb(void) { | |
| 4151 | static inline void* zig_windows_teb(void) { | |
| 4152 | 4152 | void* teb = 0; |
| 4153 | 4153 | #if defined(zig_msvc) |
| 4154 | 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); |
| ... | ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { |
| 4160 | 4160 | |
| 4161 | 4161 | #elif defined(zig_aarch64) |
| 4162 | 4162 | |
| 4163 | static inline void* zig_aarch64_windows_teb(void) { | |
| 4163 | static inline void* zig_windows_teb(void) { | |
| 4164 | 4164 | void* teb = 0; |
| 4165 | 4165 | #if defined(zig_msvc) |
| 4166 | 4166 | teb = (void*)__readx18qword(0x0); |
| ... | ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { |
| 4172 | 4172 | |
| 4173 | 4173 | #elif defined(zig_x86_32) |
| 4174 | 4174 | |
| 4175 | static inline void* zig_x86_windows_teb(void) { | |
| 4175 | static inline void* zig_windows_teb(void) { | |
| 4176 | 4176 | void* teb = 0; |
| 4177 | 4177 | #if defined(zig_msvc) |
| 4178 | 4178 | teb = (void*)__readfsdword(0x18); |
| ... | ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { |
| 4182 | 4182 | return teb; |
| 4183 | 4183 | } |
| 4184 | 4184 | |
| 4185 | static 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 | 4195 | #elif defined(zig_x86_64) |
| 4186 | 4196 | |
| 4187 | static inline void* zig_x86_64_windows_teb(void) { | |
| 4197 | static inline void* zig_windows_teb(void) { | |
| 4188 | 4198 | void* teb = 0; |
| 4189 | 4199 | #if defined(zig_msvc) |
| 4190 | 4200 | teb = (void*)__readgsqword(0x30); |
| ... | ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { |
| 4194 | 4204 | return teb; |
| 4195 | 4205 | } |
| 4196 | 4206 | |
| 4207 | static 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 | 4217 | #endif |
| 4198 | 4218 | |
| 4199 | 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 | 4148 | |
| 4149 | 4149 | #if defined(zig_thumb) |
| 4150 | 4150 | |
| 4151 | static inline void* zig_thumb_windows_teb(void) { | |
| 4151 | static inline void* zig_windows_teb(void) { | |
| 4152 | 4152 | void* teb = 0; |
| 4153 | 4153 | #if defined(zig_msvc) |
| 4154 | 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); |
| ... | ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { |
| 4160 | 4160 | |
| 4161 | 4161 | #elif defined(zig_aarch64) |
| 4162 | 4162 | |
| 4163 | static inline void* zig_aarch64_windows_teb(void) { | |
| 4163 | static inline void* zig_windows_teb(void) { | |
| 4164 | 4164 | void* teb = 0; |
| 4165 | 4165 | #if defined(zig_msvc) |
| 4166 | 4166 | teb = (void*)__readx18qword(0x0); |
| ... | ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { |
| 4172 | 4172 | |
| 4173 | 4173 | #elif defined(zig_x86_32) |
| 4174 | 4174 | |
| 4175 | static inline void* zig_x86_windows_teb(void) { | |
| 4175 | static inline void* zig_windows_teb(void) { | |
| 4176 | 4176 | void* teb = 0; |
| 4177 | 4177 | #if defined(zig_msvc) |
| 4178 | 4178 | teb = (void*)__readfsdword(0x18); |
| ... | ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { |
| 4182 | 4182 | return teb; |
| 4183 | 4183 | } |
| 4184 | 4184 | |
| 4185 | static 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 | 4195 | #elif defined(zig_x86_64) |
| 4186 | 4196 | |
| 4187 | static inline void* zig_x86_64_windows_teb(void) { | |
| 4197 | static inline void* zig_windows_teb(void) { | |
| 4188 | 4198 | void* teb = 0; |
| 4189 | 4199 | #if defined(zig_msvc) |
| 4190 | 4200 | teb = (void*)__readgsqword(0x30); |
| ... | ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { |
| 4194 | 4204 | return teb; |
| 4195 | 4205 | } |
| 4196 | 4206 | |
| 4207 | static 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 | 4217 | #endif |
| 4198 | 4218 | |
| 4199 | 4219 | #if defined(zig_loongarch) |
test/standalone/coff_dwarf/main.zig+3-4| ... | ... | @@ -4,17 +4,16 @@ const fatal = std.process.fatal; |
| 4 | 4 | extern fn add(a: u32, b: u32, addr: *usize) u32; |
| 5 | 5 | |
| 6 | 6 | pub fn main(init: std.process.Init) void { |
| 7 | const gpa = init.gpa; | |
| 8 | 7 | const io = init.io; |
| 9 | 8 | |
| 10 | 9 | var di: std.debug.SelfInfo = .init; |
| 11 | defer di.deinit(gpa); | |
| 10 | defer di.deinit(io); | |
| 12 | 11 | |
| 13 | 12 | var add_addr: usize = undefined; |
| 14 | 13 | _ = add(1, 2, &add_addr); |
| 15 | 14 | |
| 16 | const symbol = di.getSymbol(gpa, io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); | |
| 17 | defer if (symbol.source_location) |sl| gpa.free(sl.file_name); | |
| 15 | const symbol = di.getSymbol(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); | |
| 16 | defer if (symbol.source_location) |sl| std.debug.getDebugInfoAllocator().free(sl.file_name); | |
| 18 | 17 | |
| 19 | 18 | if (symbol.name == null) fatal("failed to resolve symbol name", .{}); |
| 20 | 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 | 127 | .hStdOutput = null, |
| 128 | 128 | .hStdError = windows.peb().ProcessParameters.hStdError, |
| 129 | 129 | }; |
| 130 | var proc_info: windows.PROCESS_INFORMATION = undefined; | |
| 130 | var proc_info: windows.PROCESS.INFORMATION = undefined; | |
| 131 | 131 | |
| 132 | 132 | if (windows.kernel32.CreateProcessW( |
| 133 | 133 | @constCast(verify_path.ptr), |
| ... | ... | @@ -141,7 +141,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO |
| 141 | 141 | &startup_info, |
| 142 | 142 | &proc_info, |
| 143 | 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 | } |
| 146 | 146 | |
| 147 | 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 | 156 | else => |status| return windows.unexpectedStatus(status), |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | var exit_code: windows.DWORD = undefined; | |
| 160 | if (windows.kernel32.GetExitCodeProcess(child_proc, &exit_code) == 0) { | |
| 161 | return error.UnableToGetExitCode; | |
| 159 | var info: windows.PROCESS.BASIC_INFORMATION = undefined; | |
| 160 | switch (windows.ntdll.NtQueryInformationProcess( | |
| 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 | 16 | defer arena_state.deinit(); |
| 17 | 17 | const allocator = arena_state.allocator(); |
| 18 | 18 | |
| 19 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | |
| 20 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | |
| 21 | const raw_args: std.process.Args = .{ .vector = cmd_line_w }; | |
| 19 | const raw_args: std.process.Args = .{ | |
| 20 | .vector = std.os.windows.peb().ProcessParameters.CommandLine.slice(), | |
| 21 | }; | |
| 22 | 22 | const args = try raw_args.toSlice(allocator); |
| 23 | 23 | var wtf8_buf = std.array_list.Managed(u8).init(allocator); |
| 24 | 24 |