Skip to content

Commit ccc5e58

Browse files
authored
Merge pull request #26030 from squeek502/windows-cleanup
Cleanup some Windows stuff, delete unused functions and kernel32 bindings
2 parents b311731 + bf25816 commit ccc5e58

5 files changed

Lines changed: 132 additions & 278 deletions

File tree

lib/std/heap.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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`.
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-
7459
pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool {
7560
return switch (os.tag) {
7661
.windows,

lib/std/os/windows.zig

Lines changed: 127 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -306,22 +306,6 @@ pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) C
306306
wr.* = write;
307307
}
308308

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-
325309
pub 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

601-
pub fn FindClose(hFindFile: HANDLE) void {
602-
assert(kernel32.FindClose(hFindFile) != 0);
603-
}
604-
605585
pub 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

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;
11081102

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);
11141124

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,
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

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-
15421612
pub 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

16591729
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.
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

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-
16821739
pub 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

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-
17291773
pub const SetConsoleTextAttributeError = error{Unexpected};
17301774

17311775
pub 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

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-
26412675
inline fn MAKELANGID(p: c_ushort, s: c_ushort) LANGID {
26422676
return (s << 10) | p;
26432677
}

0 commit comments

Comments
 (0)