authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-28 20:05:20-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 03:39:46+01:00
log9b415761dd66904aef363e387b4501f3ddd0bf76
tree353b7dc77df1458eb126722fd73cc8b8c81ccd2a
parent5571c08e6603173378db7cfe1436e33e902f9c0a

std.os.windows: delete unused APIs

Intention is to go through std.Io for these things.

6 files changed, 36 insertions(+), 398 deletions(-)

lib/std/Io/File/Reader.zig+1-1
......@@ -48,7 +48,7 @@ pub const Error = error{
4848 LockViolation,
4949} || Io.Cancelable || Io.UnexpectedError;
5050
51pub const SizeError = std.os.windows.GetFileSizeError || File.StatError || error{
51pub const SizeError = File.StatError || error{
5252 /// Occurs if, for example, the file handle is a network socket and therefore does not have a size.
5353 Streaming,
5454};
lib/std/Io/Threaded.zig+13-2
......@@ -13960,8 +13960,19 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child
1396013960fn childCleanupWindows(child: *process.Child) void {
1396113961 const handle = child.id orelse return;
1396213962
13963 if (child.request_resource_usage_statistics)
13964 child.resource_usage_statistics.rusage = windows.GetProcessMemoryInfo(handle) catch null;
13963 if (child.request_resource_usage_statistics) {
13964 var vmc: windows.VM_COUNTERS = undefined;
13965 switch (windows.ntdll.NtQueryInformationProcess(
13966 handle,
13967 .VmCounters,
13968 &vmc,
13969 @sizeOf(windows.VM_COUNTERS),
13970 null,
13971 )) {
13972 .SUCCESS => child.resource_usage_statistics.rusage = vmc,
13973 else => child.resource_usage_statistics.rusage = null,
13974 }
13975 }
1396513976
1396613977 windows.CloseHandle(handle);
1396713978 child.id = null;
lib/std/os/windows.zig+5-367
......@@ -2906,275 +2906,6 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
29062906 return buffer[0..end_index];
29072907}
29082908
2909pub const DeleteFileError = error{
2910 FileNotFound,
2911 AccessDenied,
2912 NameTooLong,
2913 /// Also known as sharing violation.
2914 FileBusy,
2915 Unexpected,
2916 NotDir,
2917 IsDir,
2918 DirNotEmpty,
2919 NetworkNotFound,
2920};
2921
2922pub const DeleteFileOptions = struct {
2923 dir: ?HANDLE,
2924 remove_dir: bool = false,
2925};
2926
2927pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFileError!void {
2928 const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));
2929 var nt_name: UNICODE_STRING = .{
2930 .Length = path_len_bytes,
2931 .MaximumLength = path_len_bytes,
2932 // The Windows API makes this mutable, but it will not mutate here.
2933 .Buffer = @constCast(sub_path_w.ptr),
2934 };
2935
2936 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
2937 // Windows does not recognize this, but it does work with empty string.
2938 nt_name.Length = 0;
2939 }
2940 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
2941 // Can't remove the parent directory with an open handle.
2942 return error.FileBusy;
2943 }
2944
2945 var io: IO_STATUS_BLOCK = undefined;
2946 var tmp_handle: HANDLE = undefined;
2947 var rc = ntdll.NtCreateFile(
2948 &tmp_handle,
2949 .{ .STANDARD = .{
2950 .RIGHTS = .{ .DELETE = true },
2951 .SYNCHRONIZE = true,
2952 } },
2953 &.{
2954 .Length = @sizeOf(OBJECT_ATTRIBUTES),
2955 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir,
2956 .Attributes = .{},
2957 .ObjectName = &nt_name,
2958 .SecurityDescriptor = null,
2959 .SecurityQualityOfService = null,
2960 },
2961 &io,
2962 null,
2963 .{},
2964 .VALID_FLAGS,
2965 .OPEN,
2966 .{
2967 .DIRECTORY_FILE = options.remove_dir,
2968 .NON_DIRECTORY_FILE = !options.remove_dir,
2969 .OPEN_REPARSE_POINT = true, // would we ever want to delete the target instead?
2970 },
2971 null,
2972 0,
2973 );
2974 switch (rc) {
2975 .SUCCESS => {},
2976 .OBJECT_NAME_INVALID => unreachable,
2977 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2978 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2979 .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found
2980 .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't
2981 .INVALID_PARAMETER => unreachable,
2982 .FILE_IS_A_DIRECTORY => return error.IsDir,
2983 .NOT_A_DIRECTORY => return error.NotDir,
2984 .SHARING_VIOLATION => return error.FileBusy,
2985 .ACCESS_DENIED => return error.AccessDenied,
2986 .DELETE_PENDING => return,
2987 else => return unexpectedStatus(rc),
2988 }
2989 defer CloseHandle(tmp_handle);
2990
2991 // FileDispositionInformationEx has varying levels of support:
2992 // - FILE_DISPOSITION_INFORMATION_EX requires >= win10_rs1
2993 // (INVALID_INFO_CLASS is returned if not supported)
2994 // - Requires the NTFS filesystem
2995 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
2996 // - FILE_DISPOSITION_POSIX_SEMANTICS requires >= win10_rs1
2997 // - FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
2998 // (NOT_SUPPORTED is returned if a flag is unsupported)
2999 //
3000 // The strategy here is just to try using FileDispositionInformationEx and fall back to
3001 // FileDispositionInformation if the return value lets us know that some aspect of it is not supported.
3002 const need_fallback = need_fallback: {
3003 // Deletion with posix semantics if the filesystem supports it.
3004 var info: FILE.DISPOSITION.INFORMATION.EX = .{ .Flags = .{
3005 .DELETE = true,
3006 .POSIX_SEMANTICS = true,
3007 .IGNORE_READONLY_ATTRIBUTE = true,
3008 } };
3009 rc = ntdll.NtSetInformationFile(
3010 tmp_handle,
3011 &io,
3012 &info,
3013 @sizeOf(FILE.DISPOSITION.INFORMATION.EX),
3014 .DispositionEx,
3015 );
3016 switch (rc) {
3017 .SUCCESS => return,
3018 // The filesystem does not support FileDispositionInformationEx
3019 .INVALID_PARAMETER,
3020 // The operating system does not support FileDispositionInformationEx
3021 .INVALID_INFO_CLASS,
3022 // The operating system does not support one of the flags
3023 .NOT_SUPPORTED,
3024 => break :need_fallback true,
3025 // For all other statuses, fall down to the switch below to handle them.
3026 else => break :need_fallback false,
3027 }
3028 };
3029
3030 if (need_fallback) {
3031 // Deletion with file pending semantics, which requires waiting or moving
3032 // files to get them removed (from here).
3033 var file_dispo: FILE.DISPOSITION.INFORMATION = .{
3034 .DeleteFile = TRUE,
3035 };
3036 rc = ntdll.NtSetInformationFile(
3037 tmp_handle,
3038 &io,
3039 &file_dispo,
3040 @sizeOf(FILE.DISPOSITION.INFORMATION),
3041 .Disposition,
3042 );
3043 }
3044 switch (rc) {
3045 .SUCCESS => {},
3046 .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
3047 .INVALID_PARAMETER => unreachable,
3048 .CANNOT_DELETE => return error.AccessDenied,
3049 .MEDIA_WRITE_PROTECTED => return error.AccessDenied,
3050 .ACCESS_DENIED => return error.AccessDenied,
3051 else => return unexpectedStatus(rc),
3052 }
3053}
3054
3055pub const RenameError = error{
3056 IsDir,
3057 NotDir,
3058 FileNotFound,
3059 NoDevice,
3060 AccessDenied,
3061 PipeBusy,
3062 PathAlreadyExists,
3063 Unexpected,
3064 NameTooLong,
3065 NetworkNotFound,
3066 AntivirusInterference,
3067 BadPathName,
3068 CrossDevice,
3069} || UnexpectedError;
3070
3071pub fn RenameFile(
3072 /// May only be `null` if `old_path_w` is a fully-qualified absolute path.
3073 old_dir_fd: ?HANDLE,
3074 old_path_w: []const u16,
3075 /// May only be `null` if `new_path_w` is a fully-qualified absolute path,
3076 /// or if the file is not being moved to a different directory.
3077 new_dir_fd: ?HANDLE,
3078 new_path_w: []const u16,
3079 replace_if_exists: bool,
3080) RenameError!void {
3081 const src_fd = OpenFile(old_path_w, .{
3082 .dir = old_dir_fd,
3083 .access_mask = .{
3084 .STANDARD = .{
3085 .RIGHTS = .{ .DELETE = true },
3086 .SYNCHRONIZE = true,
3087 },
3088 .GENERIC = .{ .WRITE = true },
3089 },
3090 .creation = .OPEN,
3091 .filter = .any, // This function is supposed to rename both files and directories.
3092 .follow_symlinks = false,
3093 }) catch |err| switch (err) {
3094 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
3095 else => |e| return e,
3096 };
3097 defer CloseHandle(src_fd);
3098
3099 var rc: NTSTATUS = undefined;
3100 // FileRenameInformationEx has varying levels of support:
3101 // - FILE_RENAME_INFORMATION_EX requires >= win10_rs1
3102 // (INVALID_INFO_CLASS is returned if not supported)
3103 // - Requires the NTFS filesystem
3104 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
3105 // - FILE_RENAME_POSIX_SEMANTICS requires >= win10_rs1
3106 // - FILE_RENAME_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
3107 // (NOT_SUPPORTED is returned if a flag is unsupported)
3108 //
3109 // The strategy here is just to try using FileRenameInformationEx and fall back to
3110 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.
3111 const need_fallback = need_fallback: {
3112 var rename_info: FILE.RENAME_INFORMATION = .init(.{
3113 .Flags = .{
3114 .REPLACE_IF_EXISTS = replace_if_exists,
3115 .POSIX_SEMANTICS = true,
3116 .IGNORE_READONLY_ATTRIBUTE = true,
3117 },
3118 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
3119 .FileName = new_path_w,
3120 });
3121 var io_status_block: IO_STATUS_BLOCK = undefined;
3122 const rename_info_buf = rename_info.toBuffer();
3123 rc = ntdll.NtSetInformationFile(
3124 src_fd,
3125 &io_status_block,
3126 rename_info_buf.ptr,
3127 @intCast(rename_info_buf.len), // already checked for error.NameTooLong
3128 .RenameEx,
3129 );
3130 switch (rc) {
3131 .SUCCESS => return,
3132 // The filesystem does not support FileDispositionInformationEx
3133 .INVALID_PARAMETER,
3134 // The operating system does not support FileDispositionInformationEx
3135 .INVALID_INFO_CLASS,
3136 // The operating system does not support one of the flags
3137 .NOT_SUPPORTED,
3138 => break :need_fallback true,
3139 // For all other statuses, fall down to the switch below to handle them.
3140 else => break :need_fallback false,
3141 }
3142 };
3143
3144 if (need_fallback) {
3145 var rename_info: FILE.RENAME_INFORMATION = .init(.{
3146 .Flags = .{ .REPLACE_IF_EXISTS = replace_if_exists },
3147 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
3148 .FileName = new_path_w,
3149 });
3150 var io_status_block: IO_STATUS_BLOCK = undefined;
3151 const rename_info_buf = rename_info.toBuffer();
3152 rc = ntdll.NtSetInformationFile(
3153 src_fd,
3154 &io_status_block,
3155 rename_info_buf.ptr,
3156 @intCast(rename_info_buf.len), // already checked for error.NameTooLong
3157 .Rename,
3158 );
3159 }
3160
3161 switch (rc) {
3162 .SUCCESS => {},
3163 .INVALID_HANDLE => unreachable,
3164 .INVALID_PARAMETER => unreachable,
3165 .OBJECT_PATH_SYNTAX_BAD => unreachable,
3166 .ACCESS_DENIED => return error.AccessDenied,
3167 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
3168 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
3169 .NOT_SAME_DEVICE => return error.CrossDevice,
3170 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
3171 .DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
3172 .FILE_IS_A_DIRECTORY => return error.IsDir,
3173 .NOT_A_DIRECTORY => return error.NotDir,
3174 else => return unexpectedStatus(rc),
3175 }
3176}
3177
31782909pub const GetStdHandleError = error{
31792910 NoStandardHandleAttached,
31802911 Unexpected,
......@@ -3508,18 +3239,6 @@ test GetFinalPathNameByHandle {
35083239 _ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0..required_len_in_u16]);
35093240}
35103241
3511pub const GetFileSizeError = error{Unexpected};
3512
3513pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
3514 var file_size: LARGE_INTEGER = undefined;
3515 if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) {
3516 switch (GetLastError()) {
3517 else => |err| return unexpectedError(err),
3518 }
3519 }
3520 return @as(u64, @bitCast(file_size));
3521}
3522
35233242pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
35243243 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
35253244}
......@@ -3714,69 +3433,6 @@ pub const CreateProcessFlags = packed struct(u32) {
37143433 create_ignore_system_default: bool = false,
37153434};
37163435
3717pub fn CreateProcessW(
3718 lpApplicationName: ?LPCWSTR,
3719 lpCommandLine: ?LPWSTR,
3720 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
3721 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
3722 bInheritHandles: BOOL,
3723 dwCreationFlags: CreateProcessFlags,
3724 lpEnvironment: ?[*:0]u16,
3725 lpCurrentDirectory: ?LPCWSTR,
3726 lpStartupInfo: *STARTUPINFOW,
3727 lpProcessInformation: *PROCESS_INFORMATION,
3728) CreateProcessError!void {
3729 if (kernel32.CreateProcessW(
3730 lpApplicationName,
3731 lpCommandLine,
3732 lpProcessAttributes,
3733 lpThreadAttributes,
3734 bInheritHandles,
3735 dwCreationFlags,
3736 lpEnvironment,
3737 lpCurrentDirectory,
3738 lpStartupInfo,
3739 lpProcessInformation,
3740 ) == 0) {
3741 switch (GetLastError()) {
3742 .FILE_NOT_FOUND => return error.FileNotFound,
3743 .PATH_NOT_FOUND => return error.FileNotFound,
3744 .DIRECTORY => return error.FileNotFound,
3745 .ACCESS_DENIED => return error.AccessDenied,
3746 .INVALID_PARAMETER => unreachable,
3747 .INVALID_NAME => return error.InvalidName,
3748 .FILENAME_EXCED_RANGE => return error.NameTooLong,
3749 .SHARING_VIOLATION => return error.FileBusy,
3750 // These are all the system errors that are mapped to ENOEXEC by
3751 // the undocumented _dosmaperr (old CRT) or __acrt_errno_map_os_error
3752 // (newer CRT) functions. Their code can be found in crt/src/dosmap.c (old SDK)
3753 // or urt/misc/errno.cpp (newer SDK) in the Windows SDK.
3754 .BAD_FORMAT,
3755 .INVALID_STARTING_CODESEG, // MIN_EXEC_ERROR in errno.cpp
3756 .INVALID_STACKSEG,
3757 .INVALID_MODULETYPE,
3758 .INVALID_EXE_SIGNATURE,
3759 .EXE_MARKED_INVALID,
3760 .BAD_EXE_FORMAT,
3761 .ITERATED_DATA_EXCEEDS_64k,
3762 .INVALID_MINALLOCSIZE,
3763 .DYNLINK_FROM_INVALID_RING,
3764 .IOPL_NOT_ENABLED,
3765 .INVALID_SEGDPL,
3766 .AUTODATASEG_EXCEEDS_64k,
3767 .RING2SEG_MUST_BE_MOVABLE,
3768 .RELOC_CHAIN_XEEDS_SEGLIM,
3769 .INFLOOP_IN_RELOC_CHAIN, // MAX_EXEC_ERROR in errno.cpp
3770 // This one is not mapped to ENOEXEC but it is possible, for example
3771 // when calling CreateProcessW on a plain text file with a .exe extension
3772 .EXE_MACHINE_TYPE_MISMATCH,
3773 => return error.InvalidExe,
3774 .COMMITMENT_LIMIT => return error.SystemResources,
3775 else => |err| return unexpectedError(err),
3776 }
3777 }
3778}
3779
37803436pub const LoadLibraryError = error{
37813437 FileNotFound,
37823438 Unexpected,
......@@ -3843,10 +3499,6 @@ pub fn QueryPerformanceCounter() u64 {
38433499 return @as(u64, @bitCast(result));
38443500}
38453501
3846pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*anyopaque, Context: ?*anyopaque) void {
3847 assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
3848}
3849
38503502/// This is a workaround for the C backend until zig has the ability to put
38513503/// C code in inline assembly.
38523504extern fn zig_thumb_windows_teb() callconv(.c) *anyopaque;
......@@ -6072,24 +5724,6 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {
60725724 PrivateUsage: SIZE_T,
60735725};
60745726
6075pub const GetProcessMemoryInfoError = error{
6076 AccessDenied,
6077 InvalidHandle,
6078 Unexpected,
6079};
6080
6081pub fn GetProcessMemoryInfo(hProcess: HANDLE) GetProcessMemoryInfoError!VM_COUNTERS {
6082 var vmc: VM_COUNTERS = undefined;
6083 const rc = ntdll.NtQueryInformationProcess(hProcess, .VmCounters, &vmc, @sizeOf(VM_COUNTERS), null);
6084 switch (rc) {
6085 .SUCCESS => return vmc,
6086 .ACCESS_DENIED => return error.AccessDenied,
6087 .INVALID_HANDLE => return error.InvalidHandle,
6088 .INVALID_PARAMETER => unreachable,
6089 else => return unexpectedStatus(rc),
6090 }
6091}
6092
60935727pub const PERFORMANCE_INFORMATION = extern struct {
60945728 cb: DWORD,
60955729 CommitTotal: SIZE_T,
......@@ -6623,7 +6257,11 @@ pub fn WriteProcessMemory(handle: HANDLE, addr: ?LPVOID, buffer: []const u8) Wri
66236257 }
66246258}
66256259
6626pub const ProcessBaseAddressError = GetProcessMemoryInfoError || ReadMemoryError;
6260pub const ProcessBaseAddressError = error{
6261 AccessDenied,
6262 InvalidHandle,
6263 Unexpected,
6264} || ReadMemoryError;
66276265
66286266/// Returns the base address of the process loaded into memory.
66296267pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
lib/std/os/windows/kernel32.zig-19
......@@ -117,12 +117,6 @@ pub extern "kernel32" fn WriteFile(
117117 in_out_lpOverlapped: ?*OVERLAPPED,
118118) callconv(.winapi) BOOL;
119119
120// TODO: wrapper for NtQueryInformationFile + `FILE_STANDARD_INFORMATION`
121pub extern "kernel32" fn GetFileSizeEx(
122 hFile: HANDLE,
123 lpFileSize: *LARGE_INTEGER,
124) callconv(.winapi) BOOL;
125
126120// TODO: Wrapper around GetStdHandle + NtFlushBuffersFile.
127121pub extern "kernel32" fn FlushFileBuffers(
128122 hFile: HANDLE,
......@@ -283,12 +277,6 @@ pub extern "kernel32" fn GetExitCodeProcess(
283277 lpExitCode: *DWORD,
284278) callconv(.winapi) BOOL;
285279
286// TODO: Wrapper around RtlSetEnvironmentVar.
287pub extern "kernel32" fn SetEnvironmentVariableW(
288 lpName: LPCWSTR,
289 lpValue: ?LPCWSTR,
290) callconv(.winapi) BOOL;
291
292280pub extern "kernel32" fn CreateToolhelp32Snapshot(
293281 dwFlags: DWORD,
294282 th32ProcessID: DWORD,
......@@ -311,13 +299,6 @@ pub extern "kernel32" fn CreateThread(
311299
312300// Locks, critical sections, initializers
313301
314pub extern "kernel32" fn InitOnceExecuteOnce(
315 InitOnce: *INIT_ONCE,
316 InitFn: INIT_ONCE_FN,
317 Parameter: ?*anyopaque,
318 Context: ?*anyopaque,
319) callconv(.winapi) BOOL;
320
321302// TODO:
322303// - dwMilliseconds -> LARGE_INTEGER.
323304// - RtlSleepConditionVariableSRW
test/standalone/windows_argv/fuzz.zig+5-2
......@@ -129,7 +129,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
129129 };
130130 var proc_info: windows.PROCESS_INFORMATION = undefined;
131131
132 try windows.CreateProcessW(
132 if (windows.kernel32.CreateProcessW(
133133 @constCast(verify_path.ptr),
134134 @constCast(cmd_line.ptr),
135135 null,
......@@ -140,7 +140,10 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
140140 null,
141141 &startup_info,
142142 &proc_info,
143 );
143 ) == 0) {
144 std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.kernel32.GetLastError()});
145 }
146
144147 windows.CloseHandle(proc_info.hThread);
145148
146149 break :spawn proc_info.hProcess;
test/standalone/windows_spawn/main.zig+12-7
......@@ -31,13 +31,13 @@ pub fn main(init: std.process.Init) !void {
3131 defer gpa.free(tmp_relative_path);
3232
3333 // Clear PATH
34 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
34 std.debug.assert(SetEnvironmentVariableW(
3535 utf16Literal("PATH"),
3636 null,
3737 ) == windows.TRUE);
3838
3939 // Set PATHEXT to something predictable
40 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
40 std.debug.assert(SetEnvironmentVariableW(
4141 utf16Literal("PATHEXT"),
4242 utf16Literal(".COM;.EXE;.BAT;.CMD;.JS"),
4343 ) == windows.TRUE);
......@@ -48,7 +48,7 @@ pub fn main(init: std.process.Init) !void {
4848 // make sure we don't get error.BadPath traversing out of cwd with a relative path
4949 try testExecError(error.FileNotFound, gpa, io, "..\\.\\.\\.\\\\..\\more_missing");
5050
51 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
51 std.debug.assert(SetEnvironmentVariableW(
5252 utf16Literal("PATH"),
5353 tmp_absolute_path_w,
5454 ) == windows.TRUE);
......@@ -131,7 +131,7 @@ pub fn main(init: std.process.Init) !void {
131131 const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
132132 defer gpa.free(something_subdir_abs_path);
133133
134 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
134 std.debug.assert(SetEnvironmentVariableW(
135135 utf16Literal("PATH"),
136136 something_subdir_abs_path,
137137 ) == windows.TRUE);
......@@ -171,7 +171,7 @@ pub fn main(init: std.process.Init) !void {
171171 defer gpa.free(denormed_something_subdir_wtf8);
172172
173173 // clear the path to ensure that the match comes from the cwd
174 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
174 std.debug.assert(SetEnvironmentVariableW(
175175 utf16Literal("PATH"),
176176 null,
177177 ) == windows.TRUE);
......@@ -179,7 +179,7 @@ pub fn main(init: std.process.Init) !void {
179179 try testExecWithCwd(gpa, io, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
180180
181181 // normalization should also work if the non-normalized path is found in the PATH var.
182 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
182 std.debug.assert(SetEnvironmentVariableW(
183183 utf16Literal("PATH"),
184184 denormed_something_subdir_abs_path,
185185 ) == windows.TRUE);
......@@ -193,7 +193,7 @@ pub fn main(init: std.process.Init) !void {
193193 try std.process.setCurrentDir(io, subdir_cwd);
194194
195195 // clear the PATH again
196 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
196 std.debug.assert(SetEnvironmentVariableW(
197197 utf16Literal("PATH"),
198198 null,
199199 ) == windows.TRUE);
......@@ -235,3 +235,8 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons
235235 else => |e| return e,
236236 };
237237}
238
239pub extern "kernel32" fn SetEnvironmentVariableW(
240 lpName: windows.LPCWSTR,
241 lpValue: ?windows.LPCWSTR,
242) callconv(.winapi) windows.BOOL;