diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 04:00:32 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 04:00:32 -0300 |
| commit | 8dc84e6f9f1c3802f1d28de4d49907381cdf224b (patch) | |
| tree | 3ed7727a61de9ae4c473413d81de3ac95844af78 /src/9p_io.zig | |
| parent | a4e17d350a7afdeee4916584c44c4770243c84e4 (diff) | |
| download | pardes-8dc84e6f9f1c3802f1d28de4d49907381cdf224b.tar.gz pardes-8dc84e6f9f1c3802f1d28de4d49907381cdf224b.zip | |
pardes - asks /pager for its +Pager and reads the serial on the same open: another client's exec meanwhile can never take the text into its pane
pardes - wrote `pager <dir>` to /ctl, then read /exec on a fresh open,
which answers the session's last answer: a client that exec'd in
between had its pane overwritten by the paged text. /pager takes the
directory and answers the +Pager's serial on the open that wrote it,
as /pane/new answers its own open; the ctl verb is gone. Client.ask
writes and reads on one open. The README's look recipe reads its
answer on its own open too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/9p_io.zig')
| -rw-r--r-- | src/9p_io.zig | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/9p_io.zig b/src/9p_io.zig index b11a4997..9fc19df9 100644 --- a/src/9p_io.zig +++ b/src/9p_io.zig @@ -2319,6 +2319,32 @@ pub const Client = struct { gpa.destroy(s); } + /// Writes `request` to `path` and reads the answer on the same open, + /// as /pane/new answers its own open: a session's last answer, from + /// another client, can never be what comes back. `exec 3<>file`. + pub fn ask(gpa: std.mem.Allocator, dial: []const u8, path: []const u8, request: []const u8) ![]u8 { + if (comptime !supported) return error.Unsupported; + var names: [max_depth][]const u8 = undefined; + const n = try elements(path, &names); + var sock_buf: [sun_path_len]u8 = undefined; + const sock = try resolve(&sock_buf, dial); + var remote: RemoteError = .{}; + errdefer said = remote; + const s = try startSession(gpa, sock, path); + defer endSession(gpa, s); + const fid = (try walkTo(s, names[0..n], &remote)).fid; + _ = try s.ask(.{ .open = .{ .fid = fid, .mode = ninep.ordwr } }, &remote); + _ = try s.ask(.{ .write = .{ .fid = fid, .offset = 0, .data = request } }, &remote); + var out: std.ArrayList(u8) = .empty; + errdefer out.deinit(gpa); + while (true) { + const data = (try s.ask(.{ .read = .{ .fid = fid, .offset = out.items.len, .count = s.cl.maxRead() } }, &remote)).read; + if (data.len == 0) return out.toOwnedSlice(gpa); + if (out.items.len + data.len > 4096) return Error.FileTooLarge; + try out.appendSlice(gpa, data); + } + } + /// Opens `path` on one connection and writes `first` to it (/log's /// `follow new`), all with the usual deadline; then, once `ready(ctx)` /// has said it is not done already, reads it with no deadline, a read at |
