diff options
Diffstat (limited to 'src/ninep/tree.zig')
| -rw-r--r-- | src/ninep/tree.zig | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index aca8d109..f98429ab 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -117,8 +117,8 @@ pub const TopFile = enum(u4) { pub fn mode(f: TopFile) u16 { return switch (f) { .root, .pane => 0o755, - .look, .exec => 0o666, - .README, .index, .status, .log, .screen, .listeners, .new => 0o444, + .look, .exec, .log => 0o666, + .README, .index, .status, .screen, .listeners, .new => 0o444, }; } @@ -375,7 +375,7 @@ fn topSize(p: *Pardes, f: TopFile) u64 { .README => fs.help.len, .status => ctl.statusLen(p), .look, .exec => ctl.resultsLen(p), - .log => events.pending(&p.fs.log), + .log => events.logLen(&p.fs.log), .listeners => screen.listenersLen(p), }; } @@ -497,7 +497,7 @@ fn open(p: *Pardes, req: Req, target: Target) Reply { .top => |f| switch (f) { .new => return .{ .tag = req.tag, .handle = makePane(p) orelse return Reply.fail(req.tag, E.NFILE) }, .screen => return screen.openSnapshot(p, req, true), - .log => p.fs.log_readers +|= 1, + .log => return events.openLog(p, req), else => {}, }, .pane => |t| { @@ -543,10 +543,7 @@ fn releaseHandle(p: *Pardes, req: Req) Reply { if (screen.releaseSnapshot(p, req)) return .{ .tag = req.tag }; const target = Node.target(req.node) orelse return .{ .tag = req.tag }; switch (target) { - .top => |f| if (f == .log and p.fs.log_readers > 0) { - p.fs.log_readers -= 1; - if (p.fs.log_readers == 0) p.fs.log.clearAndFree(p.gpa); - }, + .top => {}, .pane => |t| { if (t.file != .event and t.file != .pty_data) return .{ .tag = req.tag }; const id = p.paneBySerial(t.serial) orelse return .{ .tag = req.tag }; @@ -597,7 +594,7 @@ fn read(p: *Pardes, req: Req, target: Target) Reply { }, .status => ctl.readStatus(p, req), .look, .exec => ctl.readResults(p, req), - .log => events.readQueue(p, req, &p.fs.log), + .log => events.readLog(p, req), .screen => screen.readSnapshot(p, req, null), .listeners => screen.readListeners(p, req), // The serial the open handed this fid, so that two reads of one @@ -623,6 +620,7 @@ fn write(p: *Pardes, req: Req, target: Target) Reply { switch (target) { .top => |f| return switch (f) { .look, .exec => ctl.command(p, req, null, f == .exec), + .log => events.writeLog(p, req), else => Reply.fail(req.tag, E.PERM), }, .pane => |t| { @@ -730,6 +728,36 @@ test "filesystem pane creation and truncation cancel Look hover" { } } +test "README names every file the tree serves" { + // /README is the whole manual a client gets; a file it never mentions + // is one nobody can find without reading this source. + const words = struct { + fn has(name: []const u8) bool { + var it = std.mem.tokenizeAny(u8, fs.help, " \t\n,.:;()'\"$<>|=/"); + while (it.next()) |w| if (std.mem.eql(u8, w, name)) return true; + return false; + } + }; + inline for (@typeInfo(TopFile).@"enum".fields) |f| { + const t: TopFile = @enumFromInt(f.value); + if (t != .root and !words.has(t.fileName())) { + std.debug.print("README does not mention /{s}\n", .{t.fileName()}); + return error.Undocumented; + } + } + inline for (@typeInfo(PaneFile).@"enum".fields) |f| { + const t: PaneFile = @enumFromInt(f.value); + const ok = if (t == .dir) true else if (t.inPty() and t != .pty) + std.mem.indexOf(u8, fs.help, "pty/" ++ comptime @as(PaneFile, @enumFromInt(f.value)).fileName()) != null + else + words.has(t.fileName()); + if (!ok) { + std.debug.print("README does not mention pane file {s}\n", .{@tagName(t)}); + return error.Undocumented; + } + } +} + test "readdir lists the root and a pane directory without creating anything" { const gpa = testing.allocator; const p = try withFile(gpa, "hello\n"); |
