summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/config.zig16
-rw-r--r--src/ninep/ctl.zig18
-rw-r--r--src/pardes.zig7
3 files changed, 35 insertions, 6 deletions
diff --git a/src/config.zig b/src/config.zig
index b6eb4520..cc46adfc 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -1148,8 +1148,18 @@ pub const Runtime = struct {
if (percent > 100) return false;
state.window_blur = percent;
},
- // Bare, it returns to the default directory.
- .dump_dir => if (!state.dump_dir.set(std.mem.trim(u8, argument orelse "", " \t\r\n"))) return false,
+ // Bare, it returns to the default directory. Else an absolute or
+ // `~` path, to a directory there or to be made, that may be
+ // written: a Dump there could never be, refused now.
+ .dump_dir => {
+ const text = std.mem.trim(u8, argument orelse "", " \t\r\n");
+ if (text.len > 0) {
+ if (text[0] != '/' and text[0] != '~') return false;
+ var home_buf: [4096]u8 = undefined;
+ if (pardes.filesystem.deniedAbove(pardes.filesystem.expandHome(text, &home_buf))) return false;
+ }
+ if (!state.dump_dir.set(text)) return false;
+ },
.message_ms => |which| {
const text = std.mem.trim(u8, argument orelse return false, " \t\r\n");
for (text) |byte| if (!std.ascii.isDigit(byte)) return false;
@@ -1267,7 +1277,7 @@ pub const Runtime = struct {
.tagline_size => std.fmt.comptimePrint("{d}-{d} (a percentage)", .{ tagline_percent_min, tagline_percent_max }),
.message_ms => std.fmt.comptimePrint("0-{d} (milliseconds)", .{message_ms_max}),
.shell => "a path of at most 255 bytes; bare, $SHELL, else /bin/sh",
- .dump_dir => std.fmt.comptimePrint("a path of at most {d} bytes; bare, the default", .{limits.host_path_cap}),
+ .dump_dir => std.fmt.comptimePrint("an absolute or ~ path of at most {d} bytes, to a directory that may be written; bare, the default", .{limits.host_path_cap}),
.shader => "a Shadertoy file's path, or off",
.font => "a name or path, :8 to :72 after it (Mono:14)",
else => null,
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 89c2e5dd..d4d09e0b 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -2332,8 +2332,9 @@ test "a Restore of a file that is no dump fails the write before any warning, an
try testing.expect(p.panes[0].?.discard_warned == null);
p.fs.late_failure_len = 0;
- p.dumpFailed("/nowhere/pardes.dump.zon", error.FileNotFound);
- try testing.expectEqualStrings("Dump /nowhere/pardes.dump.zon: no such directory", p.fs.late_failure[0..p.fs.late_failure_len]);
+ // (Under /tmp: under / a user's Dump is refused permission, not missing.)
+ p.dumpFailed("/tmp/pardes-nowhere-zz/pardes.dump.zon", error.FileNotFound);
+ try testing.expectEqualStrings("Dump /tmp/pardes-nowhere-zz/pardes.dump.zon: no such directory", p.fs.late_failure[0..p.fs.late_failure_len]);
// A DumpDir that is there but no directory says that.
p.fs.late_failure_len = 0;
p.dumpFailed("/dev/null/pardes.dump.zon", error.NotDir);
@@ -4357,3 +4358,16 @@ test "a ctl line over 1 MiB is refused once, EINVAL, and its tail is not run as
try testing.expectEqualStrings("", pane_files.fileOf(p.panes[0].?).?.content);
_ = call(p, .{ .tag = 4, .op = .release, .node = node, .handle = h });
}
+
+test "DumpDir refuses a relative directory and one that may not be written, up front; a Dump there says permission denied" {
+ if (comptime !pardes.hosted) return;
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const root_ctl = @intFromEnum(tree.TopFile.ctl);
+ try testing.expectEqual(E.INVAL, wr(p, root_ctl, "DumpDir dumps\n").errno());
+ try testing.expectEqual(E.INVAL, wr(p, root_ctl, "DumpDir /proc/1/root/dumps\n").errno());
+ try testing.expectEqual(Status.ok, wr(p, root_ctl, "DumpDir /tmp/pardes-dumps-test\n").reply.status);
+ p.fs.late_failure_len = 0;
+ p.dumpFailed("/proc/1/root/x/pardes.dump.zon", error.FileNotFound);
+ try testing.expect(std.mem.endsWith(u8, p.fs.late_failure[0..p.fs.late_failure_len], ": permission denied"));
+}
diff --git a/src/pardes.zig b/src/pardes.zig
index 2b0ed8f0..dbb37084 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -5563,7 +5563,12 @@ pub const Pardes = struct {
const parent = std.fs.path.dirname(path) orelse "/";
const kind: ?std.Io.File.Kind = if (comptime hosted) (if (filesystem.localPath(parent)) |local| exec.kindOf(local) else .directory) else .directory;
const no_dir = err == error.FileNotFound or err == error.NotDir or kind != .directory;
- if (kind != null and kind != .directory) {
+ // Not there because one above refuses: that is why, EACCES.
+ const denied = no_dir and kind == null and (if (comptime hosted) (if (filesystem.localPath(parent)) |local| filesystem.deniedAbove(local) else false) else false);
+ if (denied) {
+ var said: [limits.host_path_cap + 48]u8 = undefined;
+ p.reportFailure(p.active, std.fmt.bufPrint(&said, "{s}: permission denied", .{operation}) catch "Dump: permission denied");
+ } else if (kind != null and kind != .directory) {
var said: [limits.host_path_cap + 48]u8 = undefined;
p.reportFailure(p.active, std.fmt.bufPrint(&said, "{s}: {s} is not a directory", .{ operation, parent }) catch "Dump: not a directory");
} else if (no_dir) {