fix: windows build

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

View file

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