fix(windows): seed path_types to avoid unknown paths
This commit is contained in:
parent
4e5ff53d0d
commit
ecdb311c89
1 changed files with 35 additions and 2 deletions
|
|
@ -168,8 +168,11 @@ fn thread_fn(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
// Determine object_type: try GetFileAttributesW; cache result.
|
// Determine object_type: try GetFileAttributesW; cache result.
|
||||||
const object_type: ObjectType = if (event_type == .deleted) blk: {
|
// For deleted paths and the old name in a rename, the path no
|
||||||
// Path no longer exists; use cached type if available.
|
// longer exists at event time so GetFileAttributesW would fail;
|
||||||
|
// use the cached type instead.
|
||||||
|
const object_type: ObjectType = if (event_type == .deleted or
|
||||||
|
info.Action == FILE_ACTION_RENAMED_OLD_NAME) blk: {
|
||||||
const cached = path_types.fetchRemove(full_path);
|
const cached = path_types.fetchRemove(full_path);
|
||||||
break :blk if (cached) |kv| blk2: {
|
break :blk if (cached) |kv| blk2: {
|
||||||
allocator.free(kv.key);
|
allocator.free(kv.key);
|
||||||
|
|
@ -251,6 +254,36 @@ pub fn add_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8)
|
||||||
if (win32.ReadDirectoryChangesW(handle, buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null) == 0)
|
if (win32.ReadDirectoryChangesW(handle, buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null) == 0)
|
||||||
return error.WatchFailed;
|
return error.WatchFailed;
|
||||||
try self.watches.put(allocator, owned_path, w);
|
try self.watches.put(allocator, owned_path, w);
|
||||||
|
// Seed path_types with pre-existing entries so delete/rename events for
|
||||||
|
// paths that existed before this watch started can resolve their ObjectType.
|
||||||
|
self.scan_path_types(allocator, owned_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk root recursively and seed path_types with the type of every entry.
|
||||||
|
// Called from add_watch (mutex already held) so pre-existing paths are
|
||||||
|
// known before any FILE_ACTION_REMOVED or FILE_ACTION_RENAMED_OLD_NAME fires.
|
||||||
|
fn scan_path_types(self: *@This(), allocator: std.mem.Allocator, root: []const u8) void {
|
||||||
|
var dir = std.fs.openDirAbsolute(root, .{ .iterate = true }) catch return;
|
||||||
|
defer dir.close();
|
||||||
|
var iter = dir.iterate();
|
||||||
|
while (iter.next() catch return) |entry| {
|
||||||
|
const ot: ObjectType = switch (entry.kind) {
|
||||||
|
.directory => .dir,
|
||||||
|
.file => .file,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const full_path = std.fmt.bufPrint(&path_buf, "{s}\\{s}", .{ root, entry.name }) catch continue;
|
||||||
|
const gop = self.path_types.getOrPut(allocator, full_path) catch continue;
|
||||||
|
if (!gop.found_existing) {
|
||||||
|
gop.key_ptr.* = allocator.dupe(u8, full_path) catch {
|
||||||
|
_ = self.path_types.remove(full_path);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
gop.value_ptr.* = ot;
|
||||||
|
if (ot == .dir) self.scan_path_types(allocator, gop.key_ptr.*);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8) void {
|
pub fn remove_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8) void {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue