summaryrefslogtreecommitdiff
path: root/src/fs.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 13:36:33 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commitfea3f2c5abf14aada5d9187b82985e51eb5b7a98 (patch)
tree6dd3c54c8aaa1ad5941a74200b18da12e512b7fb /src/fs.zig
parentbe5f559939fc11cbfba95b4a7d518816bec8677a (diff)
downloadpardes-fea3f2c5abf14aada5d9187b82985e51eb5b7a98.tar.gz
pardes-fea3f2c5abf14aada5d9187b82985e51eb5b7a98.zip
A path with a part over 255 bytes is refused, never a panic
std's statFile takes the kernel's ENAMETOOLONG for a bug (errnoBug), so a name, look, DumpDir or Save path with a part over 255 bytes panicked the editor (exec.kindOf via writeName, recentKeeps, dumpFailed). Every non-test statFile now goes through fs.statPath, which refuses such a name as NameTooLong first; fs.py drives long, looping, not-a-directory and not-ours paths through name, look, DumpDir, Dump and Save. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/fs.zig b/src/fs.zig
index 5fd1fd4e..753a4446 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -159,7 +159,7 @@ pub fn osHandle(p: *pardes.Pardes, req: Req) Reply {
const stat = stat: {
pardes.turn.yield();
defer pardes.turn.back();
- break :stat std.Io.Dir.cwd().statFile(io, path, .{}) catch return Reply.fail(req.tag, E.NOENT);
+ break :stat statPath(io, path, .{}) catch return Reply.fail(req.tag, E.NOENT);
};
const attr: Reply.Attr = .{ .name = if (req.node == os_root) "os" else std.fs.path.basename(path), .node = req.node, .dir = stat.kind == .directory, .size = stat.size, .mode = if (stat.kind == .directory) 0o755 else 0o644, .mtime = std.math.cast(u32, stat.mtime.toSeconds()) orelse 0 };
switch (req.op) {
@@ -622,6 +622,21 @@ pub fn isVirtual(path: []const u8) bool {
std.mem.eql(u8, path, "/n") or std.mem.startsWith(u8, path, "/n/");
}
+/// std's `statFile`, but a name with a part over 255 bytes is NameTooLong:
+/// std's own takes the kernel's ENAMETOOLONG for that for a bug and panics
+/// (Io.Threaded dirStatFileLinux), and such a name comes from anyone who
+/// writes one to `name`, `look` or DumpDir.
+pub fn statPath(io: std.Io, path: []const u8, options: std.Io.Dir.StatFileOptions) !std.Io.File.Stat {
+ var parts = std.mem.tokenizeScalar(u8, path, '/');
+ while (parts.next()) |part| if (part.len > 255) return error.NameTooLong;
+ return std.Io.Dir.cwd().statFile(io, path, options);
+}
+
+test "a path with a part over 255 bytes is NameTooLong, never a panic" {
+ const long = "/tmp/" ++ "x" ** 300 ++ "/f";
+ try std.testing.expectError(error.NameTooLong, statPath(std.testing.io, long, .{}));
+}
+
pub fn localPath(path: []const u8) ?[]const u8 {
if (std.mem.eql(u8, path, "/n/os")) return "/";
if (std.mem.startsWith(u8, path, "/n/os/")) return path[5..];