diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 23:29:17 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:18 -0300 |
| commit | afaa2428b346f6dd1d165abe1396dce9150fa05c (patch) | |
| tree | 8c7f14cd5f720e61f0eb0104d862fe4f0cc17d4e /src/main.zig | |
| parent | afe51fc6c3675a6aa8ab2f5caf64796b65597c2c (diff) | |
| download | pardes-afaa2428b346f6dd1d165abe1396dce9150fa05c.tar.gz pardes-afaa2428b346f6dd1d165abe1396dce9150fa05c.zip | |
Forwarding pardes FILE for a new name in a directory it may not read or write is refused with words, not a pane that only fails at Save
A new name forwarded into a directory that is there but locked opened
an empty pane named for it, and the failure came only at its Save,
long after the launch. The directory is checked first: one that cannot
be read, written and entered is refused, exit 1, no pane made.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/main.zig')
| -rw-r--r-- | src/main.zig | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/src/main.zig b/src/main.zig index 3218fef1..9dce559f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -106,6 +106,7 @@ fn forwardWords(err: anyerror, buf: []u8) []const u8 { error.NotOneLine => "a file name is one line, and this one holds a newline", error.NotAFileName => "names a directory, not a file", error.NoWorkingDirectory => "this shell's working directory is gone", + error.DirectoryNotWritable => "its directory may not be read or written, so it could never be saved", error.NotAPaneAddress => "not a pane address: @p and a pane's number", error.NoSuchPane => "this session has no such pane", else => if (pardes.Messages.dialReason(err)) |why| why else words: { @@ -483,6 +484,15 @@ fn nativeMain(init: std.process.Init) !void { const cwd = std.mem.sliceTo(&cwd_buf, 0); break :named std.fs.path.resolvePosix(arena, &.{ cwd, target.path }) catch |err| Refuse.with(init.io, word, err); }; + // A directory that is there but may not be read or written: a + // pane for the name could only fail at its Save, so refused now. + var dir_z_buf: [4096]u8 = undefined; + if (std.fmt.bufPrintSentinel(&dir_z_buf, "{s}", .{dir.path}, 0)) |dir_z| { + const R_OK = 4; + const W_OK = 2; + const X_OK = 1; + if (std.c.access(dir_z.ptr, R_OK | W_OK | X_OK) != 0) Refuse.with(init.io, word, error.DirectoryNotWritable); + } else |_| {} break :named std.fmt.bufPrint(&newbuf, "{s}/{s}", .{ std.mem.trimEnd(u8, dir.path, "/"), base }) catch |err| Refuse.with(init.io, word, err); }; var made_serial: ?u32 = null; |
