fix: windows build

This commit is contained in:
CJ van den Berg 2026-02-20 11:33:29 +01:00
parent 7672eb3c51
commit 3f132173d5
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9

View file

@ -302,6 +302,36 @@ const MacosBackend = struct {
const WindowsBackend = struct {
const windows = std.os.windows;
const win32 = struct {
pub extern "kernel32" fn CloseHandle(hObject: windows.HANDLE) callconv(.winapi) windows.BOOL;
pub extern "kernel32" fn ReadDirectoryChangesW(
hDirectory: windows.HANDLE,
lpBuffer: *anyopaque,
nBufferLength: windows.DWORD,
bWatchSubtree: windows.BOOL,
dwNotifyFilter: windows.DWORD,
lpBytesReturned: ?*windows.DWORD,
lpOverlapped: ?*windows.OVERLAPPED,
lpCompletionRoutine: ?*anyopaque,
) callconv(.winapi) windows.BOOL;
pub extern "kernel32" fn GetQueuedCompletionStatus(
CompletionPort: windows.HANDLE,
lpNumberOfBytesTransferred: *windows.DWORD,
lpCompletionKey: *windows.ULONG_PTR,
lpOverlapped: *?*windows.OVERLAPPED,
dwMilliseconds: windows.DWORD,
) callconv(.winapi) windows.BOOL;
pub extern "kernel32" fn CreateFileW(
lpFileName: [*:0]const windows.WCHAR,
dwDesiredAccess: windows.DWORD,
dwShareMode: windows.DWORD,
lpSecurityAttributes: ?*anyopaque,
dwCreationDisposition: windows.DWORD,
dwFlagsAndAttributes: windows.DWORD,
hTemplateFile: ?windows.HANDLE,
) callconv(.winapi) windows.HANDLE;
};
iocp: windows.HANDLE,
poll_timer: ?tp.timeout,
watches: std.StringHashMapUnmanaged(Watch),
@ -310,12 +340,13 @@ const WindowsBackend = struct {
const Watch = struct {
handle: windows.HANDLE,
buf: *align(4) [buf_size]u8,
buf: Buf,
overlapped: windows.OVERLAPPED,
path: []u8, // owned
};
const buf_size = 65536;
const Buf = []align(4) u8;
const FILE_NOTIFY_INFORMATION = extern struct {
NextEntryOffset: windows.DWORD,
@ -347,12 +378,12 @@ const WindowsBackend = struct {
if (self.poll_timer) |*t| t.deinit();
var it = self.watches.iterator();
while (it.next()) |entry| {
_ = windows.kernel32.CloseHandle(entry.value_ptr.*.handle);
_ = win32.CloseHandle(entry.value_ptr.*.handle);
allocator.free(entry.value_ptr.*.path);
allocator.destroy(entry.value_ptr.*.buf);
allocator.free(entry.value_ptr.*.buf);
}
self.watches.deinit(allocator);
_ = windows.kernel32.CloseHandle(self.iocp);
_ = win32.CloseHandle(self.iocp);
}
fn arm(self: *WindowsBackend) void {
@ -364,7 +395,7 @@ const WindowsBackend = struct {
if (self.watches.contains(path)) return;
const path_w = try std.unicode.utf8ToUtf16LeAllocZ(allocator, path);
defer allocator.free(path_w);
const handle = windows.kernel32.CreateFileW(
const handle = win32.CreateFileW(
path_w,
windows.GENERIC_READ,
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
@ -374,14 +405,14 @@ const WindowsBackend = struct {
null,
);
if (handle == windows.INVALID_HANDLE_VALUE) return error.FileWatcherFailed;
errdefer _ = windows.kernel32.CloseHandle(handle);
errdefer _ = win32.CloseHandle(handle);
_ = windows.CreateIoCompletionPort(handle, self.iocp, @intFromPtr(handle), 0) catch return error.FileWatcherFailed;
const buf = try allocator.create([buf_size]u8);
errdefer allocator.destroy(buf);
const buf = try allocator.alignedAlloc(u8, .fromByteUnits(4), buf_size);
errdefer allocator.free(buf);
const owned_path = try allocator.dupe(u8, path);
errdefer allocator.free(owned_path);
var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
if (windows.kernel32.ReadDirectoryChangesW(handle, buf, buf_size, 1, notify_filter, null, &overlapped, null) == 0)
if (win32.ReadDirectoryChangesW(handle, buf.ptr, buf_size, 1, notify_filter, null, &overlapped, null) == 0)
return error.FileWatcherFailed;
try self.watches.put(allocator, owned_path, .{
.handle = handle,
@ -393,9 +424,9 @@ const WindowsBackend = struct {
fn remove_watch(self: *WindowsBackend, allocator: std.mem.Allocator, path: []const u8) void {
if (self.watches.fetchRemove(path)) |entry| {
_ = windows.kernel32.CloseHandle(entry.value.handle);
_ = win32.CloseHandle(entry.value.handle);
allocator.free(entry.value.path);
allocator.destroy(entry.value.buf);
allocator.free(entry.value.buf);
}
}
@ -405,7 +436,7 @@ const WindowsBackend = struct {
var key: windows.ULONG_PTR = 0;
var overlapped_ptr: ?*windows.OVERLAPPED = null;
while (true) {
const ok = windows.kernel32.GetQueuedCompletionStatus(self.iocp, &bytes, &key, &overlapped_ptr, 0);
const ok = win32.GetQueuedCompletionStatus(self.iocp, &bytes, &key, &overlapped_ptr, 0);
if (ok == 0 or overlapped_ptr == null) break;
const triggered_handle: windows.HANDLE = @ptrFromInt(key);
var it = self.watches.iterator();
@ -416,7 +447,7 @@ const WindowsBackend = struct {
var offset: usize = 0;
while (offset < bytes) {
const info: *FILE_NOTIFY_INFORMATION = @ptrCast(@alignCast(w.buf[offset..].ptr));
const name_wchars = info.FileName[0 .. info.FileNameLength / 2];
const name_wchars = (&info.FileName).ptr[0 .. info.FileNameLength / 2];
var name_buf: [std.fs.max_path_bytes]u8 = undefined;
const name_len = std.unicode.utf16LeToUtf8(&name_buf, name_wchars) catch 0;
const event_type: EventType = switch (info.Action) {
@ -439,7 +470,7 @@ const WindowsBackend = struct {
}
// Re-arm ReadDirectoryChangesW for the next batch.
w.overlapped = std.mem.zeroes(windows.OVERLAPPED);
_ = windows.kernel32.ReadDirectoryChangesW(w.handle, w.buf, buf_size, 1, notify_filter, null, &w.overlapped, null);
_ = win32.ReadDirectoryChangesW(w.handle, w.buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null);
break;
}
}