fix(windows): cache renamed-to path

This commit is contained in:
CJ van den Berg 2026-03-29 17:47:14 +02:00
parent ef01e2590e
commit 6927431726
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
2 changed files with 23 additions and 8 deletions

View file

@ -183,8 +183,19 @@ fn thread_fn(
if (info.Action == FILE_ACTION_RENAMED_NEW_NAME) {
if (pending_rename) |pr| {
const src = pr.path_buf[0..pr.path_len];
// Re-scan renamed directory contents into cache so
// subsequent delete events for children resolve correctly.
// Cache the new path so future delete/rename events can
// resolve its type (OLD_NAME removed it from the cache).
if (pr.object_type != .unknown) cache_new: {
const gop = path_types.getOrPut(allocator, full_path) catch break :cache_new;
if (!gop.found_existing) {
gop.key_ptr.* = allocator.dupe(u8, full_path) catch {
_ = path_types.remove(full_path);
break :cache_new;
};
}
gop.value_ptr.* = pr.object_type;
}
// For dirs, also scan children into cache.
if (pr.object_type == .dir)
scan_path_types_into(allocator, path_types, full_path);
const next_entry_offset = info.NextEntryOffset;

View file

@ -550,8 +550,6 @@ fn testMultipleFiles(comptime Watcher: type, allocator: std.mem.Allocator) !void
}
fn testRenameOrder(comptime Watcher: type, allocator: std.mem.Allocator) !void {
// inotify pairs MOVED_FROM + MOVED_TO into a single rename event; nothing to order.
if (builtin.os.tag == .linux) return error.SkipZigTest;
const TH = MakeTestHandler(Watcher);
@ -581,6 +579,10 @@ fn testRenameOrder(comptime Watcher: type, allocator: std.mem.Allocator) !void {
try std.fs.renameAbsolute(src_path, dst_path);
try drainEvents(Watcher, &watcher);
// Backends that deliver a paired rename() callback (INotify, Windows) have
// no two-event ordering to verify - the pair is a single atomic event.
if (th.hasRename(src_path, dst_path)) return;
const src_idx = th.indexOfAnyPath(src_path) orelse
return error.MissingSrcEvent;
const dst_idx = th.indexOfChange(dst_path, .renamed, .file) orelse
@ -628,10 +630,12 @@ fn testRenameThenModify(comptime Watcher: type, allocator: std.mem.Allocator) !v
}
try drainEvents(Watcher, &watcher);
const rename_idx: usize = if (builtin.os.tag == .linux)
th.indexOfRename(src_path, dst_path) orelse return error.MissingRenameEvent
else
th.indexOfAnyPath(src_path) orelse return error.MissingSrcEvent;
// Prefer the paired rename event (INotify, Windows); fall back to any
// event touching src_path for backends that emit separate events.
const rename_idx: usize =
th.indexOfRename(src_path, dst_path) orelse
th.indexOfAnyPath(src_path) orelse
return error.MissingSrcEvent;
const modify_idx = th.indexOfChange(dst_path, .modified, .file) orelse
return error.MissingModifyEvent;