diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 09:11:37 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | a550753fb60be3cdc040c521ddaab9022f5d3248 (patch) | |
| tree | 9d392076f417b6a9d53b6a1bc9ce7fe44d4e499b /src/ninep/pane.zig | |
| parent | 4d4818f7baf356866d323e4b337a64a3dddd8adb (diff) | |
| download | pardes-a550753fb60be3cdc040c521ddaab9022f5d3248.tar.gz pardes-a550753fb60be3cdc040c521ddaab9022f5d3248.zip | |
Every EINVAL a write gets says why; DEL in an exec or look line is a control character
An empty name, a word written to log other than follow, a data, sel, dot
or dirty write to a pane with no text, a truncate other than to zero,
and a control character in a look line written through a held open were
refused with no words, logged as `Invalid argument`. Each says its reason
now; and DEL is refused in exec and look lines as in names.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/pane.zig')
| -rw-r--r-- | src/ninep/pane.zig | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index 66b3728c..4c967fc5 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -481,8 +481,11 @@ fn writeTag(req: Req, pane: *Pane) Reply { return .{ .tag = req.tag, .written = @intCast(take) }; } +/// A write only text takes, to a pane with none: said, as every EINVAL is. +pub const e_no_text = "invalid write: this pane has no text (a terminal, an image or a PDF)"; + fn writeData(p: *Pardes, req: Req, pane: *Pane) Reply { - if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL); + if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text); const pf = &pane.fs; if (pf.addr_failed) return tree.failText(req.tag, E.INVAL, e_addr_failed); clampAddr(pf, bodyOf(pane).len); @@ -501,7 +504,7 @@ fn writeData(p: *Pardes, req: Req, pane: *Pane) Reply { } fn writeSel(p: *Pardes, req: Req, pane: *Pane) Reply { - if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL); + if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text); const d = dotOf(pane); const q0: usize = d.q0; const q1: usize = @max(q0, @as(usize, d.q1)); @@ -558,7 +561,7 @@ fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply { .limit => pf.limit = range, // Setting dot scrolls to it, which is the whole of acme's `show`. .dot => { - if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL); + if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text); setDot(pane, range); }, else => unreachable, @@ -573,7 +576,7 @@ fn writeFlag(p: *Pardes, req: Req, pane: *Pane, file: PaneFile) Reply { const pf = &pane.fs; switch (file) { .dirty => { - const f = fileOf(pane) orelse return Reply.fail(req.tag, E.INVAL); + const f = fileOf(pane) orelse return tree.failText(req.tag, E.INVAL, e_no_text); f.saved_revision = if (on) f.revision -% 1 else f.revision; }, // acme's nomark joins the writes after it into one undo step. The @@ -616,7 +619,7 @@ fn nameFault(name: []const u8) ?[]const u8 { fn writeName(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply { // One name: its newline ends it, as `echo` writes it, and it is one. const name = if (std.mem.endsWith(u8, req.data, "\n")) req.data[0 .. req.data.len - 1] else req.data; - if (name.len == 0) return Reply.fail(req.tag, E.INVAL); + if (name.len == 0) return tree.failText(req.tag, E.INVAL, e_name_char ++ ": an empty name"); if (nameFault(name)) |why| return tree.failText(req.tag, E.INVAL, why); if (fileOf(pane) == null) return tree.failText(req.tag, E.PERM, if (pane.isTerminal()) "rename not allowed: a terminal is named by its shell's directory; cd there, or Tty in another" @@ -624,7 +627,7 @@ fn writeName(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply { "rename not allowed: an image or PDF is named by the file it shows"); const full = std.fs.path.resolvePosix(p.scratch.allocator(), &.{ pardes.Pardes.paneDir(pane), name }) catch return Reply.fail(req.tag, E.NOMEM); - if (!std.fs.path.isAbsolute(full) or full.len >= 4096) return Reply.fail(req.tag, E.INVAL); + if (!std.fs.path.isAbsolute(full) or full.len >= 4096) return tree.failText(req.tag, E.INVAL, "invalid file name: longer than a path may be"); nameBuffer(p, id, full, false) catch |err| return Reply.fail(req.tag, switch (err) { error.OutOfMemory => E.NOMEM, else => E.INVAL, |
