authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-11-24 06:14:21-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-11-24 06:14:21-08:00
logccc5e581a862ba3cf635da847d279a5cac552791
treeb93721b756b90e5b9a5fda2182b849c6120e5d1b
parentb31173179bc0fba53c87d6ca82eabaf4e59c3fef
parentbf25816067844efbdb7fe26e8ca7a96341fb919a
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #26030 from squeek502/windows-cleanup

Cleanup some Windows stuff, delete unused functions and kernel32 bindings

5 files changed, 132 insertions(+), 278 deletions(-)

lib/std/heap.zig+1-1
......@@ -46,7 +46,7 @@ pub var next_mmap_addr_hint: ?[*]align(page_size_min) u8 = null;
4646
4747/// comptime-known minimum page size of the target.
4848///
49/// All pointers from `mmap` or `VirtualAlloc` are aligned to at least
49/// All pointers from `mmap` or `NtAllocateVirtualMemory` are aligned to at least
5050/// `page_size_min`, but their actual alignment may be bigger.
5151///
5252/// This value can be overridden via `std.options.page_size_min`.
lib/std/os.zig-15
......@@ -56,21 +56,6 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (native_o
5656 else => undefined,
5757};
5858
59/// Call from Windows-specific code if you already have a WTF-16LE encoded, null terminated string.
60/// Otherwise use `access`.
61pub fn accessW(path: [*:0]const u16) windows.GetFileAttributesError!void {
62 const ret = try windows.GetFileAttributesW(path);
63 if (ret != windows.INVALID_FILE_ATTRIBUTES) {
64 return;
65 }
66 switch (windows.GetLastError()) {
67 .FILE_NOT_FOUND => return error.FileNotFound,
68 .PATH_NOT_FOUND => return error.FileNotFound,
69 .ACCESS_DENIED => return error.AccessDenied,
70 else => |err| return windows.unexpectedError(err),
71 }
72}
73
7459pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool {
7560 return switch (os.tag) {
7661 .windows,
lib/std/os/windows.zig+127-93
......@@ -306,22 +306,6 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C
306306 wr.* = write;
307307}
308308
309pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {
310 const nameW = try sliceToPrefixedFileW(null, name);
311 return CreateEventExW(attributes, nameW.span().ptr, flags, desired_access);
312}
313
314pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: ?LPCWSTR, flags: DWORD, desired_access: DWORD) !HANDLE {
315 const handle = kernel32.CreateEventExW(attributes, nameW, flags, desired_access);
316 if (handle) |h| {
317 return h;
318 } else {
319 switch (GetLastError()) {
320 else => |err| return unexpectedError(err),
321 }
322 }
323}
324
325309pub const DeviceIoControlError = error{
326310 AccessDenied,
327311 /// The volume does not contain a recognized file system. File system
......@@ -598,10 +582,6 @@ pub fn CloseHandle(hObject: HANDLE) void {
598582 assert(ntdll.NtClose(hObject) == .SUCCESS);
599583}
600584
601pub fn FindClose(hFindFile: HANDLE) void {
602 assert(kernel32.FindClose(hFindFile) != 0);
603}
604
605585pub const ReadFileError = error{
606586 BrokenPipe,
607587 /// The specified network name is no longer available.
......@@ -1104,21 +1084,135 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
11041084 }
11051085}
11061086
1107pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
1087pub const RenameError = error{
1088 IsDir,
1089 NotDir,
1090 FileNotFound,
1091 NoDevice,
1092 AccessDenied,
1093 PipeBusy,
1094 PathAlreadyExists,
1095 Unexpected,
1096 NameTooLong,
1097 NetworkNotFound,
1098 AntivirusInterference,
1099 BadPathName,
1100 RenameAcrossMountPoints,
1101} || UnexpectedError;
11081102
1109pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) (MoveFileError || Wtf8ToPrefixedFileWError)!void {
1110 const old_path_w = try sliceToPrefixedFileW(null, old_path);
1111 const new_path_w = try sliceToPrefixedFileW(null, new_path);
1112 return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags);
1113}
1103pub fn RenameFile(
1104 /// May only be `null` if `old_path_w` is a fully-qualified absolute path.
1105 old_dir_fd: ?HANDLE,
1106 old_path_w: []const u16,
1107 /// May only be `null` if `new_path_w` is a fully-qualified absolute path,
1108 /// or if the file is not being moved to a different directory.
1109 new_dir_fd: ?HANDLE,
1110 new_path_w: []const u16,
1111 replace_if_exists: bool,
1112) RenameError!void {
1113 const src_fd = OpenFile(old_path_w, .{
1114 .dir = old_dir_fd,
1115 .access_mask = SYNCHRONIZE | GENERIC_WRITE | DELETE,
1116 .creation = FILE_OPEN,
1117 .filter = .any, // This function is supposed to rename both files and directories.
1118 .follow_symlinks = false,
1119 }) catch |err| switch (err) {
1120 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
1121 else => |e| return e,
1122 };
1123 defer CloseHandle(src_fd);
11141124
1115pub fn MoveFileExW(old_path: [*:0]const u16, new_path: [*:0]const u16, flags: DWORD) MoveFileError!void {
1116 if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) {
1117 switch (GetLastError()) {
1118 .FILE_NOT_FOUND => return error.FileNotFound,
1119 .ACCESS_DENIED => return error.AccessDenied,
1120 else => |err| return unexpectedError(err),
1125 var rc: NTSTATUS = undefined;
1126 // FileRenameInformationEx has varying levels of support:
1127 // - FILE_RENAME_INFORMATION_EX requires >= win10_rs1
1128 // (INVALID_INFO_CLASS is returned if not supported)
1129 // - Requires the NTFS filesystem
1130 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
1131 // - FILE_RENAME_POSIX_SEMANTICS requires >= win10_rs1
1132 // - FILE_RENAME_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
1133 // (NOT_SUPPORTED is returned if a flag is unsupported)
1134 //
1135 // The strategy here is just to try using FileRenameInformationEx and fall back to
1136 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.
1137 const need_fallback = need_fallback: {
1138 const struct_buf_len = @sizeOf(FILE_RENAME_INFORMATION_EX) + (PATH_MAX_WIDE * 2);
1139 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(FILE_RENAME_INFORMATION_EX)) = undefined;
1140 const struct_len = @sizeOf(FILE_RENAME_INFORMATION_EX) + new_path_w.len * 2;
1141 if (struct_len > struct_buf_len) return error.NameTooLong;
1142
1143 const rename_info: *FILE_RENAME_INFORMATION_EX = @ptrCast(&rename_info_buf);
1144 var io_status_block: IO_STATUS_BLOCK = undefined;
1145
1146 var flags: ULONG = FILE_RENAME_POSIX_SEMANTICS | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE;
1147 if (replace_if_exists) flags |= FILE_RENAME_REPLACE_IF_EXISTS;
1148 rename_info.* = .{
1149 .Flags = flags,
1150 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
1151 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
1152 .FileName = undefined,
1153 };
1154 @memcpy((&rename_info.FileName).ptr, new_path_w);
1155 rc = ntdll.NtSetInformationFile(
1156 src_fd,
1157 &io_status_block,
1158 rename_info,
1159 @intCast(struct_len), // already checked for error.NameTooLong
1160 .FileRenameInformationEx,
1161 );
1162 switch (rc) {
1163 .SUCCESS => return,
1164 // The filesystem does not support FileDispositionInformationEx
1165 .INVALID_PARAMETER,
1166 // The operating system does not support FileDispositionInformationEx
1167 .INVALID_INFO_CLASS,
1168 // The operating system does not support one of the flags
1169 .NOT_SUPPORTED,
1170 => break :need_fallback true,
1171 // For all other statuses, fall down to the switch below to handle them.
1172 else => break :need_fallback false,
11211173 }
1174 };
1175
1176 if (need_fallback) {
1177 const struct_buf_len = @sizeOf(FILE_RENAME_INFORMATION) + (PATH_MAX_WIDE * 2);
1178 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(FILE_RENAME_INFORMATION)) = undefined;
1179 const struct_len = @sizeOf(FILE_RENAME_INFORMATION) + new_path_w.len * 2;
1180 if (struct_len > struct_buf_len) return error.NameTooLong;
1181
1182 const rename_info: *FILE_RENAME_INFORMATION = @ptrCast(&rename_info_buf);
1183 var io_status_block: IO_STATUS_BLOCK = undefined;
1184
1185 rename_info.* = .{
1186 .Flags = @intFromBool(replace_if_exists),
1187 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
1188 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
1189 .FileName = undefined,
1190 };
1191 @memcpy((&rename_info.FileName).ptr, new_path_w);
1192
1193 rc = ntdll.NtSetInformationFile(
1194 src_fd,
1195 &io_status_block,
1196 rename_info,
1197 @intCast(struct_len), // already checked for error.NameTooLong
1198 .FileRenameInformation,
1199 );
1200 }
1201
1202 switch (rc) {
1203 .SUCCESS => {},
1204 .INVALID_HANDLE => unreachable,
1205 .INVALID_PARAMETER => unreachable,
1206 .OBJECT_PATH_SYNTAX_BAD => unreachable,
1207 .ACCESS_DENIED => return error.AccessDenied,
1208 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
1209 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
1210 .NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
1211 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
1212 .DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
1213 .FILE_IS_A_DIRECTORY => return error.IsDir,
1214 .NOT_A_DIRECTORY => return error.NotDir,
1215 else => return unexpectedStatus(rc),
11221216 }
11231217}
11241218
......@@ -1515,30 +1609,6 @@ pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
15151609 return @as(u64, @bitCast(file_size));
15161610}
15171611
1518pub const GetFileAttributesError = error{
1519 FileNotFound,
1520 AccessDenied,
1521 Unexpected,
1522};
1523
1524pub fn GetFileAttributes(filename: []const u8) (GetFileAttributesError || Wtf8ToPrefixedFileWError)!DWORD {
1525 const filename_w = try sliceToPrefixedFileW(null, filename);
1526 return GetFileAttributesW(filename_w.span().ptr);
1527}
1528
1529pub fn GetFileAttributesW(lpFileName: [*:0]const u16) GetFileAttributesError!DWORD {
1530 const rc = kernel32.GetFileAttributesW(lpFileName);
1531 if (rc == INVALID_FILE_ATTRIBUTES) {
1532 switch (GetLastError()) {
1533 .FILE_NOT_FOUND => return error.FileNotFound,
1534 .PATH_NOT_FOUND => return error.FileNotFound,
1535 .ACCESS_DENIED => return error.AccessDenied,
1536 else => |err| return unexpectedError(err),
1537 }
1538 }
1539 return rc;
1540}
1541
15421612pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
15431613 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
15441614}
......@@ -1657,6 +1727,7 @@ pub const NtFreeVirtualMemoryError = error{
16571727};
16581728
16591729pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_type: ULONG) NtFreeVirtualMemoryError!void {
1730 // TODO: If the return value is .INVALID_PAGE_PROTECTION, call RtlFlushSecureMemoryCache and try again.
16601731 return switch (ntdll.NtFreeVirtualMemory(hProcess, addr, size, free_type)) {
16611732 .SUCCESS => return,
16621733 .ACCESS_DENIED => NtFreeVirtualMemoryError.AccessDenied,
......@@ -1665,20 +1736,6 @@ pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_
16651736 };
16661737}
16671738
1668pub const VirtualAllocError = error{Unexpected};
1669
1670pub fn VirtualAlloc(addr: ?LPVOID, size: usize, alloc_type: DWORD, flProtect: DWORD) VirtualAllocError!LPVOID {
1671 return kernel32.VirtualAlloc(addr, size, alloc_type, flProtect) orelse {
1672 switch (GetLastError()) {
1673 else => |err| return unexpectedError(err),
1674 }
1675 };
1676}
1677
1678pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
1679 assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
1680}
1681
16821739pub const VirtualProtectError = error{
16831740 InvalidAddress,
16841741 Unexpected,
......@@ -1713,19 +1770,6 @@ pub fn VirtualProtectEx(handle: HANDLE, addr: ?LPVOID, size: SIZE_T, new_prot: D
17131770 }
17141771}
17151772
1716pub const VirtualQueryError = error{Unexpected};
1717
1718pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQueryError!SIZE_T {
1719 const rc = kernel32.VirtualQuery(lpAddress, lpBuffer, dwLength);
1720 if (rc == 0) {
1721 switch (GetLastError()) {
1722 else => |err| return unexpectedError(err),
1723 }
1724 }
1725
1726 return rc;
1727}
1728
17291773pub const SetConsoleTextAttributeError = error{Unexpected};
17301774
17311775pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
......@@ -2628,16 +2672,6 @@ test ntToWin32Namespace {
26282672 try std.testing.expectError(error.NameTooLong, ntToWin32Namespace(L("\\??\\C:\\test"), &too_small_buf));
26292673}
26302674
2631fn getFullPathNameW(path: [*:0]const u16, out: []u16) !usize {
2632 const result = kernel32.GetFullPathNameW(path, @as(u32, @intCast(out.len)), out.ptr, null);
2633 if (result == 0) {
2634 switch (GetLastError()) {
2635 else => |err| return unexpectedError(err),
2636 }
2637 }
2638 return result;
2639}
2640
26412675inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID {
26422676 return (s << 10) | p;
26432677}
lib/std/os/windows/kernel32.zig-62
......@@ -86,34 +86,11 @@ pub extern "kernel32" fn CreateNamedPipeW(
8686 lpSecurityAttributes: ?*const SECURITY_ATTRIBUTES,
8787) callconv(.winapi) HANDLE;
8888
89pub extern "kernel32" fn FindFirstFileW(
90 lpFileName: LPCWSTR,
91 lpFindFileData: *WIN32_FIND_DATAW,
92) callconv(.winapi) HANDLE;
93
94pub extern "kernel32" fn FindClose(
95 hFindFile: HANDLE,
96) callconv(.winapi) BOOL;
97
98// TODO: Wrapper around RtlGetFullPathName_UEx
99pub extern "kernel32" fn GetFullPathNameW(
100 lpFileName: LPCWSTR,
101 nBufferLength: DWORD,
102 lpBuffer: LPWSTR,
103 lpFilePart: ?*?LPWSTR,
104) callconv(.winapi) DWORD;
105
10689// TODO: Matches `STD_*_HANDLE` to peb().ProcessParameters.Standard*
10790pub extern "kernel32" fn GetStdHandle(
10891 nStdHandle: DWORD,
10992) callconv(.winapi) ?HANDLE;
11093
111pub extern "kernel32" fn MoveFileExW(
112 lpExistingFileName: LPCWSTR,
113 lpNewFileName: LPCWSTR,
114 dwFlags: DWORD,
115) callconv(.winapi) BOOL;
116
11794// TODO: Wrapper around NtSetInformationFile + `FILE_POSITION_INFORMATION`.
11895// `FILE_STANDARD_INFORMATION` is also used if dwMoveMethod is `FILE_END`
11996pub extern "kernel32" fn SetFilePointerEx(
......@@ -162,11 +139,6 @@ pub extern "kernel32" fn GetCurrentDirectoryW(
162139 lpBuffer: ?[*]WCHAR,
163140) callconv(.winapi) DWORD;
164141
165// TODO: RtlDosPathNameToNtPathNameU_WithStatus + NtQueryAttributesFile.
166pub extern "kernel32" fn GetFileAttributesW(
167 lpFileName: LPCWSTR,
168) callconv(.winapi) DWORD;
169
170142pub extern "kernel32" fn ReadFile(
171143 hFile: HANDLE,
172144 lpBuffer: LPVOID,
......@@ -182,14 +154,6 @@ pub extern "kernel32" fn GetSystemDirectoryW(
182154
183155// I/O - Kernel Objects
184156
185// TODO: Wrapper around NtCreateEvent.
186pub extern "kernel32" fn CreateEventExW(
187 lpEventAttributes: ?*SECURITY_ATTRIBUTES,
188 lpName: ?LPCWSTR,
189 dwFlags: DWORD,
190 dwDesiredAccess: DWORD,
191) callconv(.winapi) ?HANDLE;
192
193157// TODO: Wrapper around GetStdHandle + NtDuplicateObject.
194158pub extern "kernel32" fn DuplicateHandle(
195159 hSourceProcessHandle: HANDLE,
......@@ -318,9 +282,6 @@ pub extern "kernel32" fn GetExitCodeProcess(
318282 lpExitCode: *DWORD,
319283) callconv(.winapi) BOOL;
320284
321// TODO: Already a wrapper for this, see `windows.GetCurrentProcess`.
322pub extern "kernel32" fn GetCurrentProcess() callconv(.winapi) HANDLE;
323
324285// TODO: Wrapper around RtlSetEnvironmentVar.
325286pub extern "kernel32" fn SetEnvironmentVariableW(
326287 lpName: LPCWSTR,
......@@ -465,29 +426,6 @@ pub extern "kernel32" fn HeapValidate(
465426 lpMem: ?*const anyopaque,
466427) callconv(.winapi) BOOL;
467428
468// TODO: Wrapper around NtAllocateVirtualMemory.
469pub extern "kernel32" fn VirtualAlloc(
470 lpAddress: ?LPVOID,
471 dwSize: SIZE_T,
472 flAllocationType: DWORD,
473 flProtect: DWORD,
474) callconv(.winapi) ?LPVOID;
475
476// TODO: Wrapper around NtFreeVirtualMemory.
477// If the return value is .INVALID_PAGE_PROTECTION, calls RtlFlushSecureMemoryCache and try again.
478pub extern "kernel32" fn VirtualFree(
479 lpAddress: ?LPVOID,
480 dwSize: SIZE_T,
481 dwFreeType: DWORD,
482) callconv(.winapi) BOOL;
483
484// TODO: Wrapper around NtQueryVirtualMemory.
485pub extern "kernel32" fn VirtualQuery(
486 lpAddress: ?LPVOID,
487 lpBuffer: PMEMORY_BASIC_INFORMATION,
488 dwLength: SIZE_T,
489) callconv(.winapi) SIZE_T;
490
491429// TODO: Getter for peb.ProcessHeap
492430pub extern "kernel32" fn GetProcessHeap() callconv(.winapi) ?HANDLE;
493431
lib/std/posix.zig+4-107
......@@ -2470,8 +2470,8 @@ pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!voi
24702470/// Same as `rename` except the parameters are null-terminated and WTF16LE encoded.
24712471/// Assumes target is Windows.
24722472pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!void {
2473 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
2474 return windows.MoveFileExW(old_path, new_path, flags);
2473 const cwd_handle = std.fs.cwd().fd;
2474 return windows.RenameFile(cwd_handle, mem.span(old_path), cwd_handle, mem.span(new_path), true);
24752475}
24762476
24772477/// Change the name or location of a file based on an open directory handle.
......@@ -2588,110 +2588,7 @@ pub fn renameatW(
25882588 new_path_w: []const u16,
25892589 ReplaceIfExists: windows.BOOLEAN,
25902590) RenameError!void {
2591 const src_fd = windows.OpenFile(old_path_w, .{
2592 .dir = old_dir_fd,
2593 .access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE,
2594 .creation = windows.FILE_OPEN,
2595 .filter = .any, // This function is supposed to rename both files and directories.
2596 .follow_symlinks = false,
2597 }) catch |err| switch (err) {
2598 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
2599 else => |e| return e,
2600 };
2601 defer windows.CloseHandle(src_fd);
2602
2603 var rc: windows.NTSTATUS = undefined;
2604 // FileRenameInformationEx has varying levels of support:
2605 // - FILE_RENAME_INFORMATION_EX requires >= win10_rs1
2606 // (INVALID_INFO_CLASS is returned if not supported)
2607 // - Requires the NTFS filesystem
2608 // (on filesystems like FAT32, INVALID_PARAMETER is returned)
2609 // - FILE_RENAME_POSIX_SEMANTICS requires >= win10_rs1
2610 // - FILE_RENAME_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5
2611 // (NOT_SUPPORTED is returned if a flag is unsupported)
2612 //
2613 // The strategy here is just to try using FileRenameInformationEx and fall back to
2614 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.
2615 const need_fallback = need_fallback: {
2616 const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) + (max_path_bytes - 1);
2617 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION_EX)) = undefined;
2618 const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) - 1 + new_path_w.len * 2;
2619 if (struct_len > struct_buf_len) return error.NameTooLong;
2620
2621 const rename_info: *windows.FILE_RENAME_INFORMATION_EX = @ptrCast(&rename_info_buf);
2622 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
2623
2624 var flags: windows.ULONG = windows.FILE_RENAME_POSIX_SEMANTICS | windows.FILE_RENAME_IGNORE_READONLY_ATTRIBUTE;
2625 if (ReplaceIfExists == windows.TRUE) flags |= windows.FILE_RENAME_REPLACE_IF_EXISTS;
2626 rename_info.* = .{
2627 .Flags = flags,
2628 .RootDirectory = if (fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
2629 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
2630 .FileName = undefined,
2631 };
2632 @memcpy((&rename_info.FileName).ptr, new_path_w);
2633 rc = windows.ntdll.NtSetInformationFile(
2634 src_fd,
2635 &io_status_block,
2636 rename_info,
2637 @intCast(struct_len), // already checked for error.NameTooLong
2638 .FileRenameInformationEx,
2639 );
2640 switch (rc) {
2641 .SUCCESS => return,
2642 // The filesystem does not support FileDispositionInformationEx
2643 .INVALID_PARAMETER,
2644 // The operating system does not support FileDispositionInformationEx
2645 .INVALID_INFO_CLASS,
2646 // The operating system does not support one of the flags
2647 .NOT_SUPPORTED,
2648 => break :need_fallback true,
2649 // For all other statuses, fall down to the switch below to handle them.
2650 else => break :need_fallback false,
2651 }
2652 };
2653
2654 if (need_fallback) {
2655 const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (max_path_bytes - 1);
2656 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
2657 const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path_w.len * 2;
2658 if (struct_len > struct_buf_len) return error.NameTooLong;
2659
2660 const rename_info: *windows.FILE_RENAME_INFORMATION = @ptrCast(&rename_info_buf);
2661 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
2662
2663 rename_info.* = .{
2664 .Flags = ReplaceIfExists,
2665 .RootDirectory = if (fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir_fd,
2666 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
2667 .FileName = undefined,
2668 };
2669 @memcpy((&rename_info.FileName).ptr, new_path_w);
2670
2671 rc = windows.ntdll.NtSetInformationFile(
2672 src_fd,
2673 &io_status_block,
2674 rename_info,
2675 @intCast(struct_len), // already checked for error.NameTooLong
2676 .FileRenameInformation,
2677 );
2678 }
2679
2680 switch (rc) {
2681 .SUCCESS => {},
2682 .INVALID_HANDLE => unreachable,
2683 .INVALID_PARAMETER => unreachable,
2684 .OBJECT_PATH_SYNTAX_BAD => unreachable,
2685 .ACCESS_DENIED => return error.AccessDenied,
2686 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2687 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2688 .NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
2689 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
2690 .DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
2691 .FILE_IS_A_DIRECTORY => return error.IsDir,
2692 .NOT_A_DIRECTORY => return error.NotDir,
2693 else => return windows.unexpectedStatus(rc),
2694 }
2591 return windows.RenameFile(old_dir_fd, old_path_w, new_dir_fd, new_path_w, ReplaceIfExists != 0);
26952592}
26962593
26972594/// On Windows, `sub_dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
......@@ -4409,7 +4306,7 @@ pub fn mmap(
44094306/// Note that while POSIX allows unmapping a region in the middle of an existing mapping,
44104307/// Zig's munmap function does not, for two reasons:
44114308/// * It violates the Zig principle that resource deallocation must succeed.
4412/// * The Windows function, VirtualFree, has this restriction.
4309/// * The Windows function, NtFreeVirtualMemory, has this restriction.
44134310pub fn munmap(memory: []align(page_size_min) const u8) void {
44144311 switch (errno(system.munmap(memory.ptr, memory.len))) {
44154312 .SUCCESS => return,