summaryrefslogtreecommitdiff
path: root/src/9p_io.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/9p_io.zig')
-rw-r--r--src/9p_io.zig26
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