fix: dangling interceptor crash
This commit is contained in:
parent
9b4d7c2121
commit
ae4b56b62a
1 changed files with 21 additions and 18 deletions
|
|
@ -48,25 +48,26 @@ pub const ReadableStatus = enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
interceptor: Interceptor,
|
interceptor: *Interceptor,
|
||||||
backend: Backend,
|
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, handler: *Handler) !@This() {
|
pub fn init(allocator: std.mem.Allocator, handler: *Handler) !@This() {
|
||||||
var self: @This() = undefined;
|
const ic = try allocator.create(Interceptor);
|
||||||
self.allocator = allocator;
|
errdefer allocator.destroy(ic);
|
||||||
self.interceptor = .{
|
ic.* = .{
|
||||||
.handler = .{ .vtable = &Interceptor.vtable },
|
.handler = .{ .vtable = &Interceptor.vtable },
|
||||||
.user_handler = handler,
|
.user_handler = handler,
|
||||||
.backend_ptr = &self.backend,
|
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
.backend = undefined,
|
||||||
};
|
};
|
||||||
self.backend = try Backend.init(&self.interceptor.handler);
|
ic.backend = try Backend.init(&ic.handler);
|
||||||
try self.backend.arm(self.allocator);
|
errdefer ic.backend.deinit(allocator);
|
||||||
return self;
|
try ic.backend.arm(allocator);
|
||||||
|
return .{ .allocator = allocator, .interceptor = ic };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
self.backend.deinit(self.allocator);
|
self.interceptor.backend.deinit(self.allocator);
|
||||||
|
self.allocator.destroy(self.interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Watch a path (file or directory) for changes. The handler will receive
|
/// Watch a path (file or directory) for changes. The handler will receive
|
||||||
|
|
@ -74,35 +75,37 @@ pub fn deinit(self: *@This()) void {
|
||||||
/// all subdirectories are watched recursively and new directories created
|
/// all subdirectories are watched recursively and new directories created
|
||||||
/// inside are watched automatically.
|
/// inside are watched automatically.
|
||||||
pub fn watch(self: *@This(), path: []const u8) Error!void {
|
pub fn watch(self: *@This(), path: []const u8) Error!void {
|
||||||
try self.backend.add_watch(self.allocator, path);
|
try self.interceptor.backend.add_watch(self.allocator, path);
|
||||||
if (!Backend.watches_recursively) {
|
if (!Backend.watches_recursively) {
|
||||||
recurse_watch(&self.backend, self.allocator, path);
|
recurse_watch(&self.interceptor.backend, self.allocator, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop watching a previously watched path
|
/// Stop watching a previously watched path
|
||||||
pub fn unwatch(self: *@This(), path: []const u8) void {
|
pub fn unwatch(self: *@This(), path: []const u8) void {
|
||||||
self.backend.remove_watch(self.allocator, path);
|
self.interceptor.backend.remove_watch(self.allocator, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_read_ready(self: *@This()) !void {
|
pub fn handle_read_ready(self: *@This()) !void {
|
||||||
try self.backend.handle_read_ready(self.allocator);
|
try self.interceptor.backend.handle_read_ready(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inotify file descriptor that should be polled for POLLIN
|
/// Returns the inotify file descriptor that should be polled for POLLIN
|
||||||
/// before calling handle_read_ready(). Only available on Linux.
|
/// before calling handle_read_ready(). Only available on Linux.
|
||||||
pub fn poll_fd(self: *const @This()) std.posix.fd_t {
|
pub fn poll_fd(self: *const @This()) std.posix.fd_t {
|
||||||
comptime if (builtin.os.tag != .linux) @compileError("poll_fd is only available on Linux");
|
comptime if (builtin.os.tag != .linux) @compileError("poll_fd is only available on Linux");
|
||||||
return self.backend.inotify_fd;
|
return self.interceptor.backend.inotify_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wraps the user's handler to intercept dir_created events and auto-watch
|
// Wraps the user's handler to intercept dir_created events and auto-watch
|
||||||
// new directories before forwarding to the user.
|
// new directories before forwarding to the user.
|
||||||
|
// Heap-allocated so that &ic.handler stays valid regardless of how the
|
||||||
|
// nightwatch struct is moved after init() returns.
|
||||||
const Interceptor = struct {
|
const Interceptor = struct {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
user_handler: *Handler,
|
user_handler: *Handler,
|
||||||
backend_ptr: *Backend,
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
backend: Backend,
|
||||||
|
|
||||||
const vtable = Handler.VTable{
|
const vtable = Handler.VTable{
|
||||||
.change = change_cb,
|
.change = change_cb,
|
||||||
|
|
@ -113,8 +116,8 @@ const Interceptor = struct {
|
||||||
fn change_cb(h: *Handler, path: []const u8, event_type: EventType) error{HandlerFailed}!void {
|
fn change_cb(h: *Handler, path: []const u8, event_type: EventType) error{HandlerFailed}!void {
|
||||||
const self: *Interceptor = @fieldParentPtr("handler", h);
|
const self: *Interceptor = @fieldParentPtr("handler", h);
|
||||||
if (event_type == .dir_created and !Backend.watches_recursively) {
|
if (event_type == .dir_created and !Backend.watches_recursively) {
|
||||||
self.backend_ptr.add_watch(self.allocator, path) catch {};
|
self.backend.add_watch(self.allocator, path) catch {};
|
||||||
recurse_watch(self.backend_ptr, self.allocator, path);
|
recurse_watch(&self.backend, self.allocator, path);
|
||||||
}
|
}
|
||||||
return self.user_handler.change(path, event_type);
|
return self.user_handler.change(path, event_type);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue