summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 17:22:57 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commite626219c9e35b37dece1348f1349c40866871f4c (patch)
treed6726a3571df9a1dd212ad057760ce5c481d2e56 /src
parent8d25618ea575611e5b1cbe48f4ac48532f2e32be (diff)
downloadpardes-e626219c9e35b37dece1348f1349c40866871f4c.tar.gz
pardes-e626219c9e35b37dece1348f1349c40866871f4c.zip
fs.md says that in a > to a tag cut into several writes, those taken before a refused one stand
A `>` to a tag that a client sends in several writes is checked a write at a time. When a later one is refused, the earlier accepted ones stay in the tag. Buffering the whole open to apply it or none would cost more than it saves, so fs.md now says what happens: each write stands on its own, and only the refused one changes nothing. A test covers a truncation, an accepted write, then a refused one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/ninep/cols.zig12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/ninep/cols.zig b/src/ninep/cols.zig
index 4e497545..a1fe9ecc 100644
--- a/src/ninep/cols.zig
+++ b/src/ninep/cols.zig
@@ -253,6 +253,18 @@ test "pane/new takes rows from a pane in another column before refusing ENOSPC"
try testing.expect(moved);
}
+test "in a > cut into several tag writes, those taken before a refused one stand" {
+ const p = try th.withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const node = tree.Node.of(th.serialOf(p), .tag);
+ _ = th.call(p, .{ .tag = 1, .op = .setattr, .node = node, .truncate = true });
+ const h = th.call(p, .{ .tag = 2, .op = .open, .node = node, .omode = 1 }).reply.handle;
+ try testing.expectEqual(tree.Status.ok, th.call(p, .{ .tag = 3, .op = .write, .node = node, .handle = h, .data = "Make" }).reply.status);
+ try testing.expectEqual(E.INVAL, th.call(p, .{ .tag = 4, .op = .write, .node = node, .handle = h, .data = " \x01" }).errno());
+ _ = th.call(p, .{ .tag = 5, .op = .release, .node = node, .handle = h, .opened = true });
+ try testing.expect(std.mem.endsWith(u8, th.rd(p, node, 0, 4096).bytes, "Make"));
+}
+
test "exactly 4096 bytes written with echo's newline after a truncation fit every kind of tag" {
const p = try th.withFile(testing.allocator, "x\n");
defer p.deinit();