summaryrefslogtreecommitdiff
path: root/src/ninep/tree.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/tree.zig')
-rw-r--r--src/ninep/tree.zig15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index 60778b9c..d6f4211b 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 };
@@ -512,6 +515,7 @@ fn attrOf(p: *Pardes, target: Target) ?Reply.Attr {
.col => |c| {
if (layout.columnBySerial(p, c.serial) == null) return null;
return .{
+ // unreachable: a u32 serial fits node_name (16)
.name = if (c.file == .dir) (std.fmt.bufPrint(&p.fs.node_name, "{d}", .{c.serial}) catch unreachable) else c.file.fileName(),
.node = Node.ofCol(c.serial, c.file),
.dir = c.file == .dir,
@@ -534,6 +538,7 @@ fn attrOf(p: *Pardes, target: Target) ?Reply.Attr {
const pn = p.panes[id].?;
if (t.file.inPty() and !pn.isTerminal()) return null;
return .{
+ // unreachable: a u32 serial fits node_name (16)
.name = if (t.file == .dir) (std.fmt.bufPrint(&p.fs.node_name, "{d}", .{t.serial}) catch unreachable) else t.file.fileName(),
.node = Node.of(t.serial, t.file),
.dir = t.file.isDir(),
@@ -579,6 +584,7 @@ fn topSize(p: *Pardes, f: TopFile) u64 {
if (p.header_focus) break :focus 0;
const pn = p.panes[p.active] orelse break :focus 0;
var digits: [16]u8 = undefined;
+ // unreachable: a u32 serial and a newline fit 16
break :focus (std.fmt.bufPrint(&digits, "{d}\n", .{pn.serial}) catch unreachable).len;
},
};
@@ -688,6 +694,7 @@ fn readdir(p: *Pardes, req: Req, target: Target) Reply {
continue;
}
var buf: [16]u8 = undefined;
+ // unreachable: a u32 serial fits 16
const name = std.fmt.bufPrint(&buf, "{d}", .{serial}) catch unreachable;
stageDirent(out, p.gpa, Node.of(serial, .dir), true, name);
}
@@ -699,6 +706,7 @@ fn readdir(p: *Pardes, req: Req, target: Target) Reply {
}
var buf: [16]u8 = undefined;
const serial = layout.columnSerial(p, c);
+ // unreachable: a u32 serial fits 16
stageDirent(out, p.gpa, Node.ofCol(serial, .dir), true, std.fmt.bufPrint(&buf, "{d}", .{serial}) catch unreachable);
},
else => return Reply.fail(req.tag, E.NOTDIR),
@@ -1071,6 +1079,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..]);