| author | |
| committer | |
| log | ccc5e581a862ba3cf635da847d279a5cac552791 |
| tree | b93721b756b90e5b9a5fda2182b849c6120e5d1b |
| parent | b31173179bc0fba53c87d6ca82eabaf4e59c3fef |
| parent | bf25816067844efbdb7fe26e8ca7a96341fb919a |
| signature |
Cleanup some Windows stuff, delete unused functions and kernel32 bindings5 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; |
| 46 | 46 | |
| 47 | 47 | /// comptime-known minimum page size of the target. |
| 48 | 48 | /// |
| 49 | /// All pointers from `mmap` or `VirtualAlloc` are aligned to at least | |
| 49 | /// All pointers from `mmap` or `NtAllocateVirtualMemory` are aligned to at least | |
| 50 | 50 | /// `page_size_min`, but their actual alignment may be bigger. |
| 51 | 51 | /// |
| 52 | 52 | /// 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 |
| 56 | 56 | else => undefined, |
| 57 | 57 | }; |
| 58 | 58 | |
| 59 | /// Call from Windows-specific code if you already have a WTF-16LE encoded, null terminated string. | |
| 60 | /// Otherwise use `access`. | |
| 61 | pub 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 | ||
| 74 | 59 | pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool { |
| 75 | 60 | return switch (os.tag) { |
| 76 | 61 | .windows, |
lib/std/os/windows.zig+127-93| ... | ... | @@ -306,22 +306,6 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C |
| 306 | 306 | wr.* = write; |
| 307 | 307 | } |
| 308 | 308 | |
| 309 | pub 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 | ||
| 314 | pub 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 | ||
| 325 | 309 | pub const DeviceIoControlError = error{ |
| 326 | 310 | AccessDenied, |
| 327 | 311 | /// The volume does not contain a recognized file system. File system |
| ... | ... | @@ -598,10 +582,6 @@ pub fn CloseHandle(hObject: HANDLE) void { |
| 598 | 582 | assert(ntdll.NtClose(hObject) == .SUCCESS); |
| 599 | 583 | } |
| 600 | 584 | |
| 601 | pub fn FindClose(hFindFile: HANDLE) void { | |
| 602 | assert(kernel32.FindClose(hFindFile) != 0); | |
| 603 | } | |
| 604 | ||
| 605 | 585 | pub const ReadFileError = error{ |
| 606 | 586 | BrokenPipe, |
| 607 | 587 | /// The specified network name is no longer available. |
| ... | ... | @@ -1104,21 +1084,135 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 1104 | 1084 | } |
| 1105 | 1085 | } |
| 1106 | 1086 | |
| 1107 | pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected }; | |
| 1087 | pub 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; | |
| 1108 | 1102 | |
| 1109 | pub 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 | } | |
| 1103 | pub 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); | |
| 1114 | 1124 | |
| 1115 | pub 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, | |
| 1121 | 1173 | } |
| 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), | |
| 1122 | 1216 | } |
| 1123 | 1217 | } |
| 1124 | 1218 | |
| ... | ... | @@ -1515,30 +1609,6 @@ pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 { |
| 1515 | 1609 | return @as(u64, @bitCast(file_size)); |
| 1516 | 1610 | } |
| 1517 | 1611 | |
| 1518 | pub const GetFileAttributesError = error{ | |
| 1519 | FileNotFound, | |
| 1520 | AccessDenied, | |
| 1521 | Unexpected, | |
| 1522 | }; | |
| 1523 | ||
| 1524 | pub 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 | ||
| 1529 | pub 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 | ||
| 1542 | 1612 | pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 { |
| 1543 | 1613 | return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen))); |
| 1544 | 1614 | } |
| ... | ... | @@ -1657,6 +1727,7 @@ pub const NtFreeVirtualMemoryError = error{ |
| 1657 | 1727 | }; |
| 1658 | 1728 | |
| 1659 | 1729 | pub 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. | |
| 1660 | 1731 | return switch (ntdll.NtFreeVirtualMemory(hProcess, addr, size, free_type)) { |
| 1661 | 1732 | .SUCCESS => return, |
| 1662 | 1733 | .ACCESS_DENIED => NtFreeVirtualMemoryError.AccessDenied, |
| ... | ... | @@ -1665,20 +1736,6 @@ pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_ |
| 1665 | 1736 | }; |
| 1666 | 1737 | } |
| 1667 | 1738 | |
| 1668 | pub const VirtualAllocError = error{Unexpected}; | |
| 1669 | ||
| 1670 | pub 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 | ||
| 1678 | pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void { | |
| 1679 | assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0); | |
| 1680 | } | |
| 1681 | ||
| 1682 | 1739 | pub const VirtualProtectError = error{ |
| 1683 | 1740 | InvalidAddress, |
| 1684 | 1741 | Unexpected, |
| ... | ... | @@ -1713,19 +1770,6 @@ pub fn VirtualProtectEx(handle: HANDLE, addr: ?LPVOID, size: SIZE_T, new_prot: D |
| 1713 | 1770 | } |
| 1714 | 1771 | } |
| 1715 | 1772 | |
| 1716 | pub const VirtualQueryError = error{Unexpected}; | |
| 1717 | ||
| 1718 | pub 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 | ||
| 1729 | 1773 | pub const SetConsoleTextAttributeError = error{Unexpected}; |
| 1730 | 1774 | |
| 1731 | 1775 | pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void { |
| ... | ... | @@ -2628,16 +2672,6 @@ test ntToWin32Namespace { |
| 2628 | 2672 | try std.testing.expectError(error.NameTooLong, ntToWin32Namespace(L("\\??\\C:\\test"), &too_small_buf)); |
| 2629 | 2673 | } |
| 2630 | 2674 | |
| 2631 | fn 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 | ||
| 2641 | 2675 | inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID { |
| 2642 | 2676 | return (s << 10) | p; |
| 2643 | 2677 | } |
lib/std/os/windows/kernel32.zig-62| ... | ... | @@ -86,34 +86,11 @@ pub extern "kernel32" fn CreateNamedPipeW( |
| 86 | 86 | lpSecurityAttributes: ?*const SECURITY_ATTRIBUTES, |
| 87 | 87 | ) callconv(.winapi) HANDLE; |
| 88 | 88 | |
| 89 | pub extern "kernel32" fn FindFirstFileW( | |
| 90 | lpFileName: LPCWSTR, | |
| 91 | lpFindFileData: *WIN32_FIND_DATAW, | |
| 92 | ) callconv(.winapi) HANDLE; | |
| 93 | ||
| 94 | pub extern "kernel32" fn FindClose( | |
| 95 | hFindFile: HANDLE, | |
| 96 | ) callconv(.winapi) BOOL; | |
| 97 | ||
| 98 | // TODO: Wrapper around RtlGetFullPathName_UEx | |
| 99 | pub extern "kernel32" fn GetFullPathNameW( | |
| 100 | lpFileName: LPCWSTR, | |
| 101 | nBufferLength: DWORD, | |
| 102 | lpBuffer: LPWSTR, | |
| 103 | lpFilePart: ?*?LPWSTR, | |
| 104 | ) callconv(.winapi) DWORD; | |
| 105 | ||
| 106 | 89 | // TODO: Matches `STD_*_HANDLE` to peb().ProcessParameters.Standard* |
| 107 | 90 | pub extern "kernel32" fn GetStdHandle( |
| 108 | 91 | nStdHandle: DWORD, |
| 109 | 92 | ) callconv(.winapi) ?HANDLE; |
| 110 | 93 | |
| 111 | pub extern "kernel32" fn MoveFileExW( | |
| 112 | lpExistingFileName: LPCWSTR, | |
| 113 | lpNewFileName: LPCWSTR, | |
| 114 | dwFlags: DWORD, | |
| 115 | ) callconv(.winapi) BOOL; | |
| 116 | ||
| 117 | 94 | // TODO: Wrapper around NtSetInformationFile + `FILE_POSITION_INFORMATION`. |
| 118 | 95 | // `FILE_STANDARD_INFORMATION` is also used if dwMoveMethod is `FILE_END` |
| 119 | 96 | pub extern "kernel32" fn SetFilePointerEx( |
| ... | ... | @@ -162,11 +139,6 @@ pub extern "kernel32" fn GetCurrentDirectoryW( |
| 162 | 139 | lpBuffer: ?[*]WCHAR, |
| 163 | 140 | ) callconv(.winapi) DWORD; |
| 164 | 141 | |
| 165 | // TODO: RtlDosPathNameToNtPathNameU_WithStatus + NtQueryAttributesFile. | |
| 166 | pub extern "kernel32" fn GetFileAttributesW( | |
| 167 | lpFileName: LPCWSTR, | |
| 168 | ) callconv(.winapi) DWORD; | |
| 169 | ||
| 170 | 142 | pub extern "kernel32" fn ReadFile( |
| 171 | 143 | hFile: HANDLE, |
| 172 | 144 | lpBuffer: LPVOID, |
| ... | ... | @@ -182,14 +154,6 @@ pub extern "kernel32" fn GetSystemDirectoryW( |
| 182 | 154 | |
| 183 | 155 | // I/O - Kernel Objects |
| 184 | 156 | |
| 185 | // TODO: Wrapper around NtCreateEvent. | |
| 186 | pub extern "kernel32" fn CreateEventExW( | |
| 187 | lpEventAttributes: ?*SECURITY_ATTRIBUTES, | |
| 188 | lpName: ?LPCWSTR, | |
| 189 | dwFlags: DWORD, | |
| 190 | dwDesiredAccess: DWORD, | |
| 191 | ) callconv(.winapi) ?HANDLE; | |
| 192 | ||
| 193 | 157 | // TODO: Wrapper around GetStdHandle + NtDuplicateObject. |
| 194 | 158 | pub extern "kernel32" fn DuplicateHandle( |
| 195 | 159 | hSourceProcessHandle: HANDLE, |
| ... | ... | @@ -318,9 +282,6 @@ pub extern "kernel32" fn GetExitCodeProcess( |
| 318 | 282 | lpExitCode: *DWORD, |
| 319 | 283 | ) callconv(.winapi) BOOL; |
| 320 | 284 | |
| 321 | // TODO: Already a wrapper for this, see `windows.GetCurrentProcess`. | |
| 322 | pub extern "kernel32" fn GetCurrentProcess() callconv(.winapi) HANDLE; | |
| 323 | ||
| 324 | 285 | // TODO: Wrapper around RtlSetEnvironmentVar. |
| 325 | 286 | pub extern "kernel32" fn SetEnvironmentVariableW( |
| 326 | 287 | lpName: LPCWSTR, |
| ... | ... | @@ -465,29 +426,6 @@ pub extern "kernel32" fn HeapValidate( |
| 465 | 426 | lpMem: ?*const anyopaque, |
| 466 | 427 | ) callconv(.winapi) BOOL; |
| 467 | 428 | |
| 468 | // TODO: Wrapper around NtAllocateVirtualMemory. | |
| 469 | pub 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. | |
| 478 | pub extern "kernel32" fn VirtualFree( | |
| 479 | lpAddress: ?LPVOID, | |
| 480 | dwSize: SIZE_T, | |
| 481 | dwFreeType: DWORD, | |
| 482 | ) callconv(.winapi) BOOL; | |
| 483 | ||
| 484 | // TODO: Wrapper around NtQueryVirtualMemory. | |
| 485 | pub extern "kernel32" fn VirtualQuery( | |
| 486 | lpAddress: ?LPVOID, | |
| 487 | lpBuffer: PMEMORY_BASIC_INFORMATION, | |
| 488 | dwLength: SIZE_T, | |
| 489 | ) callconv(.winapi) SIZE_T; | |
| 490 | ||
| 491 | 429 | // TODO: Getter for peb.ProcessHeap |
| 492 | 430 | pub extern "kernel32" fn GetProcessHeap() callconv(.winapi) ?HANDLE; |
| 493 | 431 |
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 |
| 2470 | 2470 | /// Same as `rename` except the parameters are null-terminated and WTF16LE encoded. |
| 2471 | 2471 | /// Assumes target is Windows. |
| 2472 | 2472 | pub 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); | |
| 2475 | 2475 | } |
| 2476 | 2476 | |
| 2477 | 2477 | /// Change the name or location of a file based on an open directory handle. |
| ... | ... | @@ -2588,110 +2588,7 @@ pub fn renameatW( |
| 2588 | 2588 | new_path_w: []const u16, |
| 2589 | 2589 | ReplaceIfExists: windows.BOOLEAN, |
| 2590 | 2590 | ) 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); | |
| 2695 | 2592 | } |
| 2696 | 2593 | |
| 2697 | 2594 | /// On Windows, `sub_dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). |
| ... | ... | @@ -4409,7 +4306,7 @@ pub fn mmap( |
| 4409 | 4306 | /// Note that while POSIX allows unmapping a region in the middle of an existing mapping, |
| 4410 | 4307 | /// Zig's munmap function does not, for two reasons: |
| 4411 | 4308 | /// * 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. | |
| 4413 | 4310 | pub fn munmap(memory: []align(page_size_min) const u8) void { |
| 4414 | 4311 | switch (errno(system.munmap(memory.ptr, memory.len))) { |
| 4415 | 4312 | .SUCCESS => return, |