diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 17:38:06 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 13ef34f1c10a5880be411475cfabd7bb1344916b (patch) | |
| tree | 8d83a2248790195774d082bf300c6979d1b0e7e7 /src/ninep | |
| parent | daf833bccf5aca958593738ecc59fd58dbb697b6 (diff) | |
| download | pardes-13ef34f1c10a5880be411475cfabd7bb1344916b.tar.gz pardes-13ef34f1c10a5880be411475cfabd7bb1344916b.zip | |
A rename (mv) of a pane's directory or any file of the tree is refused as not permitted, EPERM, not an EIO
cloud9's engine passes a wstat that changes a name to the backend, and
the tree's setattr ignored the name: the rename answered as done, the
name did not change, and a mount then gave `mv` EIO. The tree names its
own files, so a setattr with a name is now refused, "rename not
permitted", which 9ns reads as EPERM. A pane's buffer is still renamed
through its name file.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep')
| -rw-r--r-- | src/ninep/tree.zig | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index 53d33731..4300d2b5 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -987,6 +987,10 @@ fn releaseHandle(p: *Pardes, req: Req) void { } fn setattr(p: *Pardes, req: Req, target: Target) Reply { + // A rename (`mv`) of a pane's directory, a column's or any file here: + // the tree names them, not the client. Refused as not permitted + // (EPERM), not taken and then lost, which a mount read as EIO. + if (req.set.name) return failText(req.tag, E.PERM, "rename not permitted: the tree names its files (a pane's name file renames its buffer)"); if (req.truncate) switch (target) { .pane => |t| { const id = p.paneBySerial(t.serial) orelse return Reply.fail(req.tag, E.NOENT); @@ -1850,6 +1854,17 @@ test "a write cut where a writer's 4096-byte buffer filled holds its partial lin try testing.expect(!th.logHas(p, "wrong #args")); } +test "a rename of a pane's directory or file is refused as not permitted" { + const p = try th.withFile(testing.allocator, "x\n"); + defer p.deinit(); + const serial = serialOf(p); + for ([_]u64{ Node.of(serial, .dir), Node.of(serial, .body) }) |node| { + const r = call(p, .{ .tag = 1, .op = .setattr, .node = node, .set = .{ .name = true } }); + try testing.expectEqual(E.PERM, r.errno()); + try testing.expect(std.mem.indexOf(u8, r.reply.ename, "not permitted") != null); + } +} + test "no placement leaves a pane shorter than its tag and two rows; a full column refuses the next" { const p = try th.withFile(testing.allocator, "x\n"); defer p.deinit(); |
