fix: fix the fixes and add more error logging

This commit is contained in:
CJ van den Berg 2026-03-15 00:17:52 +01:00
parent eb42d23fc8
commit f60f9e6a21
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
4 changed files with 30 additions and 8 deletions

View file

@ -93,7 +93,7 @@ pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
self.file_watches.deinit(allocator);
var sit = self.snapshots.iterator();
while (sit.next()) |entry| {
// Keys are borrowed from self.watches and freed in the watches loop above.
allocator.free(entry.key_ptr.*); // independently owned; see take_snapshot/scan_dir
var names = entry.value_ptr.*;
var nit = names.iterator();
while (nit.next()) |ne| allocator.free(ne.key_ptr.*);
@ -436,7 +436,15 @@ fn take_snapshot(self: *@This(), allocator: std.mem.Allocator, dir_path: []const
self.snapshots_mutex.lock();
errdefer self.snapshots_mutex.unlock();
const gop = try self.snapshots.getOrPut(allocator, dir_path);
if (!gop.found_existing) gop.value_ptr.* = .empty;
if (!gop.found_existing) {
// Snapshot outer keys are independently owned so they can be safely
// freed in deinit/remove_watch regardless of how the entry was created.
gop.key_ptr.* = allocator.dupe(u8, dir_path) catch |e| {
_ = self.snapshots.remove(dir_path);
return e;
};
gop.value_ptr.* = .empty;
}
var snapshot = gop.value_ptr;
for (names.items) |name| {
if (snapshot.contains(name)) continue;
@ -464,6 +472,7 @@ pub fn remove_watch(self: *@This(), allocator: std.mem.Allocator, path: []const
const snap_entry = self.snapshots.fetchRemove(path);
self.snapshots_mutex.unlock();
if (snap_entry) |entry| {
allocator.free(entry.key); // independently owned; see take_snapshot/scan_dir
var names = entry.value;
var it = names.iterator();
while (it.next()) |ne| {

View file

@ -78,7 +78,7 @@ pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
self.watches.deinit(allocator);
var sit = self.snapshots.iterator();
while (sit.next()) |entry| {
// Keys are borrowed from self.watches and freed in the watches loop above.
allocator.free(entry.key_ptr.*); // independently owned; see take_snapshot/scan_dir
var snap = entry.value_ptr.*;
var nit = snap.iterator();
while (nit.next()) |ne| allocator.free(ne.key_ptr.*);
@ -385,7 +385,15 @@ fn take_snapshot(self: *@This(), allocator: std.mem.Allocator, dir_path: []const
self.snapshots_mutex.lock();
errdefer self.snapshots_mutex.unlock();
const gop = try self.snapshots.getOrPut(allocator, dir_path);
if (!gop.found_existing) gop.value_ptr.* = .empty;
if (!gop.found_existing) {
// Snapshot outer keys are independently owned so they can be safely
// freed in deinit/remove_watch regardless of how the entry was created.
gop.key_ptr.* = allocator.dupe(u8, dir_path) catch |e| {
_ = self.snapshots.remove(dir_path);
return e;
};
gop.value_ptr.* = .empty;
}
const snapshot = gop.value_ptr;
for (entries.items) |e| {
if (snapshot.contains(e.name)) continue;
@ -407,6 +415,7 @@ pub fn remove_watch(self: *@This(), allocator: std.mem.Allocator, path: []const
const snap_entry = self.snapshots.fetchRemove(path);
self.snapshots_mutex.unlock();
if (snap_entry) |entry| {
allocator.free(entry.key); // independently owned; see take_snapshot/scan_dir
var snap = entry.value;
var it = snap.iterator();
while (it.next()) |ne| allocator.free(ne.key_ptr.*);

View file

@ -210,7 +210,8 @@ fn thread_fn(
}
// Re-arm ReadDirectoryChangesW for the next batch.
w.overlapped = std.mem.zeroes(windows.OVERLAPPED);
_ = win32.ReadDirectoryChangesW(w.handle, w.buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null);
if (win32.ReadDirectoryChangesW(w.handle, w.buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null) == 0)
std.log.err("nightwatch: ReadDirectoryChangesW re-arm failed for {s}, future events lost", .{entry.key_ptr.*});
break;
}
watches_mutex.unlock();

View file

@ -225,7 +225,8 @@ pub fn Create(comptime variant: Variant) type {
fn change_cb(h: *Handler, path: []const u8, event_type: EventType, object_type: ObjectType) error{HandlerFailed}!void {
const self: *Interceptor = @fieldParentPtr("handler", h);
if (event_type == .created and object_type == .dir and !Backend.watches_recursively) {
self.backend.add_watch(self.allocator, path) catch {};
self.backend.add_watch(self.allocator, path) catch |e|
std.log.err("nightwatch: add_watch failed for {s}: {s}", .{ path, @errorName(e) });
recurse_watch(&self.backend, self.allocator, path);
}
return self.user_handler.change(path, event_type, object_type);
@ -254,7 +255,8 @@ pub fn Create(comptime variant: Variant) type {
fn change_cb(h: *PollingHandler, path: []const u8, event_type: EventType, object_type: ObjectType) error{HandlerFailed}!void {
const self: *PollingInterceptor = @fieldParentPtr("handler", h);
if (event_type == .created and object_type == .dir and !Backend.watches_recursively) {
self.backend.add_watch(self.allocator, path) catch {};
self.backend.add_watch(self.allocator, path) catch |e|
std.log.err("nightwatch: add_watch failed for {s}: {s}", .{ path, @errorName(e) });
recurse_watch(&self.backend, self.allocator, path);
}
return self.user_handler.change(path, event_type, object_type);
@ -280,7 +282,8 @@ pub fn Create(comptime variant: Variant) type {
if (entry.kind != .directory) continue;
var buf: [std.fs.max_path_bytes]u8 = undefined;
const sub = std.fmt.bufPrint(&buf, "{s}{c}{s}", .{ dir_path, std.fs.path.sep, entry.name }) catch continue;
backend.add_watch(allocator, sub) catch {};
backend.add_watch(allocator, sub) catch |e|
std.log.err("nightwatch: add_watch failed for {s}: {s}", .{ sub, @errorName(e) });
recurse_watch(backend, allocator, sub);
}
}