diff options
| -rw-r--r-- | docs/fs.md | 5 | ||||
| -rw-r--r-- | src/ninep/tree.zig | 9 |
2 files changed, 11 insertions, 3 deletions
@@ -574,8 +574,9 @@ directory. A name alone is no edit: the pane's `dirty` stays what its text made (a renamed clean file is still 0, and nothing asks about it at Exit, Restore or Del, which ask only about text edited), and `Save` writes it under the new name all the same. An open's writes are one name: held -until its newline, or its close when it has none, then applied once, however -the writes cut it; nothing else is trimmed. Two lines are refused, EINVAL, +until its newline, applied once however the writes cut it; a write with +no newline that is whole in its Twrite is the name then, so a bad one fails +that write, not the close. Nothing else is trimmed. Two lines are refused, EINVAL, in one write or as a second line on the same open (bash's `printf 'a\nb\n' > name` writes a line at a time: the first names it). A blank inside a name is taken (`two words.zig`); refused, EINVAL, in acme's words (xfid.c:650) and why, diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index 6d09b9a6..94fa5d1e 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -1039,7 +1039,7 @@ fn linesFile(target: Target) bool { .top => |f| f == .look or f == .exec or f == .ctl or f == .tagexec, .col => |c| c.file == .ctl or c.file == .exec, // `name` too: one name, however its writes cut it, applied once - // its newline or its close comes. + // its newline comes, or with its write when that is whole. .pane => |t| t.file == .look or t.file == .exec or t.file == .ctl or t.file == .tagexec or t.file == .name, }; } @@ -1634,6 +1634,13 @@ test "a write with no newline, whole in its Twrite, runs then and fails the writ const r = call(p, .{ .tag = 7, .op = .open, .node = root_ctl, .omode = 1 }).reply.handle; try testing.expectEqual(Status.err, call(p, .{ .tag = 8, .op = .write, .node = root_ctl, .handle = r, .data = "bogus" }).reply.status); _ = call(p, .{ .tag = 9, .op = .release, .node = root_ctl, .handle = r, .opened = true }); + // And a name: a bad one fails its write, not the close after it. + const name = Node.of(serial, .name); + const n = call(p, .{ .tag = 10, .op = .open, .node = name, .omode = 1 }).reply.handle; + const bad = call(p, .{ .tag = 11, .op = .write, .node = name, .handle = n, .data = "delete " }); + try testing.expectEqual(Status.err, bad.reply.status); + try testing.expect(std.mem.indexOf(u8, bad.reply.ename, "a blank at its end") != null); + try testing.expectEqual(Status.ok, call(p, .{ .tag = 12, .op = .release, .node = name, .handle = n, .opened = true }).reply.status); } test "look and exec read back what their own open's write touched; a fresh open reads the session's last" { |
