diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 02:16:21 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | 9fa0969549108bcdf05201e846226470e278a798 (patch) | |
| tree | ff5f4e6f55f8968d3e51f7bbf2e0602b78e3bb89 | |
| parent | 9391d35d357ebf18759c10f6c756855e5a8f7b50 (diff) | |
| download | pardes-9fa0969549108bcdf05201e846226470e278a798.tar.gz pardes-9fa0969549108bcdf05201e846226470e278a798.zip | |
addr reads empty after a failed address instead of failing
With no address after a failed write, a read of addr itself failed (EIO
through a mount), which reads as a broken file rather than as no address.
It now reads empty, as an unset limit does; data and xdata still refuse.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
| -rw-r--r-- | .agents/skills/pardes-9p/SKILL.md | 2 | ||||
| -rw-r--r-- | docs/fs.md | 6 | ||||
| -rw-r--r-- | src/ninep/addr.zig | 3 | ||||
| -rw-r--r-- | src/ninep/pane.zig | 12 |
4 files changed, 13 insertions, 10 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md index cc129d5c..feb4f703 100644 --- a/.agents/skills/pardes-9p/SKILL.md +++ b/.agents/skills/pardes-9p/SKILL.md @@ -234,7 +234,7 @@ and a search that backtracks past a step budget (about 300 ms) fails with `regular expression search gave up, ...`. A failed address says why (`no match for regexp`, `address out of range`) and leaves no address: -`data` refuses until the next good one, so a missed target is never +`addr` reads empty and `data` refuses until the next good one, so a missed target is never written at the old one. Moving `dot` scrolls the pane to it. `limit` bounds only the end of a forward search, as in acme, and reads empty until set; truncate it to lift it. In `12:5` the column counts bytes from 1 and clamps @@ -563,9 +563,9 @@ expression`, `regular expression search gave up, ...`, or sam's `addresses out of order` for a range that ends before it starts (`#100,#50`), which acme lets through. A failed write to `addr` leaves no address at all, where acme -keeps the old one: until a good address is written, -reading `addr`, and reading, writing or truncating `data` and `xdata`, fail -with `no address: the last one written to addr failed`, so a script that +keeps the old one: until a good address is written, `addr` reads empty +(as an unset `limit` does), and reading, writing or truncating `data` and +`xdata` fail with `no address: the last one written to addr failed`, so a script that missed its target cannot then write at the last one. The three flag files `dirty`, `mark` and `scroll` read `0` or `1` and take diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig index e731ba24..15f23a55 100644 --- a/src/ninep/addr.zig +++ b/src/ninep/addr.zig @@ -373,7 +373,8 @@ test "a failed address leaves none, so data refuses rather than act at the last try testing.expectEqualStrings(e_no_match, th.wr(p, addr, "/zzz/").reply.ename); try testing.expectEqualStrings(pane_files.e_addr_failed, th.wr(p, data, "ONE").reply.ename); try testing.expectEqualStrings(pane_files.e_addr_failed, th.rd(p, data, 0, 64).reply.ename); - try testing.expectEqualStrings(pane_files.e_addr_failed, th.rd(p, addr, 0, 64).reply.ename); + try testing.expectEqual(Status.ok, th.rd(p, addr, 0, 64).reply.status); + try testing.expectEqualStrings("", th.rd(p, addr, 0, 64).bytes); try testing.expectEqual(E.INVAL, th.call(p, .{ .tag = 1, .op = .setattr, .node = Node.of(serial, .xdata), .truncate = true }).errno()); try testing.expectEqualStrings("one\ntwo\n", p.panes[0].?.file.?.content); // A good address gives it one again; truncating addr does not. diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index e7b72c88..3307eb47 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -250,7 +250,8 @@ pub fn fileSize(p: *Pardes, id: usize, f: PaneFile) u64 { const d = dotOf(pane); break :sel @max(d.q0, d.q1) - d.q0; }, - .addr, .dot => range_len, + .addr => if (pf.addr_failed) 0 else range_len, + .dot => range_len, .limit => if (pf.limit == null) 0 else range_len, .dirty, .mark, .scroll => 2, .look, .exec => ctl.resultsLen(p), @@ -308,11 +309,12 @@ pub fn read(p: *Pardes, req: Req, id: usize, pane: *Pane, file: PaneFile) Reply break :tag tree.stagedReply(p, req); }, .ctl => ctl.readPane(p, req, pane), - .addr => addr: { - if (pf.addr_failed) break :addr tree.failText(req.tag, E.INVAL, e_addr_failed); + // A failed address reads empty, as an unset limit does: there is + // none. data and xdata are what refuse. + .addr => readRange(p, req, if (pf.addr_failed) null else addr: { clampAddr(pf, bodyOf(pane).len); - break :addr readRange(p, req, pf.addr); - }, + break :addr pf.addr; + }), .dot => readRange(p, req, dotOf(pane)), .limit => readRange(p, req, pf.limit), .data => readData(req, id, pane, pf, false), |
