diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 23:03:35 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | a628330543d1c2a0b29062036f23b1c74e4ccc6e (patch) | |
| tree | 69a223c58586130d1c37b96debed58cddc0131d8 /src | |
| parent | 1ab1d412e2768d9fe56a9e97ab60716a6d31063a (diff) | |
| download | pardes-a628330543d1c2a0b29062036f23b1c74e4ccc6e.tar.gz pardes-a628330543d1c2a0b29062036f23b1c74e4ccc6e.zip | |
A builtin refused when its record is written back through event fails that write, EIO and its err, as fs.md says
A Del refused over unsaved text, written back by an event reader, said
so on the message row and answered the write ok, so the script that
wrote it could not tell. The write-back now captures failures as an
exec write does: the first one fails the write with its words and the
errno they read as.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ninep/ctl.zig | 21 | ||||
| -rw-r--r-- | src/ninep/events.zig | 10 |
2 files changed, 30 insertions, 1 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 31265a94..aa309ad1 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -296,7 +296,7 @@ pub fn captured(p: *Pardes, req: Req, id: usize, exec: bool, text: []const u8, i /// The errno a builtin's failure answers with: ENOENT for what is not /// there (`no such`, `not found`, the words 9ns reads as ENOENT too), else /// EIO. -fn failureErrno(failure: []const u8) u16 { +pub fn failureErrno(failure: []const u8) u16 { if (std.mem.indexOf(u8, failure, "no such") != null or std.mem.indexOf(u8, failure, "not found") != null) return E.NOENT; // A pattern refused (Edit's too) is malformed input, as 9ns reads it; // so is a word this build has not (`invalid: acme's Put ...`). @@ -1760,6 +1760,25 @@ test "exec Save writes the named file through the host" { try testing.expectEqualStrings(pane.file.?.content, p.fallback.get("/tmp/renamed.txt").?); } +test "a refused Del written back through event fails that write, EIO, with its err" { + const gpa = testing.allocator; + const p = try withFile(gpa, "text\n"); + defer p.deinit(); + const serial = serialOf(p); + try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .body), "more\n").reply.status); // unsaved + const event = Node.of(serial, .event); + const h = call(p, .{ .tag = 1, .op = .open, .node = event }).reply.handle; + defer _ = call(p, .{ .tag = 9, .op = .release, .node = event, .handle = h }); + try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .exec), "Del\n").reply.status); + const record = call(p, .{ .tag = 2, .op = .read, .node = event, .handle = h, .size = 256 }).bytes; + var copy: [256]u8 = undefined; + @memcpy(copy[0..record.len], record); + const back = wr(p, event, copy[0..record.len]); + try testing.expectEqual(E.IO, back.errno()); + try testing.expect(std.mem.indexOf(u8, back.reply.ename, "Modified") != null); + try testing.expect(p.paneBySerial(serial) != null); +} + test "a pane's own look and exec go to the event reader holding it, which writes them back to act" { const gpa = testing.allocator; const p = try withFile(gpa, "Msg routed\n"); diff --git a/src/ninep/events.zig b/src/ninep/events.zig index 4d1bbe64..1ffbaab9 100644 --- a/src/ninep/events.zig +++ b/src/ninep/events.zig @@ -6,6 +6,7 @@ const exec = @import("../exec.zig"); const look = @import("../look.zig"); const cloud9 = @import("cloud9"); const tree = @import("tree.zig"); +const ctl = @import("ctl.zig"); const pane_files = @import("pane.zig"); const dump = @import("../dump.zig"); @@ -736,6 +737,11 @@ pub fn writeEvent(p: *Pardes, asked: Req, id: usize) Reply { } if (check.i != req.data.len) return tree.failText(req.tag, E.INVAL, tree.e_bad_event ++ ": a record is <origin><action><q0> <q1> <flag> <count> <text>, a line each"); } + // What a record written back runs fails the write as a click written + // to exec would (a refused Del: EIO and its err), not said and lost. + p.fs.capturing = true; + p.fs.failure_len = 0; + defer p.fs.capturing = false; var run: EventReader = .{ .data = req.data }; while (run.next()) |r| { const live = p.paneBySerial(serial) orelse break; @@ -815,6 +821,10 @@ pub fn writeEvent(p: *Pardes, asked: Req, id: usize) Reply { else => unreachable, } } + if (p.fs.failure_len > 0) { + const failure = p.fs.failure[0..p.fs.failure_len]; + return tree.failText(req.tag, ctl.failureErrno(failure), std.fmt.bufPrint(&p.fs.ename, "{s}", .{failure}) catch failure); + } return .{ .tag = req.tag, .written = @intCast(asked.data.len) }; } |
