| 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,7 +46,7 @@ pub var next_mmap_addr_hint: ?[*]align(page_size_min) u8 = null; |
| 46 | 46 | ||
| 47 | /// comptime-known minimum page size of the target. | 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 | /// `page_size_min`, but their actual alignment may be bigger. | 50 | /// `page_size_min`, but their actual alignment may be bigger. |
| 51 | /// | 51 | /// |
| 52 | /// This value can be overridden via `std.options.page_size_min`. | 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,21 +56,6 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (native_o |
| 56 | else => undefined, | 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 | pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool { | 59 | pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool { |
| 75 | return switch (os.tag) { | 60 | return switch (os.tag) { |
| 76 | .windows, | 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,22 +306,6 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C |
| 306 | wr.* = write; | 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 | pub const DeviceIoControlError = error{ | 309 | pub const DeviceIoControlError = error{ |
| 326 | AccessDenied, | 310 | AccessDenied, |
| 327 | /// The volume does not contain a recognized file system. File system | 311 | /// The volume does not contain a recognized file system. File system |
| ... | @@ -598,10 +582,6 @@ pub fn CloseHandle(hObject: HANDLE) void { | ... | @@ -598,10 +582,6 @@ pub fn CloseHandle(hObject: HANDLE) void { |
| 598 | assert(ntdll.NtClose(hObject) == .SUCCESS); | 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 | pub const ReadFileError = error{ | 585 | pub const ReadFileError = error{ |
| 606 | BrokenPipe, | 586 | BrokenPipe, |
| 607 | /// The specified network name is no longer available. | 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,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 { | 1103 | pub fn RenameFile( |
| 1110 | const old_path_w = try sliceToPrefixedFileW(null, old_path); | 1104 | /// May only be `null` if `old_path_w` is a fully-qualified absolute path. |
| 1111 | const new_path_w = try sliceToPrefixedFileW(null, new_path); | 1105 | old_dir_fd: ?HANDLE, |
| 1112 | return MoveFileExW(old_path_w.span().ptr, new_path_w.span().ptr, flags); | 1106 | old_path_w: []const u16, |
| 1113 | } | 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 { | 1125 | var rc: NTSTATUS = undefined; |
| 1116 | if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) { | 1126 | // FileRenameInformationEx has varying levels of support: |
| 1117 | switch (GetLastError()) { | 1127 | // - FILE_RENAME_INFORMATION_EX requires >= win10_rs1 |
| 1118 | .FILE_NOT_FOUND => return error.FileNotFound, | 1128 | // (INVALID_INFO_CLASS is returned if not supported) |
| 1119 | .ACCESS_DENIED => return error.AccessDenied, | 1129 | // - Requires the NTFS filesystem |
| 1120 | else => |err| return unexpectedError(err), | 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,30 +1609,6 @@ pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 { |
| 1515 | return @as(u64, @bitCast(file_size)); | 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 | pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 { | 1612 | pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 { |
| 1543 | return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen))); | 1613 | return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen))); |
| 1544 | } | 1614 | } |
| ... | @@ -1657,6 +1727,7 @@ pub const NtFreeVirtualMemoryError = error{ | ... | @@ -1657,6 +1727,7 @@ pub const NtFreeVirtualMemoryError = error{ |
| 1657 | }; | 1727 | }; |
| 1658 | 1728 | ||
| 1659 | pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_type: ULONG) NtFreeVirtualMemoryError!void { | 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 | return switch (ntdll.NtFreeVirtualMemory(hProcess, addr, size, free_type)) { | 1731 | return switch (ntdll.NtFreeVirtualMemory(hProcess, addr, size, free_type)) { |
| 1661 | .SUCCESS => return, | 1732 | .SUCCESS => return, |
| 1662 | .ACCESS_DENIED => NtFreeVirtualMemoryError.AccessDenied, | 1733 | .ACCESS_DENIED => NtFreeVirtualMemoryError.AccessDenied, |
| ... | @@ -1665,20 +1736,6 @@ pub fn NtFreeVirtualMemory(hProcess: HANDLE, addr: ?*PVOID, size: *SIZE_T, free_ | ... | @@ -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 | pub const VirtualProtectError = error{ | 1739 | pub const VirtualProtectError = error{ |
| 1683 | InvalidAddress, | 1740 | InvalidAddress, |
| 1684 | Unexpected, | 1741 | Unexpected, |
| ... | @@ -1713,19 +1770,6 @@ pub fn VirtualProtectEx(handle: HANDLE, addr: ?LPVOID, size: SIZE_T, new_prot: D | ... | @@ -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 | pub const SetConsoleTextAttributeError = error{Unexpected}; | 1773 | pub const SetConsoleTextAttributeError = error{Unexpected}; |
| 1730 | 1774 | ||
| 1731 | pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void { | 1775 | pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void { |
| ... | @@ -2628,16 +2672,6 @@ test ntToWin32Namespace { | ... | @@ -2628,16 +2672,6 @@ test ntToWin32Namespace { |
| 2628 | try std.testing.expectError(error.NameTooLong, ntToWin32Namespace(L("\\??\\C:\\test"), &too_small_buf)); | 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 | inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID { | 2675 | inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID { |
| 2642 | return (s << 10) | p; | 2676 | return (s << 10) | p; |
| 2643 | } | 2677 | } |
lib/std/os/windows/kernel32.zig-62| ... | @@ -86,34 +86,11 @@ pub extern "kernel32" fn CreateNamedPipeW( | ... | @@ -86,34 +86,11 @@ pub extern "kernel32" fn CreateNamedPipeW( |
| 86 | lpSecurityAttributes: ?*const SECURITY_ATTRIBUTES, | 86 | lpSecurityAttributes: ?*const SECURITY_ATTRIBUTES, |
| 87 | ) callconv(.winapi) HANDLE; | 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 | // TODO: Matches `STD_*_HANDLE` to peb().ProcessParameters.Standard* | 89 | // TODO: Matches `STD_*_HANDLE` to peb().ProcessParameters.Standard* |
| 107 | pub extern "kernel32" fn GetStdHandle( | 90 | pub extern "kernel32" fn GetStdHandle( |
| 108 | nStdHandle: DWORD, | 91 | nStdHandle: DWORD, |
| 109 | ) callconv(.winapi) ?HANDLE; | 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 | // TODO: Wrapper around NtSetInformationFile + `FILE_POSITION_INFORMATION`. | 94 | // TODO: Wrapper around NtSetInformationFile + `FILE_POSITION_INFORMATION`. |
| 118 | // `FILE_STANDARD_INFORMATION` is also used if dwMoveMethod is `FILE_END` | 95 | // `FILE_STANDARD_INFORMATION` is also used if dwMoveMethod is `FILE_END` |
| 119 | pub extern "kernel32" fn SetFilePointerEx( | 96 | pub extern "kernel32" fn SetFilePointerEx( |
| ... | @@ -162,11 +139,6 @@ pub extern "kernel32" fn GetCurrentDirectoryW( | ... | @@ -162,11 +139,6 @@ pub extern "kernel32" fn GetCurrentDirectoryW( |
| 162 | lpBuffer: ?[*]WCHAR, | 139 | lpBuffer: ?[*]WCHAR, |
| 163 | ) callconv(.winapi) DWORD; | 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 | pub extern "kernel32" fn ReadFile( | 142 | pub extern "kernel32" fn ReadFile( |
| 171 | hFile: HANDLE, | 143 | hFile: HANDLE, |
| 172 | lpBuffer: LPVOID, | 144 | lpBuffer: LPVOID, |
| ... | @@ -182,14 +154,6 @@ pub extern "kernel32" fn GetSystemDirectoryW( | ... | @@ -182,14 +154,6 @@ pub extern "kernel32" fn GetSystemDirectoryW( |
| 182 | 154 | ||
| 183 | // I/O - Kernel Objects | 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 | // TODO: Wrapper around GetStdHandle + NtDuplicateObject. | 157 | // TODO: Wrapper around GetStdHandle + NtDuplicateObject. |
| 194 | pub extern "kernel32" fn DuplicateHandle( | 158 | pub extern "kernel32" fn DuplicateHandle( |
| 195 | hSourceProcessHandle: HANDLE, | 159 | hSourceProcessHandle: HANDLE, |
| ... | @@ -318,9 +282,6 @@ pub extern "kernel32" fn GetExitCodeProcess( | ... | @@ -318,9 +282,6 @@ pub extern "kernel32" fn GetExitCodeProcess( |
| 318 | lpExitCode: *DWORD, | 282 | lpExitCode: *DWORD, |
| 319 | ) callconv(.winapi) BOOL; | 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 | // TODO: Wrapper around RtlSetEnvironmentVar. | 285 | // TODO: Wrapper around RtlSetEnvironmentVar. |
| 325 | pub extern "kernel32" fn SetEnvironmentVariableW( | 286 | pub extern "kernel32" fn SetEnvironmentVariableW( |
| 326 | lpName: LPCWSTR, | 287 | lpName: LPCWSTR, |
| ... | @@ -465,29 +426,6 @@ pub extern "kernel32" fn HeapValidate( | ... | @@ -465,29 +426,6 @@ pub extern "kernel32" fn HeapValidate( |
| 465 | lpMem: ?*const anyopaque, | 426 | lpMem: ?*const anyopaque, |
| 466 | ) callconv(.winapi) BOOL; | 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 | // TODO: Getter for peb.ProcessHeap | 429 | // TODO: Getter for peb.ProcessHeap |
| 492 | pub extern "kernel32" fn GetProcessHeap() callconv(.winapi) ?HANDLE; | 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,8 +2470,8 @@ pub fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!voi |
| 2470 | /// Same as `rename` except the parameters are null-terminated and WTF16LE encoded. | 2470 | /// Same as `rename` except the parameters are null-terminated and WTF16LE encoded. |
| 2471 | /// Assumes target is Windows. | 2471 | /// Assumes target is Windows. |
| 2472 | pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!void { | 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; | 2473 | const cwd_handle = std.fs.cwd().fd; |
| 2474 | return windows.MoveFileExW(old_path, new_path, flags); | 2474 | return windows.RenameFile(cwd_handle, mem.span(old_path), cwd_handle, mem.span(new_path), true); |
| 2475 | } | 2475 | } |
| 2476 | 2476 | ||
| 2477 | /// Change the name or location of a file based on an open directory handle. | 2477 | /// Change the name or location of a file based on an open directory handle. |
| ... | @@ -2588,110 +2588,7 @@ pub fn renameatW( | ... | @@ -2588,110 +2588,7 @@ pub fn renameatW( |
| 2588 | new_path_w: []const u16, | 2588 | new_path_w: []const u16, |
| 2589 | ReplaceIfExists: windows.BOOLEAN, | 2589 | ReplaceIfExists: windows.BOOLEAN, |
| 2590 | ) RenameError!void { | 2590 | ) RenameError!void { |
| 2591 | const src_fd = windows.OpenFile(old_path_w, .{ | 2591 | return windows.RenameFile(old_dir_fd, old_path_w, new_dir_fd, new_path_w, ReplaceIfExists != 0); |
| 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 | } | ||
| 2695 | } | 2592 | } |
| 2696 | 2593 | ||
| 2697 | /// On Windows, `sub_dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). | 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,7 +4306,7 @@ pub fn mmap( |
| 4409 | /// Note that while POSIX allows unmapping a region in the middle of an existing mapping, | 4306 | /// Note that while POSIX allows unmapping a region in the middle of an existing mapping, |
| 4410 | /// Zig's munmap function does not, for two reasons: | 4307 | /// Zig's munmap function does not, for two reasons: |
| 4411 | /// * It violates the Zig principle that resource deallocation must succeed. | 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 | pub fn munmap(memory: []align(page_size_min) const u8) void { | 4310 | pub fn munmap(memory: []align(page_size_min) const u8) void { |
| 4414 | switch (errno(system.munmap(memory.ptr, memory.len))) { | 4311 | switch (errno(system.munmap(memory.ptr, memory.len))) { |
| 4415 | .SUCCESS => return, | 4312 | .SUCCESS => return, |