| 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,7 +35,7 @@ Set-Location -Path 'build-debug' |
| 35 | 35 | ||
| 36 | # CMake gives a syntax error when file paths with backward slashes are used. | 36 | # CMake gives a syntax error when file paths with backward slashes are used. |
| 37 | # Here, we use forward slashes only to work around this. | 37 | # Here, we use forward slashes only to work around this. |
| 38 | & cmake .. ` | 38 | cmake .. ` |
| 39 | -GNinja ` | 39 | -GNinja ` |
| 40 | -DCMAKE_INSTALL_PREFIX="stage3-debug" ` | 40 | -DCMAKE_INSTALL_PREFIX="stage3-debug" ` |
| 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` | 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` |
| ... | @@ -54,7 +54,7 @@ ninja install | ... | @@ -54,7 +54,7 @@ ninja install |
| 54 | CheckLastExitCode | 54 | CheckLastExitCode |
| 55 | 55 | ||
| 56 | Write-Output "Main test suite..." | 56 | Write-Output "Main test suite..." |
| 57 | & "stage3-debug\bin\zig.exe" build test docs ` | 57 | stage3-debug\bin\zig build test docs ` |
| 58 | --maxrss $ZSF_MAX_RSS ` | 58 | --maxrss $ZSF_MAX_RSS ` |
| 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 60 | --search-prefix "$PREFIX_PATH" ` | 60 | --search-prefix "$PREFIX_PATH" ` |
| ... | @@ -66,26 +66,25 @@ Write-Output "Main test suite..." | ... | @@ -66,26 +66,25 @@ Write-Output "Main test suite..." |
| 66 | CheckLastExitCode | 66 | CheckLastExitCode |
| 67 | 67 | ||
| 68 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." | 68 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." |
| 69 | & "stage3-debug\bin\zig.exe" test ` | 69 | stage3-debug\bin\zig build-obj ` |
| 70 | ..\test\behavior.zig ` | ||
| 71 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 70 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 72 | -ofmt=c ` | 71 | -ofmt=c ` |
| 73 | -femit-bin="test-x86_64-windows-msvc.c" ` | 72 | -OReleaseSmall ` |
| 74 | --test-no-exec ` | 73 | --name compiler_rt ` |
| 74 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | ||
| 75 | -target x86_64-windows-msvc ` | 75 | -target x86_64-windows-msvc ` |
| 76 | -lc | 76 | -lc ` |
| 77 | ..\lib\compiler_rt.zig | ||
| 77 | CheckLastExitCode | 78 | CheckLastExitCode |
| 78 | 79 | ||
| 79 | & "stage3-debug\bin\zig.exe" build-obj ` | 80 | stage3-debug\bin\zig test ` |
| 80 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 81 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 81 | -ofmt=c ` | 82 | -ofmt=c ` |
| 82 | -OReleaseSmall ` | 83 | -femit-bin="behavior-x86_64-windows-msvc.c" ` |
| 83 | --name compiler_rt ` | 84 | --test-no-exec ` |
| 84 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | ||
| 85 | --dep build_options ` | ||
| 86 | -target x86_64-windows-msvc ` | 85 | -target x86_64-windows-msvc ` |
| 87 | -Mroot="..\lib\compiler_rt.zig" ` | 86 | -lc ` |
| 88 | -Mbuild_options="config.zig" | 87 | ..\test\behavior.zig |
| 89 | CheckLastExitCode | 88 | CheckLastExitCode |
| 90 | 89 | ||
| 91 | Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" | 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,8 +96,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\ |
| 97 | CheckLastExitCode | 96 | CheckLastExitCode |
| 98 | 97 | ||
| 99 | Write-Output "Build and run behavior tests with msvc..." | 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 | CheckLastExitCode | 100 | CheckLastExitCode |
| 102 | 101 | ||
| 103 | & .\test-x86_64-windows-msvc.exe | 102 | .\behavior-x86_64-windows-msvc |
| 104 | CheckLastExitCode | 103 | CheckLastExitCode |
ci/x86_64-windows-release.ps1+16-17| ... | @@ -35,7 +35,7 @@ Set-Location -Path 'build-release' | ... | @@ -35,7 +35,7 @@ Set-Location -Path 'build-release' |
| 35 | 35 | ||
| 36 | # CMake gives a syntax error when file paths with backward slashes are used. | 36 | # CMake gives a syntax error when file paths with backward slashes are used. |
| 37 | # Here, we use forward slashes only to work around this. | 37 | # Here, we use forward slashes only to work around this. |
| 38 | & cmake .. ` | 38 | cmake .. ` |
| 39 | -GNinja ` | 39 | -GNinja ` |
| 40 | -DCMAKE_INSTALL_PREFIX="stage3-release" ` | 40 | -DCMAKE_INSTALL_PREFIX="stage3-release" ` |
| 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` | 41 | -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` |
| ... | @@ -54,7 +54,7 @@ ninja install | ... | @@ -54,7 +54,7 @@ ninja install |
| 54 | CheckLastExitCode | 54 | CheckLastExitCode |
| 55 | 55 | ||
| 56 | Write-Output "Main test suite..." | 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 | --maxrss $ZSF_MAX_RSS ` | 58 | --maxrss $ZSF_MAX_RSS ` |
| 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 59 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 60 | --search-prefix "$PREFIX_PATH" ` | 60 | --search-prefix "$PREFIX_PATH" ` |
| ... | @@ -67,7 +67,7 @@ CheckLastExitCode | ... | @@ -67,7 +67,7 @@ CheckLastExitCode |
| 67 | 67 | ||
| 68 | # Ensure that stage3 and stage4 are byte-for-byte identical. | 68 | # Ensure that stage3 and stage4 are byte-for-byte identical. |
| 69 | Write-Output "Build and compare stage4..." | 69 | Write-Output "Build and compare stage4..." |
| 70 | & "stage3-release\bin\zig.exe" build ` | 70 | stage3-release\bin\zig.exe build ` |
| 71 | --prefix stage4-release ` | 71 | --prefix stage4-release ` |
| 72 | -Denable-llvm ` | 72 | -Denable-llvm ` |
| 73 | -Dno-lib ` | 73 | -Dno-lib ` |
| ... | @@ -85,26 +85,25 @@ Compare-Object (Get-Content stage3-release\bin\zig.exe) (Get-Content stage4-rele | ... | @@ -85,26 +85,25 @@ Compare-Object (Get-Content stage3-release\bin\zig.exe) (Get-Content stage4-rele |
| 85 | CheckLastExitCode | 85 | CheckLastExitCode |
| 86 | 86 | ||
| 87 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." | 87 | Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." |
| 88 | & "stage3-release\bin\zig.exe" test ` | 88 | stage3-release\bin\zig.exe build-obj ` |
| 89 | ..\test\behavior.zig ` | ||
| 90 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 89 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 91 | -ofmt=c ` | 90 | -ofmt=c ` |
| 92 | -femit-bin="test-x86_64-windows-msvc.c" ` | 91 | -OReleaseSmall ` |
| 93 | --test-no-exec ` | 92 | --name compiler_rt ` |
| 93 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | ||
| 94 | -target x86_64-windows-msvc ` | 94 | -target x86_64-windows-msvc ` |
| 95 | -lc | 95 | -lc ` |
| 96 | ..\lib\compiler_rt.zig | ||
| 96 | CheckLastExitCode | 97 | CheckLastExitCode |
| 97 | 98 | ||
| 98 | & "stage3-release\bin\zig.exe" build-obj ` | 99 | stage3-release\bin\zig.exe test ` |
| 99 | --zig-lib-dir "$ZIG_LIB_DIR" ` | 100 | --zig-lib-dir "$ZIG_LIB_DIR" ` |
| 100 | -ofmt=c ` | 101 | -ofmt=c ` |
| 101 | -OReleaseSmall ` | 102 | -femit-bin="behavior-x86_64-windows-msvc.c" ` |
| 102 | --name compiler_rt ` | 103 | --test-no-exec ` |
| 103 | -femit-bin="compiler_rt-x86_64-windows-msvc.c" ` | ||
| 104 | --dep build_options ` | ||
| 105 | -target x86_64-windows-msvc ` | 104 | -target x86_64-windows-msvc ` |
| 106 | -Mroot="..\lib\compiler_rt.zig" ` | 105 | -lc ` |
| 107 | -Mbuild_options="config.zig" | 106 | ..\test\behavior.zig |
| 108 | CheckLastExitCode | 107 | CheckLastExitCode |
| 109 | 108 | ||
| 110 | Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" | 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,8 +115,8 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\ |
| 116 | CheckLastExitCode | 115 | CheckLastExitCode |
| 117 | 116 | ||
| 118 | Write-Output "Build and run behavior tests with msvc..." | 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 | CheckLastExitCode | 119 | CheckLastExitCode |
| 121 | 120 | ||
| 122 | & .\test-x86_64-windows-msvc.exe | 121 | .\behavior-x86_64-windows-msvc |
| 123 | CheckLastExitCode | 122 | CheckLastExitCode |
lib/compiler/build_runner.zig+1-1| ... | @@ -621,7 +621,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -621,7 +621,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 621 | }) catch &caption_buf; | 621 | }) catch &caption_buf; |
| 622 | var debouncing_node = main_progress_node.start(caption, 0); | 622 | var debouncing_node = main_progress_node.start(caption, 0); |
| 623 | var in_debounce = false; | 623 | var in_debounce = false; |
| 624 | while (true) switch (try w.wait(gpa, if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) { | 624 | while (true) switch (try w.wait(gpa, io, if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) { |
| 625 | .timeout => { | 625 | .timeout => { |
| 626 | assert(in_debounce); | 626 | assert(in_debounce); |
| 627 | debouncing_node.end(); | 627 | debouncing_node.end(); |
lib/fuzzer.zig+1-1| ... | @@ -632,7 +632,7 @@ export fn fuzzer_main(limit_kind: abi.LimitKind, amount: u64) void { | ... | @@ -632,7 +632,7 @@ export fn fuzzer_main(limit_kind: abi.LimitKind, amount: u64) void { |
| 632 | 632 | ||
| 633 | export fn fuzzer_unslide_address(addr: usize) usize { | 633 | export fn fuzzer_unslide_address(addr: usize) usize { |
| 634 | const si = std.debug.getSelfDebugInfo() catch @compileError("unsupported"); | 634 | const si = std.debug.getSelfDebugInfo() catch @compileError("unsupported"); |
| 635 | const slide = si.getModuleSlide(std.debug.getDebugInfoAllocator(), io, addr) catch |err| { | 635 | const slide = si.getModuleSlide(io, addr) catch |err| { |
| 636 | std.debug.panic("failed to find virtual address slide: {t}", .{err}); | 636 | std.debug.panic("failed to find virtual address slide: {t}", .{err}); |
| 637 | }; | 637 | }; |
| 638 | return addr - slide; | 638 | return addr - slide; |
lib/std/Build/Watch.zig+145-133| ... | @@ -180,7 +180,7 @@ const Os = switch (builtin.os.tag) { | ... | @@ -180,7 +180,7 @@ const Os = switch (builtin.os.tag) { |
| 180 | const gop = try w.dir_table.getOrPut(gpa, path); | 180 | const gop = try w.dir_table.getOrPut(gpa, path); |
| 181 | if (!gop.found_existing) { | 181 | if (!gop.found_existing) { |
| 182 | var mount_id: MountId = undefined; | 182 | var mount_id: MountId = undefined; |
| 183 | const dir_handle = Os.getDirHandle(gpa, path, &mount_id) catch |err| switch (err) { | 183 | const dir_handle = getDirHandle(gpa, path, &mount_id) catch |err| switch (err) { |
| 184 | error.FileNotFound => { | 184 | error.FileNotFound => { |
| 185 | std.debug.assert(w.dir_table.swapRemove(path)); | 185 | std.debug.assert(w.dir_table.swapRemove(path)); |
| 186 | continue; | 186 | continue; |
| ... | @@ -291,12 +291,13 @@ const Os = switch (builtin.os.tag) { | ... | @@ -291,12 +291,13 @@ const Os = switch (builtin.os.tag) { |
| 291 | w.dir_count = w.dir_table.count(); | 291 | w.dir_count = w.dir_table.count(); |
| 292 | } | 292 | } |
| 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 | const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms()); | 296 | const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms()); |
| 296 | if (events_len == 0) | 297 | if (events_len == 0) |
| 297 | return .timeout; | 298 | return .timeout; |
| 298 | for (w.os.poll_fds.values()) |poll_fd| { | 299 | for (w.os.poll_fds.values()) |poll_fd| { |
| 299 | if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try Os.markDirtySteps(w, gpa, poll_fd.fd)) | 300 | if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try markDirtySteps(w, gpa, poll_fd.fd)) |
| 300 | return .dirty; | 301 | return .dirty; |
| 301 | } | 302 | } |
| 302 | return .clean; | 303 | return .clean; |
| ... | @@ -306,12 +307,8 @@ const Os = switch (builtin.os.tag) { | ... | @@ -306,12 +307,8 @@ const Os = switch (builtin.os.tag) { |
| 306 | const windows = std.os.windows; | 307 | const windows = std.os.windows; |
| 307 | 308 | ||
| 308 | /// Keyed differently but indexes correspond 1:1 with `dir_table`. | 309 | /// Keyed differently but indexes correspond 1:1 with `dir_table`. |
| 309 | handle_table: HandleTable, | 310 | handle_table: std.ArrayHashMapUnmanaged(*Directory, void, Directory.TableAdapter, false), |
| 310 | dir_list: std.AutoArrayHashMapUnmanaged(usize, *Directory), | 311 | ready_dirs: std.DoublyLinkedList, |
| 311 | io_cp: ?windows.HANDLE, | ||
| 312 | counter: usize = 0, | ||
| 313 | |||
| 314 | const HandleTable = std.AutoArrayHashMapUnmanaged(FileId, ReactionSet); | ||
| 315 | 312 | ||
| 316 | const FileId = struct { | 313 | const FileId = struct { |
| 317 | volumeSerialNumber: windows.ULONG, | 314 | volumeSerialNumber: windows.ULONG, |
| ... | @@ -319,55 +316,61 @@ const Os = switch (builtin.os.tag) { | ... | @@ -319,55 +316,61 @@ const Os = switch (builtin.os.tag) { |
| 319 | }; | 316 | }; |
| 320 | 317 | ||
| 321 | const Directory = struct { | 318 | const Directory = struct { |
| 322 | handle: windows.HANDLE, | 319 | reaction_set: ReactionSet, |
| 323 | id: FileId, | 320 | id: FileId, |
| 324 | overlapped: windows.OVERLAPPED, | 321 | file: Io.File, |
| 322 | state: enum { idle, listening, ready }, | ||
| 323 | iosb: windows.IO_STATUS_BLOCK, | ||
| 325 | // 64 KB is the packet size limit when monitoring over a network. | 324 | // 64 KB is the packet size limit when monitoring over a network. |
| 326 | // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw#remarks | 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 | /// Start listening for events, buffer field will be overwritten eventually. | 329 | /// Start listening for events, buffer field will be overwritten eventually. |
| 330 | fn startListening(self: *@This()) !void { | 330 | fn startListening(dir: *Directory, w: *Watch) !void { |
| 331 | const r = windows.kernel32.ReadDirectoryChangesW( | 331 | assert(dir.file.flags.nonblocking); |
| 332 | self.handle, | 332 | assert(dir.state == .idle); |
| 333 | @ptrCast(&self.buffer), | 333 | switch (windows.ntdll.NtNotifyChangeDirectoryFileEx( |
| 334 | self.buffer.len, | 334 | dir.file.handle, |
| 335 | 0, | 335 | null, |
| 336 | &notifyApc, | ||
| 337 | w, | ||
| 338 | &dir.iosb, | ||
| 339 | &dir.buffer, | ||
| 340 | dir.buffer.len, | ||
| 336 | .{ | 341 | .{ |
| 337 | .creation = true, | 342 | .FILE_NAME = true, |
| 338 | .dir_name = true, | 343 | .DIR_NAME = true, |
| 339 | .file_name = true, | 344 | .SIZE = true, |
| 340 | .last_write = true, | 345 | .LAST_WRITE = true, |
| 341 | .size = true, | 346 | .CREATION = true, |
| 342 | }, | 347 | }, |
| 343 | null, | 348 | windows.FALSE, |
| 344 | &self.overlapped, | 349 | .Notify, |
| 345 | null, | 350 | )) { |
| 346 | ); | 351 | .SUCCESS, .PENDING => dir.state = .listening, |
| 347 | if (r == windows.FALSE) { | 352 | .ILLEGAL_FUNCTION => return error.ReadDirectoryChangesUnsupported, |
| 348 | switch (windows.GetLastError()) { | 353 | else => |status| return windows.unexpectedStatus(status), |
| 349 | .INVALID_FUNCTION => return error.ReadDirectoryChangesUnsupported, | ||
| 350 | else => |err| return windows.unexpectedError(err), | ||
| 351 | } | ||
| 352 | } | 354 | } |
| 353 | } | 355 | } |
| 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 | // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW) | 367 | // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW) |
| 357 | // It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW. | 368 | // It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW. |
| 358 | var dir_handle: windows.HANDLE = undefined; | 369 | var dir_handle: windows.HANDLE = undefined; |
| 359 | const root_fd = path.root_dir.handle.handle; | 370 | const root_fd = path.root_dir.handle.handle; |
| 360 | const sub_path = path.subPathOrDot(); | 371 | const sub_path = path.subPathOrDot(); |
| 361 | const sub_path_w = try std.Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call | 372 | const sub_path_w = try Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call |
| 362 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | ||
| 363 | |||
| 364 | var nt_name = windows.UNICODE_STRING{ | ||
| 365 | .Length = @intCast(path_len_bytes), | ||
| 366 | .MaximumLength = @intCast(path_len_bytes), | ||
| 367 | .Buffer = @constCast(sub_path_w.span().ptr), | ||
| 368 | }; | ||
| 369 | var iosb: windows.IO_STATUS_BLOCK = undefined; | 373 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 370 | |||
| 371 | switch (windows.ntdll.NtCreateFile( | 374 | switch (windows.ntdll.NtCreateFile( |
| 372 | &dir_handle, | 375 | &dir_handle, |
| 373 | .{ | 376 | .{ |
| ... | @@ -379,7 +382,7 @@ const Os = switch (builtin.os.tag) { | ... | @@ -379,7 +382,7 @@ const Os = switch (builtin.os.tag) { |
| 379 | }, | 382 | }, |
| 380 | &.{ | 383 | &.{ |
| 381 | .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd, | 384 | .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else root_fd, |
| 382 | .ObjectName = &nt_name, | 385 | .ObjectName = @constCast(&sub_path_w.string()), |
| 383 | }, | 386 | }, |
| 384 | &iosb, | 387 | &iosb, |
| 385 | null, | 388 | null, |
| ... | @@ -410,20 +413,49 @@ const Os = switch (builtin.os.tag) { | ... | @@ -410,20 +413,49 @@ const Os = switch (builtin.os.tag) { |
| 410 | 413 | ||
| 411 | const dir_id = try getFileId(dir_handle); | 414 | const dir_id = try getFileId(dir_handle); |
| 412 | 415 | ||
| 413 | const dir_ptr = try gpa.create(@This()); | 416 | const dir = try gpa.create(Directory); |
| 414 | dir_ptr.* = .{ | 417 | dir.* = .{ |
| 415 | .handle = dir_handle, | 418 | .reaction_set = .empty, |
| 416 | .id = dir_id, | 419 | .id = dir_id, |
| 417 | .overlapped = std.mem.zeroes(windows.OVERLAPPED), | 420 | .file = .{ .handle = dir_handle, .flags = .{ .nonblocking = true } }, |
| 421 | .state = .idle, | ||
| 422 | .iosb = undefined, | ||
| 423 | .buffer = undefined, | ||
| 424 | .ready_node = undefined, | ||
| 418 | }; | 425 | }; |
| 419 | return dir_ptr; | 426 | return dir; |
| 420 | } | 427 | } |
| 421 | 428 | ||
| 422 | fn deinit(self: *@This(), gpa: Allocator) void { | 429 | fn deinit(dir: *Directory, gpa: Allocator, w: *Watch) void { |
| 423 | _ = windows.kernel32.CancelIo(self.handle); | 430 | state: switch (dir.state) { |
| 424 | windows.CloseHandle(self.handle); | 431 | .idle => {}, |
| 425 | gpa.destroy(self); | 432 | .listening => { |
| 433 | var cancel_iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 434 | _ = windows.ntdll.NtCancelIoFileEx(dir.file.handle, &dir.iosb, &cancel_iosb); | ||
| 435 | while (switch (dir.state) { | ||
| 436 | .idle => unreachable, | ||
| 437 | .listening => true, | ||
| 438 | .ready => false, | ||
| 439 | }) Io.Threaded.waitForApcOrAlert(); | ||
| 440 | continue :state .ready; | ||
| 441 | }, | ||
| 442 | .ready => w.os.ready_dirs.remove(&dir.ready_node), | ||
| 443 | } | ||
| 444 | windows.CloseHandle(dir.file.handle); | ||
| 445 | gpa.destroy(dir); | ||
| 426 | } | 446 | } |
| 447 | |||
| 448 | /// Useful to make `*Directory` a key in `std.ArrayHashMap`. | ||
| 449 | const TableAdapter = struct { | ||
| 450 | pub fn hash(_: TableAdapter, lhs_dir: *Directory) u32 { | ||
| 451 | return @truncate(Hash.hash(lhs_dir.id.volumeSerialNumber, @ptrCast(&lhs_dir.id.indexNumber))); | ||
| 452 | } | ||
| 453 | pub fn eql(_: TableAdapter, lhs_dir: *Directory, rhs_dir: *Directory, rhs_index: usize) bool { | ||
| 454 | _ = rhs_index; | ||
| 455 | return lhs_dir.id.volumeSerialNumber == rhs_dir.id.volumeSerialNumber and | ||
| 456 | lhs_dir.id.indexNumber == rhs_dir.id.indexNumber; | ||
| 457 | } | ||
| 458 | }; | ||
| 427 | }; | 459 | }; |
| 428 | 460 | ||
| 429 | fn init(cwd_path: []const u8) !Watch { | 461 | fn init(cwd_path: []const u8) !Watch { |
| ... | @@ -433,9 +465,8 @@ const Os = switch (builtin.os.tag) { | ... | @@ -433,9 +465,8 @@ const Os = switch (builtin.os.tag) { |
| 433 | .dir_count = 0, | 465 | .dir_count = 0, |
| 434 | .os = switch (builtin.os.tag) { | 466 | .os = switch (builtin.os.tag) { |
| 435 | .windows => .{ | 467 | .windows => .{ |
| 436 | .handle_table = .{}, | 468 | .handle_table = .empty, |
| 437 | .dir_list = .{}, | 469 | .ready_dirs = .{}, |
| 438 | .io_cp = null, | ||
| 439 | }, | 470 | }, |
| 440 | else => {}, | 471 | else => {}, |
| 441 | }, | 472 | }, |
| ... | @@ -479,29 +510,22 @@ const Os = switch (builtin.os.tag) { | ... | @@ -479,29 +510,22 @@ const Os = switch (builtin.os.tag) { |
| 479 | 510 | ||
| 480 | fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool { | 511 | fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool { |
| 481 | var any_dirty = false; | 512 | var any_dirty = false; |
| 482 | const bytes_returned = try windows.GetOverlappedResult(dir.handle, &dir.overlapped, false); | 513 | const bytes_returned = dir.iosb.Information; |
| 483 | if (bytes_returned == 0) { | 514 | if (bytes_returned == 0) { |
| 484 | std.log.warn("file system watch queue overflowed; falling back to fstat", .{}); | 515 | std.log.warn("file system watch queue overflowed; falling back to fstat", .{}); |
| 485 | markAllFilesDirty(w, gpa); | 516 | markAllFilesDirty(w, gpa); |
| 486 | try dir.startListening(); | 517 | try dir.startListening(w); |
| 487 | return true; | 518 | return true; |
| 488 | } | 519 | } |
| 489 | var file_name_buf: [std.fs.max_path_bytes]u8 = undefined; | 520 | var file_name_buf: [std.fs.max_path_bytes]u8 = undefined; |
| 490 | var notify: *align(1) windows.FILE_NOTIFY_INFORMATION = undefined; | ||
| 491 | var offset: usize = 0; | 521 | var offset: usize = 0; |
| 492 | while (true) { | 522 | while (true) { |
| 493 | notify = @ptrCast(&dir.buffer[offset]); | 523 | const notify: *windows.FILE.NOTIFY.INFORMATION = @ptrCast(@alignCast(&dir.buffer[offset])); |
| 494 | const file_name_field: [*]u16 = @ptrFromInt(@intFromPtr(notify) + @sizeOf(windows.FILE_NOTIFY_INFORMATION)); | 524 | const file_name = file_name_buf[0..std.unicode.wtf16LeToWtf8(&file_name_buf, notify.fileName())]; |
| 495 | const file_name_len = std.unicode.wtf16LeToWtf8(&file_name_buf, file_name_field[0 .. notify.FileNameLength / 2]); | 525 | if (dir.reaction_set.getPtr(".")) |glob_set| |
| 496 | const file_name = file_name_buf[0..file_name_len]; | 526 | any_dirty = markStepSetDirty(gpa, glob_set, any_dirty); |
| 497 | if (w.os.handle_table.getIndex(dir.id)) |reaction_set_i| { | 527 | if (dir.reaction_set.getPtr(file_name)) |step_set| |
| 498 | const reaction_set = w.os.handle_table.values()[reaction_set_i]; | 528 | any_dirty = markStepSetDirty(gpa, step_set, any_dirty); |
| 499 | if (reaction_set.getPtr(".")) |glob_set| | ||
| 500 | any_dirty = markStepSetDirty(gpa, glob_set, any_dirty); | ||
| 501 | if (reaction_set.getPtr(file_name)) |step_set| { | ||
| 502 | any_dirty = markStepSetDirty(gpa, step_set, any_dirty); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | if (notify.NextEntryOffset == 0) | 529 | if (notify.NextEntryOffset == 0) |
| 506 | break; | 530 | break; |
| 507 | 531 | ||
| ... | @@ -509,7 +533,7 @@ const Os = switch (builtin.os.tag) { | ... | @@ -509,7 +533,7 @@ const Os = switch (builtin.os.tag) { |
| 509 | } | 533 | } |
| 510 | 534 | ||
| 511 | // We call this now since at this point we have finished reading dir.buffer. | 535 | // We call this now since at this point we have finished reading dir.buffer. |
| 512 | try dir.startListening(); | 536 | try dir.startListening(w); |
| 513 | return any_dirty; | 537 | return any_dirty; |
| 514 | } | 538 | } |
| 515 | 539 | ||
| ... | @@ -517,41 +541,32 @@ const Os = switch (builtin.os.tag) { | ... | @@ -517,41 +541,32 @@ const Os = switch (builtin.os.tag) { |
| 517 | // Add missing marks and note persisted ones. | 541 | // Add missing marks and note persisted ones. |
| 518 | for (steps) |step| { | 542 | for (steps) |step| { |
| 519 | for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| { | 543 | for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| { |
| 520 | const reaction_set = rs: { | 544 | const dir = dir: { |
| 521 | const gop = try w.dir_table.getOrPut(gpa, path); | 545 | const gop = try w.dir_table.getOrPut(gpa, path); |
| 522 | if (!gop.found_existing) { | 546 | if (!gop.found_existing) { |
| 523 | const dir = try Os.Directory.init(gpa, path); | 547 | const dir: *Directory = try .init(gpa, path); |
| 524 | errdefer dir.deinit(gpa); | 548 | errdefer dir.deinit(gpa, w); |
| 525 | // `dir.id` may already be present in the table in | 549 | // `dir.id` may already be present in the table in |
| 526 | // the case that we have multiple Cache.Path instances | 550 | // the case that we have multiple Cache.Path instances |
| 527 | // that compare inequal but ultimately point to the same | 551 | // that compare inequal but ultimately point to the same |
| 528 | // directory on the file system. | 552 | // directory on the file system. |
| 529 | // In such case, we must revert adding this directory, but keep | 553 | // In such case, we must revert adding this directory, but keep |
| 530 | // the additions to the step set. | 554 | // the additions to the step set. |
| 531 | const dh_gop = try w.os.handle_table.getOrPut(gpa, dir.id); | 555 | const dh_gop = try w.os.handle_table.getOrPut(gpa, dir); |
| 532 | if (dh_gop.found_existing) { | 556 | if (dh_gop.found_existing) { |
| 533 | dir.deinit(gpa); | 557 | dir.deinit(gpa, w); |
| 534 | _ = w.dir_table.pop(); | 558 | _ = w.dir_table.pop(); |
| 559 | break :dir w.os.handle_table.keys()[dh_gop.index]; | ||
| 535 | } else { | 560 | } else { |
| 536 | assert(dh_gop.index == gop.index); | 561 | assert(dh_gop.index == gop.index); |
| 537 | dh_gop.value_ptr.* = .{}; | 562 | try dir.startListening(w); |
| 538 | try dir.startListening(); | 563 | break :dir dir; |
| 539 | const key = w.os.counter; | ||
| 540 | w.os.counter +%= 1; | ||
| 541 | try w.os.dir_list.put(gpa, key, dir); | ||
| 542 | w.os.io_cp = try windows.CreateIoCompletionPort( | ||
| 543 | dir.handle, | ||
| 544 | w.os.io_cp, | ||
| 545 | key, | ||
| 546 | 0, | ||
| 547 | ); | ||
| 548 | } | 564 | } |
| 549 | break :rs &w.os.handle_table.values()[dh_gop.index]; | ||
| 550 | } | 565 | } |
| 551 | break :rs &w.os.handle_table.values()[gop.index]; | 566 | break :dir w.os.handle_table.keys()[gop.index]; |
| 552 | }; | 567 | }; |
| 553 | for (files.items) |basename| { | 568 | for (files.items) |basename| { |
| 554 | const gop = try reaction_set.getOrPut(gpa, basename); | 569 | const gop = try dir.reaction_set.getOrPut(gpa, basename); |
| 555 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 570 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 556 | try gop.value_ptr.put(gpa, step, w.generation); | 571 | try gop.value_ptr.put(gpa, step, w.generation); |
| 557 | } | 572 | } |
| ... | @@ -562,11 +577,11 @@ const Os = switch (builtin.os.tag) { | ... | @@ -562,11 +577,11 @@ const Os = switch (builtin.os.tag) { |
| 562 | // Remove marks for files that are no longer inputs. | 577 | // Remove marks for files that are no longer inputs. |
| 563 | var i: usize = 0; | 578 | var i: usize = 0; |
| 564 | while (i < w.os.handle_table.entries.len) { | 579 | while (i < w.os.handle_table.entries.len) { |
| 580 | const dir = w.os.handle_table.keys()[i]; | ||
| 565 | { | 581 | { |
| 566 | const reaction_set = &w.os.handle_table.values()[i]; | ||
| 567 | var step_set_i: usize = 0; | 582 | var step_set_i: usize = 0; |
| 568 | while (step_set_i < reaction_set.entries.len) { | 583 | while (step_set_i < dir.reaction_set.entries.len) { |
| 569 | const step_set = &reaction_set.values()[step_set_i]; | 584 | const step_set = &dir.reaction_set.values()[step_set_i]; |
| 570 | var dirent_i: usize = 0; | 585 | var dirent_i: usize = 0; |
| 571 | while (dirent_i < step_set.entries.len) { | 586 | while (dirent_i < step_set.entries.len) { |
| 572 | const generations = step_set.values(); | 587 | const generations = step_set.values(); |
| ... | @@ -580,53 +595,45 @@ const Os = switch (builtin.os.tag) { | ... | @@ -580,53 +595,45 @@ const Os = switch (builtin.os.tag) { |
| 580 | step_set_i += 1; | 595 | step_set_i += 1; |
| 581 | continue; | 596 | continue; |
| 582 | } | 597 | } |
| 583 | reaction_set.swapRemoveAt(step_set_i); | 598 | dir.reaction_set.swapRemoveAt(step_set_i); |
| 584 | } | 599 | } |
| 585 | if (reaction_set.entries.len > 0) { | 600 | if (dir.reaction_set.entries.len > 0) { |
| 586 | i += 1; | 601 | i += 1; |
| 587 | continue; | 602 | continue; |
| 588 | } | 603 | } |
| 589 | } | 604 | } |
| 590 | 605 | ||
| 591 | w.os.dir_list.values()[i].deinit(gpa); | ||
| 592 | w.os.dir_list.swapRemoveAt(i); | ||
| 593 | w.dir_table.swapRemoveAt(i); | 606 | w.dir_table.swapRemoveAt(i); |
| 594 | w.os.handle_table.swapRemoveAt(i); | 607 | w.os.handle_table.swapRemoveAt(i); |
| 608 | dir.deinit(gpa, w); | ||
| 595 | } | 609 | } |
| 596 | w.generation +%= 1; | 610 | w.generation +%= 1; |
| 597 | } | 611 | } |
| 598 | w.dir_count = w.dir_table.count(); | 612 | w.dir_count = w.dir_table.count(); |
| 599 | } | 613 | } |
| 600 | 614 | ||
| 601 | fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult { | 615 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { |
| 602 | var bytes_transferred: std.os.windows.DWORD = undefined; | 616 | for (0..2) |attempt| { |
| 603 | var key: usize = undefined; | 617 | while (w.os.ready_dirs.popFirst()) |ready_node| { |
| 604 | var overlapped_ptr: ?*std.os.windows.OVERLAPPED = undefined; | 618 | const dir: *Directory = @fieldParentPtr("ready_node", ready_node); |
| 605 | return while (true) switch (std.os.windows.GetQueuedCompletionStatus( | 619 | assert(dir.state == .ready); |
| 606 | w.os.io_cp.?, | 620 | dir.state = .idle; |
| 607 | &bytes_transferred, | 621 | switch (dir.iosb.u.Status) { |
| 608 | &key, | 622 | .SUCCESS => return if (try markDirtySteps(w, gpa, dir)) .dirty else .clean, |
| 609 | &overlapped_ptr, | 623 | .PENDING => unreachable, |
| 610 | @bitCast(timeout.to_i32_ms()), | 624 | .CANCELLED => {}, |
| 611 | )) { | 625 | else => |status| return windows.unexpectedStatus(status), |
| 612 | .Normal => { | 626 | } |
| 613 | if (bytes_transferred == 0) | 627 | try dir.startListening(w); |
| 614 | break error.Unexpected; | 628 | } |
| 615 | 629 | try io.checkCancel(); | |
| 616 | // This 'orelse' detects a race condition that happens when we receive a | 630 | if (attempt == 1) return .timeout; |
| 617 | // completion notification for a directory that no longer exists in our list. | 631 | const delay_interval: windows.LARGE_INTEGER = switch (timeout) { |
| 618 | const dir = w.os.dir_list.get(key) orelse break .clean; | 632 | .none => std.math.minInt(windows.LARGE_INTEGER), |
| 619 | 633 | .ms => |ms| -@as(windows.LARGE_INTEGER, ms) * (std.time.ns_per_ms / 100), | |
| 620 | break if (try Os.markDirtySteps(w, gpa, dir)) | 634 | }; |
| 621 | .dirty | 635 | _ = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval); |
| 622 | else | 636 | } else unreachable; |
| 623 | .clean; | ||
| 624 | }, | ||
| 625 | .Timeout => break .timeout, | ||
| 626 | // This status is issued because CancelIo was called, skip and try again. | ||
| 627 | .Canceled => continue, | ||
| 628 | else => break error.Unexpected, | ||
| 629 | }; | ||
| 630 | } | 637 | } |
| 631 | }, | 638 | }, |
| 632 | .dragonfly, .freebsd, .netbsd, .openbsd, .ios, .tvos, .visionos, .watchos => struct { | 639 | .dragonfly, .freebsd, .netbsd, .openbsd, .ios, .tvos, .visionos, .watchos => struct { |
| ... | @@ -796,7 +803,8 @@ const Os = switch (builtin.os.tag) { | ... | @@ -796,7 +803,8 @@ const Os = switch (builtin.os.tag) { |
| 796 | w.dir_count = w.dir_table.count(); | 803 | w.dir_count = w.dir_table.count(); |
| 797 | } | 804 | } |
| 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 | var timespec_buffer: posix.timespec = undefined; | 808 | var timespec_buffer: posix.timespec = undefined; |
| 801 | var event_buffer: [100]posix.Kevent = undefined; | 809 | var event_buffer: [100]posix.Kevent = undefined; |
| 802 | var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(&timespec_buffer)); | 810 | var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(&timespec_buffer)); |
| ... | @@ -852,7 +860,8 @@ const Os = switch (builtin.os.tag) { | ... | @@ -852,7 +860,8 @@ const Os = switch (builtin.os.tag) { |
| 852 | try w.os.fse.setPaths(gpa, steps); | 860 | try w.os.fse.setPaths(gpa, steps); |
| 853 | w.dir_count = w.os.fse.watch_roots.len; | 861 | w.dir_count = w.os.fse.watch_roots.len; |
| 854 | } | 862 | } |
| 855 | fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult { | 863 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { |
| 864 | _ = io; | ||
| 856 | return w.os.fse.wait(gpa, switch (timeout) { | 865 | return w.os.fse.wait(gpa, switch (timeout) { |
| 857 | .none => null, | 866 | .none => null, |
| 858 | .ms => |ms| @as(u64, ms) * std.time.ns_per_ms, | 867 | .ms => |ms| @as(u64, ms) * std.time.ns_per_ms, |
| ... | @@ -890,10 +899,13 @@ pub const Match = struct { | ... | @@ -890,10 +899,13 @@ pub const Match = struct { |
| 890 | }; | 899 | }; |
| 891 | 900 | ||
| 892 | fn markAllFilesDirty(w: *Watch, gpa: Allocator) void { | 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 | const reaction_set = switch (builtin.os.tag) { | 906 | const reaction_set = switch (builtin.os.tag) { |
| 895 | .linux => value.reaction_set, | 907 | .linux, .windows => item.reaction_set, |
| 896 | else => value, | 908 | else => item, |
| 897 | }; | 909 | }; |
| 898 | for (reaction_set.values()) |step_set| { | 910 | for (reaction_set.values()) |step_set| { |
| 899 | for (step_set.keys()) |step| { | 911 | for (step_set.keys()) |step| { |
| ... | @@ -951,6 +963,6 @@ pub const WaitResult = enum { | ... | @@ -951,6 +963,6 @@ pub const WaitResult = enum { |
| 951 | clean, | 963 | clean, |
| 952 | }; | 964 | }; |
| 953 | 965 | ||
| 954 | pub fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult { | 966 | pub fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { |
| 955 | return Os.wait(w, gpa, timeout); | 967 | return Os.wait(w, gpa, io, timeout); |
| 956 | } | 968 | } |
lib/std/Io/Threaded.zig+465-493| ... | @@ -83,7 +83,7 @@ csprng: Csprng = .{}, | ... | @@ -83,7 +83,7 @@ csprng: Csprng = .{}, |
| 83 | system_basic_information: SystemBasicInformation = .{}, | 83 | system_basic_information: SystemBasicInformation = .{}, |
| 84 | 84 | ||
| 85 | const SystemBasicInformation = if (!is_windows) struct {} else struct { | 85 | const SystemBasicInformation = if (!is_windows) struct {} else struct { |
| 86 | buffer: windows.SYSTEM_BASIC_INFORMATION = undefined, | 86 | buffer: windows.SYSTEM.BASIC_INFORMATION = undefined, |
| 87 | initialized: std.atomic.Value(bool) = .{ .raw = false }, | 87 | initialized: std.atomic.Value(bool) = .{ .raw = false }, |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| ... | @@ -1392,7 +1392,7 @@ const AlertableSyscall = struct { | ... | @@ -1392,7 +1392,7 @@ const AlertableSyscall = struct { |
| 1392 | } | 1392 | } |
| 1393 | }; | 1393 | }; |
| 1394 | 1394 | ||
| 1395 | fn waitForApcOrAlert() void { | 1395 | pub fn waitForApcOrAlert() void { |
| 1396 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); | 1396 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); |
| 1397 | _ = windows.ntdll.NtDelayExecution(windows.TRUE, &infinite_timeout); | 1397 | _ = windows.ntdll.NtDelayExecution(windows.TRUE, &infinite_timeout); |
| 1398 | } | 1398 | } |
| ... | @@ -2556,9 +2556,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper | ... | @@ -2556,9 +2556,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper |
| 2556 | else => |e| e, | 2556 | else => |e| e, |
| 2557 | }, | 2557 | }, |
| 2558 | }, | 2558 | }, |
| 2559 | .device_io_control => |*o| return .{ | 2559 | .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) }, |
| 2560 | .device_io_control = try deviceIoControl(t, o), | ||
| 2561 | }, | ||
| 2562 | } | 2560 | } |
| 2563 | } | 2561 | } |
| 2564 | 2562 | ||
| ... | @@ -2970,7 +2968,7 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren | ... | @@ -2970,7 +2968,7 @@ fn batchAwaitWindows(b: *Io.Batch, concurrency: bool) error{ Canceled, Concurren |
| 2970 | break :o; | 2968 | break :o; |
| 2971 | } | 2969 | } |
| 2972 | const buffer = o.data[data_index]; | 2970 | const buffer = o.data[data_index]; |
| 2973 | const short_buffer_len = @min(std.math.maxInt(u32), buffer.len); | 2971 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); |
| 2974 | 2972 | ||
| 2975 | if (o.file.flags.nonblocking) { | 2973 | if (o.file.flags.nonblocking) { |
| 2976 | context.file = o.file.handle; | 2974 | context.file = o.file.handle; |
| ... | @@ -3259,22 +3257,11 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe | ... | @@ -3259,22 +3257,11 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe |
| 3259 | _ = t; | 3257 | _ = t; |
| 3260 | _ = permissions; // TODO use this value | 3258 | _ = permissions; // TODO use this value |
| 3261 | 3259 | ||
| 3262 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | 3260 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); |
| 3263 | const sub_path_w = sub_path_w_array.span(); | 3261 | const attr: windows.OBJECT.ATTRIBUTES = .{ |
| 3264 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | 3262 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, |
| 3265 | 3263 | .Attributes = .{ .INHERIT = false }, | |
| 3266 | var nt_name: windows.UNICODE_STRING = .{ | 3264 | .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w.span())), |
| 3267 | .Length = path_len_bytes, | ||
| 3268 | .MaximumLength = path_len_bytes, | ||
| 3269 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 3270 | }; | ||
| 3271 | const attr: windows.OBJECT_ATTRIBUTES = .{ | ||
| 3272 | .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), | ||
| 3273 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 3274 | .Attributes = .{ | ||
| 3275 | .INHERIT = false, | ||
| 3276 | }, | ||
| 3277 | .ObjectName = &nt_name, | ||
| 3278 | .SecurityDescriptor = null, | 3265 | .SecurityDescriptor = null, |
| 3279 | .SecurityQualityOfService = null, | 3266 | .SecurityQualityOfService = null, |
| 3280 | }; | 3267 | }; |
| ... | @@ -3438,21 +3425,14 @@ fn dirCreateDirPathOpenWindows( | ... | @@ -3438,21 +3425,14 @@ fn dirCreateDirPathOpenWindows( |
| 3438 | }; | 3425 | }; |
| 3439 | 3426 | ||
| 3440 | components: while (true) { | 3427 | components: while (true) { |
| 3441 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, component.path); | 3428 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, component.path); |
| 3442 | const sub_path_w = sub_path_w_array.span(); | 3429 | const attr: windows.OBJECT.ATTRIBUTES = .{ |
| 3430 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | ||
| 3431 | .ObjectName = @constCast(&sub_path_w.string()), | ||
| 3432 | }; | ||
| 3443 | const is_last = it.peekNext() == null; | 3433 | const is_last = it.peekNext() == null; |
| 3444 | const create_disposition: w.FILE.CREATE_DISPOSITION = if (is_last) .OPEN_IF else .CREATE; | ||
| 3445 | |||
| 3446 | var result: Dir = .{ .handle = undefined }; | 3434 | var result: Dir = .{ .handle = undefined }; |
| 3447 | 3435 | var iosb: w.IO_STATUS_BLOCK = undefined; | |
| 3448 | const path_len_bytes: u16 = @intCast(sub_path_w.len * 2); | ||
| 3449 | var nt_name: w.UNICODE_STRING = .{ | ||
| 3450 | .Length = path_len_bytes, | ||
| 3451 | .MaximumLength = path_len_bytes, | ||
| 3452 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 3453 | }; | ||
| 3454 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | ||
| 3455 | |||
| 3456 | const syscall: Syscall = try .start(); | 3436 | const syscall: Syscall = try .start(); |
| 3457 | while (true) switch (w.ntdll.NtCreateFile( | 3437 | while (true) switch (w.ntdll.NtCreateFile( |
| 3458 | &result.handle, | 3438 | &result.handle, |
| ... | @@ -3468,15 +3448,12 @@ fn dirCreateDirPathOpenWindows( | ... | @@ -3468,15 +3448,12 @@ fn dirCreateDirPathOpenWindows( |
| 3468 | .SYNCHRONIZE = true, | 3448 | .SYNCHRONIZE = true, |
| 3469 | }, | 3449 | }, |
| 3470 | }, | 3450 | }, |
| 3471 | &.{ | 3451 | &attr, |
| 3472 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | 3452 | &iosb, |
| 3473 | .ObjectName = &nt_name, | ||
| 3474 | }, | ||
| 3475 | &io_status_block, | ||
| 3476 | null, | 3453 | null, |
| 3477 | .{ .NORMAL = true }, | 3454 | .{ .NORMAL = true }, |
| 3478 | .VALID_FLAGS, | 3455 | .VALID_FLAGS, |
| 3479 | create_disposition, | 3456 | if (is_last) .OPEN_IF else .CREATE, |
| 3480 | .{ | 3457 | .{ |
| 3481 | .DIRECTORY_FILE = true, | 3458 | .DIRECTORY_FILE = true, |
| 3482 | .IO = .SYNCHRONOUS_NONALERT, | 3459 | .IO = .SYNCHRONOUS_NONALERT, |
| ... | @@ -3944,15 +3921,15 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | ... | @@ -3944,15 +3921,15 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 3944 | }; | 3921 | }; |
| 3945 | } | 3922 | } |
| 3946 | 3923 | ||
| 3947 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM_BASIC_INFORMATION { | 3924 | fn systemBasicInformation(t: *Threaded) ?*const windows.SYSTEM.BASIC_INFORMATION { |
| 3948 | if (!t.system_basic_information.initialized.load(.acquire)) { | 3925 | if (!t.system_basic_information.initialized.load(.acquire)) { |
| 3949 | mutexLock(&t.mutex); | 3926 | mutexLock(&t.mutex); |
| 3950 | defer mutexUnlock(&t.mutex); | 3927 | defer mutexUnlock(&t.mutex); |
| 3951 | 3928 | ||
| 3952 | switch (windows.ntdll.NtQuerySystemInformation( | 3929 | switch (windows.ntdll.NtQuerySystemInformation( |
| 3953 | .SystemBasicInformation, | 3930 | .Basic, |
| 3954 | &t.system_basic_information.buffer, | 3931 | &t.system_basic_information.buffer, |
| 3955 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | 3932 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), |
| 3956 | null, | 3933 | null, |
| 3957 | )) { | 3934 | )) { |
| 3958 | .SUCCESS => {}, | 3935 | .SUCCESS => {}, |
| ... | @@ -4139,22 +4116,11 @@ fn dirAccessWindows( | ... | @@ -4139,22 +4116,11 @@ fn dirAccessWindows( |
| 4139 | 4116 | ||
| 4140 | _ = options; // TODO | 4117 | _ = options; // TODO |
| 4141 | 4118 | ||
| 4142 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | 4119 | if (std.mem.eql(u8, sub_path, ".") or std.mem.eql(u8, sub_path, "..")) return; |
| 4143 | const sub_path_w = sub_path_w_array.span(); | 4120 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); |
| 4144 | 4121 | const attr: windows.OBJECT.ATTRIBUTES = .{ | |
| 4145 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) return; | 4122 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, |
| 4146 | if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) return; | 4123 | .ObjectName = @constCast(&sub_path_w.string()), |
| 4147 | |||
| 4148 | const path_len_bytes = std.math.cast(u16, std.mem.sliceTo(sub_path_w, 0).len * 2) orelse | ||
| 4149 | return error.NameTooLong; | ||
| 4150 | var nt_name: windows.UNICODE_STRING = .{ | ||
| 4151 | .Length = path_len_bytes, | ||
| 4152 | .MaximumLength = path_len_bytes, | ||
| 4153 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 4154 | }; | ||
| 4155 | const attr: windows.OBJECT_ATTRIBUTES = .{ | ||
| 4156 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 4157 | .ObjectName = &nt_name, | ||
| 4158 | }; | 4124 | }; |
| 4159 | var basic_info: windows.FILE.BASIC_INFORMATION = undefined; | 4125 | var basic_info: windows.FILE.BASIC_INFORMATION = undefined; |
| 4160 | const syscall: Syscall = try .start(); | 4126 | const syscall: Syscall = try .start(); |
| ... | @@ -4360,18 +4326,10 @@ fn dirCreateFileWindows( | ... | @@ -4360,18 +4326,10 @@ fn dirCreateFileWindows( |
| 4360 | if (std.mem.eql(u8, sub_path, ".")) return error.IsDir; | 4326 | if (std.mem.eql(u8, sub_path, ".")) return error.IsDir; |
| 4361 | if (std.mem.eql(u8, sub_path, "..")) return error.IsDir; | 4327 | if (std.mem.eql(u8, sub_path, "..")) return error.IsDir; |
| 4362 | 4328 | ||
| 4363 | const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); | 4329 | const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); |
| 4364 | const sub_path_w = sub_path_w_array.span(); | 4330 | const attr: windows.OBJECT.ATTRIBUTES = .{ |
| 4365 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | 4331 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, |
| 4366 | 4332 | .ObjectName = @constCast(&sub_path_w.string()), | |
| 4367 | var nt_name: windows.UNICODE_STRING = .{ | ||
| 4368 | .Length = path_len_bytes, | ||
| 4369 | .MaximumLength = path_len_bytes, | ||
| 4370 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 4371 | }; | ||
| 4372 | const attr: windows.OBJECT_ATTRIBUTES = .{ | ||
| 4373 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 4374 | .ObjectName = &nt_name, | ||
| 4375 | }; | 4333 | }; |
| 4376 | const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive) | 4334 | const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive) |
| 4377 | .CREATE | 4335 | .CREATE |
| ... | @@ -4966,20 +4924,14 @@ fn dirOpenFileWindows( | ... | @@ -4966,20 +4924,14 @@ fn dirOpenFileWindows( |
| 4966 | 4924 | ||
| 4967 | pub fn dirOpenFileWtf16( | 4925 | pub fn dirOpenFileWtf16( |
| 4968 | dir_handle: ?windows.HANDLE, | 4926 | dir_handle: ?windows.HANDLE, |
| 4969 | sub_path_w: [:0]const u16, | 4927 | sub_path_w: []const u16, |
| 4970 | flags: File.OpenFlags, | 4928 | flags: File.OpenFlags, |
| 4971 | ) File.OpenError!File { | 4929 | ) File.OpenError!File { |
| 4972 | const allow_directory = flags.allow_directory and !flags.isWrite(); | 4930 | const allow_directory = flags.allow_directory and !flags.isWrite(); |
| 4973 | if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir; | 4931 | if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir; |
| 4974 | if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir; | 4932 | if (!allow_directory and std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir; |
| 4975 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | ||
| 4976 | const w = windows; | 4933 | const w = windows; |
| 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 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | 4935 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 4984 | var attempt: u5 = 0; | 4936 | var attempt: u5 = 0; |
| 4985 | var syscall: Syscall = try .start(); | 4937 | var syscall: Syscall = try .start(); |
| ... | @@ -4996,7 +4948,7 @@ pub fn dirOpenFileWtf16( | ... | @@ -4996,7 +4948,7 @@ pub fn dirOpenFileWtf16( |
| 4996 | }, | 4948 | }, |
| 4997 | &.{ | 4949 | &.{ |
| 4998 | .RootDirectory = dir_handle, | 4950 | .RootDirectory = dir_handle, |
| 4999 | .ObjectName = &nt_name, | 4951 | .ObjectName = @constCast(&w.UNICODE_STRING.init(sub_path_w)), |
| 5000 | }, | 4952 | }, |
| 5001 | &io_status_block, | 4953 | &io_status_block, |
| 5002 | null, | 4954 | null, |
| ... | @@ -5329,20 +5281,19 @@ fn dirOpenDirHaiku( | ... | @@ -5329,20 +5281,19 @@ fn dirOpenDirHaiku( |
| 5329 | 5281 | ||
| 5330 | pub fn dirOpenDirWindows( | 5282 | pub fn dirOpenDirWindows( |
| 5331 | dir: Dir, | 5283 | dir: Dir, |
| 5332 | sub_path_w: [:0]const u16, | 5284 | sub_path_w: []const u16, |
| 5333 | options: Dir.OpenOptions, | 5285 | options: Dir.OpenOptions, |
| 5334 | ) Dir.OpenError!Dir { | 5286 | ) Dir.OpenError!Dir { |
| 5335 | const w = windows; | 5287 | const w = windows; |
| 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 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | 5289 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 5344 | var result: Dir = .{ .handle = undefined }; | 5290 | var result: Dir = .{ .handle = undefined }; |
| 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 | const syscall: Syscall = try .start(); | 5297 | const syscall: Syscall = try .start(); |
| 5347 | while (true) switch (w.ntdll.NtCreateFile( | 5298 | while (true) switch (w.ntdll.NtCreateFile( |
| 5348 | &result.handle, | 5299 | &result.handle, |
| ... | @@ -5359,10 +5310,7 @@ pub fn dirOpenDirWindows( | ... | @@ -5359,10 +5310,7 @@ pub fn dirOpenDirWindows( |
| 5359 | .SYNCHRONIZE = true, | 5310 | .SYNCHRONIZE = true, |
| 5360 | }, | 5311 | }, |
| 5361 | }, | 5312 | }, |
| 5362 | &.{ | 5313 | &attr, |
| 5363 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 5364 | .ObjectName = &nt_name, | ||
| 5365 | }, | ||
| 5366 | &io_status_block, | 5314 | &io_status_block, |
| 5367 | null, | 5315 | null, |
| 5368 | .{ .NORMAL = true }, | 5316 | .{ .NORMAL = true }, |
| ... | @@ -6194,13 +6142,15 @@ pub fn GetFinalPathNameByHandle( | ... | @@ -6194,13 +6142,15 @@ pub fn GetFinalPathNameByHandle( |
| 6194 | input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2); | 6142 | input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2); |
| 6195 | @memcpy(input_buf[@sizeOf(windows.MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr))); | 6143 | @memcpy(input_buf[@sizeOf(windows.MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr))); |
| 6196 | 6144 | ||
| 6197 | { | 6145 | switch ((try deviceIoControl(&.{ |
| 6198 | const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_POINTS, .{ .in = &input_buf, .out = &output_buf }); | 6146 | .file = .{ .handle = mgmt_handle, .flags = .{ .nonblocking = false } }, |
| 6199 | switch (rc) { | 6147 | .code = windows.IOCTL.MOUNTMGR.QUERY_POINTS, |
| 6200 | .SUCCESS => {}, | 6148 | .in = &input_buf, |
| 6201 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | 6149 | .out = &output_buf, |
| 6202 | else => return windows.unexpectedStatus(rc), | 6150 | })).u.Status) { |
| 6203 | } | 6151 | .SUCCESS => {}, |
| 6152 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | ||
| 6153 | else => |status| return windows.unexpectedStatus(status), | ||
| 6204 | } | 6154 | } |
| 6205 | const mount_points_struct: *const windows.MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]); | 6155 | const mount_points_struct: *const windows.MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]); |
| 6206 | 6156 | ||
| ... | @@ -6251,11 +6201,15 @@ pub fn GetFinalPathNameByHandle( | ... | @@ -6251,11 +6201,15 @@ pub fn GetFinalPathNameByHandle( |
| 6251 | vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2); | 6201 | vol_input_struct.DeviceNameLength = @intCast(symlink.len * 2); |
| 6252 | @memcpy(@as([*]windows.WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink); | 6202 | @memcpy(@as([*]windows.WCHAR, &vol_input_struct.DeviceName)[0..symlink.len], symlink); |
| 6253 | 6203 | ||
| 6254 | const rc = windows.DeviceIoControl(mgmt_handle, windows.IOCTL.MOUNTMGR.QUERY_DOS_VOLUME_PATH, .{ .in = &vol_input_buf, .out = &vol_output_buf }); | 6204 | switch ((try deviceIoControl(&.{ |
| 6255 | switch (rc) { | 6205 | .file = .{ .handle = mgmt_handle, .flags = .{ .nonblocking = true } }, |
| 6206 | .code = windows.IOCTL.MOUNTMGR.QUERY_DOS_VOLUME_PATH, | ||
| 6207 | .in = &vol_input_buf, | ||
| 6208 | .out = &vol_output_buf, | ||
| 6209 | })).u.Status) { | ||
| 6256 | .SUCCESS => {}, | 6210 | .SUCCESS => {}, |
| 6257 | .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume, | 6211 | .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume, |
| 6258 | else => return windows.unexpectedStatus(rc), | 6212 | else => |status| return windows.unexpectedStatus(status), |
| 6259 | } | 6213 | } |
| 6260 | const volume_paths_struct: *const windows.MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]); | 6214 | const volume_paths_struct: *const windows.MOUNTMGR_VOLUME_PATHS = @ptrCast(&vol_output_buf[0]); |
| 6261 | const volume_path = std.mem.sliceTo(@as( | 6215 | const volume_path = std.mem.sliceTo(@as( |
| ... | @@ -6352,20 +6306,17 @@ pub const QueryObjectNameError = error{ | ... | @@ -6352,20 +6306,17 @@ pub const QueryObjectNameError = error{ |
| 6352 | }; | 6306 | }; |
| 6353 | 6307 | ||
| 6354 | pub fn QueryObjectName(handle: windows.HANDLE, out_buffer: []u16) QueryObjectNameError![]u16 { | 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 | // buffer size is specified in bytes | 6312 | // buffer size is specified in bytes |
| 6359 | const out_buffer_len = std.math.cast(windows.ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(windows.ULONG); | 6313 | const out_buffer_len = std.math.cast(windows.ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(windows.ULONG); |
| 6360 | // last argument would return the length required for full_buffer, not exposed here | 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)) { | 6315 | return switch (windows.ntdll.NtQueryObject(handle, .Name, info, out_buffer_len, null)) { |
| 6362 | .SUCCESS => blk: { | 6316 | .SUCCESS => { |
| 6363 | // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0) | 6317 | // info.Name from ObQueryNameString is documented to be empty if the object |
| 6364 | // if the object was "unnamed", not sure if this can happen for file handles | 6318 | // was "unnamed", not sure if this can happen for file handles |
| 6365 | if (info.Name.MaximumLength == 0) break :blk error.Unexpected; | 6319 | return if (info.Name.isEmpty()) error.Unexpected else info.Name.slice(); |
| 6366 | // resulting string length is specified in bytes | ||
| 6367 | const path_length_unterminated = @divExact(info.Name.Length, 2); | ||
| 6368 | break :blk info.Name.Buffer.?[0..path_length_unterminated]; | ||
| 6369 | }, | 6320 | }, |
| 6370 | .ACCESS_DENIED => error.AccessDenied, | 6321 | .ACCESS_DENIED => error.AccessDenied, |
| 6371 | .INVALID_HANDLE => error.InvalidHandle, | 6322 | .INVALID_HANDLE => error.InvalidHandle, |
| ... | @@ -6620,8 +6571,12 @@ pub const WindowsPathSpace = struct { | ... | @@ -6620,8 +6571,12 @@ pub const WindowsPathSpace = struct { |
| 6620 | data: [windows.PATH_MAX_WIDE:0]u16, | 6571 | data: [windows.PATH_MAX_WIDE:0]u16, |
| 6621 | len: usize, | 6572 | len: usize, |
| 6622 | 6573 | ||
| 6623 | pub fn span(self: *const WindowsPathSpace) [:0]const u16 { | 6574 | pub fn span(wps: *const WindowsPathSpace) [:0]const u16 { |
| 6624 | return self.data[0..self.len :0]; | 6575 | return wps.data[0..wps.len :0]; |
| 6576 | } | ||
| 6577 | |||
| 6578 | pub fn string(wps: *const WindowsPathSpace) windows.UNICODE_STRING { | ||
| 6579 | return .init(wps.span()); | ||
| 6625 | } | 6580 | } |
| 6626 | }; | 6581 | }; |
| 6627 | 6582 | ||
| ... | @@ -7076,25 +7031,19 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov | ... | @@ -7076,25 +7031,19 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov |
| 7076 | _ = t; | 7031 | _ = t; |
| 7077 | const w = windows; | 7032 | const w = windows; |
| 7078 | 7033 | ||
| 7079 | const sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, sub_path); | 7034 | if (std.mem.eql(u8, sub_path, "..")) { |
| 7080 | const sub_path_w = sub_path_w_buf.span(); | ||
| 7081 | |||
| 7082 | const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2)); | ||
| 7083 | var nt_name: w.UNICODE_STRING = .{ | ||
| 7084 | .Length = path_len_bytes, | ||
| 7085 | .MaximumLength = path_len_bytes, | ||
| 7086 | // The Windows API makes this mutable, but it will not mutate here. | ||
| 7087 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 7088 | }; | ||
| 7089 | |||
| 7090 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { | ||
| 7091 | // Windows does not recognize this, but it does work with empty string. | ||
| 7092 | nt_name.Length = 0; | ||
| 7093 | } | ||
| 7094 | if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { | ||
| 7095 | // Can't remove the parent directory with an open handle. | 7035 | // Can't remove the parent directory with an open handle. |
| 7096 | return error.FileBusy; | 7036 | return error.FileBusy; |
| 7097 | } | 7037 | } |
| 7038 | var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); | ||
| 7039 | if (std.mem.eql(u8, sub_path, ".")) { | ||
| 7040 | // Windows does not recognize this, but it does work with empty string. | ||
| 7041 | sub_path_w.len = 0; | ||
| 7042 | } | ||
| 7043 | const attr: w.OBJECT.ATTRIBUTES = .{ | ||
| 7044 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, | ||
| 7045 | .ObjectName = @constCast(&sub_path_w.string()), | ||
| 7046 | }; | ||
| 7098 | 7047 | ||
| 7099 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | 7048 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| 7100 | var tmp_handle: w.HANDLE = undefined; | 7049 | var tmp_handle: w.HANDLE = undefined; |
| ... | @@ -7106,10 +7055,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov | ... | @@ -7106,10 +7055,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov |
| 7106 | .RIGHTS = .{ .DELETE = true }, | 7055 | .RIGHTS = .{ .DELETE = true }, |
| 7107 | .SYNCHRONIZE = true, | 7056 | .SYNCHRONIZE = true, |
| 7108 | } }, | 7057 | } }, |
| 7109 | &.{ | 7058 | &attr, |
| 7110 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 7111 | .ObjectName = &nt_name, | ||
| 7112 | }, | ||
| 7113 | &io_status_block, | 7059 | &io_status_block, |
| 7114 | null, | 7060 | null, |
| 7115 | .{}, | 7061 | .{}, |
| ... | @@ -7741,7 +7687,7 @@ fn dirSymLinkWindows( | ... | @@ -7741,7 +7687,7 @@ fn dirSymLinkWindows( |
| 7741 | // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw | 7687 | // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw |
| 7742 | var is_target_absolute = false; | 7688 | var is_target_absolute = false; |
| 7743 | const final_target_path = target_path: { | 7689 | const final_target_path = target_path: { |
| 7744 | if (windows.hasCommonNtPrefix(u16, target_path_w.span())) { | 7690 | if (w.hasCommonNtPrefix(u16, target_path_w.span())) { |
| 7745 | // Already an NT path, no need to do anything to it | 7691 | // Already an NT path, no need to do anything to it |
| 7746 | break :target_path target_path_w.span(); | 7692 | break :target_path target_path_w.span(); |
| 7747 | } else { | 7693 | } else { |
| ... | @@ -7785,13 +7731,16 @@ fn dirSymLinkWindows( | ... | @@ -7785,13 +7731,16 @@ fn dirSymLinkWindows( |
| 7785 | @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); | 7731 | @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); |
| 7786 | const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2; | 7732 | const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2; |
| 7787 | @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); | 7733 | @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); |
| 7788 | const rc = w.DeviceIoControl(symlink_handle, .SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] }); | 7734 | switch ((try deviceIoControl(&.{ |
| 7789 | switch (rc) { | 7735 | .file = .{ .handle = symlink_handle, .flags = .{ .nonblocking = false } }, |
| 7736 | .code = .SET_REPARSE_POINT, | ||
| 7737 | .in = buffer[0..buf_len], | ||
| 7738 | })).u.Status) { | ||
| 7790 | .SUCCESS => {}, | 7739 | .SUCCESS => {}, |
| 7791 | .PRIVILEGE_NOT_HELD => return error.PermissionDenied, | 7740 | .PRIVILEGE_NOT_HELD => return error.PermissionDenied, |
| 7792 | .ACCESS_DENIED => return error.AccessDenied, | 7741 | .ACCESS_DENIED => return error.AccessDenied, |
| 7793 | .INVALID_DEVICE_REQUEST => return error.FileSystem, | 7742 | .INVALID_DEVICE_REQUEST => return error.FileSystem, |
| 7794 | else => return windows.unexpectedStatus(rc), | 7743 | else => |status| return w.unexpectedStatus(status), |
| 7795 | } | 7744 | } |
| 7796 | } | 7745 | } |
| 7797 | 7746 | ||
| ... | @@ -7905,17 +7854,10 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: [] | ... | @@ -7905,17 +7854,10 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: [] |
| 7905 | fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize { | 7854 | fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize { |
| 7906 | // This gets used once for `sub_path` and then reused again temporarily | 7855 | // This gets used once for `sub_path` and then reused again temporarily |
| 7907 | // before converting back to `buffer`. | 7856 | // before converting back to `buffer`. |
| 7908 | var sub_path_w_buf = try sliceToPrefixedFileW(dir.handle, sub_path); | 7857 | var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); |
| 7909 | const sub_path_w = sub_path_w_buf.span(); | 7858 | const attr: windows.OBJECT.ATTRIBUTES = .{ |
| 7910 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | 7859 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, |
| 7911 | var nt_name: windows.UNICODE_STRING = .{ | 7860 | .ObjectName = @constCast(&sub_path_w.string()), |
| 7912 | .Length = path_len_bytes, | ||
| 7913 | .MaximumLength = path_len_bytes, | ||
| 7914 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 7915 | }; | ||
| 7916 | const attr: windows.OBJECT_ATTRIBUTES = .{ | ||
| 7917 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 7918 | .ObjectName = &nt_name, | ||
| 7919 | }; | 7861 | }; |
| 7920 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | 7862 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 7921 | var result_handle: windows.HANDLE = undefined; | 7863 | var result_handle: windows.HANDLE = undefined; |
| ... | @@ -8038,14 +7980,14 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink | ... | @@ -8038,14 +7980,14 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink |
| 8038 | const len = buf.SubstituteNameLength >> 1; | 7980 | const len = buf.SubstituteNameLength >> 1; |
| 8039 | const path_buf = @as([*]const u16, &buf.PathBuffer); | 7981 | const path_buf = @as([*]const u16, &buf.PathBuffer); |
| 8040 | const is_relative = buf.Flags & windows.SYMLINK_FLAG_RELATIVE != 0; | 7982 | const is_relative = buf.Flags & windows.SYMLINK_FLAG_RELATIVE != 0; |
| 8041 | break :r try parseReadLinkPath(path_buf[offset..][0..len], is_relative, &sub_path_w_buf.data); | 7983 | break :r try parseReadLinkPath(path_buf[offset..][0..len], is_relative, &sub_path_w.data); |
| 8042 | }, | 7984 | }, |
| 8043 | @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: { | 7985 | @as(IoReparseTagInt, @bitCast(windows.IO_REPARSE_TAG.MOUNT_POINT)) => r: { |
| 8044 | const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0])); | 7986 | const buf: *const windows.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0])); |
| 8045 | const offset = buf.SubstituteNameOffset >> 1; | 7987 | const offset = buf.SubstituteNameOffset >> 1; |
| 8046 | const len = buf.SubstituteNameLength >> 1; | 7988 | const len = buf.SubstituteNameLength >> 1; |
| 8047 | const path_buf = @as([*]const u16, &buf.PathBuffer); | 7989 | const path_buf = @as([*]const u16, &buf.PathBuffer); |
| 8048 | break :r try parseReadLinkPath(path_buf[offset..][0..len], false, &sub_path_w_buf.data); | 7990 | break :r try parseReadLinkPath(path_buf[offset..][0..len], false, &sub_path_w.data); |
| 8049 | }, | 7991 | }, |
| 8050 | else => return error.UnsupportedReparsePointType, | 7992 | else => return error.UnsupportedReparsePointType, |
| 8051 | }; | 7993 | }; |
| ... | @@ -8541,13 +8483,14 @@ fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void { | ... | @@ -8541,13 +8483,14 @@ fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 8541 | 8483 | ||
| 8542 | fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { | 8484 | fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 8543 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 8485 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8544 | return t.isTty(file); | 8486 | _ = t; |
| 8487 | return isTty(file); | ||
| 8545 | } | 8488 | } |
| 8546 | 8489 | ||
| 8547 | fn isTty(t: *Threaded, file: File) Io.Cancelable!bool { | 8490 | fn isTty(file: File) Io.Cancelable!bool { |
| 8548 | if (is_windows) { | 8491 | if (is_windows) { |
| 8549 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; | 8492 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8550 | switch ((try t.deviceIoControl(&.{ | 8493 | switch ((try deviceIoControl(&.{ |
| 8551 | .file = .{ | 8494 | .file = .{ |
| 8552 | .handle = windows.peb().ProcessParameters.ConsoleHandle, | 8495 | .handle = windows.peb().ProcessParameters.ConsoleHandle, |
| 8553 | .flags = .{ .nonblocking = false }, | 8496 | .flags = .{ .nonblocking = false }, |
| ... | @@ -8626,8 +8569,9 @@ fn isTty(t: *Threaded, file: File) Io.Cancelable!bool { | ... | @@ -8626,8 +8569,9 @@ fn isTty(t: *Threaded, file: File) Io.Cancelable!bool { |
| 8626 | 8569 | ||
| 8627 | fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void { | 8570 | fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void { |
| 8628 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 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 | // For Windows Terminal, VT Sequences processing is enabled by default. | 8576 | // For Windows Terminal, VT Sequences processing is enabled by default. |
| 8633 | const console: File = .{ | 8577 | const console: File = .{ |
| ... | @@ -8635,7 +8579,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE | ... | @@ -8635,7 +8579,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8635 | .flags = .{ .nonblocking = false }, | 8579 | .flags = .{ .nonblocking = false }, |
| 8636 | }; | 8580 | }; |
| 8637 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; | 8581 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8638 | switch ((try t.deviceIoControl(&.{ | 8582 | switch ((try deviceIoControl(&.{ |
| 8639 | .file = console, | 8583 | .file = console, |
| 8640 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, | 8584 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, |
| 8641 | .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), | 8585 | .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), |
| ... | @@ -8661,7 +8605,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE | ... | @@ -8661,7 +8605,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8661 | var set_console_mode = windows.CONSOLE.USER_IO.SET_MODE( | 8605 | var set_console_mode = windows.CONSOLE.USER_IO.SET_MODE( |
| 8662 | get_console_mode.Data | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING, | 8606 | get_console_mode.Data | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING, |
| 8663 | ); | 8607 | ); |
| 8664 | switch ((try t.deviceIoControl(&.{ | 8608 | switch ((try deviceIoControl(&.{ |
| 8665 | .file = console, | 8609 | .file = console, |
| 8666 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, | 8610 | .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, |
| 8667 | .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})), | 8611 | .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})), |
| ... | @@ -8673,13 +8617,14 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE | ... | @@ -8673,13 +8617,14 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE |
| 8673 | 8617 | ||
| 8674 | fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { | 8618 | fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 8675 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 8619 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8676 | return t.supportsAnsiEscapeCodes(file); | 8620 | _ = t; |
| 8621 | return supportsAnsiEscapeCodes(file); | ||
| 8677 | } | 8622 | } |
| 8678 | 8623 | ||
| 8679 | fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { | 8624 | fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool { |
| 8680 | if (is_windows) { | 8625 | if (is_windows) { |
| 8681 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; | 8626 | var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; |
| 8682 | switch ((try t.deviceIoControl(&.{ | 8627 | switch ((try deviceIoControl(&.{ |
| 8683 | .file = .{ | 8628 | .file = .{ |
| 8684 | .handle = windows.peb().ProcessParameters.ConsoleHandle, | 8629 | .handle = windows.peb().ProcessParameters.ConsoleHandle, |
| 8685 | .flags = .{ .nonblocking = false }, | 8630 | .flags = .{ .nonblocking = false }, |
| ... | @@ -8701,7 +8646,7 @@ fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { | ... | @@ -8701,7 +8646,7 @@ fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { |
| 8701 | return false; | 8646 | return false; |
| 8702 | } | 8647 | } |
| 8703 | 8648 | ||
| 8704 | if (try t.isTty(file)) return true; | 8649 | if (try isTty(file)) return true; |
| 8705 | 8650 | ||
| 8706 | return false; | 8651 | return false; |
| 8707 | } | 8652 | } |
| ... | @@ -8775,7 +8720,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool { | ... | @@ -8775,7 +8720,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool { |
| 8775 | }, | 8720 | }, |
| 8776 | }; | 8721 | }; |
| 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 | const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength]; | 8724 | const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength]; |
| 8780 | const name_wide = std.mem.bytesAsSlice(u16, name_bytes); | 8725 | const name_wide = std.mem.bytesAsSlice(u16, name_bytes); |
| 8781 | // The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master | 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,49 +8947,38 @@ fn fileSetTimestamps( |
| 9002 | _ = t; | 8947 | _ = t; |
| 9003 | 8948 | ||
| 9004 | if (is_windows) { | 8949 | if (is_windows) { |
| 9005 | var access_time_buffer: windows.FILETIME = undefined; | 8950 | const now_sys = if (options.access_timestamp == .now or options.modify_timestamp == .now) |
| 9006 | var modify_time_buffer: windows.FILETIME = undefined; | 8951 | windows.ntdll.RtlGetSystemTimePrecise() |
| 9007 | var system_time_buffer: windows.LARGE_INTEGER = undefined; | 8952 | else |
| 9008 | 8953 | undefined; | |
| 9009 | if (options.access_timestamp == .now or options.modify_timestamp == .now) { | 8954 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 9010 | system_time_buffer = windows.ntdll.RtlGetSystemTimePrecise(); | 8955 | var info: windows.FILE.BASIC_INFORMATION = .{ |
| 9011 | } | 8956 | .CreationTime = 0, |
| 9012 | 8957 | .LastAccessTime = switch (options.access_timestamp) { | |
| 9013 | const access_ptr = switch (options.access_timestamp) { | 8958 | .unchanged => 0, |
| 9014 | .unchanged => null, | 8959 | .now => now_sys, |
| 9015 | .now => @panic("TODO do SystemTimeToFileTime logic here"), | 8960 | .new => |ts| windows.toSysTime(ts), |
| 9016 | .new => |ts| p: { | 8961 | }, |
| 9017 | access_time_buffer = windows.nanoSecondsToFileTime(ts); | 8962 | .LastWriteTime = switch (options.modify_timestamp) { |
| 9018 | break :p &access_time_buffer; | 8963 | .unchanged => 0, |
| 9019 | }, | 8964 | .now => now_sys, |
| 8965 | .new => |ts| windows.toSysTime(ts), | ||
| 8966 | }, | ||
| 8967 | .ChangeTime = 0, | ||
| 8968 | .FileAttributes = .{}, | ||
| 9020 | }; | 8969 | }; |
| 9021 | 8970 | var syscall: Syscall = try .start(); | |
| 9022 | const modify_ptr = switch (options.modify_timestamp) { | 8971 | while (true) switch (windows.ntdll.NtSetInformationFile( |
| 9023 | .unchanged => null, | 8972 | file.handle, |
| 9024 | .now => @panic("TODO do SystemTimeToFileTime logic here"), | 8973 | &iosb, |
| 9025 | .new => |ts| p: { | 8974 | &info, |
| 9026 | modify_time_buffer = windows.nanoSecondsToFileTime(ts); | 8975 | @sizeOf(windows.FILE.BASIC_INFORMATION), |
| 9027 | break :p &modify_time_buffer; | 8976 | .Basic, |
| 9028 | }, | 8977 | )) { |
| 8978 | .SUCCESS => return syscall.finish(), | ||
| 8979 | .CANCELLED => try syscall.checkCancel(), | ||
| 8980 | else => |status| return syscall.unexpectedNtstatus(status), | ||
| 9029 | }; | 8981 | }; |
| 9030 | |||
| 9031 | // https://github.com/ziglang/zig/issues/1840 | ||
| 9032 | const syscall: Syscall = try .start(); | ||
| 9033 | while (true) { | ||
| 9034 | switch (windows.kernel32.SetFileTime(file.handle, null, access_ptr, modify_ptr)) { | ||
| 9035 | 0 => switch (windows.GetLastError()) { | ||
| 9036 | .OPERATION_ABORTED => { | ||
| 9037 | try syscall.checkCancel(); | ||
| 9038 | continue; | ||
| 9039 | }, | ||
| 9040 | else => |err| { | ||
| 9041 | syscall.finish(); | ||
| 9042 | return windows.unexpectedError(err); | ||
| 9043 | }, | ||
| 9044 | }, | ||
| 9045 | else => return syscall.finish(), | ||
| 9046 | } | ||
| 9047 | } | ||
| 9048 | } | 8982 | } |
| 9049 | 8983 | ||
| 9050 | if (native_os == .wasi and !builtin.link_libc) { | 8984 | if (native_os == .wasi and !builtin.link_libc) { |
| ... | @@ -9636,15 +9570,43 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingErro | ... | @@ -9636,15 +9570,43 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingErro |
| 9636 | } | 9570 | } |
| 9637 | 9571 | ||
| 9638 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize { | 9572 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize { |
| 9573 | var iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 9639 | var index: usize = 0; | 9574 | var index: usize = 0; |
| 9640 | while (data.len - index != 0 and data[index].len == 0) index += 1; | 9575 | while (data.len - index != 0 and data[index].len == 0) index += 1; |
| 9641 | if (data.len - index == 0) return 0; | 9576 | if (data.len - index == 0) return 0; |
| 9642 | const buffer = data[index]; | 9577 | const buffer = data[index]; |
| 9643 | const short_buffer_len = @min(std.math.maxInt(u32), buffer.len); | 9578 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); |
| 9644 | 9579 | if (file.flags.nonblocking) { | |
| 9645 | var iosb: windows.IO_STATUS_BLOCK = undefined; | 9580 | var done: bool = false; |
| 9646 | 9581 | switch (windows.ntdll.NtReadFile( | |
| 9647 | if (!file.flags.nonblocking) { | 9582 | file.handle, |
| 9583 | null, // event | ||
| 9584 | flagApc, | ||
| 9585 | &done, // APC context | ||
| 9586 | &iosb, | ||
| 9587 | buffer.ptr, | ||
| 9588 | short_buffer_len, | ||
| 9589 | null, // byte offset | ||
| 9590 | null, // key | ||
| 9591 | )) { | ||
| 9592 | // We must wait for the APC routine. | ||
| 9593 | .PENDING, .SUCCESS => while (!done) { | ||
| 9594 | // Once we get here we must not return from the function until the | ||
| 9595 | // operation completes, thereby releasing reference to the iosb. | ||
| 9596 | const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { | ||
| 9597 | error.Canceled => |e| { | ||
| 9598 | var cancel_iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 9599 | _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb); | ||
| 9600 | while (!done) waitForApcOrAlert(); | ||
| 9601 | return e; | ||
| 9602 | }, | ||
| 9603 | }; | ||
| 9604 | waitForApcOrAlert(); | ||
| 9605 | alertable_syscall.finish(); | ||
| 9606 | }, | ||
| 9607 | else => |status| iosb.u.Status = status, | ||
| 9608 | } | ||
| 9609 | } else { | ||
| 9648 | const syscall: Syscall = try .start(); | 9610 | const syscall: Syscall = try .start(); |
| 9649 | while (true) switch (windows.ntdll.NtReadFile( | 9611 | while (true) switch (windows.ntdll.NtReadFile( |
| 9650 | file.handle, | 9612 | file.handle, |
| ... | @@ -9665,41 +9627,10 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr | ... | @@ -9665,41 +9627,10 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr |
| 9665 | else => |status| { | 9627 | else => |status| { |
| 9666 | syscall.finish(); | 9628 | syscall.finish(); |
| 9667 | iosb.u.Status = status; | 9629 | iosb.u.Status = status; |
| 9668 | return ntReadFileResult(&iosb); | 9630 | break; |
| 9669 | }, | 9631 | }, |
| 9670 | }; | 9632 | }; |
| 9671 | } | 9633 | } |
| 9672 | |||
| 9673 | var done: bool = false; | ||
| 9674 | |||
| 9675 | switch (windows.ntdll.NtReadFile( | ||
| 9676 | file.handle, | ||
| 9677 | null, // event | ||
| 9678 | flagApc, | ||
| 9679 | &done, // APC context | ||
| 9680 | &iosb, | ||
| 9681 | buffer.ptr, | ||
| 9682 | short_buffer_len, | ||
| 9683 | null, // byte offset | ||
| 9684 | null, // key | ||
| 9685 | )) { | ||
| 9686 | // We must wait for the APC routine. | ||
| 9687 | .PENDING, .SUCCESS => while (!done) { | ||
| 9688 | // Once we get here we must not return from the function until the | ||
| 9689 | // operation completes, thereby releasing reference to io_status_block. | ||
| 9690 | const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { | ||
| 9691 | error.Canceled => |e| { | ||
| 9692 | var cancel_iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 9693 | _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb); | ||
| 9694 | while (!done) waitForApcOrAlert(); | ||
| 9695 | return e; | ||
| 9696 | }, | ||
| 9697 | }; | ||
| 9698 | waitForApcOrAlert(); | ||
| 9699 | alertable_syscall.finish(); | ||
| 9700 | }, | ||
| 9701 | else => |status| iosb.u.Status = status, | ||
| 9702 | } | ||
| 9703 | return ntReadFileResult(&iosb); | 9634 | return ntReadFileResult(&iosb); |
| 9704 | } | 9635 | } |
| 9705 | 9636 | ||
| ... | @@ -9714,8 +9645,9 @@ fn ntReadFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { | ... | @@ -9714,8 +9645,9 @@ fn ntReadFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { |
| 9714 | .CANCELLED => unreachable, | 9645 | .CANCELLED => unreachable, |
| 9715 | .SUCCESS => return io_status_block.Information, | 9646 | .SUCCESS => return io_status_block.Information, |
| 9716 | .END_OF_FILE, .PIPE_BROKEN => return error.EndOfStream, | 9647 | .END_OF_FILE, .PIPE_BROKEN => return error.EndOfStream, |
| 9648 | .INVALID_HANDLE => return error.NotOpenForReading, | ||
| 9717 | .INVALID_DEVICE_REQUEST => return error.IsDir, | 9649 | .INVALID_DEVICE_REQUEST => return error.IsDir, |
| 9718 | .LOCK_NOT_GRANTED => return error.LockViolation, | 9650 | .FILE_LOCK_CONFLICT => return error.LockViolation, |
| 9719 | .ACCESS_DENIED => return error.AccessDenied, | 9651 | .ACCESS_DENIED => return error.AccessDenied, |
| 9720 | else => |status| return windows.unexpectedStatus(status), | 9652 | else => |status| return windows.unexpectedStatus(status), |
| 9721 | } | 9653 | } |
| ... | @@ -9731,7 +9663,7 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { | ... | @@ -9731,7 +9663,7 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { |
| 9731 | .QUOTA_EXCEEDED => return error.SystemResources, | 9663 | .QUOTA_EXCEEDED => return error.SystemResources, |
| 9732 | .PIPE_BROKEN => return error.BrokenPipe, | 9664 | .PIPE_BROKEN => return error.BrokenPipe, |
| 9733 | .INVALID_HANDLE => return error.NotOpenForWriting, | 9665 | .INVALID_HANDLE => return error.NotOpenForWriting, |
| 9734 | .LOCK_NOT_GRANTED => return error.LockViolation, | 9666 | .FILE_LOCK_CONFLICT => return error.LockViolation, |
| 9735 | .ACCESS_DENIED => return error.AccessDenied, | 9667 | .ACCESS_DENIED => return error.AccessDenied, |
| 9736 | .WORKING_SET_QUOTA => return error.SystemResources, | 9668 | .WORKING_SET_QUOTA => return error.SystemResources, |
| 9737 | .DISK_FULL => return error.NoSpaceLeft, | 9669 | .DISK_FULL => return error.NoSpaceLeft, |
| ... | @@ -9740,8 +9672,6 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { | ... | @@ -9740,8 +9672,6 @@ fn ntWriteFileResult(io_status_block: *const windows.IO_STATUS_BLOCK) !usize { |
| 9740 | } | 9672 | } |
| 9741 | 9673 | ||
| 9742 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { | 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 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; | 9675 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| 9746 | var i: usize = 0; | 9676 | var i: usize = 0; |
| 9747 | for (data) |buf| { | 9677 | for (data) |buf| { |
| ... | @@ -9787,9 +9717,44 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea | ... | @@ -9787,9 +9717,44 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea |
| 9787 | } | 9717 | } |
| 9788 | } | 9718 | } |
| 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 | const syscall: Syscall = try .start(); | 9755 | const syscall: Syscall = try .start(); |
| 9791 | while (true) { | 9756 | while (true) { |
| 9792 | const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset)); | 9757 | const rc = posix.pread(file.handle, dest[0].ptr, @intCast(dest[0].len), @bitCast(offset)); |
| 9793 | switch (posix.errno(rc)) { | 9758 | switch (posix.errno(rc)) { |
| 9794 | .SUCCESS => { | 9759 | .SUCCESS => { |
| 9795 | syscall.finish(); | 9760 | syscall.finish(); |
| ... | @@ -9838,65 +9803,119 @@ fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.R | ... | @@ -9838,65 +9803,119 @@ fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.R |
| 9838 | } | 9803 | } |
| 9839 | 9804 | ||
| 9840 | fn readFilePositionalWindows(file: File, buffer: []u8, offset: u64) File.ReadPositionalError!usize { | 9805 | fn readFilePositionalWindows(file: File, buffer: []u8, offset: u64) File.ReadPositionalError!usize { |
| 9841 | const DWORD = windows.DWORD; | 9806 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 9842 | const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len); | 9807 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); |
| 9843 | var overlapped: windows.OVERLAPPED = .{ | 9808 | const signed_offset: windows.LARGE_INTEGER = @intCast(offset); |
| 9844 | .Internal = 0, | 9809 | if (file.flags.nonblocking) { |
| 9845 | .InternalHigh = 0, | 9810 | var done: bool = false; |
| 9846 | .DUMMYUNIONNAME = .{ | 9811 | switch (windows.ntdll.NtReadFile( |
| 9847 | .DUMMYSTRUCTNAME = .{ | 9812 | file.handle, |
| 9848 | .Offset = @truncate(offset), | 9813 | null, // event |
| 9849 | .OffsetHigh = @truncate(offset >> 32), | 9814 | flagApc, |
| 9815 | &done, // APC context | ||
| 9816 | &iosb, | ||
| 9817 | buffer.ptr, | ||
| 9818 | short_buffer_len, | ||
| 9819 | &signed_offset, | ||
| 9820 | null, // key | ||
| 9821 | )) { | ||
| 9822 | // We must wait for the APC routine. | ||
| 9823 | .PENDING, .SUCCESS => while (!done) { | ||
| 9824 | // Once we get here we must not return from the function until the | ||
| 9825 | // operation completes, thereby releasing reference to the iosb. | ||
| 9826 | const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { | ||
| 9827 | error.Canceled => |e| { | ||
| 9828 | var cancel_iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 9829 | _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb); | ||
| 9830 | while (!done) waitForApcOrAlert(); | ||
| 9831 | return e; | ||
| 9832 | }, | ||
| 9833 | }; | ||
| 9834 | waitForApcOrAlert(); | ||
| 9835 | alertable_syscall.finish(); | ||
| 9850 | }, | 9836 | }, |
| 9851 | }, | 9837 | else => |status| iosb.u.Status = status, |
| 9852 | .hEvent = null, | ||
| 9853 | }; | ||
| 9854 | |||
| 9855 | const syscall: Syscall = try .start(); | ||
| 9856 | while (true) { | ||
| 9857 | var n: DWORD = undefined; | ||
| 9858 | if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0) { | ||
| 9859 | syscall.finish(); | ||
| 9860 | return n; | ||
| 9861 | } | 9838 | } |
| 9862 | switch (windows.GetLastError()) { | 9839 | } else { |
| 9863 | .IO_PENDING => |err| { | 9840 | const syscall: Syscall = try .start(); |
| 9864 | syscall.finish(); | 9841 | while (true) switch (windows.ntdll.NtReadFile( |
| 9865 | return windows.errorBug(err); | 9842 | file.handle, |
| 9866 | }, | 9843 | null, // event |
| 9867 | .OPERATION_ABORTED => { | 9844 | null, // APC routine |
| 9868 | try syscall.checkCancel(); | 9845 | null, // APC context |
| 9869 | continue; | 9846 | &iosb, |
| 9870 | }, | 9847 | buffer.ptr, |
| 9871 | .BROKEN_PIPE, .HANDLE_EOF => { | 9848 | short_buffer_len, |
| 9872 | syscall.finish(); | 9849 | &signed_offset, |
| 9873 | return 0; | 9850 | null, // key |
| 9874 | }, | 9851 | )) { |
| 9875 | .NETNAME_DELETED => if (is_debug) unreachable else return error.Unexpected, | 9852 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag |
| 9876 | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), | 9853 | .CANCELLED => try syscall.checkCancel(), |
| 9877 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | 9854 | else => |status| { |
| 9878 | .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, | ||
| 9879 | // TODO: Determine if INVALID_FUNCTION is possible in more scenarios than just passing | ||
| 9880 | // a handle to a directory. | ||
| 9881 | .INVALID_FUNCTION => return syscall.fail(error.IsDir), | ||
| 9882 | else => |err| { | ||
| 9883 | syscall.finish(); | 9855 | syscall.finish(); |
| 9884 | return windows.unexpectedError(err); | 9856 | iosb.u.Status = status; |
| 9857 | break; | ||
| 9885 | }, | 9858 | }, |
| 9886 | } | 9859 | }; |
| 9887 | } | 9860 | } |
| 9861 | return ntReadFileResult(&iosb) catch |err| switch (err) { | ||
| 9862 | error.EndOfStream => 0, | ||
| 9863 | else => |e| e, | ||
| 9864 | }; | ||
| 9888 | } | 9865 | } |
| 9889 | 9866 | ||
| 9890 | fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!void { | 9867 | fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!void { |
| 9891 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 9868 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 9892 | _ = t; | 9869 | _ = t; |
| 9893 | const fd = file.handle; | ||
| 9894 | 9870 | ||
| 9895 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | 9871 | if (is_windows) { |
| 9896 | var result: u64 = undefined; | 9872 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 9873 | var info: windows.FILE.POSITION_INFORMATION = undefined; | ||
| 9874 | const syscall: Syscall = try .start(); | ||
| 9875 | while (true) switch (windows.ntdll.NtQueryInformationFile( | ||
| 9876 | file.handle, | ||
| 9877 | &iosb, | ||
| 9878 | &info, | ||
| 9879 | @sizeOf(windows.FILE.POSITION_INFORMATION), | ||
| 9880 | .Position, | ||
| 9881 | )) { | ||
| 9882 | .SUCCESS => break, | ||
| 9883 | .CANCELLED => try syscall.checkCancel(), | ||
| 9884 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | ||
| 9885 | .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable), | ||
| 9886 | else => |status| return syscall.unexpectedNtstatus(status), | ||
| 9887 | }; | ||
| 9888 | info.CurrentByteOffset = @bitCast((if (offset >= 0) std.math.add( | ||
| 9889 | u64, | ||
| 9890 | @bitCast(info.CurrentByteOffset), | ||
| 9891 | @intCast(offset), | ||
| 9892 | ) else std.math.sub( | ||
| 9893 | u64, | ||
| 9894 | @bitCast(info.CurrentByteOffset), | ||
| 9895 | @intCast(-offset), | ||
| 9896 | )) catch |err| switch (err) { | ||
| 9897 | error.Overflow => return syscall.fail(error.Unseekable), | ||
| 9898 | }); | ||
| 9899 | while (true) switch (windows.ntdll.NtSetInformationFile( | ||
| 9900 | file.handle, | ||
| 9901 | &iosb, | ||
| 9902 | &info, | ||
| 9903 | @sizeOf(windows.FILE.POSITION_INFORMATION), | ||
| 9904 | .Position, | ||
| 9905 | )) { | ||
| 9906 | .SUCCESS => return syscall.finish(), | ||
| 9907 | .CANCELLED => try syscall.checkCancel(), | ||
| 9908 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | ||
| 9909 | .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable), | ||
| 9910 | else => |status| return syscall.unexpectedNtstatus(status), | ||
| 9911 | }; | ||
| 9912 | } | ||
| 9913 | |||
| 9914 | if (native_os == .wasi and !builtin.link_libc) { | ||
| 9915 | var new_offset: std.os.wasi.filesize_t = undefined; | ||
| 9897 | const syscall: Syscall = try .start(); | 9916 | const syscall: Syscall = try .start(); |
| 9898 | while (true) { | 9917 | while (true) { |
| 9899 | switch (posix.errno(posix.system.llseek(fd, @bitCast(offset), &result, posix.SEEK.CUR))) { | 9918 | switch (std.os.wasi.fd_seek(file.handle, offset, .CUR, &new_offset)) { |
| 9900 | .SUCCESS => { | 9919 | .SUCCESS => { |
| 9901 | syscall.finish(); | 9920 | syscall.finish(); |
| 9902 | return; | 9921 | return; |
| ... | @@ -9913,6 +9932,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -9913,6 +9932,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9913 | .OVERFLOW => return error.Unseekable, | 9932 | .OVERFLOW => return error.Unseekable, |
| 9914 | .SPIPE => return error.Unseekable, | 9933 | .SPIPE => return error.Unseekable, |
| 9915 | .NXIO => return error.Unseekable, | 9934 | .NXIO => return error.Unseekable, |
| 9935 | .NOTCAPABLE => return error.AccessDenied, | ||
| 9916 | else => |err| return posix.unexpectedErrno(err), | 9936 | else => |err| return posix.unexpectedErrno(err), |
| 9917 | } | 9937 | } |
| 9918 | }, | 9938 | }, |
| ... | @@ -9920,34 +9940,13 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -9920,34 +9940,13 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9920 | } | 9940 | } |
| 9921 | } | 9941 | } |
| 9922 | 9942 | ||
| 9923 | if (is_windows) { | 9943 | if (posix.SEEK == void) return error.Unseekable; |
| 9924 | const syscall: Syscall = try .start(); | ||
| 9925 | while (true) { | ||
| 9926 | if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) { | ||
| 9927 | return syscall.finish(); | ||
| 9928 | } | ||
| 9929 | switch (windows.GetLastError()) { | ||
| 9930 | .OPERATION_ABORTED => { | ||
| 9931 | try syscall.checkCancel(); | ||
| 9932 | continue; | ||
| 9933 | }, | ||
| 9934 | .INVALID_FUNCTION => return syscall.fail(error.Unseekable), | ||
| 9935 | .NEGATIVE_SEEK => return syscall.fail(error.Unseekable), | ||
| 9936 | .INVALID_PARAMETER => unreachable, | ||
| 9937 | .INVALID_HANDLE => unreachable, | ||
| 9938 | else => |err| { | ||
| 9939 | syscall.finish(); | ||
| 9940 | return windows.unexpectedError(err); | ||
| 9941 | }, | ||
| 9942 | } | ||
| 9943 | } | ||
| 9944 | } | ||
| 9945 | 9944 | ||
| 9946 | if (native_os == .wasi and !builtin.link_libc) { | 9945 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { |
| 9947 | var new_offset: std.os.wasi.filesize_t = undefined; | 9946 | var result: u64 = undefined; |
| 9948 | const syscall: Syscall = try .start(); | 9947 | const syscall: Syscall = try .start(); |
| 9949 | while (true) { | 9948 | while (true) { |
| 9950 | switch (std.os.wasi.fd_seek(fd, offset, .CUR, &new_offset)) { | 9949 | switch (posix.errno(posix.system.llseek(file.handle, @bitCast(offset), &result, posix.SEEK.CUR))) { |
| 9951 | .SUCCESS => { | 9950 | .SUCCESS => { |
| 9952 | syscall.finish(); | 9951 | syscall.finish(); |
| 9953 | return; | 9952 | return; |
| ... | @@ -9964,7 +9963,6 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -9964,7 +9963,6 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9964 | .OVERFLOW => return error.Unseekable, | 9963 | .OVERFLOW => return error.Unseekable, |
| 9965 | .SPIPE => return error.Unseekable, | 9964 | .SPIPE => return error.Unseekable, |
| 9966 | .NXIO => return error.Unseekable, | 9965 | .NXIO => return error.Unseekable, |
| 9967 | .NOTCAPABLE => return error.AccessDenied, | ||
| 9968 | else => |err| return posix.unexpectedErrno(err), | 9966 | else => |err| return posix.unexpectedErrno(err), |
| 9969 | } | 9967 | } |
| 9970 | }, | 9968 | }, |
| ... | @@ -9972,11 +9970,9 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -9972,11 +9970,9 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 9972 | } | 9970 | } |
| 9973 | } | 9971 | } |
| 9974 | 9972 | ||
| 9975 | if (posix.SEEK == void) return error.Unseekable; | ||
| 9976 | |||
| 9977 | const syscall: Syscall = try .start(); | 9973 | const syscall: Syscall = try .start(); |
| 9978 | while (true) { | 9974 | while (true) { |
| 9979 | switch (posix.errno(lseek_sym(fd, offset, posix.SEEK.CUR))) { | 9975 | switch (posix.errno(lseek_sym(file.handle, offset, posix.SEEK.CUR))) { |
| 9980 | .SUCCESS => { | 9976 | .SUCCESS => { |
| 9981 | syscall.finish(); | 9977 | syscall.finish(); |
| 9982 | return; | 9978 | return; |
| ... | @@ -10003,41 +9999,31 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -10003,41 +9999,31 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 10003 | fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!void { | 9999 | fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!void { |
| 10004 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 10000 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 10005 | _ = t; | 10001 | _ = t; |
| 10006 | const fd = file.handle; | ||
| 10007 | 10002 | ||
| 10008 | if (is_windows) { | 10003 | if (is_windows) { |
| 10009 | // "The starting point is zero or the beginning of the file. If [FILE_BEGIN] | 10004 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 10010 | // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value." | 10005 | var info: windows.FILE.POSITION_INFORMATION = .{ .CurrentByteOffset = @bitCast(offset) }; |
| 10011 | // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex | ||
| 10012 | const ipos: windows.LARGE_INTEGER = @bitCast(offset); | ||
| 10013 | |||
| 10014 | const syscall: Syscall = try .start(); | 10006 | const syscall: Syscall = try .start(); |
| 10015 | while (true) { | 10007 | while (true) switch (windows.ntdll.NtSetInformationFile( |
| 10016 | if (windows.kernel32.SetFilePointerEx(fd, ipos, null, windows.FILE_BEGIN) != 0) { | 10008 | file.handle, |
| 10017 | return syscall.finish(); | 10009 | &iosb, |
| 10018 | } | 10010 | &info, |
| 10019 | switch (windows.GetLastError()) { | 10011 | @sizeOf(windows.FILE.POSITION_INFORMATION), |
| 10020 | .OPERATION_ABORTED => { | 10012 | .Position, |
| 10021 | try syscall.checkCancel(); | 10013 | )) { |
| 10022 | continue; | 10014 | .SUCCESS => return syscall.finish(), |
| 10023 | }, | 10015 | .CANCELLED => try syscall.checkCancel(), |
| 10024 | .INVALID_FUNCTION => return syscall.fail(error.Unseekable), | 10016 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 10025 | .NEGATIVE_SEEK => return syscall.fail(error.Unseekable), | 10017 | .PIPE_NOT_AVAILABLE => return syscall.fail(error.Unseekable), |
| 10026 | .INVALID_PARAMETER => unreachable, | 10018 | else => |status| return syscall.unexpectedNtstatus(status), |
| 10027 | .INVALID_HANDLE => unreachable, | 10019 | }; |
| 10028 | else => |err| { | ||
| 10029 | syscall.finish(); | ||
| 10030 | return windows.unexpectedError(err); | ||
| 10031 | }, | ||
| 10032 | } | ||
| 10033 | } | ||
| 10034 | } | 10020 | } |
| 10035 | 10021 | ||
| 10036 | if (native_os == .wasi and !builtin.link_libc) { | 10022 | if (native_os == .wasi and !builtin.link_libc) { |
| 10037 | const syscall: Syscall = try .start(); | 10023 | const syscall: Syscall = try .start(); |
| 10038 | while (true) { | 10024 | while (true) { |
| 10039 | var new_offset: std.os.wasi.filesize_t = undefined; | 10025 | var new_offset: std.os.wasi.filesize_t = undefined; |
| 10040 | switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) { | 10026 | switch (std.os.wasi.fd_seek(file.handle, @bitCast(offset), .SET, &new_offset)) { |
| 10041 | .SUCCESS => { | 10027 | .SUCCESS => { |
| 10042 | syscall.finish(); | 10028 | syscall.finish(); |
| 10043 | return; | 10029 | return; |
| ... | @@ -10064,7 +10050,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi | ... | @@ -10064,7 +10050,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 10064 | 10050 | ||
| 10065 | if (posix.SEEK == void) return error.Unseekable; | 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 | fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void { | 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,8 +10117,7 @@ fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.O |
| 10131 | // If ImagePathName is a symlink, then it will contain the path of the symlink, | 10117 | // If ImagePathName is a symlink, then it will contain the path of the symlink, |
| 10132 | // not the path that the symlink points to. However, because we are opening | 10118 | // not the path that the symlink points to. However, because we are opening |
| 10133 | // the file, we can let the openFileW call follow the symlink for us. | 10119 | // the file, we can let the openFileW call follow the symlink for us. |
| 10134 | const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName; | 10120 | const image_path_name = windows.peb().ProcessParameters.ImagePathName.sliceZ(); |
| 10135 | const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0]; | ||
| 10136 | const prefixed_path_w = try wToPrefixedFileW(null, image_path_name); | 10121 | const prefixed_path_w = try wToPrefixedFileW(null, image_path_name); |
| 10137 | return dirOpenFileWtf16(null, prefixed_path_w.span(), flags); | 10122 | return dirOpenFileWtf16(null, prefixed_path_w.span(), flags); |
| 10138 | }, | 10123 | }, |
| ... | @@ -10334,14 +10319,13 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut | ... | @@ -10334,14 +10319,13 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut |
| 10334 | return error.FileNotFound; | 10319 | return error.FileNotFound; |
| 10335 | }, | 10320 | }, |
| 10336 | .windows => { | 10321 | .windows => { |
| 10337 | const w = windows; | ||
| 10338 | const image_path_unicode_string = &w.peb().ProcessParameters.ImagePathName; | ||
| 10339 | const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0]; | ||
| 10340 | |||
| 10341 | // If ImagePathName is a symlink, then it will contain the path of the | 10322 | // If ImagePathName is a symlink, then it will contain the path of the |
| 10342 | // symlink, not the path that the symlink points to. We want the path | 10323 | // symlink, not the path that the symlink points to. We want the path |
| 10343 | // that the symlink points to, though, so we need to get the realpath. | 10324 | // that the symlink points to, though, so we need to get the realpath. |
| 10344 | var path_name_w_buf = try wToPrefixedFileW(null, image_path_name); | 10325 | var path_name_w_buf = try wToPrefixedFileW( |
| 10326 | null, | ||
| 10327 | windows.peb().ProcessParameters.ImagePathName.sliceZ(), | ||
| 10328 | ); | ||
| 10345 | 10329 | ||
| 10346 | const h_file = handle: { | 10330 | const h_file = handle: { |
| 10347 | if (OpenFile(path_name_w_buf.span(), .{ | 10331 | if (OpenFile(path_name_w_buf.span(), .{ |
| ... | @@ -10360,7 +10344,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut | ... | @@ -10360,7 +10344,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut |
| 10360 | else => |e| return e, | 10344 | else => |e| return e, |
| 10361 | } | 10345 | } |
| 10362 | }; | 10346 | }; |
| 10363 | defer w.CloseHandle(h_file); | 10347 | defer windows.CloseHandle(h_file); |
| 10364 | 10348 | ||
| 10365 | const wide_slice = try GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data); | 10349 | const wide_slice = try GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data); |
| 10366 | 10350 | ||
| ... | @@ -10388,15 +10372,15 @@ fn fileWritePositional( | ... | @@ -10388,15 +10372,15 @@ fn fileWritePositional( |
| 10388 | 10372 | ||
| 10389 | if (is_windows) { | 10373 | if (is_windows) { |
| 10390 | if (header.len != 0) { | 10374 | if (header.len != 0) { |
| 10391 | return writeFilePositionalWindows(file.handle, header, offset); | 10375 | return writeFilePositionalWindows(file, header, offset); |
| 10392 | } | 10376 | } |
| 10393 | for (data[0 .. data.len - 1]) |buf| { | 10377 | for (data[0 .. data.len - 1]) |buf| { |
| 10394 | if (buf.len == 0) continue; | 10378 | if (buf.len == 0) continue; |
| 10395 | return writeFilePositionalWindows(file.handle, buf, offset); | 10379 | return writeFilePositionalWindows(file, buf, offset); |
| 10396 | } | 10380 | } |
| 10397 | const pattern = data[data.len - 1]; | 10381 | const pattern = data[data.len - 1]; |
| 10398 | if (pattern.len == 0 or splat == 0) return 0; | 10382 | if (pattern.len == 0 or splat == 0) return 0; |
| 10399 | return writeFilePositionalWindows(file.handle, pattern, offset); | 10383 | return writeFilePositionalWindows(file, pattern, offset); |
| 10400 | } | 10384 | } |
| 10401 | 10385 | ||
| 10402 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; | 10386 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| ... | @@ -10505,50 +10489,64 @@ fn fileWritePositional( | ... | @@ -10505,50 +10489,64 @@ fn fileWritePositional( |
| 10505 | } | 10489 | } |
| 10506 | } | 10490 | } |
| 10507 | 10491 | ||
| 10508 | fn writeFilePositionalWindows( | 10492 | fn writeFilePositionalWindows(file: File, buffer: []const u8, offset: u64) File.WritePositionalError!usize { |
| 10509 | handle: windows.HANDLE, | 10493 | assert(buffer.len != 0); |
| 10510 | bytes: []const u8, | 10494 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 10511 | offset: u64, | 10495 | const short_buffer_len = std.math.lossyCast(u32, buffer.len); |
| 10512 | ) File.WritePositionalError!usize { | 10496 | const signed_offset: windows.LARGE_INTEGER = @intCast(offset); |
| 10513 | var bytes_written: windows.DWORD = undefined; | 10497 | if (file.flags.nonblocking) { |
| 10514 | var overlapped: windows.OVERLAPPED = .{ | 10498 | var done: bool = false; |
| 10515 | .Internal = 0, | 10499 | switch (windows.ntdll.NtWriteFile( |
| 10516 | .InternalHigh = 0, | 10500 | file.handle, |
| 10517 | .DUMMYUNIONNAME = .{ | 10501 | null, // event |
| 10518 | .DUMMYSTRUCTNAME = .{ | 10502 | flagApc, |
| 10519 | .Offset = @truncate(offset), | 10503 | &done, // APC context |
| 10520 | .OffsetHigh = @truncate(offset >> 32), | 10504 | &iosb, |
| 10505 | buffer.ptr, | ||
| 10506 | short_buffer_len, | ||
| 10507 | &signed_offset, | ||
| 10508 | null, // key | ||
| 10509 | )) { | ||
| 10510 | // We must wait for the APC routine. | ||
| 10511 | .PENDING, .SUCCESS => while (!done) { | ||
| 10512 | // Once we get here we must not return from the function until the | ||
| 10513 | // operation completes, thereby releasing reference to the iosb. | ||
| 10514 | const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { | ||
| 10515 | error.Canceled => |e| { | ||
| 10516 | var cancel_iosb: windows.IO_STATUS_BLOCK = undefined; | ||
| 10517 | _ = windows.ntdll.NtCancelIoFileEx(file.handle, &iosb, &cancel_iosb); | ||
| 10518 | while (!done) waitForApcOrAlert(); | ||
| 10519 | return e; | ||
| 10520 | }, | ||
| 10521 | }; | ||
| 10522 | waitForApcOrAlert(); | ||
| 10523 | alertable_syscall.finish(); | ||
| 10521 | }, | 10524 | }, |
| 10522 | }, | 10525 | else => |status| iosb.u.Status = status, |
| 10523 | .hEvent = null, | ||
| 10524 | }; | ||
| 10525 | const adjusted_len = std.math.lossyCast(u32, bytes.len); | ||
| 10526 | const syscall: Syscall = try .start(); | ||
| 10527 | while (true) { | ||
| 10528 | if (windows.kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, &overlapped) != 0) { | ||
| 10529 | syscall.finish(); | ||
| 10530 | return bytes_written; | ||
| 10531 | } | 10526 | } |
| 10532 | switch (windows.GetLastError()) { | 10527 | } else { |
| 10533 | .OPERATION_ABORTED => { | 10528 | const syscall: Syscall = try .start(); |
| 10534 | try syscall.checkCancel(); | 10529 | while (true) switch (windows.ntdll.NtWriteFile( |
| 10535 | continue; | 10530 | file.handle, |
| 10536 | }, | 10531 | null, // event |
| 10537 | .INVALID_USER_BUFFER => return syscall.fail(error.SystemResources), | 10532 | null, // APC routine |
| 10538 | .NOT_ENOUGH_MEMORY => return syscall.fail(error.SystemResources), | 10533 | null, // APC context |
| 10539 | .NOT_ENOUGH_QUOTA => return syscall.fail(error.SystemResources), | 10534 | &iosb, |
| 10540 | .NO_DATA => return syscall.fail(error.BrokenPipe), | 10535 | buffer.ptr, |
| 10541 | .INVALID_HANDLE => if (is_debug) unreachable else return error.Unexpected, // use after free | 10536 | short_buffer_len, |
| 10542 | .LOCK_VIOLATION => return syscall.fail(error.LockViolation), | 10537 | &signed_offset, |
| 10543 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | 10538 | null, // key |
| 10544 | .WORKING_SET_QUOTA => return syscall.fail(error.SystemResources), | 10539 | )) { |
| 10545 | .DISK_FULL => return syscall.fail(error.NoSpaceLeft), | 10540 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag |
| 10546 | else => |err| { | 10541 | .CANCELLED => try syscall.checkCancel(), |
| 10542 | else => |status| { | ||
| 10547 | syscall.finish(); | 10543 | syscall.finish(); |
| 10548 | return windows.unexpectedError(err); | 10544 | iosb.u.Status = status; |
| 10545 | return ntWriteFileResult(&iosb); | ||
| 10549 | }, | 10546 | }, |
| 10550 | } | 10547 | }; |
| 10551 | } | 10548 | } |
| 10549 | return ntWriteFileResult(&iosb); | ||
| 10552 | } | 10550 | } |
| 10553 | 10551 | ||
| 10554 | fn fileWriteStreaming( | 10552 | fn fileWriteStreaming( |
| ... | @@ -10673,9 +10671,7 @@ fn fileWriteStreaming( | ... | @@ -10673,9 +10671,7 @@ fn fileWriteStreaming( |
| 10673 | 10671 | ||
| 10674 | fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!usize { | 10672 | fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!usize { |
| 10675 | assert(buffer.len != 0); | 10673 | assert(buffer.len != 0); |
| 10676 | |||
| 10677 | var iosb: windows.IO_STATUS_BLOCK = undefined; | 10674 | var iosb: windows.IO_STATUS_BLOCK = undefined; |
| 10678 | |||
| 10679 | if (file.flags.nonblocking) { | 10675 | if (file.flags.nonblocking) { |
| 10680 | var done: bool = false; | 10676 | var done: bool = false; |
| 10681 | switch (windows.ntdll.NtWriteFile( | 10677 | switch (windows.ntdll.NtWriteFile( |
| ... | @@ -10706,7 +10702,6 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u | ... | @@ -10706,7 +10702,6 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u |
| 10706 | }, | 10702 | }, |
| 10707 | else => |status| iosb.u.Status = status, | 10703 | else => |status| iosb.u.Status = status, |
| 10708 | } | 10704 | } |
| 10709 | return ntWriteFileResult(&iosb); | ||
| 10710 | } else { | 10705 | } else { |
| 10711 | const syscall: Syscall = try .start(); | 10706 | const syscall: Syscall = try .start(); |
| 10712 | while (true) switch (windows.ntdll.NtWriteFile( | 10707 | while (true) switch (windows.ntdll.NtWriteFile( |
| ... | @@ -10721,17 +10716,15 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u | ... | @@ -10721,17 +10716,15 @@ fn fileWriteStreamingWindows(file: File, buffer: []const u8) File.Writer.Error!u |
| 10721 | null, // key | 10716 | null, // key |
| 10722 | )) { | 10717 | )) { |
| 10723 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag | 10718 | .PENDING => unreachable, // unrecoverable: wrong File nonblocking flag |
| 10724 | .CANCELLED => { | 10719 | .CANCELLED => try syscall.checkCancel(), |
| 10725 | try syscall.checkCancel(); | ||
| 10726 | continue; | ||
| 10727 | }, | ||
| 10728 | else => |status| { | 10720 | else => |status| { |
| 10729 | syscall.finish(); | 10721 | syscall.finish(); |
| 10730 | iosb.u.Status = status; | 10722 | iosb.u.Status = status; |
| 10731 | return ntWriteFileResult(&iosb); | 10723 | break; |
| 10732 | }, | 10724 | }, |
| 10733 | }; | 10725 | }; |
| 10734 | } | 10726 | } |
| 10727 | return ntWriteFileResult(&iosb); | ||
| 10735 | } | 10728 | } |
| 10736 | 10729 | ||
| 10737 | fn fileWriteFileStreaming( | 10730 | fn fileWriteFileStreaming( |
| ... | @@ -11433,13 +11426,22 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { | ... | @@ -11433,13 +11426,22 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11433 | return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 + epoch_ns }; | 11426 | return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 + epoch_ns }; |
| 11434 | }, | 11427 | }, |
| 11435 | .awake, .boot => { | 11428 | .awake, .boot => { |
| 11436 | // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. | ||
| 11437 | const qpc = windows.QueryPerformanceCounter(); | ||
| 11438 | // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA | 11429 | // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA |
| 11439 | // (a read-only page of info updated and mapped by the kernel to all processes): | 11430 | // (a read-only page of info updated and mapped by the kernel to all processes): |
| 11440 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data | 11431 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data |
| 11441 | // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm | 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 | // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. | 11446 | // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. |
| 11445 | // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 | 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,7 +11460,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11458 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L442-L485 | 11460 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L442-L485 |
| 11459 | if (windows.ntdll.NtQueryInformationProcess( | 11461 | if (windows.ntdll.NtQueryInformationProcess( |
| 11460 | handle, | 11462 | handle, |
| 11461 | windows.PROCESSINFOCLASS.Times, | 11463 | .Times, |
| 11462 | &times, | 11464 | &times, |
| 11463 | @sizeOf(windows.KERNEL_USER_TIMES), | 11465 | @sizeOf(windows.KERNEL_USER_TIMES), |
| 11464 | null, | 11466 | null, |
| ... | @@ -11474,7 +11476,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { | ... | @@ -11474,7 +11476,7 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp { |
| 11474 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L2971-L3019 | 11476 | // https://github.com/reactos/reactos/blob/master/ntoskrnl/ps/query.c#L2971-L3019 |
| 11475 | if (windows.ntdll.NtQueryInformationThread( | 11477 | if (windows.ntdll.NtQueryInformationThread( |
| 11476 | handle, | 11478 | handle, |
| 11477 | windows.THREADINFOCLASS.Times, | 11479 | .Times, |
| 11478 | &times, | 11480 | &times, |
| 11479 | @sizeOf(windows.KERNEL_USER_TIMES), | 11481 | @sizeOf(windows.KERNEL_USER_TIMES), |
| 11480 | null, | 11482 | null, |
| ... | @@ -14132,21 +14134,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr | ... | @@ -14132,21 +14134,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr |
| 14132 | } | 14134 | } |
| 14133 | 14135 | ||
| 14134 | fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirError!void { | 14136 | fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirError!void { |
| 14135 | if (native_os == .wasi) return error.OperationUnsupported; | ||
| 14136 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 14137 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 14137 | _ = t; | 14138 | _ = t; |
| 14138 | 14139 | ||
| 14140 | if (native_os == .wasi) return error.OperationUnsupported; | ||
| 14141 | |||
| 14139 | if (is_windows) { | 14142 | if (is_windows) { |
| 14140 | var dir_path_buffer: [windows.PATH_MAX_WIDE]u16 = undefined; | 14143 | var dir_path_buf: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 14141 | const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buffer); | 14144 | const dir_path = try GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buf); |
| 14142 | const path_len_bytes = std.math.cast(u16, dir_path.len * 2) orelse return error.NameTooLong; | ||
| 14143 | var nt_name: windows.UNICODE_STRING = .{ | ||
| 14144 | .Length = path_len_bytes, | ||
| 14145 | .MaximumLength = path_len_bytes, | ||
| 14146 | .Buffer = @constCast(dir_path.ptr), | ||
| 14147 | }; | ||
| 14148 | const syscall: Syscall = try .start(); | 14145 | const syscall: Syscall = try .start(); |
| 14149 | while (true) switch (windows.ntdll.RtlSetCurrentDirectory_U(&nt_name)) { | 14146 | while (true) switch (windows.ntdll.RtlSetCurrentDirectory_U(&.init(dir_path))) { |
| 14150 | .SUCCESS => return syscall.finish(), | 14147 | .SUCCESS => return syscall.finish(), |
| 14151 | .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName), | 14148 | .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName), |
| 14152 | .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound), | 14149 | .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound), |
| ... | @@ -15465,26 +15462,27 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { | ... | @@ -15465,26 +15462,27 @@ fn childKill(userdata: ?*anyopaque, child: *process.Child) void { |
| 15465 | fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT) !void { | 15462 | fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT) !void { |
| 15466 | _ = t; // TODO cancelation | 15463 | _ = t; // TODO cancelation |
| 15467 | const handle = child.id.?; | 15464 | const handle = child.id.?; |
| 15468 | if (windows.kernel32.TerminateProcess(handle, exit_code) == 0) { | 15465 | _ = windows.ntdll.RtlReportSilentProcessExit(handle, @enumFromInt(exit_code)); |
| 15469 | switch (windows.GetLastError()) { | 15466 | switch (windows.ntdll.NtTerminateProcess(handle, @enumFromInt(exit_code))) { |
| 15470 | .ACCESS_DENIED => { | 15467 | .SUCCESS => { |
| 15471 | // Usually when TerminateProcess triggers a ACCESS_DENIED error, it | 15468 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); |
| 15472 | // indicates that the process has already exited, but there may be | 15469 | _ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout); |
| 15473 | // some rare edge cases where our process handle no longer has the | 15470 | childCleanupWindows(child); |
| 15474 | // PROCESS_TERMINATE access right, so let's do another check to make | 15471 | }, |
| 15475 | // sure the process is really no longer running: | 15472 | .ACCESS_DENIED => { |
| 15476 | const minimal_timeout: windows.LARGE_INTEGER = -1; | 15473 | // Usually when TerminateProcess triggers a ACCESS_DENIED error, it |
| 15477 | switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) { | 15474 | // indicates that the process has already exited, but there may be |
| 15478 | .SUCCESS => return error.AlreadyTerminated, | 15475 | // some rare edge cases where our process handle no longer has the |
| 15479 | else => return error.AccessDenied, | 15476 | // PROCESS_TERMINATE access right, so let's do another check to make |
| 15480 | } | 15477 | // sure the process is really no longer running: |
| 15481 | }, | 15478 | const minimal_timeout: windows.LARGE_INTEGER = -1; |
| 15482 | else => |err| return windows.unexpectedError(err), | 15479 | return switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) { |
| 15483 | } | 15480 | windows.NTSTATUS.WAIT_0 => error.AlreadyTerminated, |
| 15481 | else => error.AccessDenied, | ||
| 15482 | }; | ||
| 15483 | }, | ||
| 15484 | else => |status| return windows.unexpectedStatus(status), | ||
| 15484 | } | 15485 | } |
| 15485 | const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); | ||
| 15486 | _ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout); | ||
| 15487 | childCleanupWindows(child); | ||
| 15488 | } | 15486 | } |
| 15489 | 15487 | ||
| 15490 | fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child.Term { | 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,12 +15499,12 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child |
| 15501 | else => |status| return alertable_syscall.unexpectedNtstatus(status), | 15499 | else => |status| return alertable_syscall.unexpectedNtstatus(status), |
| 15502 | }; | 15500 | }; |
| 15503 | 15501 | ||
| 15504 | var info: windows.PROCESS_BASIC_INFORMATION = undefined; | 15502 | var info: windows.PROCESS.BASIC_INFORMATION = undefined; |
| 15505 | const term: process.Child.Term = switch (windows.ntdll.NtQueryInformationProcess( | 15503 | const term: process.Child.Term = switch (windows.ntdll.NtQueryInformationProcess( |
| 15506 | handle, | 15504 | handle, |
| 15507 | .BasicInformation, | 15505 | .BasicInformation, |
| 15508 | &info, | 15506 | &info, |
| 15509 | @sizeOf(windows.PROCESS_BASIC_INFORMATION), | 15507 | @sizeOf(windows.PROCESS.BASIC_INFORMATION), |
| 15510 | null, | 15508 | null, |
| 15511 | )) { | 15509 | )) { |
| 15512 | .SUCCESS => .{ .exited = @as(u8, @truncate(@intFromEnum(info.ExitStatus))) }, | 15510 | .SUCCESS => .{ .exited = @as(u8, @truncate(@intFromEnum(info.ExitStatus))) }, |
| ... | @@ -15521,12 +15519,12 @@ fn childCleanupWindows(child: *process.Child) void { | ... | @@ -15521,12 +15519,12 @@ fn childCleanupWindows(child: *process.Child) void { |
| 15521 | const handle = child.id orelse return; | 15519 | const handle = child.id orelse return; |
| 15522 | 15520 | ||
| 15523 | if (child.request_resource_usage_statistics) { | 15521 | if (child.request_resource_usage_statistics) { |
| 15524 | var vmc: windows.VM_COUNTERS = undefined; | 15522 | var vmc: windows.PROCESS.VM_COUNTERS = undefined; |
| 15525 | switch (windows.ntdll.NtQueryInformationProcess( | 15523 | switch (windows.ntdll.NtQueryInformationProcess( |
| 15526 | handle, | 15524 | handle, |
| 15527 | .VmCounters, | 15525 | .VmCounters, |
| 15528 | &vmc, | 15526 | &vmc, |
| 15529 | @sizeOf(windows.VM_COUNTERS), | 15527 | @sizeOf(windows.PROCESS.VM_COUNTERS), |
| 15530 | null, | 15528 | null, |
| 15531 | )) { | 15529 | )) { |
| 15532 | .SUCCESS => child.resource_usage_statistics.rusage = vmc, | 15530 | .SUCCESS => child.resource_usage_statistics.rusage = vmc, |
| ... | @@ -15853,7 +15851,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro | ... | @@ -15853,7 +15851,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro |
| 15853 | .cbReserved2 = 0, | 15851 | .cbReserved2 = 0, |
| 15854 | .lpReserved2 = null, | 15852 | .lpReserved2 = null, |
| 15855 | }; | 15853 | }; |
| 15856 | var piProcInfo: windows.PROCESS_INFORMATION = undefined; | 15854 | var piProcInfo: windows.PROCESS.INFORMATION = undefined; |
| 15857 | 15855 | ||
| 15858 | var arena_allocator = std.heap.ArenaAllocator.init(t.allocator); | 15856 | var arena_allocator = std.heap.ArenaAllocator.init(t.allocator); |
| 15859 | defer arena_allocator.deinit(); | 15857 | defer arena_allocator.deinit(); |
| ... | @@ -16062,7 +16060,6 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { | ... | @@ -16062,7 +16060,6 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 16062 | if (t.random_file.handle) |handle| return handle; | 16060 | if (t.random_file.handle) |handle| return handle; |
| 16063 | } | 16061 | } |
| 16064 | 16062 | ||
| 16065 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' }; | ||
| 16066 | var fresh_handle: windows.HANDLE = undefined; | 16063 | var fresh_handle: windows.HANDLE = undefined; |
| 16067 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | 16064 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16068 | var syscall: Syscall = try .start(); | 16065 | var syscall: Syscall = try .start(); |
| ... | @@ -16072,13 +16069,9 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { | ... | @@ -16072,13 +16069,9 @@ fn getCngDevice(t: *Threaded) Io.RandomSecureError!windows.HANDLE { |
| 16072 | .STANDARD = .{ .SYNCHRONIZE = true }, | 16069 | .STANDARD = .{ .SYNCHRONIZE = true }, |
| 16073 | .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } }, | 16070 | .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } }, |
| 16074 | }, | 16071 | }, |
| 16075 | &.{ | 16072 | &.{ .ObjectName = @constCast(&windows.UNICODE_STRING.init( |
| 16076 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | 16073 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' }, |
| 16077 | .Length = @sizeOf(@TypeOf(device_path)), | 16074 | )) }, |
| 16078 | .MaximumLength = 0, | ||
| 16079 | .Buffer = @constCast(&device_path), | ||
| 16080 | }), | ||
| 16081 | }, | ||
| 16082 | &io_status_block, | 16075 | &io_status_block, |
| 16083 | .VALID_FLAGS, | 16076 | .VALID_FLAGS, |
| 16084 | .{ .IO = .SYNCHRONOUS_NONALERT }, | 16077 | .{ .IO = .SYNCHRONOUS_NONALERT }, |
| ... | @@ -16111,7 +16104,6 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { | ... | @@ -16111,7 +16104,6 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { |
| 16111 | if (t.null_file.handle) |handle| return handle; | 16104 | if (t.null_file.handle) |handle| return handle; |
| 16112 | } | 16105 | } |
| 16113 | 16106 | ||
| 16114 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' }; | ||
| 16115 | var fresh_handle: windows.HANDLE = undefined; | 16107 | var fresh_handle: windows.HANDLE = undefined; |
| 16116 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | 16108 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16117 | var syscall: Syscall = try .start(); | 16109 | var syscall: Syscall = try .start(); |
| ... | @@ -16123,11 +16115,9 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { | ... | @@ -16123,11 +16115,9 @@ fn getNulDevice(t: *Threaded) !windows.HANDLE { |
| 16123 | }, | 16115 | }, |
| 16124 | &.{ | 16116 | &.{ |
| 16125 | .Attributes = .{ .INHERIT = true }, | 16117 | .Attributes = .{ .INHERIT = true }, |
| 16126 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | 16118 | .ObjectName = @constCast(&windows.UNICODE_STRING.init( |
| 16127 | .Length = @sizeOf(@TypeOf(device_path)), | 16119 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' }, |
| 16128 | .MaximumLength = 0, | 16120 | )), |
| 16129 | .Buffer = @constCast(&device_path), | ||
| 16130 | }), | ||
| 16131 | }, | 16121 | }, |
| 16132 | &io_status_block, | 16122 | &io_status_block, |
| 16133 | .VALID_FLAGS, | 16123 | .VALID_FLAGS, |
| ... | @@ -16173,7 +16163,6 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { | ... | @@ -16173,7 +16163,6 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { |
| 16173 | if (t.pipe_file.handle) |handle| return handle; | 16163 | if (t.pipe_file.handle) |handle| return handle; |
| 16174 | } | 16164 | } |
| 16175 | 16165 | ||
| 16176 | const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' }; | ||
| 16177 | var fresh_handle: windows.HANDLE = undefined; | 16166 | var fresh_handle: windows.HANDLE = undefined; |
| 16178 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | 16167 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 16179 | var syscall: Syscall = try .start(); | 16168 | var syscall: Syscall = try .start(); |
| ... | @@ -16181,11 +16170,9 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { | ... | @@ -16181,11 +16170,9 @@ fn getNamedPipeDevice(t: *Threaded) !windows.HANDLE { |
| 16181 | &fresh_handle, | 16170 | &fresh_handle, |
| 16182 | .{ .STANDARD = .{ .SYNCHRONIZE = true } }, | 16171 | .{ .STANDARD = .{ .SYNCHRONIZE = true } }, |
| 16183 | &.{ | 16172 | &.{ |
| 16184 | .ObjectName = @constCast(&windows.UNICODE_STRING{ | 16173 | .ObjectName = @constCast(&windows.UNICODE_STRING.init( |
| 16185 | .Length = @sizeOf(@TypeOf(device_path)), | 16174 | &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', '\\' }, |
| 16186 | .MaximumLength = 0, | 16175 | )), |
| 16187 | .Buffer = @constCast(&device_path), | ||
| 16188 | }), | ||
| 16189 | }, | 16176 | }, |
| 16190 | &io_status_block, | 16177 | &io_status_block, |
| 16191 | .VALID_FLAGS, | 16178 | .VALID_FLAGS, |
| ... | @@ -16253,7 +16240,7 @@ fn windowsCreateProcessPathExt( | ... | @@ -16253,7 +16240,7 @@ fn windowsCreateProcessPathExt( |
| 16253 | cwd_ptr: ?[*:0]u16, | 16240 | cwd_ptr: ?[*:0]u16, |
| 16254 | flags: windows.CreateProcessFlags, | 16241 | flags: windows.CreateProcessFlags, |
| 16255 | lpStartupInfo: *windows.STARTUPINFOW, | 16242 | lpStartupInfo: *windows.STARTUPINFOW, |
| 16256 | lpProcessInformation: *windows.PROCESS_INFORMATION, | 16243 | lpProcessInformation: *windows.PROCESS.INFORMATION, |
| 16257 | ) !void { | 16244 | ) !void { |
| 16258 | const app_name_len = app_buf.items.len; | 16245 | const app_name_len = app_buf.items.len; |
| 16259 | const dir_path_len = dir_buf.items.len; | 16246 | const dir_path_len = dir_buf.items.len; |
| ... | @@ -16341,13 +16328,9 @@ fn windowsCreateProcessPathExt( | ... | @@ -16341,13 +16328,9 @@ fn windowsCreateProcessPathExt( |
| 16341 | // On NTFS, `blah.exe*` will always return `blah.exe` first if it exists. | 16328 | // On NTFS, `blah.exe*` will always return `blah.exe` first if it exists. |
| 16342 | // On FAT32, it's possible for something like `blah.exe.obj` to be returned first. | 16329 | // On FAT32, it's possible for something like `blah.exe.obj` to be returned first. |
| 16343 | while (true) { | 16330 | while (true) { |
| 16344 | const app_name_len_bytes = std.math.cast(u16, app_name_wildcard.len * 2) orelse return error.NameTooLong; | 16331 | // If we get nothing with the wildcard, then we can just bail out |
| 16345 | var app_name_unicode_string = windows.UNICODE_STRING{ | 16332 | // as we know appending PATHEXT will not yield anything. |
| 16346 | .Length = app_name_len_bytes, | 16333 | switch (windows.ntdll.NtQueryDirectoryFile( |
| 16347 | .MaximumLength = app_name_len_bytes, | ||
| 16348 | .Buffer = @constCast(app_name_wildcard.ptr), | ||
| 16349 | }; | ||
| 16350 | const rc = windows.ntdll.NtQueryDirectoryFile( | ||
| 16351 | dir.handle, | 16334 | dir.handle, |
| 16352 | null, | 16335 | null, |
| 16353 | null, | 16336 | null, |
| ... | @@ -16357,18 +16340,14 @@ fn windowsCreateProcessPathExt( | ... | @@ -16357,18 +16340,14 @@ fn windowsCreateProcessPathExt( |
| 16357 | file_information_buf.len, | 16340 | file_information_buf.len, |
| 16358 | .Directory, | 16341 | .Directory, |
| 16359 | windows.FALSE, // single result | 16342 | windows.FALSE, // single result |
| 16360 | &app_name_unicode_string, | 16343 | &.init(app_name_wildcard), |
| 16361 | windows.FALSE, // restart iteration | 16344 | windows.FALSE, // restart iteration |
| 16362 | ); | 16345 | )) { |
| 16363 | |||
| 16364 | // If we get nothing with the wildcard, then we can just bail out | ||
| 16365 | // as we know appending PATHEXT will not yield anything. | ||
| 16366 | switch (rc) { | ||
| 16367 | .SUCCESS => {}, | 16346 | .SUCCESS => {}, |
| 16368 | .NO_SUCH_FILE => return error.FileNotFound, | 16347 | .NO_SUCH_FILE => return error.FileNotFound, |
| 16369 | .NO_MORE_FILES => break, | 16348 | .NO_MORE_FILES => break, |
| 16370 | .ACCESS_DENIED => return error.AccessDenied, | 16349 | .ACCESS_DENIED => return error.AccessDenied, |
| 16371 | else => return windows.unexpectedStatus(rc), | 16350 | else => |status| return windows.unexpectedStatus(status), |
| 16372 | } | 16351 | } |
| 16373 | 16352 | ||
| 16374 | // According to the docs, this can only happen if there is not enough room in the | 16353 | // According to the docs, this can only happen if there is not enough room in the |
| ... | @@ -16514,7 +16493,7 @@ fn windowsCreateProcess( | ... | @@ -16514,7 +16493,7 @@ fn windowsCreateProcess( |
| 16514 | cwd_ptr: ?[*:0]u16, | 16493 | cwd_ptr: ?[*:0]u16, |
| 16515 | flags: windows.CreateProcessFlags, | 16494 | flags: windows.CreateProcessFlags, |
| 16516 | lpStartupInfo: *windows.STARTUPINFOW, | 16495 | lpStartupInfo: *windows.STARTUPINFOW, |
| 16517 | lpProcessInformation: *windows.PROCESS_INFORMATION, | 16496 | lpProcessInformation: *windows.PROCESS.INFORMATION, |
| 16518 | ) !void { | 16497 | ) !void { |
| 16519 | const syscall: Syscall = try .start(); | 16498 | const syscall: Syscall = try .start(); |
| 16520 | while (true) { | 16499 | while (true) { |
| ... | @@ -17138,7 +17117,7 @@ pub const CreatePipeOptions = struct { | ... | @@ -17138,7 +17117,7 @@ pub const CreatePipeOptions = struct { |
| 17138 | default_timeout: windows.LARGE_INTEGER = -120 * std.time.ns_per_s / 100, | 17117 | default_timeout: windows.LARGE_INTEGER = -120 * std.time.ns_per_s / 100, |
| 17139 | 17118 | ||
| 17140 | pub const End = struct { | 17119 | pub const End = struct { |
| 17141 | attributes: windows.OBJECT_ATTRIBUTES.ATTRIBUTES = .{}, | 17120 | attributes: windows.OBJECT.ATTRIBUTES.Flags = .{}, |
| 17142 | mode: windows.FILE.MODE, | 17121 | mode: windows.FILE.MODE, |
| 17143 | }; | 17122 | }; |
| 17144 | }; | 17123 | }; |
| ... | @@ -18373,7 +18352,7 @@ const CreateFileMapError = error{ | ... | @@ -18373,7 +18352,7 @@ const CreateFileMapError = error{ |
| 18373 | OutOfMemory, | 18352 | OutOfMemory, |
| 18374 | MappingAlreadyExists, | 18353 | MappingAlreadyExists, |
| 18375 | Unseekable, | 18354 | Unseekable, |
| 18376 | FileLockConflict, | 18355 | LockViolation, |
| 18377 | } || Io.Cancelable || Io.UnexpectedError; | 18356 | } || Io.Cancelable || Io.UnexpectedError; |
| 18378 | 18357 | ||
| 18379 | fn createFileMap( | 18358 | fn createFileMap( |
| ... | @@ -18408,7 +18387,7 @@ fn createFileMap( | ... | @@ -18408,7 +18387,7 @@ fn createFileMap( |
| 18408 | file.handle, | 18387 | file.handle, |
| 18409 | )) { | 18388 | )) { |
| 18410 | .SUCCESS => {}, | 18389 | .SUCCESS => {}, |
| 18411 | .FILE_LOCK_CONFLICT => return error.FileLockConflict, | 18390 | .FILE_LOCK_CONFLICT => return error.LockViolation, |
| 18412 | .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported, | 18391 | .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported, |
| 18413 | .ACCESS_DENIED => return error.AccessDenied, | 18392 | .ACCESS_DENIED => return error.AccessDenied, |
| 18414 | .SECTION_TOO_BIG => return error.SectionOversize, | 18393 | .SECTION_TOO_BIG => return error.SectionOversize, |
| ... | @@ -18724,7 +18703,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! | ... | @@ -18724,7 +18703,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! |
| 18724 | while (true) { | 18703 | while (true) { |
| 18725 | const buf = memory[i..]; | 18704 | const buf = memory[i..]; |
| 18726 | if (buf.len == 0) break; | 18705 | if (buf.len == 0) break; |
| 18727 | i += try writeFilePositionalWindows(file.handle, memory[i..], offset + i); | 18706 | i += try writeFilePositionalWindows(file, memory[i..], offset + i); |
| 18728 | } | 18707 | } |
| 18729 | } else if (native_os == .wasi and !builtin.link_libc) { | 18708 | } else if (native_os == .wasi and !builtin.link_libc) { |
| 18730 | var i: usize = 0; | 18709 | var i: usize = 0; |
| ... | @@ -18809,8 +18788,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! | ... | @@ -18809,8 +18788,7 @@ fn mmSyncWrite(file: File, memory: []u8, offset: u64) File.WritePositionalError! |
| 18809 | } | 18788 | } |
| 18810 | } | 18789 | } |
| 18811 | 18790 | ||
| 18812 | fn deviceIoControl(t: *Threaded, o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result { | 18791 | fn deviceIoControl(o: *const Io.Operation.DeviceIoControl) Io.Cancelable!Io.Operation.DeviceIoControl.Result { |
| 18813 | _ = t; | ||
| 18814 | if (is_windows) { | 18792 | if (is_windows) { |
| 18815 | const NtControlFile = switch (o.code.DeviceType) { | 18793 | const NtControlFile = switch (o.code.DeviceType) { |
| 18816 | .FILE_SYSTEM, .NAMED_PIPE => &windows.ntdll.NtFsControlFile, | 18794 | .FILE_SYSTEM, .NAMED_PIPE => &windows.ntdll.NtFsControlFile, |
| ... | @@ -19104,16 +19082,10 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows | ... | @@ -19104,16 +19082,10 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows |
| 19104 | 19082 | ||
| 19105 | var result: windows.HANDLE = undefined; | 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; | 19085 | const attr: windows.OBJECT.ATTRIBUTES = .{ |
| 19108 | var nt_name: windows.UNICODE_STRING = .{ | ||
| 19109 | .Length = path_len_bytes, | ||
| 19110 | .MaximumLength = path_len_bytes, | ||
| 19111 | .Buffer = @constCast(sub_path_w.ptr), | ||
| 19112 | }; | ||
| 19113 | const attr: windows.OBJECT_ATTRIBUTES = .{ | ||
| 19114 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir, | 19086 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir, |
| 19115 | .Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle != windows.FALSE else false }, | 19087 | .Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle != windows.FALSE else false }, |
| 19116 | .ObjectName = &nt_name, | 19088 | .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w)), |
| 19117 | .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null, | 19089 | .SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null, |
| 19118 | }; | 19090 | }; |
| 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,7 +290,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpa |
| 290 | defer windows.ntdll.RtlFreeUnicodeString(&out); | 290 | defer windows.ntdll.RtlFreeUnicodeString(&out); |
| 291 | 291 | ||
| 292 | var path_space: Io.Threaded.WindowsPathSpace = undefined; | 292 | var path_space: Io.Threaded.WindowsPathSpace = undefined; |
| 293 | const out_path = out.Buffer.?[0 .. out.Length / 2]; | 293 | const out_path = out.slice(); |
| 294 | @memcpy(path_space.data[0..out_path.len], out_path); | 294 | @memcpy(path_space.data[0..out_path.len], out_path); |
| 295 | path_space.len = out.Length / 2; | 295 | path_space.len = out.Length / 2; |
| 296 | path_space.data[path_space.len] = 0; | 296 | path_space.data[path_space.len] = 0; |
lib/std/Thread.zig+3-13| ... | @@ -88,20 +88,10 @@ pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void { | ... | @@ -88,20 +88,10 @@ pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void { |
| 88 | }, | 88 | }, |
| 89 | .windows => { | 89 | .windows => { |
| 90 | var buf: [max_name_len]u16 = undefined; | 90 | var buf: [max_name_len]u16 = undefined; |
| 91 | const len = try std.unicode.wtf8ToWtf16Le(&buf, name); | ||
| 92 | const byte_len = math.cast(c_ushort, len * 2) orelse return error.NameTooLong; | ||
| 93 | |||
| 94 | // Note: NT allocates its own copy, no use-after-free here. | ||
| 95 | const unicode_string = windows.UNICODE_STRING{ | ||
| 96 | .Length = byte_len, | ||
| 97 | .MaximumLength = byte_len, | ||
| 98 | .Buffer = &buf, | ||
| 99 | }; | ||
| 100 | |||
| 101 | switch (windows.ntdll.NtSetInformationThread( | 91 | switch (windows.ntdll.NtSetInformationThread( |
| 102 | self.getHandle(), | 92 | self.getHandle(), |
| 103 | .NameInformation, | 93 | .NameInformation, |
| 104 | &unicode_string, | 94 | &windows.UNICODE_STRING.init(buf[0..try std.unicode.wtf8ToWtf16Le(&buf, name)]), |
| 105 | @sizeOf(windows.UNICODE_STRING), | 95 | @sizeOf(windows.UNICODE_STRING), |
| 106 | )) { | 96 | )) { |
| 107 | .SUCCESS => return, | 97 | .SUCCESS => return, |
| ... | @@ -217,8 +207,8 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co | ... | @@ -217,8 +207,8 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co |
| 217 | null, | 207 | null, |
| 218 | )) { | 208 | )) { |
| 219 | .SUCCESS => { | 209 | .SUCCESS => { |
| 220 | const string = @as(*const windows.UNICODE_STRING, @ptrCast(&buf)); | 210 | const string: *const windows.UNICODE_STRING = @ptrCast(&buf); |
| 221 | const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]); | 211 | const len = std.unicode.wtf16LeToWtf8(buffer, string.slice()); |
| 222 | return if (len > 0) buffer[0..len] else null; | 212 | return if (len > 0) buffer[0..len] else null; |
| 223 | }, | 213 | }, |
| 224 | .NOT_IMPLEMENTED => return error.Unsupported, | 214 | .NOT_IMPLEMENTED => return error.Unsupported, |
lib/std/debug.zig+18-27| ... | @@ -37,12 +37,13 @@ pub const cpu_context = @import("debug/cpu_context.zig"); | ... | @@ -37,12 +37,13 @@ pub const cpu_context = @import("debug/cpu_context.zig"); |
| 37 | /// | 37 | /// |
| 38 | /// ``` | 38 | /// ``` |
| 39 | /// pub const init: SelfInfo; | 39 | /// pub const init: SelfInfo; |
| 40 | /// pub fn deinit(si: *SelfInfo, gpa: Allocator) void; | 40 | /// pub fn deinit(si: *SelfInfo, io: Io) void; |
| 41 | /// | 41 | /// |
| 42 | /// /// Returns the symbol and source location of the instruction at `address`. | 42 | /// /// Returns the symbol and source location of the instruction at `address`. |
| 43 | /// pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) SelfInfoError!Symbol; | 43 | /// pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) SelfInfoError!Symbol; |
| 44 | /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. | 44 | /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. |
| 45 | /// pub fn getModuleName(si: *SelfInfo, gpa: Allocator, address: usize) SelfInfoError![]const u8; | 45 | /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; |
| 46 | /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; | ||
| 46 | /// | 47 | /// |
| 47 | /// /// Whether a reliable stack unwinding strategy, such as DWARF unwinding, is available. | 48 | /// /// Whether a reliable stack unwinding strategy, such as DWARF unwinding, is available. |
| 48 | /// pub const can_unwind: bool; | 49 | /// pub const can_unwind: bool; |
| ... | @@ -51,15 +52,15 @@ pub const cpu_context = @import("debug/cpu_context.zig"); | ... | @@ -51,15 +52,15 @@ pub const cpu_context = @import("debug/cpu_context.zig"); |
| 51 | /// /// An address representing the instruction pointer in the last frame. | 52 | /// /// An address representing the instruction pointer in the last frame. |
| 52 | /// pc: usize, | 53 | /// pc: usize, |
| 53 | /// | 54 | /// |
| 54 | /// pub fn init(ctx: *cpu_context.Native, gpa: Allocator) Allocator.Error!UnwindContext; | 55 | /// pub fn init(ctx: *cpu_context.Native) Allocator.Error!UnwindContext; |
| 55 | /// pub fn deinit(ctx: *UnwindContext, gpa: Allocator) void; | 56 | /// pub fn deinit(ctx: *UnwindContext) void; |
| 56 | /// /// Returns the frame pointer associated with the last unwound stack frame. | 57 | /// /// Returns the frame pointer associated with the last unwound stack frame. |
| 57 | /// /// If the frame pointer is unknown, 0 may be returned instead. | 58 | /// /// If the frame pointer is unknown, 0 may be returned instead. |
| 58 | /// pub fn getFp(uc: *UnwindContext) usize; | 59 | /// pub fn getFp(uc: *UnwindContext) usize; |
| 59 | /// }; | 60 | /// }; |
| 60 | /// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's | 61 | /// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's |
| 61 | /// /// return address, or 0 if the end of the stack has been reached. | 62 | /// /// return address, or 0 if the end of the stack has been reached. |
| 62 | /// pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) SelfInfoError!usize; | 63 | /// pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) SelfInfoError!usize; |
| 63 | /// ``` | 64 | /// ``` |
| 64 | pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) | 65 | pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) |
| 65 | root.debug.SelfInfo | 66 | root.debug.SelfInfo |
| ... | @@ -669,7 +670,6 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin | ... | @@ -669,7 +670,6 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 669 | t.setColor(.reset) catch {}; | 670 | t.setColor(.reset) catch {}; |
| 670 | return; | 671 | return; |
| 671 | } | 672 | } |
| 672 | const di_gpa = getDebugInfoAllocator(); | ||
| 673 | const di = getSelfDebugInfo() catch |err| switch (err) { | 673 | const di = getSelfDebugInfo() catch |err| switch (err) { |
| 674 | error.UnsupportedTarget => { | 674 | error.UnsupportedTarget => { |
| 675 | t.setColor(.dim) catch {}; | 675 | t.setColor(.dim) catch {}; |
| ... | @@ -696,7 +696,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin | ... | @@ -696,7 +696,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 696 | .useless, .unsafe => {}, | 696 | .useless, .unsafe => {}, |
| 697 | .safe, .ideal => continue, // no need to even warn | 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 | const caption: []const u8 = switch (unwind_error.err) { | 700 | const caption: []const u8 = switch (unwind_error.err) { |
| 701 | error.MissingDebugInfo => "unwind info unavailable", | 701 | error.MissingDebugInfo => "unwind info unavailable", |
| 702 | error.InvalidDebugInfo => "unwind info invalid", | 702 | error.InvalidDebugInfo => "unwind info invalid", |
| ... | @@ -741,7 +741,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin | ... | @@ -741,7 +741,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 741 | } | 741 | } |
| 742 | // `ret_addr` is the return address, which is *after* the function call. | 742 | // `ret_addr` is the return address, which is *after* the function call. |
| 743 | // Subtract 1 to get an address *in* the function call for a better source location. | 743 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 744 | try printSourceAtAddress(di_gpa, io, di, t, ret_addr -| StackIterator.ra_call_offset); | 744 | try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); |
| 745 | printed_any_frame = true; | 745 | printed_any_frame = true; |
| 746 | }, | 746 | }, |
| 747 | }; | 747 | }; |
| ... | @@ -788,7 +788,6 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void | ... | @@ -788,7 +788,6 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void |
| 788 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. | 788 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. |
| 789 | const n_frames = st.index; | 789 | const n_frames = st.index; |
| 790 | if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); | 790 | if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); |
| 791 | const di_gpa = getDebugInfoAllocator(); | ||
| 792 | const di = getSelfDebugInfo() catch |err| switch (err) { | 791 | const di = getSelfDebugInfo() catch |err| switch (err) { |
| 793 | error.UnsupportedTarget => { | 792 | error.UnsupportedTarget => { |
| 794 | t.setColor(.dim) catch {}; | 793 | t.setColor(.dim) catch {}; |
| ... | @@ -802,7 +801,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void | ... | @@ -802,7 +801,7 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void |
| 802 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { | 801 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { |
| 803 | // `ret_addr` is the return address, which is *after* the function call. | 802 | // `ret_addr` is the return address, which is *after* the function call. |
| 804 | // Subtract 1 to get an address *in* the function call for a better source location. | 803 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 805 | try printSourceAtAddress(di_gpa, io, di, t, ret_addr -| StackIterator.ra_call_offset); | 804 | try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); |
| 806 | } | 805 | } |
| 807 | if (n_frames > captured_frames) { | 806 | if (n_frames > captured_frames) { |
| 808 | t.setColor(.bold) catch {}; | 807 | t.setColor(.bold) catch {}; |
| ... | @@ -875,7 +874,7 @@ const StackIterator = union(enum) { | ... | @@ -875,7 +874,7 @@ const StackIterator = union(enum) { |
| 875 | switch (si.*) { | 874 | switch (si.*) { |
| 876 | .ctx_first => {}, | 875 | .ctx_first => {}, |
| 877 | .fp => {}, | 876 | .fp => {}, |
| 878 | .di => |*unwind_context| unwind_context.deinit(getDebugInfoAllocator()), | 877 | .di => |*unwind_context| unwind_context.deinit(), |
| 879 | } | 878 | } |
| 880 | } | 879 | } |
| 881 | 880 | ||
| ... | @@ -980,8 +979,7 @@ const StackIterator = union(enum) { | ... | @@ -980,8 +979,7 @@ const StackIterator = union(enum) { |
| 980 | }, | 979 | }, |
| 981 | .di => |*unwind_context| { | 980 | .di => |*unwind_context| { |
| 982 | const di = getSelfDebugInfo() catch unreachable; | 981 | const di = getSelfDebugInfo() catch unreachable; |
| 983 | const di_gpa = getDebugInfoAllocator(); | 982 | const ret_addr = di.unwindFrame(io, unwind_context) catch |err| { |
| 984 | const ret_addr = di.unwindFrame(di_gpa, io, unwind_context) catch |err| { | ||
| 985 | const pc = unwind_context.pc; | 983 | const pc = unwind_context.pc; |
| 986 | const fp = unwind_context.getFp(); | 984 | const fp = unwind_context.getFp(); |
| 987 | it.* = .{ .fp = fp }; | 985 | it.* = .{ .fp = fp }; |
| ... | @@ -1109,14 +1107,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { | ... | @@ -1109,14 +1107,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { |
| 1109 | return ptr; | 1107 | return ptr; |
| 1110 | } | 1108 | } |
| 1111 | 1109 | ||
| 1112 | fn printSourceAtAddress( | 1110 | fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void { |
| 1113 | gpa: Allocator, | 1111 | const symbol: Symbol = debug_info.getSymbol(io, address) catch |err| switch (err) { |
| 1114 | io: Io, | ||
| 1115 | debug_info: *SelfInfo, | ||
| 1116 | t: Io.Terminal, | ||
| 1117 | address: usize, | ||
| 1118 | ) Writer.Error!void { | ||
| 1119 | const symbol: Symbol = debug_info.getSymbol(gpa, io, address) catch |err| switch (err) { | ||
| 1120 | error.MissingDebugInfo, | 1112 | error.MissingDebugInfo, |
| 1121 | error.UnsupportedDebugInfo, | 1113 | error.UnsupportedDebugInfo, |
| 1122 | error.InvalidDebugInfo, | 1114 | error.InvalidDebugInfo, |
| ... | @@ -1134,14 +1126,14 @@ fn printSourceAtAddress( | ... | @@ -1134,14 +1126,14 @@ fn printSourceAtAddress( |
| 1134 | break :s .unknown; | 1126 | break :s .unknown; |
| 1135 | }, | 1127 | }, |
| 1136 | }; | 1128 | }; |
| 1137 | defer if (symbol.source_location) |sl| gpa.free(sl.file_name); | 1129 | defer if (symbol.source_location) |sl| getDebugInfoAllocator().free(sl.file_name); |
| 1138 | return printLineInfo( | 1130 | return printLineInfo( |
| 1139 | io, | 1131 | io, |
| 1140 | t, | 1132 | t, |
| 1141 | symbol.source_location, | 1133 | symbol.source_location, |
| 1142 | address, | 1134 | address, |
| 1143 | symbol.name orelse "???", | 1135 | symbol.name orelse "???", |
| 1144 | symbol.compile_unit_name orelse debug_info.getModuleName(gpa, io, address) catch "???", | 1136 | symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", |
| 1145 | ); | 1137 | ); |
| 1146 | } | 1138 | } |
| 1147 | fn printLineInfo( | 1139 | fn printLineInfo( |
| ... | @@ -1608,14 +1600,13 @@ test "manage resources correctly" { | ... | @@ -1608,14 +1600,13 @@ test "manage resources correctly" { |
| 1608 | return @returnAddress(); | 1600 | return @returnAddress(); |
| 1609 | } | 1601 | } |
| 1610 | }; | 1602 | }; |
| 1611 | const gpa = testing.allocator; | ||
| 1612 | const io = testing.io; | 1603 | const io = testing.io; |
| 1613 | 1604 | ||
| 1614 | var discarding: Writer.Discarding = .init(&.{}); | 1605 | var discarding: Writer.Discarding = .init(&.{}); |
| 1615 | var di: SelfInfo = .init; | 1606 | var di: SelfInfo = .init; |
| 1616 | defer di.deinit(gpa); | 1607 | defer di.deinit(io); |
| 1617 | const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; | 1608 | const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; |
| 1618 | try printSourceAtAddress(gpa, io, &di, t, S.showMyTrace()); | 1609 | try printSourceAtAddress(io, &di, t, S.showMyTrace()); |
| 1619 | } | 1610 | } |
| 1620 | 1611 | ||
| 1621 | /// This API helps you track where a value originated and where it was mutated, | 1612 | /// This API helps you track where a value originated and where it was mutated, |
lib/std/debug/Dwarf/SelfUnwinder.zig+2-1| ... | @@ -55,7 +55,8 @@ pub fn init(cpu_context: *const std.debug.cpu_context.Native) SelfUnwinder { | ... | @@ -55,7 +55,8 @@ pub fn init(cpu_context: *const std.debug.cpu_context.Native) SelfUnwinder { |
| 55 | }; | 55 | }; |
| 56 | } | 56 | } |
| 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 | unwinder.cfi_vm.deinit(gpa); | 60 | unwinder.cfi_vm.deinit(gpa); |
| 60 | unwinder.expr_vm.deinit(gpa); | 61 | unwinder.expr_vm.deinit(gpa); |
| 61 | unwinder.* = undefined; | 62 | unwinder.* = undefined; |
lib/std/debug/SelfInfo/Elf.zig+11-5| ... | @@ -11,7 +11,9 @@ pub const init: SelfInfo = .{ | ... | @@ -11,7 +11,9 @@ pub const init: SelfInfo = .{ |
| 11 | .ranges = .empty, | 11 | .ranges = .empty, |
| 12 | .unwind_cache = null, | 12 | .unwind_cache = null, |
| 13 | }; | 13 | }; |
| 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 | for (si.modules.items) |*mod| { | 17 | for (si.modules.items) |*mod| { |
| 16 | unwind: { | 18 | unwind: { |
| 17 | const u = &(mod.unwind orelse break :unwind catch break :unwind); | 19 | const u = &(mod.unwind orelse break :unwind catch break :unwind); |
| ... | @@ -28,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | ... | @@ -28,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 28 | if (si.unwind_cache) |cache| gpa.free(cache); | 30 | if (si.unwind_cache) |cache| gpa.free(cache); |
| 29 | } | 31 | } |
| 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 | const module = try si.findModule(gpa, io, address, .exclusive); | 35 | const module = try si.findModule(gpa, io, address, .exclusive); |
| 33 | defer si.rwlock.unlock(io); | 36 | defer si.rwlock.unlock(io); |
| 34 | 37 | ||
| ... | @@ -73,13 +76,15 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st | ... | @@ -73,13 +76,15 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st |
| 73 | error.OutOfMemory => |e| return e, | 76 | error.OutOfMemory => |e| return e, |
| 74 | }; | 77 | }; |
| 75 | } | 78 | } |
| 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 | const module = try si.findModule(gpa, io, address, .shared); | 81 | const module = try si.findModule(gpa, io, address, .shared); |
| 78 | defer si.rwlock.unlockShared(io); | 82 | defer si.rwlock.unlockShared(io); |
| 79 | if (module.name.len == 0) return error.MissingDebugInfo; | 83 | if (module.name.len == 0) return error.MissingDebugInfo; |
| 80 | return module.name; | 84 | return module.name; |
| 81 | } | 85 | } |
| 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 | const module = try si.findModule(gpa, io, address, .shared); | 88 | const module = try si.findModule(gpa, io, address, .shared); |
| 84 | defer si.rwlock.unlockShared(io); | 89 | defer si.rwlock.unlockShared(io); |
| 85 | return module.load_offset; | 90 | return module.load_offset; |
| ... | @@ -179,8 +184,9 @@ comptime { | ... | @@ -179,8 +184,9 @@ comptime { |
| 179 | } | 184 | } |
| 180 | } | 185 | } |
| 181 | pub const UnwindContext = Dwarf.SelfUnwinder; | 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 | comptime assert(can_unwind); | 188 | comptime assert(can_unwind); |
| 189 | const gpa = std.debug.getDebugInfoAllocator(); | ||
| 184 | 190 | ||
| 185 | { | 191 | { |
| 186 | si.rwlock.lockSharedUncancelable(io); | 192 | si.rwlock.lockSharedUncancelable(io); |
lib/std/debug/SelfInfo/MachO.zig+12-8| ... | @@ -6,7 +6,9 @@ pub const init: SelfInfo = .{ | ... | @@ -6,7 +6,9 @@ pub const init: SelfInfo = .{ |
| 6 | .mutex = .init, | 6 | .mutex = .init, |
| 7 | .modules = .empty, | 7 | .modules = .empty, |
| 8 | }; | 8 | }; |
| 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 | for (si.modules.keys()) |*module| { | 12 | for (si.modules.keys()) |*module| { |
| 11 | unwind: { | 13 | unwind: { |
| 12 | const u = &(module.unwind orelse break :unwind catch break :unwind); | 14 | const u = &(module.unwind orelse break :unwind catch break :unwind); |
| ... | @@ -20,7 +22,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | ... | @@ -20,7 +22,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 20 | si.modules.deinit(gpa); | 22 | si.modules.deinit(gpa); |
| 21 | } | 23 | } |
| 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 | const module = try si.findModule(gpa, io, address); | 27 | const module = try si.findModule(gpa, io, address); |
| 25 | defer si.mutex.unlock(io); | 28 | defer si.mutex.unlock(io); |
| 26 | 29 | ||
| ... | @@ -76,9 +79,8 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st | ... | @@ -76,9 +79,8 @@ pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!st |
| 76 | ) catch null, | 79 | ) catch null, |
| 77 | }; | 80 | }; |
| 78 | } | 81 | } |
| 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 | _ = si; | 83 | _ = si; |
| 81 | _ = gpa; | ||
| 82 | _ = io; | 84 | _ = io; |
| 83 | // This function is marked as deprecated; however, it is significantly more | 85 | // This function is marked as deprecated; however, it is significantly more |
| 84 | // performant than `dladdr` (since the latter also does a very slow symbol | 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,7 +89,8 @@ pub fn getModuleName(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Erro |
| 87 | @ptrFromInt(address), | 89 | @ptrFromInt(address), |
| 88 | ) orelse return error.MissingDebugInfo); | 90 | ) orelse return error.MissingDebugInfo); |
| 89 | } | 91 | } |
| 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 | const module = try si.findModule(gpa, io, address); | 94 | const module = try si.findModule(gpa, io, address); |
| 92 | defer si.mutex.unlock(io); | 95 | defer si.mutex.unlock(io); |
| 93 | const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base); | 96 | const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base); |
| ... | @@ -107,8 +110,8 @@ pub const UnwindContext = std.debug.Dwarf.SelfUnwinder; | ... | @@ -107,8 +110,8 @@ pub const UnwindContext = std.debug.Dwarf.SelfUnwinder; |
| 107 | /// Unwind a frame using MachO compact unwind info (from `__unwind_info`). | 110 | /// Unwind a frame using MachO compact unwind info (from `__unwind_info`). |
| 108 | /// If the compact encoding can't encode a way to unwind a frame, it will | 111 | /// If the compact encoding can't encode a way to unwind a frame, it will |
| 109 | /// defer unwinding to DWARF, in which case `__eh_frame` will be used if available. | 112 | /// defer unwinding to DWARF, in which case `__eh_frame` will be used if available. |
| 110 | pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContext) Error!usize { | 113 | pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) Error!usize { |
| 111 | return unwindFrameInner(si, gpa, io, context) catch |err| switch (err) { | 114 | return unwindFrameInner(si, io, context) catch |err| switch (err) { |
| 112 | error.InvalidDebugInfo, | 115 | error.InvalidDebugInfo, |
| 113 | error.MissingDebugInfo, | 116 | error.MissingDebugInfo, |
| 114 | error.UnsupportedDebugInfo, | 117 | error.UnsupportedDebugInfo, |
| ... | @@ -134,7 +137,8 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex | ... | @@ -134,7 +137,8 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex |
| 134 | => return error.InvalidDebugInfo, | 137 | => return error.InvalidDebugInfo, |
| 135 | }; | 138 | }; |
| 136 | } | 139 | } |
| 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 | const module = try si.findModule(gpa, io, context.pc); | 142 | const module = try si.findModule(gpa, io, context.pc); |
| 139 | defer si.mutex.unlock(io); | 143 | defer si.mutex.unlock(io); |
| 140 | 144 |
lib/std/debug/SelfInfo/Windows.zig+151-86| ... | @@ -1,39 +1,51 @@ | ... | @@ -1,39 +1,51 @@ |
| 1 | mutex: Io.Mutex, | 1 | mutex: Io.Mutex, |
| 2 | ntdll_handle: ?if (load_dll_notification_procs) *anyopaque else noreturn, | ||
| 3 | notification_cookie: ?LDR.DLL_NOTIFICATION.COOKIE, | ||
| 2 | modules: std.ArrayList(Module), | 4 | modules: std.ArrayList(Module), |
| 3 | module_name_arena: std.heap.ArenaAllocator.State, | ||
| 4 | 5 | ||
| 5 | pub const init: SelfInfo = .{ | 6 | pub const init: SelfInfo = .{ |
| 6 | .mutex = .init, | 7 | .mutex = .init, |
| 8 | .ntdll_handle = null, | ||
| 9 | .notification_cookie = null, | ||
| 7 | .modules = .empty, | 10 | .modules = .empty, |
| 8 | .module_name_arena = .{}, | ||
| 9 | }; | 11 | }; |
| 10 | pub fn deinit(si: *SelfInfo, gpa: Allocator) void { | 12 | pub fn deinit(si: *SelfInfo, io: Io) void { |
| 11 | for (si.modules.items) |*module| { | 13 | const gpa = std.debug.getDebugInfoAllocator(); |
| 12 | di: { | 14 | if (si.notification_cookie) |cookie| unregister: { |
| 13 | const di = &(module.di orelse break :di catch break :di); | 15 | switch ((si.getNtdllProc(.LdrUnregisterDllNotification) catch break :unregister)(cookie)) { |
| 14 | di.deinit(gpa); | 16 | .SUCCESS => {}, |
| 17 | else => |status| windows.unexpectedStatus(status) catch break :unregister, | ||
| 15 | } | 18 | } |
| 16 | } | 19 | } |
| 20 | if (si.ntdll_handle) |handle| switch (windows.ntdll.LdrUnloadDll(handle)) { | ||
| 21 | .SUCCESS => {}, | ||
| 22 | else => |status| windows.unexpectedStatus(status) catch {}, | ||
| 23 | }; | ||
| 24 | for (si.modules.items) |*module| module.deinit(gpa, io); | ||
| 17 | si.modules.deinit(gpa); | 25 | si.modules.deinit(gpa); |
| 18 | |||
| 19 | var module_name_arena = si.module_name_arena.promote(gpa); | ||
| 20 | module_name_arena.deinit(); | ||
| 21 | } | 26 | } |
| 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 | try si.mutex.lock(io); | 30 | try si.mutex.lock(io); |
| 25 | defer si.mutex.unlock(io); | 31 | defer si.mutex.unlock(io); |
| 26 | const module = try si.findModule(gpa, address); | 32 | const module = try si.findModule(gpa, address); |
| 27 | const di = try module.getDebugInfo(gpa, io); | 33 | const di = try module.getDebugInfo(gpa, io); |
| 28 | return di.getSymbol(gpa, address - module.base_address); | 34 | return di.getSymbol(gpa, address - @intFromPtr(module.entry.DllBase)); |
| 29 | } | 35 | } |
| 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 | try si.mutex.lock(io); | 38 | try si.mutex.lock(io); |
| 32 | defer si.mutex.unlock(io); | 39 | defer si.mutex.unlock(io); |
| 33 | const module = try si.findModule(gpa, address); | 40 | const module = try si.findModule(gpa, address); |
| 34 | return module.name; | 41 | return module.name orelse { |
| 42 | const name = try std.unicode.wtf16LeToWtf8Alloc(gpa, module.entry.BaseDllName.slice()); | ||
| 43 | module.name = name; | ||
| 44 | return name; | ||
| 45 | }; | ||
| 35 | } | 46 | } |
| 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 | try si.mutex.lock(io); | 49 | try si.mutex.lock(io); |
| 38 | defer si.mutex.unlock(io); | 50 | defer si.mutex.unlock(io); |
| 39 | const module = try si.findModule(gpa, address); | 51 | const module = try si.findModule(gpa, address); |
| ... | @@ -141,18 +153,16 @@ pub const UnwindContext = struct { | ... | @@ -141,18 +153,16 @@ pub const UnwindContext = struct { |
| 141 | .history_table = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE), | 153 | .history_table = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE), |
| 142 | }; | 154 | }; |
| 143 | } | 155 | } |
| 144 | pub fn deinit(ctx: *UnwindContext, gpa: Allocator) void { | 156 | pub fn deinit(ctx: *UnwindContext) void { |
| 145 | _ = ctx; | 157 | _ = ctx; |
| 146 | _ = gpa; | ||
| 147 | } | 158 | } |
| 148 | pub fn getFp(ctx: *UnwindContext) usize { | 159 | pub fn getFp(ctx: *UnwindContext) usize { |
| 149 | return ctx.cur.getRegs().bp; | 160 | return ctx.cur.getRegs().bp; |
| 150 | } | 161 | } |
| 151 | }; | 162 | }; |
| 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 | _ = si; | 164 | _ = si; |
| 154 | _ = io; | 165 | _ = io; |
| 155 | _ = gpa; | ||
| 156 | 166 | ||
| 157 | const current_regs = context.cur.getRegs(); | 167 | const current_regs = context.cur.getRegs(); |
| 158 | var image_base: usize = undefined; | 168 | var image_base: usize = undefined; |
| ... | @@ -188,16 +198,12 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex | ... | @@ -188,16 +198,12 @@ pub fn unwindFrame(si: *SelfInfo, gpa: Allocator, io: Io, context: *UnwindContex |
| 188 | } | 198 | } |
| 189 | 199 | ||
| 190 | const Module = struct { | 200 | const Module = struct { |
| 191 | base_address: usize, | 201 | entry: *const LDR.DATA_TABLE_ENTRY, |
| 192 | size: u32, | 202 | name: ?[]const u8, |
| 193 | name: []const u8, | ||
| 194 | handle: windows.HMODULE, | ||
| 195 | |||
| 196 | di: ?(Error!DebugInfo), | 203 | di: ?(Error!DebugInfo), |
| 197 | 204 | ||
| 198 | const DebugInfo = struct { | 205 | const DebugInfo = struct { |
| 199 | arena: std.heap.ArenaAllocator.State, | 206 | arena: std.heap.ArenaAllocator.State, |
| 200 | io: Io, | ||
| 201 | coff_image_base: u64, | 207 | coff_image_base: u64, |
| 202 | mapped_file: ?MappedFile, | 208 | mapped_file: ?MappedFile, |
| 203 | dwarf: ?Dwarf, | 209 | dwarf: ?Dwarf, |
| ... | @@ -210,14 +216,19 @@ const Module = struct { | ... | @@ -210,14 +216,19 @@ const Module = struct { |
| 210 | section_view: []const u8, | 216 | section_view: []const u8, |
| 211 | fn deinit(mf: *const MappedFile, io: Io) void { | 217 | fn deinit(mf: *const MappedFile, io: Io) void { |
| 212 | const process_handle = windows.GetCurrentProcess(); | 218 | const process_handle = windows.GetCurrentProcess(); |
| 213 | assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mf.section_view.ptr)) == .SUCCESS); | 219 | switch (windows.ntdll.NtUnmapViewOfSection( |
| 220 | process_handle, | ||
| 221 | @constCast(mf.section_view.ptr), | ||
| 222 | )) { | ||
| 223 | .SUCCESS => {}, | ||
| 224 | else => |status| windows.unexpectedStatus(status) catch {}, | ||
| 225 | } | ||
| 214 | windows.CloseHandle(mf.section_handle); | 226 | windows.CloseHandle(mf.section_handle); |
| 215 | mf.file.close(io); | 227 | mf.file.close(io); |
| 216 | } | 228 | } |
| 217 | }; | 229 | }; |
| 218 | 230 | ||
| 219 | fn deinit(di: *DebugInfo, gpa: Allocator) void { | 231 | fn deinit(di: *DebugInfo, gpa: Allocator, io: Io) void { |
| 220 | const io = di.io; | ||
| 221 | if (di.dwarf) |*dwarf| dwarf.deinit(gpa); | 232 | if (di.dwarf) |*dwarf| dwarf.deinit(gpa); |
| 222 | if (di.pdb) |*pdb| { | 233 | if (di.pdb) |*pdb| { |
| 223 | pdb.file_reader.file.close(io); | 234 | pdb.file_reader.file.close(io); |
| ... | @@ -262,7 +273,10 @@ const Module = struct { | ... | @@ -262,7 +273,10 @@ const Module = struct { |
| 262 | return .{ | 273 | return .{ |
| 263 | .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address), | 274 | .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address), |
| 264 | .compile_unit_name = fs.path.basename(module.obj_file_name), | 275 | .compile_unit_name = fs.path.basename(module.obj_file_name), |
| 265 | .source_location = pdb.getLineNumberInfo(module, vaddr - coff_section.virtual_address) catch null, | 276 | .source_location = pdb.getLineNumberInfo( |
| 277 | module, | ||
| 278 | vaddr - coff_section.virtual_address, | ||
| 279 | ) catch null, | ||
| 266 | }; | 280 | }; |
| 267 | } | 281 | } |
| 268 | dwarf: { | 282 | dwarf: { |
| ... | @@ -286,13 +300,19 @@ const Module = struct { | ... | @@ -286,13 +300,19 @@ const Module = struct { |
| 286 | } | 300 | } |
| 287 | }; | 301 | }; |
| 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 | fn getDebugInfo(module: *Module, gpa: Allocator, io: Io) Error!*DebugInfo { | 309 | fn getDebugInfo(module: *Module, gpa: Allocator, io: Io) Error!*DebugInfo { |
| 290 | if (module.di == null) module.di = loadDebugInfo(module, gpa, io); | 310 | if (module.di == null) module.di = loadDebugInfo(module, gpa, io); |
| 291 | return if (module.di.?) |*di| di else |err| err; | 311 | return if (module.di.?) |*di| di else |err| err; |
| 292 | } | 312 | } |
| 293 | fn loadDebugInfo(module: *const Module, gpa: Allocator, io: Io) Error!DebugInfo { | 313 | fn loadDebugInfo(module: *const Module, gpa: Allocator, io: Io) Error!DebugInfo { |
| 294 | const mapped_ptr: [*]const u8 = @ptrFromInt(module.base_address); | 314 | const mapped_ptr: [*]const u8 = @ptrCast(module.entry.DllBase); |
| 295 | const mapped = mapped_ptr[0..module.size]; | 315 | const mapped = mapped_ptr[0..module.entry.SizeOfImage]; |
| 296 | var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo; | 316 | var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo; |
| 297 | 317 | ||
| 298 | var arena_instance: std.heap.ArenaAllocator = .init(gpa); | 318 | var arena_instance: std.heap.ArenaAllocator = .init(gpa); |
| ... | @@ -304,18 +324,15 @@ const Module = struct { | ... | @@ -304,18 +324,15 @@ const Module = struct { |
| 304 | // a binary is produced with -gdwarf, since the section names are longer than 8 bytes. | 324 | // a binary is produced with -gdwarf, since the section names are longer than 8 bytes. |
| 305 | const mapped_file: ?DebugInfo.MappedFile = mapped: { | 325 | const mapped_file: ?DebugInfo.MappedFile = mapped: { |
| 306 | if (!coff_obj.strtabRequired()) break :mapped null; | 326 | if (!coff_obj.strtabRequired()) break :mapped null; |
| 307 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; | 327 | var path_buffer: [4 + windows.PATH_MAX_WIDE]u16 = undefined; |
| 308 | name_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present | 328 | path_buffer[0..4].* = .{ '\\', '?', '?', '\\' }; // openFileAbsoluteW requires the prefix to be present |
| 309 | const process_handle = windows.GetCurrentProcess(); | 329 | const path_slice = module.entry.FullDllName.slice(); |
| 310 | const len = windows.kernel32.GetModuleFileNameExW( | 330 | @memcpy(path_buffer[4..][0..path_slice.len], path_slice); |
| 311 | process_handle, | 331 | const coff_file = Io.Threaded.dirOpenFileWtf16( |
| 312 | module.handle, | 332 | null, |
| 313 | name_buffer[4..], | 333 | path_buffer[0 .. 4 + path_slice.len], |
| 314 | windows.PATH_MAX_WIDE, | 334 | .{}, |
| 315 | ); | 335 | ) catch |err| switch (err) { |
| 316 | if (len == 0) return error.MissingDebugInfo; | ||
| 317 | const name_w = name_buffer[0 .. len + 4 :0]; | ||
| 318 | const coff_file = Io.Threaded.dirOpenFileWtf16(null, name_w, .{}) catch |err| switch (err) { | ||
| 319 | error.Canceled => |e| return e, | 336 | error.Canceled => |e| return e, |
| 320 | error.Unexpected => |e| return e, | 337 | error.Unexpected => |e| return e, |
| 321 | error.FileNotFound => return error.MissingDebugInfo, | 338 | error.FileNotFound => return error.MissingDebugInfo, |
| ... | @@ -359,7 +376,8 @@ const Module = struct { | ... | @@ -359,7 +376,8 @@ const Module = struct { |
| 359 | null, | 376 | null, |
| 360 | null, | 377 | null, |
| 361 | .{ .READONLY = true }, | 378 | .{ .READONLY = true }, |
| 362 | // The documentation states that if no AllocationAttribute is specified, then SEC_COMMIT is the default. | 379 | // The documentation states that if no AllocationAttribute is specified, |
| 380 | // then SEC_COMMIT is the default. | ||
| 363 | // In practice, this isn't the case and specifying 0 will result in INVALID_PARAMETER_6. | 381 | // In practice, this isn't the case and specifying 0 will result in INVALID_PARAMETER_6. |
| 364 | .{ .COMMIT = true }, | 382 | .{ .COMMIT = true }, |
| 365 | coff_file.handle, | 383 | coff_file.handle, |
| ... | @@ -368,6 +386,7 @@ const Module = struct { | ... | @@ -368,6 +386,7 @@ const Module = struct { |
| 368 | errdefer windows.CloseHandle(section_handle); | 386 | errdefer windows.CloseHandle(section_handle); |
| 369 | var coff_len: usize = 0; | 387 | var coff_len: usize = 0; |
| 370 | var section_view_ptr: ?[*]const u8 = null; | 388 | var section_view_ptr: ?[*]const u8 = null; |
| 389 | const process_handle = windows.GetCurrentProcess(); | ||
| 371 | const map_section_rc = windows.ntdll.NtMapViewOfSection( | 390 | const map_section_rc = windows.ntdll.NtMapViewOfSection( |
| 372 | section_handle, | 391 | section_handle, |
| 373 | process_handle, | 392 | process_handle, |
| ... | @@ -381,7 +400,13 @@ const Module = struct { | ... | @@ -381,7 +400,13 @@ const Module = struct { |
| 381 | .{ .READONLY = true }, | 400 | .{ .READONLY = true }, |
| 382 | ); | 401 | ); |
| 383 | if (map_section_rc != .SUCCESS) return error.MissingDebugInfo; | 402 | if (map_section_rc != .SUCCESS) return error.MissingDebugInfo; |
| 384 | errdefer assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(section_view_ptr.?)) == .SUCCESS); | 403 | errdefer switch (windows.ntdll.NtUnmapViewOfSection( |
| 404 | process_handle, | ||
| 405 | @constCast(section_view_ptr.?), | ||
| 406 | )) { | ||
| 407 | .SUCCESS => {}, | ||
| 408 | else => |status| windows.unexpectedStatus(status) catch {}, | ||
| 409 | }; | ||
| 385 | const section_view = section_view_ptr.?[0..coff_len]; | 410 | const section_view = section_view_ptr.?[0..coff_len]; |
| 386 | coff_obj = coff.Coff.init(section_view, false) catch return error.InvalidDebugInfo; | 411 | coff_obj = coff.Coff.init(section_view, false) catch return error.InvalidDebugInfo; |
| 387 | break :mapped .{ | 412 | break :mapped .{ |
| ... | @@ -496,7 +521,6 @@ const Module = struct { | ... | @@ -496,7 +521,6 @@ const Module = struct { |
| 496 | 521 | ||
| 497 | return .{ | 522 | return .{ |
| 498 | .arena = arena_instance.state, | 523 | .arena = arena_instance.state, |
| 499 | .io = io, | ||
| 500 | .coff_image_base = coff_image_base, | 524 | .coff_image_base = coff_image_base, |
| 501 | .mapped_file = mapped_file, | 525 | .mapped_file = mapped_file, |
| 502 | .dwarf = opt_dwarf, | 526 | .dwarf = opt_dwarf, |
| ... | @@ -509,52 +533,82 @@ const Module = struct { | ... | @@ -509,52 +533,82 @@ const Module = struct { |
| 509 | /// Assumes we already hold `si.mutex`. | 533 | /// Assumes we already hold `si.mutex`. |
| 510 | fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module { | 534 | fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module { |
| 511 | for (si.modules.items) |*mod| { | 535 | for (si.modules.items) |*mod| { |
| 512 | if (address >= mod.base_address and address < mod.base_address + mod.size) { | 536 | const base = @intFromPtr(mod.entry.DllBase); |
| 513 | return mod; | 537 | if (address >= base and address < base + mod.entry.SizeOfImage) return mod; |
| 514 | } | ||
| 515 | } | 538 | } |
| 516 | 539 | try si.modules.ensureUnusedCapacity(gpa, 1); | |
| 517 | // A new module might have been loaded; rebuild the list. | 540 | var entry: *LDR.DATA_TABLE_ENTRY = undefined; |
| 518 | { | 541 | switch (windows.ntdll.LdrFindEntryForAddress(@ptrFromInt(address), &entry)) { |
| 519 | for (si.modules.items) |*mod| { | 542 | .SUCCESS => {}, |
| 520 | const di = &(mod.di orelse continue catch continue); | 543 | .DLL_NOT_FOUND => return error.MissingDebugInfo, |
| 521 | di.deinit(gpa); | 544 | else => |status| return windows.unexpectedStatus(status), |
| 522 | } | 545 | } |
| 523 | si.modules.clearRetainingCapacity(); | 546 | if (si.notification_cookie == null) { |
| 524 | 547 | var notification_cookie: LDR.DLL_NOTIFICATION.COOKIE = undefined; | |
| 525 | var module_name_arena = si.module_name_arena.promote(gpa); | 548 | switch ((try si.getNtdllProc(.LdrRegisterDllNotification))( |
| 526 | defer si.module_name_arena = module_name_arena.state; | 549 | .{}, |
| 527 | _ = module_name_arena.reset(.retain_capacity); | 550 | &dllNotification, |
| 528 | 551 | si, | |
| 529 | const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0); | 552 | &notification_cookie, |
| 530 | if (handle == windows.INVALID_HANDLE_VALUE) { | 553 | )) { |
| 531 | return windows.unexpectedError(windows.GetLastError()); | 554 | .SUCCESS => si.notification_cookie = notification_cookie, |
| 532 | } | 555 | else => |status| return windows.unexpectedStatus(status), |
| 533 | defer windows.CloseHandle(handle); | ||
| 534 | var entry: windows.MODULEENTRY32 = undefined; | ||
| 535 | entry.dwSize = @sizeOf(windows.MODULEENTRY32); | ||
| 536 | var result = windows.kernel32.Module32First(handle, &entry); | ||
| 537 | while (result != 0) : (result = windows.kernel32.Module32Next(handle, &entry)) { | ||
| 538 | try si.modules.append(gpa, .{ | ||
| 539 | .base_address = @intFromPtr(entry.modBaseAddr), | ||
| 540 | .size = entry.modBaseSize, | ||
| 541 | .name = try module_name_arena.allocator().dupe( | ||
| 542 | u8, | ||
| 543 | std.mem.sliceTo(&entry.szModule, 0), | ||
| 544 | ), | ||
| 545 | .handle = entry.hModule, | ||
| 546 | .di = null, | ||
| 547 | }); | ||
| 548 | } | 556 | } |
| 549 | } | 557 | } |
| 558 | const mod = si.modules.addOneAssumeCapacity(); | ||
| 559 | mod.* = .{ .entry = entry, .name = null, .di = null }; | ||
| 560 | return mod; | ||
| 561 | } | ||
| 550 | 562 | ||
| 551 | for (si.modules.items) |*mod| { | 563 | inline fn getNtdllProc( |
| 552 | if (address >= mod.base_address and address < mod.base_address + mod.size) { | 564 | si: *SelfInfo, |
| 553 | return mod; | 565 | comptime proc: std.meta.DeclEnum(windows.ntdll), |
| 566 | ) !@TypeOf(&@field(windows.ntdll, @tagName(proc))) { | ||
| 567 | return if (load_dll_notification_procs) | ||
| 568 | @ptrCast(try si.loadNtdllProc(@tagName(proc))) | ||
| 569 | else | ||
| 570 | &@field(windows.ntdll, @tagName(proc)); | ||
| 571 | } | ||
| 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 | const std = @import("std"); | 614 | const std = @import("std"); |
| ... | @@ -563,12 +617,23 @@ const Allocator = std.mem.Allocator; | ... | @@ -563,12 +617,23 @@ const Allocator = std.mem.Allocator; |
| 563 | const Dwarf = std.debug.Dwarf; | 617 | const Dwarf = std.debug.Dwarf; |
| 564 | const Pdb = std.debug.Pdb; | 618 | const Pdb = std.debug.Pdb; |
| 565 | const Error = std.debug.SelfInfoError; | 619 | const Error = std.debug.SelfInfoError; |
| 566 | const assert = std.debug.assert; | ||
| 567 | const coff = std.coff; | 620 | const coff = std.coff; |
| 568 | const fs = std.fs; | 621 | const fs = std.fs; |
| 569 | const windows = std.os.windows; | 622 | const windows = std.os.windows; |
| 623 | const LDR = windows.LDR; | ||
| 570 | 624 | ||
| 571 | const builtin = @import("builtin"); | 625 | const builtin = @import("builtin"); |
| 572 | const native_endian = builtin.target.cpu.arch.endian(); | 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 | const SelfInfo = @This(); | 639 | const SelfInfo = @This(); |
lib/std/heap.zig+3-3| ... | @@ -110,11 +110,11 @@ pub fn defaultQueryPageSize() usize { | ... | @@ -110,11 +110,11 @@ pub fn defaultQueryPageSize() usize { |
| 110 | break :size @intCast(vm_info.page_size); | 110 | break :size @intCast(vm_info.page_size); |
| 111 | }, | 111 | }, |
| 112 | .windows => { | 112 | .windows => { |
| 113 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | 113 | var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined; |
| 114 | switch (windows.ntdll.NtQuerySystemInformation( | 114 | switch (windows.ntdll.NtQuerySystemInformation( |
| 115 | .SystemBasicInformation, | 115 | .Basic, |
| 116 | &sbi, | 116 | &sbi, |
| 117 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | 117 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), |
| 118 | null, | 118 | null, |
| 119 | )) { | 119 | )) { |
| 120 | .SUCCESS => break :size sbi.PageSize, | 120 | .SUCCESS => break :size sbi.PageSize, |
lib/std/os/windows.zig+569-1126| ... | @@ -24,6 +24,66 @@ pub const nls = @import("windows/nls.zig"); | ... | @@ -24,6 +24,66 @@ pub const nls = @import("windows/nls.zig"); |
| 24 | 24 | ||
| 25 | pub const current_process: HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))); | 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 | pub const FILE = struct { | 87 | pub const FILE = struct { |
| 28 | // ref: km/ntddk.h | 88 | // ref: km/ntddk.h |
| 29 | 89 | ||
| ... | @@ -73,6 +133,94 @@ pub const FILE = struct { | ... | @@ -73,6 +133,94 @@ pub const FILE = struct { |
| 73 | 133 | ||
| 74 | // ref: km/ntifs.h | 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 | pub const PIPE = struct { | 224 | pub const PIPE = struct { |
| 77 | /// Define the `NamedPipeType` flags for `NtCreateNamedPipeFile` | 225 | /// Define the `NamedPipeType` flags for `NtCreateNamedPipeFile` |
| 78 | pub const TYPE = packed struct(ULONG) { | 226 | pub const TYPE = packed struct(ULONG) { |
| ... | @@ -357,6 +505,7 @@ pub const FILE = struct { | ... | @@ -357,6 +505,7 @@ pub const FILE = struct { |
| 357 | IdAllExtdBothDirectory = 81, | 505 | IdAllExtdBothDirectory = 81, |
| 358 | StreamReservation = 82, | 506 | StreamReservation = 82, |
| 359 | MupProvider = 83, | 507 | MupProvider = 83, |
| 508 | _, | ||
| 360 | 509 | ||
| 361 | pub const Maximum: @typeInfo(@This()).@"enum".tag_type = 1 + @typeInfo(@This()).@"enum".fields.len; | 510 | pub const Maximum: @typeInfo(@This()).@"enum".tag_type = 1 + @typeInfo(@This()).@"enum".fields.len; |
| 362 | }; | 511 | }; |
| ... | @@ -647,6 +796,19 @@ pub const FILE = struct { | ... | @@ -647,6 +796,19 @@ pub const FILE = struct { |
| 647 | Mode: MODE, | 796 | Mode: MODE, |
| 648 | }; | 797 | }; |
| 649 | }; | 798 | }; |
| 799 | |||
| 800 | // ref: km/ | ||
| 801 | }; | ||
| 802 | |||
| 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 | pub const CONSOLE = struct { | 814 | pub const CONSOLE = struct { |
| ... | @@ -880,141 +1042,229 @@ pub const CONSOLE = struct { | ... | @@ -880,141 +1042,229 @@ pub const CONSOLE = struct { |
| 880 | 1042 | ||
| 881 | // ref: km/ntddk.h | 1043 | // ref: km/ntddk.h |
| 882 | 1044 | ||
| 883 | pub const PROCESSINFOCLASS = enum(c_int) { | 1045 | pub const SYSTEM = struct { |
| 884 | BasicInformation = 0, | 1046 | pub const INFORMATION_CLASS = enum(c_int) { |
| 885 | QuotaLimits = 1, | 1047 | Basic = 0, |
| 886 | IoCounters = 2, | 1048 | Performance = 2, |
| 887 | VmCounters = 3, | 1049 | TimeOfDay = 3, |
| 888 | Times = 4, | 1050 | Process = 5, |
| 889 | BasePriority = 5, | 1051 | ProcessorPerformance = 8, |
| 890 | RaisePriority = 6, | 1052 | Interrupt = 23, |
| 891 | DebugPort = 7, | 1053 | Exception = 33, |
| 892 | ExceptionPort = 8, | 1054 | RegistryQuota = 37, |
| 893 | AccessToken = 9, | 1055 | Lookaside = 45, |
| 894 | LdtInformation = 10, | 1056 | CodeIntegrity = 103, |
| 895 | LdtSize = 11, | 1057 | Policy = 134, |
| 896 | DefaultHardErrorMode = 12, | 1058 | _, |
| 897 | IoPortHandlers = 13, | 1059 | }; |
| 898 | PooledUsageAndLimits = 14, | 1060 | |
| 899 | WorkingSetWatch = 15, | 1061 | pub const BASIC_INFORMATION = extern struct { |
| 900 | UserModeIOPL = 16, | 1062 | Reserved: ULONG, |
| 901 | EnableAlignmentFaultFixup = 17, | 1063 | TimerResolution: ULONG, |
| 902 | PriorityClass = 18, | 1064 | PageSize: ULONG, |
| 903 | Wx86Information = 19, | 1065 | NumberOfPhysicalPages: ULONG, |
| 904 | HandleCount = 20, | 1066 | LowestPhysicalPageNumber: ULONG, |
| 905 | AffinityMask = 21, | 1067 | HighestPhysicalPageNumber: ULONG, |
| 906 | PriorityBoost = 22, | 1068 | AllocationGranularity: ULONG, |
| 907 | DeviceMap = 23, | 1069 | MinimumUserModeAddress: ULONG_PTR, |
| 908 | SessionInformation = 24, | 1070 | MaximumUserModeAddress: ULONG_PTR, |
| 909 | ForegroundInformation = 25, | 1071 | ActiveProcessorsAffinityMask: KAFFINITY, |
| 910 | Wow64Information = 26, | 1072 | NumberOfProcessors: UCHAR, |
| 911 | ImageFileName = 27, | 1073 | }; |
| 912 | LUIDDeviceMapsEnabled = 28, | 1074 | }; |
| 913 | BreakOnTermination = 29, | 1075 | |
| 914 | DebugObjectHandle = 30, | 1076 | pub const PROCESS = struct { |
| 915 | DebugFlags = 31, | 1077 | pub const INFORMATION = extern struct { |
| 916 | HandleTracing = 32, | 1078 | hProcess: HANDLE, |
| 917 | IoPriority = 33, | 1079 | hThread: HANDLE, |
| 918 | ExecuteFlags = 34, | 1080 | dwProcessId: DWORD, |
| 919 | TlsInformation = 35, | 1081 | dwThreadId: DWORD, |
| 920 | Cookie = 36, | 1082 | }; |
| 921 | ImageInformation = 37, | 1083 | |
| 922 | CycleTime = 38, | 1084 | pub const INFOCLASS = enum(c_int) { |
| 923 | PagePriority = 39, | 1085 | BasicInformation = 0, |
| 924 | InstrumentationCallback = 40, | 1086 | QuotaLimits = 1, |
| 925 | ThreadStackAllocation = 41, | 1087 | IoCounters = 2, |
| 926 | WorkingSetWatchEx = 42, | 1088 | VmCounters = 3, |
| 927 | ImageFileNameWin32 = 43, | 1089 | Times = 4, |
| 928 | ImageFileMapping = 44, | 1090 | BasePriority = 5, |
| 929 | AffinityUpdateMode = 45, | 1091 | RaisePriority = 6, |
| 930 | MemoryAllocationMode = 46, | 1092 | DebugPort = 7, |
| 931 | GroupInformation = 47, | 1093 | ExceptionPort = 8, |
| 932 | TokenVirtualizationEnabled = 48, | 1094 | AccessToken = 9, |
| 933 | OwnerInformation = 49, | 1095 | LdtInformation = 10, |
| 934 | WindowInformation = 50, | 1096 | LdtSize = 11, |
| 935 | HandleInformation = 51, | 1097 | DefaultHardErrorMode = 12, |
| 936 | MitigationPolicy = 52, | 1098 | IoPortHandlers = 13, |
| 937 | DynamicFunctionTableInformation = 53, | 1099 | PooledUsageAndLimits = 14, |
| 938 | HandleCheckingMode = 54, | 1100 | WorkingSetWatch = 15, |
| 939 | KeepAliveCount = 55, | 1101 | UserModeIOPL = 16, |
| 940 | RevokeFileHandles = 56, | 1102 | EnableAlignmentFaultFixup = 17, |
| 941 | WorkingSetControl = 57, | 1103 | PriorityClass = 18, |
| 942 | HandleTable = 58, | 1104 | Wx86Information = 19, |
| 943 | CheckStackExtentsMode = 59, | 1105 | HandleCount = 20, |
| 944 | CommandLineInformation = 60, | 1106 | AffinityMask = 21, |
| 945 | ProtectionInformation = 61, | 1107 | PriorityBoost = 22, |
| 946 | MemoryExhaustion = 62, | 1108 | DeviceMap = 23, |
| 947 | FaultInformation = 63, | 1109 | SessionInformation = 24, |
| 948 | TelemetryIdInformation = 64, | 1110 | ForegroundInformation = 25, |
| 949 | CommitReleaseInformation = 65, | 1111 | Wow64Information = 26, |
| 950 | Reserved1Information = 66, | 1112 | ImageFileName = 27, |
| 951 | Reserved2Information = 67, | 1113 | LUIDDeviceMapsEnabled = 28, |
| 952 | SubsystemProcess = 68, | 1114 | BreakOnTermination = 29, |
| 953 | InPrivate = 70, | 1115 | DebugObjectHandle = 30, |
| 954 | RaiseUMExceptionOnInvalidHandleClose = 71, | 1116 | DebugFlags = 31, |
| 955 | SubsystemInformation = 75, | 1117 | HandleTracing = 32, |
| 956 | Win32kSyscallFilterInformation = 79, | 1118 | IoPriority = 33, |
| 957 | EnergyTrackingState = 82, | 1119 | ExecuteFlags = 34, |
| 958 | NetworkIoCounters = 114, | 1120 | TlsInformation = 35, |
| 959 | _, | 1121 | Cookie = 36, |
| 1122 | ImageInformation = 37, | ||
| 1123 | CycleTime = 38, | ||
| 1124 | PagePriority = 39, | ||
| 1125 | InstrumentationCallback = 40, | ||
| 1126 | ThreadStackAllocation = 41, | ||
| 1127 | WorkingSetWatchEx = 42, | ||
| 1128 | ImageFileNameWin32 = 43, | ||
| 1129 | ImageFileMapping = 44, | ||
| 1130 | AffinityUpdateMode = 45, | ||
| 1131 | MemoryAllocationMode = 46, | ||
| 1132 | GroupInformation = 47, | ||
| 1133 | TokenVirtualizationEnabled = 48, | ||
| 1134 | OwnerInformation = 49, | ||
| 1135 | WindowInformation = 50, | ||
| 1136 | HandleInformation = 51, | ||
| 1137 | MitigationPolicy = 52, | ||
| 1138 | DynamicFunctionTableInformation = 53, | ||
| 1139 | HandleCheckingMode = 54, | ||
| 1140 | KeepAliveCount = 55, | ||
| 1141 | RevokeFileHandles = 56, | ||
| 1142 | WorkingSetControl = 57, | ||
| 1143 | HandleTable = 58, | ||
| 1144 | CheckStackExtentsMode = 59, | ||
| 1145 | CommandLineInformation = 60, | ||
| 1146 | ProtectionInformation = 61, | ||
| 1147 | MemoryExhaustion = 62, | ||
| 1148 | FaultInformation = 63, | ||
| 1149 | TelemetryIdInformation = 64, | ||
| 1150 | CommitReleaseInformation = 65, | ||
| 1151 | Reserved1Information = 66, | ||
| 1152 | Reserved2Information = 67, | ||
| 1153 | SubsystemProcess = 68, | ||
| 1154 | InPrivate = 70, | ||
| 1155 | RaiseUMExceptionOnInvalidHandleClose = 71, | ||
| 1156 | SubsystemInformation = 75, | ||
| 1157 | Win32kSyscallFilterInformation = 79, | ||
| 1158 | EnergyTrackingState = 82, | ||
| 1159 | NetworkIoCounters = 114, | ||
| 1160 | _, | ||
| 1161 | |||
| 1162 | pub const Max: @typeInfo(@This()).@"enum".tag_type = 117; | ||
| 1163 | }; | ||
| 1164 | |||
| 1165 | pub const BASIC_INFORMATION = extern struct { | ||
| 1166 | ExitStatus: NTSTATUS, | ||
| 1167 | PebBaseAddress: *PEB, | ||
| 1168 | AffinityMask: ULONG_PTR, | ||
| 1169 | BasePriority: KPRIORITY, | ||
| 1170 | UniqueProcessId: ULONG_PTR, | ||
| 1171 | InheritedFromUniqueProcessId: ULONG_PTR, | ||
| 1172 | }; | ||
| 1173 | |||
| 1174 | pub const VM_COUNTERS = extern struct { | ||
| 1175 | PeakVirtualSize: SIZE_T, | ||
| 1176 | VirtualSize: SIZE_T, | ||
| 1177 | PageFaultCount: ULONG, | ||
| 1178 | PeakWorkingSetSize: SIZE_T, | ||
| 1179 | WorkingSetSize: SIZE_T, | ||
| 1180 | QuotaPeakPagedPoolUsage: SIZE_T, | ||
| 1181 | QuotaPagedPoolUsage: SIZE_T, | ||
| 1182 | QuotaPeakNonPagedPoolUsage: SIZE_T, | ||
| 1183 | QuotaNonPagedPoolUsage: SIZE_T, | ||
| 1184 | PagefileUsage: SIZE_T, | ||
| 1185 | PeakPagefileUsage: SIZE_T, | ||
| 1186 | }; | ||
| 1187 | }; | ||
| 1188 | |||
| 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) { | 1257 | pub const MEMORY = struct { |
| 965 | BasicInformation = 0, | 1258 | pub const BASIC_INFORMATION = extern struct { |
| 966 | Times = 1, | 1259 | BaseAddress: PVOID, |
| 967 | Priority = 2, | 1260 | AllocationBase: PVOID, |
| 968 | BasePriority = 3, | 1261 | AllocationProtect: DWORD, |
| 969 | AffinityMask = 4, | 1262 | PartitionId: WORD, |
| 970 | ImpersonationToken = 5, | 1263 | RegionSize: SIZE_T, |
| 971 | DescriptorTableEntry = 6, | 1264 | State: DWORD, |
| 972 | EnableAlignmentFaultFixup = 7, | 1265 | Protect: DWORD, |
| 973 | EventPair_Reusable = 8, | 1266 | Type: DWORD, |
| 974 | QuerySetWin32StartAddress = 9, | 1267 | }; |
| 975 | ZeroTlsCell = 10, | ||
| 976 | PerformanceCount = 11, | ||
| 977 | AmILastThread = 12, | ||
| 978 | IdealProcessor = 13, | ||
| 979 | PriorityBoost = 14, | ||
| 980 | SetTlsArrayAddress = 15, | ||
| 981 | IsIoPending = 16, | ||
| 982 | // Windows 2000+ from here | ||
| 983 | HideFromDebugger = 17, | ||
| 984 | // Windows XP+ from here | ||
| 985 | BreakOnTermination = 18, | ||
| 986 | SwitchLegacyState = 19, | ||
| 987 | IsTerminated = 20, | ||
| 988 | // Windows Vista+ from here | ||
| 989 | LastSystemCall = 21, | ||
| 990 | IoPriority = 22, | ||
| 991 | CycleTime = 23, | ||
| 992 | PagePriority = 24, | ||
| 993 | ActualBasePriority = 25, | ||
| 994 | TebInformation = 26, | ||
| 995 | CSwitchMon = 27, | ||
| 996 | // Windows 7+ from here | ||
| 997 | CSwitchPmu = 28, | ||
| 998 | Wow64Context = 29, | ||
| 999 | GroupInformation = 30, | ||
| 1000 | UmsInformation = 31, | ||
| 1001 | CounterProfiling = 32, | ||
| 1002 | IdealProcessorEx = 33, | ||
| 1003 | // Windows 8+ from here | ||
| 1004 | CpuAccountingInformation = 34, | ||
| 1005 | // Windows 8.1+ from here | ||
| 1006 | SuspendCount = 35, | ||
| 1007 | // Windows 10+ from here | ||
| 1008 | HeterogeneousCpuPolicy = 36, | ||
| 1009 | ContainerId = 37, | ||
| 1010 | NameInformation = 38, | ||
| 1011 | SelectedCpuSets = 39, | ||
| 1012 | SystemThreadInformation = 40, | ||
| 1013 | ActualGroupAffinity = 41, | ||
| 1014 | DynamicCodePolicyInfo = 42, | ||
| 1015 | SubsystemInformation = 45, | ||
| 1016 | |||
| 1017 | pub const Max: @typeInfo(@This()).@"enum".tag_type = 60; | ||
| 1018 | }; | 1268 | }; |
| 1019 | 1269 | ||
| 1020 | // ref: km/ntifs.h | 1270 | // ref: km/ntifs.h |
| ... | @@ -2560,48 +2810,6 @@ pub fn GetProcessHeap() ?*HEAP { | ... | @@ -2560,48 +2810,6 @@ pub fn GetProcessHeap() ?*HEAP { |
| 2560 | return peb().ProcessHeap; | 2810 | return peb().ProcessHeap; |
| 2561 | } | 2811 | } |
| 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 | // ref none | 2813 | // ref none |
| 2606 | 2814 | ||
| 2607 | pub fn GetCurrentProcess() HANDLE { | 2815 | pub fn GetCurrentProcess() HANDLE { |
| ... | @@ -2623,297 +2831,13 @@ pub fn GetCurrentThreadId() DWORD { | ... | @@ -2623,297 +2831,13 @@ pub fn GetCurrentThreadId() DWORD { |
| 2623 | } | 2831 | } |
| 2624 | 2832 | ||
| 2625 | pub fn GetLastError() Win32Error { | 2833 | pub fn GetLastError() Win32Error { |
| 2626 | return @enumFromInt(teb().LastErrorValue); | 2834 | return teb().LastErrorValue; |
| 2627 | } | ||
| 2628 | /// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls. | ||
| 2629 | /// It implements similar behavior to `DeviceIoControl` and is meant to serve | ||
| 2630 | /// as a direct substitute for that call. | ||
| 2631 | /// TODO work out if we need to expose other arguments to the underlying syscalls. | ||
| 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; | ||
| 2789 | } | 2835 | } |
| 2790 | 2836 | ||
| 2791 | pub fn CloseHandle(hObject: HANDLE) void { | 2837 | pub fn CloseHandle(hObject: HANDLE) void { |
| 2792 | assert(ntdll.NtClose(hObject) == .SUCCESS); | 2838 | switch (ntdll.NtClose(hObject)) { |
| 2793 | } | 2839 | .SUCCESS => {}, |
| 2794 | 2840 | else => |status| unexpectedStatus(status) catch {}, | |
| 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 | }; | ||
| 2917 | } | 2841 | } |
| 2918 | } | 2842 | } |
| 2919 | 2843 | ||
| ... | @@ -2963,114 +2887,75 @@ pub const CreateProcessFlags = packed struct(u32) { | ... | @@ -2963,114 +2887,75 @@ pub const CreateProcessFlags = packed struct(u32) { |
| 2963 | create_ignore_system_default: bool = false, | 2887 | create_ignore_system_default: bool = false, |
| 2964 | }; | 2888 | }; |
| 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 | pub fn teb() *TEB { | 2890 | pub fn teb() *TEB { |
| 3040 | return switch (native_arch) { | 2891 | if (builtin.zig_backend == .stage2_c) return @ptrCast(@alignCast(struct { |
| 3041 | .thumb => if (builtin.zig_backend == .stage2_c) | 2892 | /// This is a workaround for the C backend until zig has the ability to put |
| 3042 | @ptrCast(@alignCast(zig_thumb_windows_teb())) | 2893 | /// C code in inline assembly. |
| 3043 | else | 2894 | extern fn zig_windows_teb() callconv(.c) *anyopaque; |
| 3044 | asm ( | 2895 | }.zig_windows_teb())); |
| 3045 | \\ mrc p15, 0, %[ptr], c13, c0, 2 | 2896 | switch (native_arch) { |
| 3046 | : [ptr] "=r" (-> *TEB), | 2897 | .thumb => return asm ( |
| 3047 | ), | 2898 | \\ mrc p15, 0, %[ptr], c13, c0, 2 |
| 3048 | .aarch64 => if (builtin.zig_backend == .stage2_c) | 2899 | : [ptr] "=r" (-> *TEB), |
| 3049 | @ptrCast(@alignCast(zig_aarch64_windows_teb())) | 2900 | ), |
| 3050 | else | 2901 | .aarch64 => return asm ( |
| 3051 | asm ( | 2902 | \\ mov %[ptr], x18 |
| 3052 | \\ mov %[ptr], x18 | 2903 | : [ptr] "=r" (-> *TEB), |
| 3053 | : [ptr] "=r" (-> *TEB), | 2904 | ), |
| 3054 | ), | 2905 | .x86 => { |
| 3055 | .x86 => if (builtin.zig_backend == .stage2_c) | 2906 | comptime assert( |
| 3056 | @ptrCast(@alignCast(zig_x86_windows_teb())) | 2907 | @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x18, |
| 3057 | else | 2908 | ); |
| 3058 | asm ( | 2909 | return asm ( |
| 3059 | \\ movl %%fs:0x18, %[ptr] | 2910 | \\ movl %%fs:0x18, %[ptr] |
| 3060 | : [ptr] "=r" (-> *TEB), | 2911 | : [ptr] "=r" (-> *TEB), |
| 3061 | ), | 2912 | ); |
| 3062 | .x86_64 => if (builtin.zig_backend == .stage2_c) | 2913 | }, |
| 3063 | @ptrCast(@alignCast(zig_x86_64_windows_teb())) | 2914 | .x86_64 => { |
| 3064 | else | 2915 | comptime assert( |
| 3065 | asm ( | 2916 | @offsetOf(TEB, "NtTib") + @offsetOf(@FieldType(TEB, "NtTib"), "Self") == 0x30, |
| 2917 | ); | ||
| 2918 | return asm ( | ||
| 3066 | \\ movq %%gs:0x30, %[ptr] | 2919 | \\ movq %%gs:0x30, %[ptr] |
| 3067 | : [ptr] "=r" (-> *TEB), | 2920 | : [ptr] "=r" (-> *TEB), |
| 3068 | ), | 2921 | ); |
| 2922 | }, | ||
| 3069 | else => @compileError("unsupported arch"), | 2923 | else => @compileError("unsupported arch"), |
| 3070 | }; | 2924 | } |
| 3071 | } | 2925 | } |
| 3072 | 2926 | ||
| 3073 | pub fn peb() *PEB { | 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 | return teb().ProcessEnvironmentBlock; | 2959 | return teb().ProcessEnvironmentBlock; |
| 3075 | } | 2960 | } |
| 3076 | 2961 | ||
| ... | @@ -3089,20 +2974,6 @@ pub fn toSysTime(ns: Io.Timestamp) i64 { | ... | @@ -3089,20 +2974,6 @@ pub fn toSysTime(ns: Io.Timestamp) i64 { |
| 3089 | return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100); | 2974 | return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100); |
| 3090 | } | 2975 | } |
| 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 | /// Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a | 2977 | /// Use RtlUpcaseUnicodeChar on Windows when not in comptime to avoid including a |
| 3107 | /// redundant copy of the uppercase data. | 2978 | /// redundant copy of the uppercase data. |
| 3108 | pub inline fn toUpperWtf16(c: u16) u16 { | 2979 | pub inline fn toUpperWtf16(c: u16) u16 { |
| ... | @@ -3126,7 +2997,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { | ... | @@ -3126,7 +2997,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { |
| 3126 | // endianness for the uppercasing | 2997 | // endianness for the uppercasing |
| 3127 | const a_c_native = std.mem.littleToNative(u16, a_c); | 2998 | const a_c_native = std.mem.littleToNative(u16, a_c); |
| 3128 | const b_c_native = std.mem.littleToNative(u16, b_c); | 2999 | const b_c_native = std.mem.littleToNative(u16, b_c); |
| 3129 | if (a_c != b_c and nls.upcaseW(a_c_native) != nls.upcaseW(b_c_native)) { | 3000 | if (a_c != b_c and toUpperWtf16(a_c_native) != toUpperWtf16(b_c_native)) { |
| 3130 | return false; | 3001 | return false; |
| 3131 | } | 3002 | } |
| 3132 | } | 3003 | } |
| ... | @@ -3134,19 +3005,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { | ... | @@ -3134,19 +3005,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool { |
| 3134 | } | 3005 | } |
| 3135 | // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a | 3006 | // Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a |
| 3136 | // redundant copy of the uppercase data. | 3007 | // redundant copy of the uppercase data. |
| 3137 | const a_bytes = @as(u16, @intCast(a.len * 2)); | 3008 | return ntdll.RtlEqualUnicodeString(&.init(a), &.init(b), TRUE) == TRUE; |
| 3138 | const a_string: UNICODE_STRING = .{ | ||
| 3139 | .Length = a_bytes, | ||
| 3140 | .MaximumLength = a_bytes, | ||
| 3141 | .Buffer = @constCast(a.ptr), | ||
| 3142 | }; | ||
| 3143 | const b_bytes = @as(u16, @intCast(b.len * 2)); | ||
| 3144 | const b_string: UNICODE_STRING = .{ | ||
| 3145 | .Length = b_bytes, | ||
| 3146 | .MaximumLength = b_bytes, | ||
| 3147 | .Buffer = @constCast(b.ptr), | ||
| 3148 | }; | ||
| 3149 | return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE; | ||
| 3150 | } | 3009 | } |
| 3151 | 3010 | ||
| 3152 | /// Compares two WTF-8 strings using the equivalent functionality of | 3011 | /// Compares two WTF-8 strings using the equivalent functionality of |
| ... | @@ -3464,13 +3323,10 @@ pub const LONG = i32; | ... | @@ -3464,13 +3323,10 @@ pub const LONG = i32; |
| 3464 | pub const ULONG64 = u64; | 3323 | pub const ULONG64 = u64; |
| 3465 | pub const ULONGLONG = u64; | 3324 | pub const ULONGLONG = u64; |
| 3466 | pub const LONGLONG = i64; | 3325 | pub const LONGLONG = i64; |
| 3467 | pub const HLOCAL = HANDLE; | ||
| 3468 | pub const LANGID = c_ushort; | 3326 | pub const LANGID = c_ushort; |
| 3469 | pub const COLORREF = DWORD; | 3327 | pub const COLORREF = DWORD; |
| 3470 | 3328 | ||
| 3471 | pub const WPARAM = usize; | ||
| 3472 | pub const LPARAM = LONG_PTR; | 3329 | pub const LPARAM = LONG_PTR; |
| 3473 | pub const LRESULT = LONG_PTR; | ||
| 3474 | 3330 | ||
| 3475 | pub const va_list = *opaque {}; | 3331 | pub const va_list = *opaque {}; |
| 3476 | 3332 | ||
| ... | @@ -3480,6 +3336,40 @@ pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWS | ... | @@ -3480,6 +3336,40 @@ pub const LPCTSTR = @compileError("Deprecated: choose between `LPCSTR` or `LPCWS |
| 3480 | pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead."); | 3336 | pub const PTSTR = @compileError("Deprecated: choose between `PSTR` or `PWSTR` directly instead."); |
| 3481 | pub const PCTSTR = @compileError("Deprecated: choose between `PCSTR` or `PCWSTR` directly instead."); | 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 | pub const TRUE = 1; | 3373 | pub const TRUE = 1; |
| 3484 | pub const FALSE = 0; | 3374 | pub const FALSE = 0; |
| 3485 | 3375 | ||
| ... | @@ -3509,111 +3399,14 @@ pub const OVERLAPPED = extern struct { | ... | @@ -3509,111 +3399,14 @@ pub const OVERLAPPED = extern struct { |
| 3509 | hEvent: ?HANDLE, | 3399 | hEvent: ?HANDLE, |
| 3510 | }; | 3400 | }; |
| 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 | pub const MAX_PATH = 260; | 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 | pub const SECURITY_ATTRIBUTES = extern struct { | 3404 | pub const SECURITY_ATTRIBUTES = extern struct { |
| 3582 | nLength: DWORD, | 3405 | nLength: DWORD, |
| 3583 | lpSecurityDescriptor: ?*anyopaque, | 3406 | lpSecurityDescriptor: ?*anyopaque, |
| 3584 | bInheritHandle: BOOL, | 3407 | bInheritHandle: BOOL, |
| 3585 | }; | 3408 | }; |
| 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 | pub const STARTUPINFOW = extern struct { | 3410 | pub const STARTUPINFOW = extern struct { |
| 3618 | cb: DWORD, | 3411 | cb: DWORD, |
| 3619 | lpReserved: ?LPWSTR, | 3412 | lpReserved: ?LPWSTR, |
| ... | @@ -3650,50 +3443,7 @@ pub const STARTF_USESHOWWINDOW = 0x00000001; | ... | @@ -3650,50 +3443,7 @@ pub const STARTF_USESHOWWINDOW = 0x00000001; |
| 3650 | pub const STARTF_USESIZE = 0x00000002; | 3443 | pub const STARTF_USESIZE = 0x00000002; |
| 3651 | pub const STARTF_USESTDHANDLES = 0x00000100; | 3444 | pub const STARTF_USESTDHANDLES = 0x00000100; |
| 3652 | 3445 | ||
| 3653 | pub const INFINITE = 4294967295; | 3446 | pub const THREAD_START_ROUTINE = fn (LPVOID) callconv(.winapi) DWORD; |
| 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 | }; | ||
| 3697 | 3447 | ||
| 3698 | pub const SYSTEM_INFO = extern struct { | 3448 | pub const SYSTEM_INFO = extern struct { |
| 3699 | anon1: extern union { | 3449 | anon1: extern union { |
| ... | @@ -3716,7 +3466,6 @@ pub const SYSTEM_INFO = extern struct { | ... | @@ -3716,7 +3466,6 @@ pub const SYSTEM_INFO = extern struct { |
| 3716 | 3466 | ||
| 3717 | pub const HRESULT = c_long; | 3467 | pub const HRESULT = c_long; |
| 3718 | 3468 | ||
| 3719 | pub const KNOWNFOLDERID = GUID; | ||
| 3720 | pub const GUID = extern struct { | 3469 | pub const GUID = extern struct { |
| 3721 | Data1: u32, | 3470 | Data1: u32, |
| 3722 | Data2: u16, | 3471 | Data2: u16, |
| ... | @@ -3771,75 +3520,11 @@ test GUID { | ... | @@ -3771,75 +3520,11 @@ test GUID { |
| 3771 | ); | 3520 | ); |
| 3772 | } | 3521 | } |
| 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 | pub const COORD = extern struct { | 3523 | pub const COORD = extern struct { |
| 3837 | X: SHORT, | 3524 | X: SHORT, |
| 3838 | Y: SHORT, | 3525 | Y: SHORT, |
| 3839 | }; | 3526 | }; |
| 3840 | 3527 | ||
| 3841 | pub const CREATE_UNICODE_ENVIRONMENT = 1024; | ||
| 3842 | |||
| 3843 | pub const TLS_OUT_OF_INDEXES = 4294967295; | 3528 | pub const TLS_OUT_OF_INDEXES = 4294967295; |
| 3844 | pub const IMAGE_TLS_DIRECTORY = extern struct { | 3529 | pub const IMAGE_TLS_DIRECTORY = extern struct { |
| 3845 | StartAddressOfRawData: usize, | 3530 | StartAddressOfRawData: usize, |
| ... | @@ -3854,8 +3539,6 @@ pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; | ... | @@ -3854,8 +3539,6 @@ pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; |
| 3854 | 3539 | ||
| 3855 | pub const PIMAGE_TLS_CALLBACK = ?*const fn (PVOID, DWORD, PVOID) callconv(.winapi) void; | 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 | pub const REGSAM = ACCESS_MASK; | 3542 | pub const REGSAM = ACCESS_MASK; |
| 3860 | pub const LSTATUS = LONG; | 3543 | pub const LSTATUS = LONG; |
| 3861 | 3544 | ||
| ... | @@ -3872,9 +3555,6 @@ pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005); | ... | @@ -3872,9 +3555,6 @@ pub const HKEY_CURRENT_CONFIG: HKEY = @ptrFromInt(0x80000005); |
| 3872 | pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006); | 3555 | pub const HKEY_DYN_DATA: HKEY = @ptrFromInt(0x80000006); |
| 3873 | pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = @ptrFromInt(0x80000007); | 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 | pub const RTL_QUERY_REGISTRY_TABLE = extern struct { | 3558 | pub const RTL_QUERY_REGISTRY_TABLE = extern struct { |
| 3879 | QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE, | 3559 | QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE, |
| 3880 | Flags: ULONG, | 3560 | Flags: ULONG, |
| ... | @@ -3975,38 +3655,6 @@ pub const REG = struct { | ... | @@ -3975,38 +3655,6 @@ pub const REG = struct { |
| 3975 | pub const QWORD_LITTLE_ENDIAN: ULONG = 11; | 3655 | pub const QWORD_LITTLE_ENDIAN: ULONG = 11; |
| 3976 | }; | 3656 | }; |
| 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 | pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4; | 3658 | pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4; |
| 4011 | pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8; | 3659 | pub const DISABLE_NEWLINE_AUTO_RETURN = 0x8; |
| 4012 | 3660 | ||
| ... | @@ -4056,26 +3704,6 @@ pub const RTL_RUN_ONCE = extern struct { | ... | @@ -4056,26 +3704,6 @@ pub const RTL_RUN_ONCE = extern struct { |
| 4056 | 3704 | ||
| 4057 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null }; | 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 | /// > The maximum path of 32,767 characters is approximate, because the "\\?\" | 3707 | /// > The maximum path of 32,767 characters is approximate, because the "\\?\" |
| 4080 | /// > prefix may be expanded to a longer string by the system at run time, and | 3708 | /// > prefix may be expanded to a longer string by the system at run time, and |
| 4081 | /// > this expansion applies to the total length. | 3709 | /// > this expansion applies to the total length. |
| ... | @@ -4544,14 +4172,6 @@ pub const UNW_FLAG_EHANDLER = 0x1; | ... | @@ -4544,14 +4172,6 @@ pub const UNW_FLAG_EHANDLER = 0x1; |
| 4544 | pub const UNW_FLAG_UHANDLER = 0x2; | 4172 | pub const UNW_FLAG_UHANDLER = 0x2; |
| 4545 | pub const UNW_FLAG_CHAININFO = 0x4; | 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 | pub const ACTIVATION_CONTEXT_DATA = opaque {}; | 4175 | pub const ACTIVATION_CONTEXT_DATA = opaque {}; |
| 4556 | pub const ASSEMBLY_STORAGE_MAP = opaque {}; | 4176 | pub const ASSEMBLY_STORAGE_MAP = opaque {}; |
| 4557 | pub const FLS_CALLBACK_INFO = opaque {}; | 4177 | pub const FLS_CALLBACK_INFO = opaque {}; |
| ... | @@ -4564,15 +4184,6 @@ pub const CLIENT_ID = extern struct { | ... | @@ -4564,15 +4184,6 @@ pub const CLIENT_ID = extern struct { |
| 4564 | UniqueThread: HANDLE, | 4184 | UniqueThread: HANDLE, |
| 4565 | }; | 4185 | }; |
| 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 | pub const TEB = extern struct { | 4187 | pub const TEB = extern struct { |
| 4577 | NtTib: NT_TIB, | 4188 | NtTib: NT_TIB, |
| 4578 | EnvironmentPointer: PVOID, | 4189 | EnvironmentPointer: PVOID, |
| ... | @@ -4580,7 +4191,7 @@ pub const TEB = extern struct { | ... | @@ -4580,7 +4191,7 @@ pub const TEB = extern struct { |
| 4580 | ActiveRpcHandle: PVOID, | 4191 | ActiveRpcHandle: PVOID, |
| 4581 | ThreadLocalStoragePointer: PVOID, | 4192 | ThreadLocalStoragePointer: PVOID, |
| 4582 | ProcessEnvironmentBlock: *PEB, | 4193 | ProcessEnvironmentBlock: *PEB, |
| 4583 | LastErrorValue: ULONG, | 4194 | LastErrorValue: Win32Error, |
| 4584 | Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8, | 4195 | Reserved2: [399 * @sizeOf(PVOID) - @sizeOf(ULONG)]u8, |
| 4585 | Reserved3: [1952]u8, | 4196 | Reserved3: [1952]u8, |
| 4586 | TlsSlots: [64]PVOID, | 4197 | TlsSlots: [64]PVOID, |
| ... | @@ -4793,7 +4404,7 @@ pub const PEB = extern struct { | ... | @@ -4793,7 +4404,7 @@ pub const PEB = extern struct { |
| 4793 | }; | 4404 | }; |
| 4794 | 4405 | ||
| 4795 | /// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process. | 4406 | /// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process. |
| 4796 | /// It is essentially the head of three double-linked lists of `LDR_DATA_TABLE_ENTRY` structures which each represent one loaded module. | 4407 | /// It is essentially the head of three double-linked lists of `LDR.DATA_TABLE_ENTRY` structures which each represent one loaded module. |
| 4797 | /// | 4408 | /// |
| 4798 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: | 4409 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: |
| 4799 | /// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm | 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,24 +4436,89 @@ pub const PEB_LDR_DATA = extern struct { |
| 4825 | ShutdownThreadId: HANDLE, | 4436 | ShutdownThreadId: HANDLE, |
| 4826 | }; | 4437 | }; |
| 4827 | 4438 | ||
| 4828 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: | 4439 | pub const LDR = struct { |
| 4829 | /// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data | 4440 | /// Microsoft documentation of this is incomplete, the fields here are taken from various resources including: |
| 4830 | /// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm | 4441 | /// - https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data |
| 4831 | pub const LDR_DATA_TABLE_ENTRY = extern struct { | 4442 | /// - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm |
| 4832 | InLoadOrderLinks: LIST_ENTRY, | 4443 | pub const DATA_TABLE_ENTRY = extern struct { |
| 4833 | InMemoryOrderLinks: LIST_ENTRY, | 4444 | InLoadOrderLinks: LIST_ENTRY, |
| 4834 | InInitializationOrderLinks: LIST_ENTRY, | 4445 | InMemoryOrderLinks: LIST_ENTRY, |
| 4835 | DllBase: PVOID, | 4446 | InInitializationOrderLinks: LIST_ENTRY, |
| 4836 | EntryPoint: PVOID, | 4447 | DllBase: PVOID, |
| 4837 | SizeOfImage: ULONG, | 4448 | EntryPoint: PVOID, |
| 4838 | FullDllName: UNICODE_STRING, | 4449 | SizeOfImage: ULONG, |
| 4839 | BaseDllName: UNICODE_STRING, | 4450 | FullDllName: UNICODE_STRING, |
| 4840 | Reserved5: [3]PVOID, | 4451 | BaseDllName: UNICODE_STRING, |
| 4841 | DUMMYUNIONNAME: extern union { | 4452 | Reserved5: [3]PVOID, |
| 4842 | CheckSum: ULONG, | 4453 | DUMMYUNIONNAME: extern union { |
| 4843 | Reserved6: PVOID, | 4454 | CheckSum: ULONG, |
| 4844 | }, | 4455 | Reserved6: PVOID, |
| 4845 | TimeDateStamp: ULONG, | 4456 | }, |
| 4457 | TimeDateStamp: ULONG, | ||
| 4458 | }; | ||
| 4459 | |||
| 4460 | pub const DLL_NOTIFICATION = struct { | ||
| 4461 | pub const REASON = enum(ULONG) { LOADED = 1, UNLOADED = 2 }; | ||
| 4462 | |||
| 4463 | pub const DATA = extern union { | ||
| 4464 | Loaded: LOADED, | ||
| 4465 | Unloaded: UNLOADED, | ||
| 4466 | |||
| 4467 | pub const LOADED = extern struct { | ||
| 4468 | Flags: REGISTER, | ||
| 4469 | FullDllName: *const UNICODE_STRING, | ||
| 4470 | BaseDllName: *const UNICODE_STRING, | ||
| 4471 | DllBase: PVOID, | ||
| 4472 | SizeOfImage: ULONG, | ||
| 4473 | }; | ||
| 4474 | |||
| 4475 | pub const UNLOADED = extern struct { | ||
| 4476 | Flags: REGISTER, | ||
| 4477 | FullDllName: *const UNICODE_STRING, | ||
| 4478 | BaseDllName: *const UNICODE_STRING, | ||
| 4479 | DllBase: PVOID, | ||
| 4480 | SizeOfImage: ULONG, | ||
| 4481 | }; | ||
| 4482 | }; | ||
| 4483 | |||
| 4484 | pub const COOKIE = *opaque {}; | ||
| 4485 | |||
| 4486 | pub const FUNCTION = fn ( | ||
| 4487 | NotificationReason: REASON, | ||
| 4488 | NotificationData: *const DATA, | ||
| 4489 | Context: ?PVOID, | ||
| 4490 | ) callconv(.winapi) void; | ||
| 4491 | |||
| 4492 | pub const REGISTER = packed struct(ULONG) { | ||
| 4493 | Reserved0: u32 = 0, | ||
| 4494 | }; | ||
| 4495 | }; | ||
| 4496 | |||
| 4497 | pub const GET_DLL_HANDLE_EX = packed struct(ULONG) { | ||
| 4498 | UNCHANGED_REFCOUNT: bool = false, | ||
| 4499 | PIN: bool = false, | ||
| 4500 | Reserved2: u30 = 0, | ||
| 4501 | }; | ||
| 4502 | |||
| 4503 | pub const GET_PROCEDURE_ADDRESS = packed struct(ULONG) { | ||
| 4504 | DONT_RECORD_FORWARDER: bool = false, | ||
| 4505 | Reserved1: u31 = 0, | ||
| 4506 | }; | ||
| 4507 | |||
| 4508 | pub const LOAD = packed struct(ULONG) { | ||
| 4509 | DONT_RESOLVE_DLL_REFERENCES: bool = false, | ||
| 4510 | LIBRARY_AS_DATAFILE: bool = false, | ||
| 4511 | PACKAGED_LIBRARY: bool = false, | ||
| 4512 | WITH_ALTERED_SEARCH_PATH: bool = false, | ||
| 4513 | IGNORE_CODE_AUTHZ_LEVEL: bool = false, | ||
| 4514 | LIBRARY_AS_IMAGE_RESOURCE: bool = false, | ||
| 4515 | LIBRARY_AS_DATAFILE_EXCLUSIVE: bool = false, | ||
| 4516 | LIBRARY_REQUERE_SIGNED_TARGET: bool = false, | ||
| 4517 | LIBRARY_SEARCH_DLL_LOAD_DIR: bool = false, | ||
| 4518 | LIBRARY_SEARCH_USER_DIRS: bool = false, | ||
| 4519 | LIBRARY_SEARCH_SYSTEM32: bool = false, | ||
| 4520 | LIBRARY_SEARCH_DEFAULT_DIRS: bool = false, | ||
| 4521 | }; | ||
| 4846 | }; | 4522 | }; |
| 4847 | 4523 | ||
| 4848 | pub const RTL_USER_PROCESS_PARAMETERS = extern struct { | 4524 | pub const RTL_USER_PROCESS_PARAMETERS = extern struct { |
| ... | @@ -4956,86 +4632,6 @@ pub const MODULEINFO = extern struct { | ... | @@ -4956,86 +4632,6 @@ pub const MODULEINFO = extern struct { |
| 4956 | EntryPoint: LPVOID, | 4632 | EntryPoint: LPVOID, |
| 4957 | }; | 4633 | }; |
| 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 | pub const OSVERSIONINFOW = extern struct { | 4635 | pub const OSVERSIONINFOW = extern struct { |
| 5040 | dwOSVersionInfoSize: ULONG, | 4636 | dwOSVersionInfoSize: ULONG, |
| 5041 | dwMajorVersion: ULONG, | 4637 | dwMajorVersion: ULONG, |
| ... | @@ -5098,20 +4694,6 @@ pub const MOUNTMGR_VOLUME_PATHS = extern struct { | ... | @@ -5098,20 +4694,6 @@ pub const MOUNTMGR_VOLUME_PATHS = extern struct { |
| 5098 | MultiSz: [1]WCHAR, | 4694 | MultiSz: [1]WCHAR, |
| 5099 | }; | 4695 | }; |
| 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 | pub const SRWLOCK_INIT = SRWLOCK{}; | 4697 | pub const SRWLOCK_INIT = SRWLOCK{}; |
| 5116 | pub const SRWLOCK = extern struct { | 4698 | pub const SRWLOCK = extern struct { |
| 5117 | Ptr: ?PVOID = null, | 4699 | Ptr: ?PVOID = null, |
| ... | @@ -5122,17 +4704,6 @@ pub const CONDITION_VARIABLE = extern struct { | ... | @@ -5122,17 +4704,6 @@ pub const CONDITION_VARIABLE = extern struct { |
| 5122 | Ptr: ?PVOID = null, | 4704 | Ptr: ?PVOID = null, |
| 5123 | }; | 4705 | }; |
| 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 | /// Processor feature enumeration. | 4707 | /// Processor feature enumeration. |
| 5137 | pub const PF = enum(DWORD) { | 4708 | pub const PF = enum(DWORD) { |
| 5138 | /// On a Pentium, a floating-point precision error can occur in rare circumstances. | 4709 | /// On a Pentium, a floating-point precision error can occur in rare circumstances. |
| ... | @@ -5431,72 +5002,13 @@ pub const KUSER_SHARED_DATA = extern struct { | ... | @@ -5431,72 +5002,13 @@ pub const KUSER_SHARED_DATA = extern struct { |
| 5431 | /// Read-only user-mode address for the shared data. | 5002 | /// Read-only user-mode address for the shared data. |
| 5432 | /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm | 5003 | /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm |
| 5433 | /// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/ | 5004 | /// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/ |
| 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 | pub fn IsProcessorFeaturePresent(feature: PF) bool { | 5007 | pub fn IsProcessorFeaturePresent(feature: PF) bool { |
| 5437 | if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false; | 5008 | if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false; |
| 5438 | return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1; | 5009 | return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1; |
| 5439 | } | 5010 | } |
| 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 | // https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L983 | 5012 | // https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L983 |
| 5501 | pub const KERNEL_USER_TIMES = extern struct { | 5013 | pub const KERNEL_USER_TIMES = extern struct { |
| 5502 | CreationTime: LARGE_INTEGER, | 5014 | CreationTime: LARGE_INTEGER, |
| ... | @@ -5505,75 +5017,6 @@ pub const KERNEL_USER_TIMES = extern struct { | ... | @@ -5505,75 +5017,6 @@ pub const KERNEL_USER_TIMES = extern struct { |
| 5505 | UserTime: LARGE_INTEGER, | 5017 | UserTime: LARGE_INTEGER, |
| 5506 | }; | 5018 | }; |
| 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 | pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize { | 5020 | pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize { |
| 5578 | // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE. | 5021 | // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE. |
| 5579 | if (wtf16le.len < wtf8.len) { | 5022 | if (wtf16le.len < wtf8.len) { |
lib/std/os/windows/kernel32.zig+4-197| ... | @@ -1,154 +1,29 @@ | ... | @@ -1,154 +1,29 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | const std = @import("../../std.zig"); |
| 2 | const windows = std.os.windows; | 2 | const windows = std.os.windows; |
| 3 | 3 | ||
| 4 | const ACCESS_MASK = windows.ACCESS_MASK; | ||
| 5 | const BOOL = windows.BOOL; | 4 | const BOOL = windows.BOOL; |
| 6 | const CONDITION_VARIABLE = windows.CONDITION_VARIABLE; | ||
| 7 | const COORD = windows.COORD; | ||
| 8 | const DWORD = windows.DWORD; | 5 | const DWORD = windows.DWORD; |
| 9 | const FARPROC = windows.FARPROC; | ||
| 10 | const FILETIME = windows.FILETIME; | ||
| 11 | const HANDLE = windows.HANDLE; | 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 | const LPCVOID = windows.LPCVOID; | 7 | const LPCVOID = windows.LPCVOID; |
| 17 | const LPCWSTR = windows.LPCWSTR; | 8 | const LPCWSTR = windows.LPCWSTR; |
| 18 | const LPTHREAD_START_ROUTINE = windows.LPTHREAD_START_ROUTINE; | ||
| 19 | const LPVOID = windows.LPVOID; | 9 | const LPVOID = windows.LPVOID; |
| 20 | const LPWSTR = windows.LPWSTR; | 10 | const LPWSTR = windows.LPWSTR; |
| 21 | const MODULEENTRY32 = windows.MODULEENTRY32; | 11 | const PROCESS = windows.PROCESS; |
| 22 | const OVERLAPPED = windows.OVERLAPPED; | 12 | const THREAD_START_ROUTINE = windows.THREAD_START_ROUTINE; |
| 23 | const OVERLAPPED_ENTRY = windows.OVERLAPPED_ENTRY; | ||
| 24 | const PROCESS_INFORMATION = windows.PROCESS_INFORMATION; | ||
| 25 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; | 13 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; |
| 26 | const SIZE_T = windows.SIZE_T; | 14 | const SIZE_T = windows.SIZE_T; |
| 27 | const SRWLOCK = windows.SRWLOCK; | ||
| 28 | const STARTUPINFOW = windows.STARTUPINFOW; | 15 | const STARTUPINFOW = windows.STARTUPINFOW; |
| 29 | const SYSTEM_INFO = windows.SYSTEM_INFO; | ||
| 30 | const UCHAR = windows.UCHAR; | ||
| 31 | const UINT = windows.UINT; | 16 | const UINT = windows.UINT; |
| 32 | const ULONG = windows.ULONG; | ||
| 33 | const ULONG_PTR = windows.ULONG_PTR; | ||
| 34 | const va_list = windows.va_list; | 17 | const va_list = windows.va_list; |
| 35 | const WCHAR = windows.WCHAR; | ||
| 36 | const Win32Error = windows.Win32Error; | 18 | const Win32Error = windows.Win32Error; |
| 37 | const WORD = windows.WORD; | ||
| 38 | 19 | ||
| 39 | // I/O - Filesystem | 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 | pub extern "kernel32" fn GetSystemDirectoryW( | 22 | pub extern "kernel32" fn GetSystemDirectoryW( |
| 97 | lpBuffer: LPWSTR, | 23 | lpBuffer: LPWSTR, |
| 98 | uSize: UINT, | 24 | uSize: UINT, |
| 99 | ) callconv(.winapi) UINT; | 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 | // Process Management | 27 | // Process Management |
| 153 | 28 | ||
| 154 | pub extern "kernel32" fn CreateProcessW( | 29 | pub extern "kernel32" fn CreateProcessW( |
| ... | @@ -161,86 +36,21 @@ pub extern "kernel32" fn CreateProcessW( | ... | @@ -161,86 +36,21 @@ pub extern "kernel32" fn CreateProcessW( |
| 161 | lpEnvironment: ?[*:0]const u16, | 36 | lpEnvironment: ?[*:0]const u16, |
| 162 | lpCurrentDirectory: ?LPCWSTR, | 37 | lpCurrentDirectory: ?LPCWSTR, |
| 163 | lpStartupInfo: *STARTUPINFOW, | 38 | lpStartupInfo: *STARTUPINFOW, |
| 164 | lpProcessInformation: *PROCESS_INFORMATION, | 39 | lpProcessInformation: *PROCESS.INFORMATION, |
| 165 | ) callconv(.winapi) BOOL; | ||
| 166 | |||
| 167 | // TODO: Wrapper around NtQueryInformationProcess with `PROCESS_BASIC_INFORMATION`. | ||
| 168 | pub extern "kernel32" fn GetExitCodeProcess( | ||
| 169 | hProcess: HANDLE, | ||
| 170 | lpExitCode: *DWORD, | ||
| 171 | ) callconv(.winapi) BOOL; | 40 | ) callconv(.winapi) BOOL; |
| 172 | 41 | ||
| 173 | pub extern "kernel32" fn CreateToolhelp32Snapshot( | ||
| 174 | dwFlags: DWORD, | ||
| 175 | th32ProcessID: DWORD, | ||
| 176 | ) callconv(.winapi) HANDLE; | ||
| 177 | |||
| 178 | // Threading | 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 | // TODO: CreateRemoteThread with hProcess=NtCurrentProcess(). | 44 | // TODO: CreateRemoteThread with hProcess=NtCurrentProcess(). |
| 184 | pub extern "kernel32" fn CreateThread( | 45 | pub extern "kernel32" fn CreateThread( |
| 185 | lpThreadAttributes: ?*SECURITY_ATTRIBUTES, | 46 | lpThreadAttributes: ?*SECURITY_ATTRIBUTES, |
| 186 | dwStackSize: SIZE_T, | 47 | dwStackSize: SIZE_T, |
| 187 | lpStartAddress: LPTHREAD_START_ROUTINE, | 48 | lpStartAddress: *const THREAD_START_ROUTINE, |
| 188 | lpParameter: ?LPVOID, | 49 | lpParameter: ?LPVOID, |
| 189 | dwCreationFlags: DWORD, | 50 | dwCreationFlags: DWORD, |
| 190 | lpThreadId: ?*DWORD, | 51 | lpThreadId: ?*DWORD, |
| 191 | ) callconv(.winapi) ?HANDLE; | 52 | ) callconv(.winapi) ?HANDLE; |
| 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 | // Error Management | 54 | // Error Management |
| 245 | 55 | ||
| 246 | pub extern "kernel32" fn FormatMessageW( | 56 | pub extern "kernel32" fn FormatMessageW( |
| ... | @@ -252,6 +62,3 @@ pub extern "kernel32" fn FormatMessageW( | ... | @@ -252,6 +62,3 @@ pub extern "kernel32" fn FormatMessageW( |
| 252 | nSize: DWORD, | 62 | nSize: DWORD, |
| 253 | Arguments: ?*va_list, | 63 | Arguments: ?*va_list, |
| 254 | ) callconv(.winapi) DWORD; | 64 | ) callconv(.winapi) DWORD; |
| 255 | |||
| 256 | // TODO: Getter for teb().LastErrorValue. | ||
| 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,6 +2,7 @@ const std = @import("../../std.zig"); |
| 2 | const windows = std.os.windows; | 2 | const windows = std.os.windows; |
| 3 | 3 | ||
| 4 | const ACCESS_MASK = windows.ACCESS_MASK; | 4 | const ACCESS_MASK = windows.ACCESS_MASK; |
| 5 | const ANSI_STRING = windows.ANSI_STRING; | ||
| 5 | const BOOL = windows.BOOL; | 6 | const BOOL = windows.BOOL; |
| 6 | const BOOLEAN = windows.BOOLEAN; | 7 | const BOOLEAN = windows.BOOLEAN; |
| 7 | const CONDITION_VARIABLE = windows.CONDITION_VARIABLE; | 8 | const CONDITION_VARIABLE = windows.CONDITION_VARIABLE; |
| ... | @@ -9,6 +10,7 @@ const CONTEXT = windows.CONTEXT; | ... | @@ -9,6 +10,7 @@ const CONTEXT = windows.CONTEXT; |
| 9 | const CRITICAL_SECTION = windows.CRITICAL_SECTION; | 10 | const CRITICAL_SECTION = windows.CRITICAL_SECTION; |
| 10 | const CTL_CODE = windows.CTL_CODE; | 11 | const CTL_CODE = windows.CTL_CODE; |
| 11 | const CURDIR = windows.CURDIR; | 12 | const CURDIR = windows.CURDIR; |
| 13 | const DIRECTORY = windows.DIRECTORY; | ||
| 12 | const DWORD = windows.DWORD; | 14 | const DWORD = windows.DWORD; |
| 13 | const DWORD64 = windows.DWORD64; | 15 | const DWORD64 = windows.DWORD64; |
| 14 | const ERESOURCE = windows.ERESOURCE; | 16 | const ERESOURCE = windows.ERESOURCE; |
| ... | @@ -22,18 +24,19 @@ const IO_APC_ROUTINE = windows.IO_APC_ROUTINE; | ... | @@ -22,18 +24,19 @@ const IO_APC_ROUTINE = windows.IO_APC_ROUTINE; |
| 22 | const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK; | 24 | const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK; |
| 23 | const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS; | 25 | const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS; |
| 24 | const LARGE_INTEGER = windows.LARGE_INTEGER; | 26 | const LARGE_INTEGER = windows.LARGE_INTEGER; |
| 27 | const LDR = windows.LDR; | ||
| 25 | const LOGICAL = windows.LOGICAL; | 28 | const LOGICAL = windows.LOGICAL; |
| 26 | const LONG = windows.LONG; | 29 | const LONG = windows.LONG; |
| 27 | const LPCVOID = windows.LPCVOID; | 30 | const LPCVOID = windows.LPCVOID; |
| 28 | const LPVOID = windows.LPVOID; | 31 | const LPVOID = windows.LPVOID; |
| 29 | const MEM = windows.MEM; | 32 | const MEM = windows.MEM; |
| 30 | const NTSTATUS = windows.NTSTATUS; | 33 | const NTSTATUS = windows.NTSTATUS; |
| 31 | const OBJECT_ATTRIBUTES = windows.OBJECT_ATTRIBUTES; | 34 | const OBJECT = windows.OBJECT; |
| 32 | const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS; | ||
| 33 | const PAGE = windows.PAGE; | 35 | const PAGE = windows.PAGE; |
| 34 | const PCWSTR = windows.PCWSTR; | 36 | const PCWSTR = windows.PCWSTR; |
| 35 | const PROCESSINFOCLASS = windows.PROCESSINFOCLASS; | 37 | const PROCESS = windows.PROCESS; |
| 36 | const PVOID = windows.PVOID; | 38 | const PVOID = windows.PVOID; |
| 39 | const PWSTR = windows.PWSTR; | ||
| 37 | const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW; | 40 | const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW; |
| 38 | const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE; | 41 | const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE; |
| 39 | const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION; | 42 | const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION; |
| ... | @@ -41,8 +44,8 @@ const SEC = windows.SEC; | ... | @@ -41,8 +44,8 @@ const SEC = windows.SEC; |
| 41 | const SECTION_INHERIT = windows.SECTION_INHERIT; | 44 | const SECTION_INHERIT = windows.SECTION_INHERIT; |
| 42 | const SIZE_T = windows.SIZE_T; | 45 | const SIZE_T = windows.SIZE_T; |
| 43 | const SRWLOCK = windows.SRWLOCK; | 46 | const SRWLOCK = windows.SRWLOCK; |
| 44 | const SYSTEM_INFORMATION_CLASS = windows.SYSTEM_INFORMATION_CLASS; | 47 | const SYSTEM = windows.SYSTEM; |
| 45 | const THREADINFOCLASS = windows.THREADINFOCLASS; | 48 | const THREAD = windows.THREAD; |
| 46 | const ULONG = windows.ULONG; | 49 | const ULONG = windows.ULONG; |
| 47 | const ULONG_PTR = windows.ULONG_PTR; | 50 | const ULONG_PTR = windows.ULONG_PTR; |
| 48 | const UNICODE_STRING = windows.UNICODE_STRING; | 51 | const UNICODE_STRING = windows.UNICODE_STRING; |
| ... | @@ -91,7 +94,7 @@ pub extern "ntdll" fn RtlCaptureContext( | ... | @@ -91,7 +94,7 @@ pub extern "ntdll" fn RtlCaptureContext( |
| 91 | 94 | ||
| 92 | pub extern "ntdll" fn NtSetInformationThread( | 95 | pub extern "ntdll" fn NtSetInformationThread( |
| 93 | ThreadHandle: HANDLE, | 96 | ThreadHandle: HANDLE, |
| 94 | ThreadInformationClass: THREADINFOCLASS, | 97 | ThreadInformationClass: THREAD.INFOCLASS, |
| 95 | ThreadInformation: *const anyopaque, | 98 | ThreadInformation: *const anyopaque, |
| 96 | ThreadInformationLength: ULONG, | 99 | ThreadInformationLength: ULONG, |
| 97 | ) callconv(.winapi) NTSTATUS; | 100 | ) callconv(.winapi) NTSTATUS; |
| ... | @@ -99,7 +102,7 @@ pub extern "ntdll" fn NtSetInformationThread( | ... | @@ -99,7 +102,7 @@ pub extern "ntdll" fn NtSetInformationThread( |
| 99 | pub extern "ntdll" fn NtCreateFile( | 102 | pub extern "ntdll" fn NtCreateFile( |
| 100 | FileHandle: *HANDLE, | 103 | FileHandle: *HANDLE, |
| 101 | DesiredAccess: ACCESS_MASK, | 104 | DesiredAccess: ACCESS_MASK, |
| 102 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | 105 | ObjectAttributes: *const OBJECT.ATTRIBUTES, |
| 103 | IoStatusBlock: *IO_STATUS_BLOCK, | 106 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 104 | AllocationSize: ?*const LARGE_INTEGER, | 107 | AllocationSize: ?*const LARGE_INTEGER, |
| 105 | FileAttributes: FILE.ATTRIBUTE, | 108 | FileAttributes: FILE.ATTRIBUTE, |
| ... | @@ -152,7 +155,7 @@ pub extern "ntdll" fn NtLockFile( | ... | @@ -152,7 +155,7 @@ pub extern "ntdll" fn NtLockFile( |
| 152 | pub extern "ntdll" fn NtOpenFile( | 155 | pub extern "ntdll" fn NtOpenFile( |
| 153 | FileHandle: *HANDLE, | 156 | FileHandle: *HANDLE, |
| 154 | DesiredAccess: ACCESS_MASK, | 157 | DesiredAccess: ACCESS_MASK, |
| 155 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | 158 | ObjectAttributes: *const OBJECT.ATTRIBUTES, |
| 156 | IoStatusBlock: *IO_STATUS_BLOCK, | 159 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 157 | ShareAccess: FILE.SHARE, | 160 | ShareAccess: FILE.SHARE, |
| 158 | OpenOptions: FILE.MODE, | 161 | OpenOptions: FILE.MODE, |
| ... | @@ -233,7 +236,7 @@ pub extern "ntdll" fn NtUnlockFile( | ... | @@ -233,7 +236,7 @@ pub extern "ntdll" fn NtUnlockFile( |
| 233 | 236 | ||
| 234 | pub extern "ntdll" fn NtQueryObject( | 237 | pub extern "ntdll" fn NtQueryObject( |
| 235 | Handle: HANDLE, | 238 | Handle: HANDLE, |
| 236 | ObjectInformationClass: OBJECT_INFORMATION_CLASS, | 239 | ObjectInformationClass: OBJECT.INFORMATION_CLASS, |
| 237 | ObjectInformation: ?PVOID, | 240 | ObjectInformation: ?PVOID, |
| 238 | ObjectInformationLength: ULONG, | 241 | ObjectInformationLength: ULONG, |
| 239 | ReturnLength: ?*ULONG, | 242 | ReturnLength: ?*ULONG, |
| ... | @@ -246,7 +249,7 @@ pub extern "ntdll" fn NtClose( | ... | @@ -246,7 +249,7 @@ pub extern "ntdll" fn NtClose( |
| 246 | pub extern "ntdll" fn NtCreateSection( | 249 | pub extern "ntdll" fn NtCreateSection( |
| 247 | SectionHandle: *HANDLE, | 250 | SectionHandle: *HANDLE, |
| 248 | DesiredAccess: ACCESS_MASK, | 251 | DesiredAccess: ACCESS_MASK, |
| 249 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | 252 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, |
| 250 | MaximumSize: ?*const LARGE_INTEGER, | 253 | MaximumSize: ?*const LARGE_INTEGER, |
| 251 | SectionPageProtection: PAGE, | 254 | SectionPageProtection: PAGE, |
| 252 | AllocationAttributes: SEC, | 255 | AllocationAttributes: SEC, |
| ... | @@ -331,7 +334,7 @@ pub extern "ntdll" fn NtWaitForSingleObject( | ... | @@ -331,7 +334,7 @@ pub extern "ntdll" fn NtWaitForSingleObject( |
| 331 | 334 | ||
| 332 | pub extern "ntdll" fn NtQueryInformationProcess( | 335 | pub extern "ntdll" fn NtQueryInformationProcess( |
| 333 | ProcessHandle: HANDLE, | 336 | ProcessHandle: HANDLE, |
| 334 | ProcessInformationClass: PROCESSINFOCLASS, | 337 | ProcessInformationClass: PROCESS.INFOCLASS, |
| 335 | ProcessInformation: *anyopaque, | 338 | ProcessInformation: *anyopaque, |
| 336 | ProcessInformationLength: ULONG, | 339 | ProcessInformationLength: ULONG, |
| 337 | ReturnLength: ?*ULONG, | 340 | ReturnLength: ?*ULONG, |
| ... | @@ -339,14 +342,14 @@ pub extern "ntdll" fn NtQueryInformationProcess( | ... | @@ -339,14 +342,14 @@ pub extern "ntdll" fn NtQueryInformationProcess( |
| 339 | 342 | ||
| 340 | pub extern "ntdll" fn NtQueryInformationThread( | 343 | pub extern "ntdll" fn NtQueryInformationThread( |
| 341 | ThreadHandle: HANDLE, | 344 | ThreadHandle: HANDLE, |
| 342 | ThreadInformationClass: THREADINFOCLASS, | 345 | ThreadInformationClass: THREAD.INFOCLASS, |
| 343 | ThreadInformation: *anyopaque, | 346 | ThreadInformation: *anyopaque, |
| 344 | ThreadInformationLength: ULONG, | 347 | ThreadInformationLength: ULONG, |
| 345 | ReturnLength: ?*ULONG, | 348 | ReturnLength: ?*ULONG, |
| 346 | ) callconv(.winapi) NTSTATUS; | 349 | ) callconv(.winapi) NTSTATUS; |
| 347 | 350 | ||
| 348 | pub extern "ntdll" fn NtQuerySystemInformation( | 351 | pub extern "ntdll" fn NtQuerySystemInformation( |
| 349 | SystemInformationClass: SYSTEM_INFORMATION_CLASS, | 352 | SystemInformationClass: SYSTEM.INFORMATION_CLASS, |
| 350 | SystemInformation: PVOID, | 353 | SystemInformation: PVOID, |
| 351 | SystemInformationLength: ULONG, | 354 | SystemInformationLength: ULONG, |
| 352 | ReturnLength: ?*ULONG, | 355 | ReturnLength: ?*ULONG, |
| ... | @@ -354,15 +357,99 @@ pub extern "ntdll" fn NtQuerySystemInformation( | ... | @@ -354,15 +357,99 @@ pub extern "ntdll" fn NtQuerySystemInformation( |
| 354 | 357 | ||
| 355 | // ref none | 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 | pub extern "ntdll" fn NtQueryAttributesFile( | 444 | pub extern "ntdll" fn NtQueryAttributesFile( |
| 358 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | 445 | ObjectAttributes: *const OBJECT.ATTRIBUTES, |
| 359 | FileAttributes: *FILE.BASIC_INFORMATION, | 446 | FileAttributes: *FILE.BASIC_INFORMATION, |
| 360 | ) callconv(.winapi) NTSTATUS; | 447 | ) callconv(.winapi) NTSTATUS; |
| 361 | 448 | ||
| 362 | pub extern "ntdll" fn NtCreateEvent( | 449 | pub extern "ntdll" fn NtCreateEvent( |
| 363 | EventHandle: *HANDLE, | 450 | EventHandle: *HANDLE, |
| 364 | DesiredAccess: ACCESS_MASK, | 451 | DesiredAccess: ACCESS_MASK, |
| 365 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | 452 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, |
| 366 | EventType: EVENT_TYPE, | 453 | EventType: EVENT_TYPE, |
| 367 | InitialState: BOOLEAN, | 454 | InitialState: BOOLEAN, |
| 368 | ) callconv(.winapi) NTSTATUS; | 455 | ) callconv(.winapi) NTSTATUS; |
| ... | @@ -374,7 +461,7 @@ pub extern "ntdll" fn NtSetEvent( | ... | @@ -374,7 +461,7 @@ pub extern "ntdll" fn NtSetEvent( |
| 374 | pub extern "ntdll" fn NtCreateKeyedEvent( | 461 | pub extern "ntdll" fn NtCreateKeyedEvent( |
| 375 | KeyedEventHandle: *HANDLE, | 462 | KeyedEventHandle: *HANDLE, |
| 376 | DesiredAccess: ACCESS_MASK, | 463 | DesiredAccess: ACCESS_MASK, |
| 377 | ObjectAttributes: ?*const OBJECT_ATTRIBUTES, | 464 | ObjectAttributes: ?*const OBJECT.ATTRIBUTES, |
| 378 | Flags: ULONG, | 465 | Flags: ULONG, |
| 379 | ) callconv(.winapi) NTSTATUS; | 466 | ) callconv(.winapi) NTSTATUS; |
| 380 | pub extern "ntdll" fn NtReleaseKeyedEvent( | 467 | pub extern "ntdll" fn NtReleaseKeyedEvent( |
| ... | @@ -390,10 +477,57 @@ pub extern "ntdll" fn NtWaitForKeyedEvent( | ... | @@ -390,10 +477,57 @@ pub extern "ntdll" fn NtWaitForKeyedEvent( |
| 390 | Timeout: ?*const LARGE_INTEGER, | 477 | Timeout: ?*const LARGE_INTEGER, |
| 391 | ) callconv(.winapi) NTSTATUS; | 478 | ) callconv(.winapi) NTSTATUS; |
| 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 | pub extern "ntdll" fn NtCreateNamedPipeFile( | 527 | pub extern "ntdll" fn NtCreateNamedPipeFile( |
| 394 | FileHandle: *HANDLE, | 528 | FileHandle: *HANDLE, |
| 395 | DesiredAccess: ACCESS_MASK, | 529 | DesiredAccess: ACCESS_MASK, |
| 396 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | 530 | ObjectAttributes: *const OBJECT.ATTRIBUTES, |
| 397 | IoStatusBlock: *IO_STATUS_BLOCK, | 531 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 398 | ShareAccess: FILE.SHARE, | 532 | ShareAccess: FILE.SHARE, |
| 399 | CreateDisposition: FILE.CREATE_DISPOSITION, | 533 | CreateDisposition: FILE.CREATE_DISPOSITION, |
| ... | @@ -437,7 +571,7 @@ pub extern "ntdll" fn NtUnmapViewOfSectionEx( | ... | @@ -437,7 +571,7 @@ pub extern "ntdll" fn NtUnmapViewOfSectionEx( |
| 437 | pub extern "ntdll" fn NtOpenKey( | 571 | pub extern "ntdll" fn NtOpenKey( |
| 438 | KeyHandle: *HANDLE, | 572 | KeyHandle: *HANDLE, |
| 439 | DesiredAccess: ACCESS_MASK, | 573 | DesiredAccess: ACCESS_MASK, |
| 440 | ObjectAttributes: *const OBJECT_ATTRIBUTES, | 574 | ObjectAttributes: *const OBJECT.ATTRIBUTES, |
| 441 | ) callconv(.winapi) NTSTATUS; | 575 | ) callconv(.winapi) NTSTATUS; |
| 442 | 576 | ||
| 443 | pub extern "ntdll" fn NtQueueApcThread( | 577 | pub extern "ntdll" fn NtQueueApcThread( |
| ... | @@ -470,6 +604,19 @@ pub extern "ntdll" fn NtProtectVirtualMemory( | ... | @@ -470,6 +604,19 @@ pub extern "ntdll" fn NtProtectVirtualMemory( |
| 470 | OldAccessProtection: *PAGE, | 604 | OldAccessProtection: *PAGE, |
| 471 | ) callconv(.winapi) NTSTATUS; | 605 | ) callconv(.winapi) NTSTATUS; |
| 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 | pub extern "ntdll" fn NtYieldExecution() callconv(.winapi) NTSTATUS; | 620 | pub extern "ntdll" fn NtYieldExecution() callconv(.winapi) NTSTATUS; |
| 474 | 621 | ||
| 475 | pub extern "ntdll" fn RtlAddVectoredExceptionHandler( | 622 | pub extern "ntdll" fn RtlAddVectoredExceptionHandler( |
| ... | @@ -527,10 +674,6 @@ pub extern "ntdll" fn RtlQueryPerformanceCounter( | ... | @@ -527,10 +674,6 @@ pub extern "ntdll" fn RtlQueryPerformanceCounter( |
| 527 | pub extern "ntdll" fn RtlQueryPerformanceFrequency( | 674 | pub extern "ntdll" fn RtlQueryPerformanceFrequency( |
| 528 | PerformanceFrequency: *LARGE_INTEGER, | 675 | PerformanceFrequency: *LARGE_INTEGER, |
| 529 | ) callconv(.winapi) BOOL; | 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 | pub extern "ntdll" fn RtlReAllocateHeap( | 678 | pub extern "ntdll" fn RtlReAllocateHeap( |
| 536 | HeapHandle: *HEAP, | 679 | HeapHandle: *HEAP, |
| ... | @@ -539,8 +682,17 @@ pub extern "ntdll" fn RtlReAllocateHeap( | ... | @@ -539,8 +682,17 @@ pub extern "ntdll" fn RtlReAllocateHeap( |
| 539 | Size: SIZE_T, | 682 | Size: SIZE_T, |
| 540 | ) callconv(.winapi) ?PVOID; | 683 | ) callconv(.winapi) ?PVOID; |
| 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 | pub extern "ntdll" fn RtlSetCurrentDirectory_U( | 694 | pub extern "ntdll" fn RtlSetCurrentDirectory_U( |
| 543 | PathName: *UNICODE_STRING, | 695 | PathName: *const UNICODE_STRING, |
| 544 | ) callconv(.winapi) NTSTATUS; | 696 | ) callconv(.winapi) NTSTATUS; |
| 545 | 697 | ||
| 546 | pub extern "ntdll" fn RtlTryAcquireSRWLockExclusive( | 698 | pub extern "ntdll" fn RtlTryAcquireSRWLockExclusive( |
| ... | @@ -572,52 +724,3 @@ pub extern "ntdll" fn RtlWakeConditionVariable( | ... | @@ -572,52 +724,3 @@ pub extern "ntdll" fn RtlWakeConditionVariable( |
| 572 | pub extern "ntdll" fn RtlWakeAllConditionVariable( | 724 | pub extern "ntdll" fn RtlWakeAllConditionVariable( |
| 573 | ConditionVariable: *CONDITION_VARIABLE, | 725 | ConditionVariable: *CONDITION_VARIABLE, |
| 574 | ) callconv(.winapi) void; | 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,5 +1,5 @@ |
| 1 | /// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d | 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 | /// The operation completed successfully. | 3 | /// The operation completed successfully. |
| 4 | SUCCESS = 0, | 4 | SUCCESS = 0, |
| 5 | /// Incorrect function. | 5 | /// Incorrect function. |
lib/std/process.zig+4-4| ... | @@ -243,7 +243,7 @@ pub fn getBaseAddress() usize { | ... | @@ -243,7 +243,7 @@ pub fn getBaseAddress() usize { |
| 243 | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { | 243 | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { |
| 244 | return @intFromPtr(&std.c._mh_execute_header); | 244 | return @intFromPtr(&std.c._mh_execute_header); |
| 245 | }, | 245 | }, |
| 246 | .windows => return @intFromPtr(windows.kernel32.GetModuleHandleW(null)), | 246 | .windows => return @intFromPtr(windows.peb().ImageBaseAddress), |
| 247 | else => @compileError("Unsupported OS"), | 247 | else => @compileError("Unsupported OS"), |
| 248 | } | 248 | } |
| 249 | } | 249 | } |
| ... | @@ -606,11 +606,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { | ... | @@ -606,11 +606,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { |
| 606 | return @as(u64, @bitCast(physmem)); | 606 | return @as(u64, @bitCast(physmem)); |
| 607 | }, | 607 | }, |
| 608 | .windows => { | 608 | .windows => { |
| 609 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | 609 | var sbi: windows.SYSTEM.BASIC_INFORMATION = undefined; |
| 610 | const rc = windows.ntdll.NtQuerySystemInformation( | 610 | const rc = windows.ntdll.NtQuerySystemInformation( |
| 611 | .SystemBasicInformation, | 611 | .Basic, |
| 612 | &sbi, | 612 | &sbi, |
| 613 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | 613 | @sizeOf(windows.SYSTEM.BASIC_INFORMATION), |
| 614 | null, | 614 | null, |
| 615 | ); | 615 | ); |
| 616 | if (rc != .SUCCESS) { | 616 | if (rc != .SUCCESS) { |
lib/std/process/Child.zig+1-1| ... | @@ -86,7 +86,7 @@ pub const ResourceUsageStatistics = struct { | ... | @@ -86,7 +86,7 @@ pub const ResourceUsageStatistics = struct { |
| 86 | .visionos, | 86 | .visionos, |
| 87 | .watchos, | 87 | .watchos, |
| 88 | => @as(?std.posix.rusage, null), | 88 | => @as(?std.posix.rusage, null), |
| 89 | .windows => @as(?std.os.windows.VM_COUNTERS, null), | 89 | .windows => @as(?std.os.windows.PROCESS.VM_COUNTERS, null), |
| 90 | else => {}, | 90 | else => {}, |
| 91 | }; | 91 | }; |
| 92 | }; | 92 | }; |
lib/std/start.zig+5-9| ... | @@ -473,10 +473,9 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn { | ... | @@ -473,10 +473,9 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn { |
| 473 | std.Thread.maybeAttachSignalStack(); | 473 | std.Thread.maybeAttachSignalStack(); |
| 474 | std.debug.maybeEnableSegfaultHandler(); | 474 | std.debug.maybeEnableSegfaultHandler(); |
| 475 | 475 | ||
| 476 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | 476 | std.os.windows.ntdll.RtlExitUserProcess( |
| 477 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | 477 | callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global), |
| 478 | 478 | ); | |
| 479 | std.os.windows.ntdll.RtlExitUserProcess(callMain(cmd_line_w, .global)); | ||
| 480 | } | 479 | } |
| 481 | 480 | ||
| 482 | fn wWinMainCRTStartup() callconv(.withStackAlign(.c, 1)) noreturn { | 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,9 +646,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal |
| 647 | // values in their intended encoding from the PEB instead. | 646 | // values in their intended encoding from the PEB instead. |
| 648 | std.Thread.maybeAttachSignalStack(); | 647 | std.Thread.maybeAttachSignalStack(); |
| 649 | std.debug.maybeEnableSegfaultHandler(); | 648 | std.debug.maybeEnableSegfaultHandler(); |
| 650 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | 649 | return callMain(std.os.windows.peb().ProcessParameters.CommandLine.slice(), .global); |
| 651 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | ||
| 652 | return callMain(cmd_line_w, .global); | ||
| 653 | }, | 650 | }, |
| 654 | else => {}, | 651 | else => {}, |
| 655 | } | 652 | } |
| ... | @@ -776,8 +773,7 @@ fn call_wWinMain() std.os.windows.INT { | ... | @@ -776,8 +773,7 @@ fn call_wWinMain() std.os.windows.INT { |
| 776 | // - With STARTF_USESHOWWINDOW unset: | 773 | // - With STARTF_USESHOWWINDOW unset: |
| 777 | // - nShowCmd is always SW_SHOWDEFAULT | 774 | // - nShowCmd is always SW_SHOWDEFAULT |
| 778 | const SW_SHOWDEFAULT = 10; | 775 | const SW_SHOWDEFAULT = 10; |
| 779 | const STARTF_USESHOWWINDOW = 1; | 776 | if (peb.ProcessParameters.dwFlags & std.os.windows.STARTF_USESHOWWINDOW != 0) { |
| 780 | if (peb.ProcessParameters.dwFlags & STARTF_USESHOWWINDOW != 0) { | ||
| 781 | break :nShowCmd @truncate(peb.ProcessParameters.dwShowWindow); | 777 | break :nShowCmd @truncate(peb.ProcessParameters.dwShowWindow); |
| 782 | } | 778 | } |
| 783 | break :nShowCmd SW_SHOWDEFAULT; | 779 | break :nShowCmd SW_SHOWDEFAULT; |
lib/std/zig/system/windows.zig+5-5| ... | @@ -100,11 +100,11 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { | ... | @@ -100,11 +100,11 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { |
| 100 | REG.MULTI_SZ, | 100 | REG.MULTI_SZ, |
| 101 | => { | 101 | => { |
| 102 | comptime assert(@sizeOf(std.os.windows.UNICODE_STRING) % 2 == 0); | 102 | comptime assert(@sizeOf(std.os.windows.UNICODE_STRING) % 2 == 0); |
| 103 | const unicode = @as(*std.os.windows.UNICODE_STRING, @ptrCast(&tmp_bufs[i])); | 103 | const unicode: *std.os.windows.UNICODE_STRING = @ptrCast(&tmp_bufs[i]); |
| 104 | unicode.* = .{ | 104 | unicode.* = .{ |
| 105 | .Length = 0, | 105 | .Length = 0, |
| 106 | .MaximumLength = max_value_len - @sizeOf(std.os.windows.UNICODE_STRING), | 106 | .MaximumLength = max_value_len - @sizeOf(std.os.windows.UNICODE_STRING), |
| 107 | .Buffer = @as([*]u16, @ptrCast(tmp_bufs[i][@sizeOf(std.os.windows.UNICODE_STRING)..])), | 107 | .Buffer = @ptrCast(tmp_bufs[i][@sizeOf(std.os.windows.UNICODE_STRING)..]), |
| 108 | }; | 108 | }; |
| 109 | break :blk unicode; | 109 | break :blk unicode; |
| 110 | }, | 110 | }, |
| ... | @@ -159,8 +159,8 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { | ... | @@ -159,8 +159,8 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { |
| 159 | REG.MULTI_SZ, | 159 | REG.MULTI_SZ, |
| 160 | => { | 160 | => { |
| 161 | var buf = @field(args, field.name).value_buf; | 161 | var buf = @field(args, field.name).value_buf; |
| 162 | const entry = @as(*align(1) const std.os.windows.UNICODE_STRING, @ptrCast(table[i + 1].EntryContext)); | 162 | const entry: *const std.os.windows.UNICODE_STRING = @ptrCast(table[i + 1].EntryContext); |
| 163 | const len = try std.unicode.utf16LeToUtf8(buf, entry.Buffer.?[0 .. entry.Length / 2]); | 163 | const len = try std.unicode.utf16LeToUtf8(buf, entry.slice()); |
| 164 | buf[len] = 0; | 164 | buf[len] = 0; |
| 165 | }, | 165 | }, |
| 166 | 166 | ||
| ... | @@ -168,7 +168,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { | ... | @@ -168,7 +168,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void { |
| 168 | REG.DWORD_BIG_ENDIAN, | 168 | REG.DWORD_BIG_ENDIAN, |
| 169 | REG.QWORD, | 169 | REG.QWORD, |
| 170 | => { | 170 | => { |
| 171 | const entry = @as([*]align(1) const u8, @ptrCast(table[i + 1].EntryContext)); | 171 | const entry: [*]const u8 = @ptrCast(table[i + 1].EntryContext); |
| 172 | switch (@field(args, field.name).value_type) { | 172 | switch (@field(args, field.name).value_type) { |
| 173 | REG.DWORD, REG.DWORD_BIG_ENDIAN => { | 173 | REG.DWORD, REG.DWORD_BIG_ENDIAN => { |
| 174 | @memcpy(@field(args, field.name).value_buf[0..4], entry[0..4]); | 174 | @memcpy(@field(args, field.name).value_buf[0..4], entry[0..4]); |
lib/zig.h+24-4| ... | @@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a | ... | @@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a |
| 4148 | 4148 | ||
| 4149 | #if defined(zig_thumb) | 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 | void* teb = 0; | 4152 | void* teb = 0; |
| 4153 | #if defined(zig_msvc) | 4153 | #if defined(zig_msvc) |
| 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); | 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); |
| ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { | ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { |
| 4160 | 4160 | ||
| 4161 | #elif defined(zig_aarch64) | 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 | void* teb = 0; | 4164 | void* teb = 0; |
| 4165 | #if defined(zig_msvc) | 4165 | #if defined(zig_msvc) |
| 4166 | teb = (void*)__readx18qword(0x0); | 4166 | teb = (void*)__readx18qword(0x0); |
| ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { | ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { |
| 4172 | 4172 | ||
| 4173 | #elif defined(zig_x86_32) | 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 | void* teb = 0; | 4176 | void* teb = 0; |
| 4177 | #if defined(zig_msvc) | 4177 | #if defined(zig_msvc) |
| 4178 | teb = (void*)__readfsdword(0x18); | 4178 | teb = (void*)__readfsdword(0x18); |
| ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { | ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { |
| 4182 | return teb; | 4182 | return teb; |
| 4183 | } | 4183 | } |
| 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 | #elif defined(zig_x86_64) | 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 | void* teb = 0; | 4198 | void* teb = 0; |
| 4189 | #if defined(zig_msvc) | 4199 | #if defined(zig_msvc) |
| 4190 | teb = (void*)__readgsqword(0x30); | 4200 | teb = (void*)__readgsqword(0x30); |
| ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { | ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { |
| 4194 | return teb; | 4204 | return teb; |
| 4195 | } | 4205 | } |
| 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 | #endif | 4217 | #endif |
| 4198 | 4218 | ||
| 4199 | #if defined(zig_loongarch) | 4219 | #if defined(zig_loongarch) |
stage1/zig.h+24-4| ... | @@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a | ... | @@ -4148,7 +4148,7 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a |
| 4148 | 4148 | ||
| 4149 | #if defined(zig_thumb) | 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 | void* teb = 0; | 4152 | void* teb = 0; |
| 4153 | #if defined(zig_msvc) | 4153 | #if defined(zig_msvc) |
| 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); | 4154 | teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); |
| ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { | ... | @@ -4160,7 +4160,7 @@ static inline void* zig_thumb_windows_teb(void) { |
| 4160 | 4160 | ||
| 4161 | #elif defined(zig_aarch64) | 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 | void* teb = 0; | 4164 | void* teb = 0; |
| 4165 | #if defined(zig_msvc) | 4165 | #if defined(zig_msvc) |
| 4166 | teb = (void*)__readx18qword(0x0); | 4166 | teb = (void*)__readx18qword(0x0); |
| ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { | ... | @@ -4172,7 +4172,7 @@ static inline void* zig_aarch64_windows_teb(void) { |
| 4172 | 4172 | ||
| 4173 | #elif defined(zig_x86_32) | 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 | void* teb = 0; | 4176 | void* teb = 0; |
| 4177 | #if defined(zig_msvc) | 4177 | #if defined(zig_msvc) |
| 4178 | teb = (void*)__readfsdword(0x18); | 4178 | teb = (void*)__readfsdword(0x18); |
| ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { | ... | @@ -4182,9 +4182,19 @@ static inline void* zig_x86_windows_teb(void) { |
| 4182 | return teb; | 4182 | return teb; |
| 4183 | } | 4183 | } |
| 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 | #elif defined(zig_x86_64) | 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 | void* teb = 0; | 4198 | void* teb = 0; |
| 4189 | #if defined(zig_msvc) | 4199 | #if defined(zig_msvc) |
| 4190 | teb = (void*)__readgsqword(0x30); | 4200 | teb = (void*)__readgsqword(0x30); |
| ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { | ... | @@ -4194,6 +4204,16 @@ static inline void* zig_x86_64_windows_teb(void) { |
| 4194 | return teb; | 4204 | return teb; |
| 4195 | } | 4205 | } |
| 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 | #endif | 4217 | #endif |
| 4198 | 4218 | ||
| 4199 | #if defined(zig_loongarch) | 4219 | #if defined(zig_loongarch) |
test/standalone/coff_dwarf/main.zig+3-4| ... | @@ -4,17 +4,16 @@ const fatal = std.process.fatal; | ... | @@ -4,17 +4,16 @@ const fatal = std.process.fatal; |
| 4 | extern fn add(a: u32, b: u32, addr: *usize) u32; | 4 | extern fn add(a: u32, b: u32, addr: *usize) u32; |
| 5 | 5 | ||
| 6 | pub fn main(init: std.process.Init) void { | 6 | pub fn main(init: std.process.Init) void { |
| 7 | const gpa = init.gpa; | ||
| 8 | const io = init.io; | 7 | const io = init.io; |
| 9 | 8 | ||
| 10 | var di: std.debug.SelfInfo = .init; | 9 | var di: std.debug.SelfInfo = .init; |
| 11 | defer di.deinit(gpa); | 10 | defer di.deinit(io); |
| 12 | 11 | ||
| 13 | var add_addr: usize = undefined; | 12 | var add_addr: usize = undefined; |
| 14 | _ = add(1, 2, &add_addr); | 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}); | 15 | const symbol = di.getSymbol(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); |
| 17 | defer if (symbol.source_location) |sl| gpa.free(sl.file_name); | 16 | defer if (symbol.source_location) |sl| std.debug.getDebugInfoAllocator().free(sl.file_name); |
| 18 | 17 | ||
| 19 | if (symbol.name == null) fatal("failed to resolve symbol name", .{}); | 18 | if (symbol.name == null) fatal("failed to resolve symbol name", .{}); |
| 20 | if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{}); | 19 | if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{}); |
test/standalone/windows_argv/fuzz.zig+12-6| ... | @@ -127,7 +127,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO | ... | @@ -127,7 +127,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO |
| 127 | .hStdOutput = null, | 127 | .hStdOutput = null, |
| 128 | .hStdError = windows.peb().ProcessParameters.hStdError, | 128 | .hStdError = windows.peb().ProcessParameters.hStdError, |
| 129 | }; | 129 | }; |
| 130 | var proc_info: windows.PROCESS_INFORMATION = undefined; | 130 | var proc_info: windows.PROCESS.INFORMATION = undefined; |
| 131 | 131 | ||
| 132 | if (windows.kernel32.CreateProcessW( | 132 | if (windows.kernel32.CreateProcessW( |
| 133 | @constCast(verify_path.ptr), | 133 | @constCast(verify_path.ptr), |
| ... | @@ -141,7 +141,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO | ... | @@ -141,7 +141,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO |
| 141 | &startup_info, | 141 | &startup_info, |
| 142 | &proc_info, | 142 | &proc_info, |
| 143 | ) == 0) { | 143 | ) == 0) { |
| 144 | std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.kernel32.GetLastError()}); | 144 | std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.GetLastError()}); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | windows.CloseHandle(proc_info.hThread); | 147 | windows.CloseHandle(proc_info.hThread); |
| ... | @@ -156,9 +156,15 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO | ... | @@ -156,9 +156,15 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO |
| 156 | else => |status| return windows.unexpectedStatus(status), | 156 | else => |status| return windows.unexpectedStatus(status), |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | var exit_code: windows.DWORD = undefined; | 159 | var info: windows.PROCESS.BASIC_INFORMATION = undefined; |
| 160 | if (windows.kernel32.GetExitCodeProcess(child_proc, &exit_code) == 0) { | 160 | switch (windows.ntdll.NtQueryInformationProcess( |
| 161 | return error.UnableToGetExitCode; | 161 | child_proc, |
| 162 | .BasicInformation, | ||
| 163 | &info, | ||
| 164 | @sizeOf(windows.PROCESS.BASIC_INFORMATION), | ||
| 165 | null, | ||
| 166 | )) { | ||
| 167 | .SUCCESS => return @intFromEnum(info.ExitStatus), | ||
| 168 | else => return error.UnableToGetExitCode, | ||
| 162 | } | 169 | } |
| 163 | return exit_code; | ||
| 164 | } | 170 | } |
test/standalone/windows_argv/lib.zig+3-3| ... | @@ -16,9 +16,9 @@ fn testArgv(expected_args: []const [*:0]const u16) !void { | ... | @@ -16,9 +16,9 @@ fn testArgv(expected_args: []const [*:0]const u16) !void { |
| 16 | defer arena_state.deinit(); | 16 | defer arena_state.deinit(); |
| 17 | const allocator = arena_state.allocator(); | 17 | const allocator = arena_state.allocator(); |
| 18 | 18 | ||
| 19 | const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine; | 19 | const raw_args: std.process.Args = .{ |
| 20 | const cmd_line_w = cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)]; | 20 | .vector = std.os.windows.peb().ProcessParameters.CommandLine.slice(), |
| 21 | const raw_args: std.process.Args = .{ .vector = cmd_line_w }; | 21 | }; |
| 22 | const args = try raw_args.toSlice(allocator); | 22 | const args = try raw_args.toSlice(allocator); |
| 23 | var wtf8_buf = std.array_list.Managed(u8).init(allocator); | 23 | var wtf8_buf = std.array_list.Managed(u8).init(allocator); |
| 24 | 24 |