summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/pane.zig18
-rw-r--r--src/ninep/tree.zig10
2 files changed, 28 insertions, 0 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index d48c8e71..66e3dad8 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -1124,6 +1124,24 @@ test "after a failed address, one that goes from it says there is none" {
try testing.expectEqual(Status.ok, wr(p, addr, ".").reply.status);
}
+test "a write of two lines to name is refused EINVAL, on a held open or not" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const node = Node.of(serial, .name);
+ try testing.expectEqual(E.INVAL, wr(p, node, "/tmp/a\n/tmp/b\n").errno());
+ const h = call(p, .{ .tag = 1, .op = .open, .node = node, .omode = 1 }).reply.handle;
+ try testing.expectEqual(E.INVAL, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h, .data = "/tmp/a\n/tmp/b\n" }).errno());
+ _ = call(p, .{ .tag = 3, .op = .release, .node = node, .handle = h, .opened = true });
+ try testing.expectEqualStrings("/test.txt", nameOf(p.panes[p.paneBySerial(serial).?].?));
+ // Line by line, as bash writes it: the second line is refused.
+ const h2 = call(p, .{ .tag = 1, .op = .open, .node = node, .omode = 1 }).reply.handle;
+ try testing.expectEqual(Status.ok, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h2, .data = "/tmp/pardes-a\n" }).reply.status);
+ try testing.expectEqual(E.INVAL, call(p, .{ .tag = 2, .op = .write, .node = node, .handle = h2, .data = "/tmp/pardes-b\n" }).errno());
+ _ = call(p, .{ .tag = 3, .op = .release, .node = node, .handle = h2, .opened = true });
+ try testing.expectEqualStrings("/tmp/pardes-a", nameOf(p.panes[p.paneBySerial(serial).?].?));
+}
+
test "a name cut across writes is one name, applied once at its newline or its close" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index 60778b9c..8c0e74a6 100644
--- a/src/ninep/tree.zig
+++ b/src/ninep/tree.zig
@@ -162,6 +162,9 @@ pub const Open = struct {
/// answered from it again: bash's `read` takes a chunk, keeps a line and
/// lseeks back to just past it, and a stream has already moved on.
replay: ?Replay = null,
+ /// A `name` open has named its pane: one name an open, so a second line
+ /// on it (bash writes `printf 'a\nb\n'` a line at a time) is refused.
+ named: bool = false,
pub const Replay = struct { off: u64, bytes: []u8 };
@@ -1071,6 +1074,13 @@ fn write(p: *Pardes, req: Req, target: Target) Reply {
o.pending.clearRetainingCapacity();
return failText(req.tag, E.INVAL, "a line or Edit block over 1 MiB");
}
+ if (target == .pane and target.pane.file == .name) {
+ if (o.named or std.mem.count(u8, o.pending.items[0..end], "\n") > 1) {
+ o.pending.clearRetainingCapacity();
+ return failText(req.tag, E.INVAL, "invalid file name: one name a write, on one line");
+ }
+ o.named = true;
+ }
const whole = p.scratch.allocator().dupe(u8, o.pending.items[0..end]) catch return Reply.fail(req.tag, E.NOMEM);
const rest = o.pending.items.len - end;
std.mem.copyForwards(u8, o.pending.items[0..rest], o.pending.items[end..]);