summaryrefslogtreecommitdiff
path: root/src/ninep/pane.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/pane.zig')
-rw-r--r--src/ninep/pane.zig18
1 files changed, 16 insertions, 2 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index ec6e8551..4327c403 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -570,8 +570,9 @@ fn writeTag(req: Req, pane: *Pane) Reply {
const pf = &pane.fs;
const had = tagline.curTail(pane).len;
const room = limits.max_tag_tail -| had -| @intFromBool(pf.tag_held_newline);
- if (room == 0) return Reply.fail(req.tag, E.NOSPC);
- const take = wholeUtf8(req.data[0..@min(req.data.len, room)]);
+ // Whole or not at all: a write that would pass the limit changes nothing.
+ if (req.data.len > room) return tree.failText(req.tag, E.NOSPC, std.fmt.comptimePrint("tag: over {d} bytes", .{limits.max_tag_tail}));
+ const take = wholeUtf8(req.data);
// A truncating write drops ONE trailing newline, its whole text's: a
// newline held from a write before goes in once more text follows it.
if (pf.tag_held_newline) {
@@ -1189,6 +1190,19 @@ test "an open's writes in a row are held and go in as one edit, seen by the next
try testing.expectEqualStrings("abone\n", rd(p, body, 0, 64).bytes);
}
+test "a tag write past the limit is refused whole, naming the limit" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const tag = Node.of(serialOf(p), .tag);
+ const before = try testing.allocator.dupe(u8, rd(p, tag, 0, 1 << 16).bytes);
+ defer testing.allocator.free(before);
+ const big = "w" ** (limits.max_tag_tail + 10);
+ const r = wr(p, tag, big);
+ try testing.expectEqual(E.NOSPC, r.errno());
+ try testing.expect(std.mem.startsWith(u8, r.reply.ename, "tag: over "));
+ try testing.expectEqualStrings(before, rd(p, tag, 0, 1 << 16).bytes);
+}
+
test "two opens writing one body are two undo steps, however their writes interleave" {
const p = try withFile(testing.allocator, "one\n");
defer p.deinit();