From 4f65855f372186406f4e48708ec3d5eb9aceb6d3 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Wed, 30 Sep 2026 22:51:17 -0300 Subject: log stats 0, and pardes re-pins cloud9 whose 9ns opens such a file direct and nonseekable: fs.md's follow recipe with cat works through a mount The log stated the length an open would freeze, a length a mount's kernel could take as its end, and a splicing cat read it from the kernel's offset. log now stats 0, as the other streams and generated views do, and the re-pinned cloud9's 9ns opens any file stating 0 FOPEN_DIRECT_IO | FOPEN_NONSEEKABLE. A look at such a file (the mounted index) reads a regular file that will not seek as a stream rather than refusing it as a pipe. selfmount runs the recipe, exec 3<>log; echo follow >&3; cat <&3, through the mount and hears a record made after it started. Co-Authored-By: Claude Opus 5.5 --- src/fs.zig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/fs.zig') diff --git a/src/fs.zig b/src/fs.zig index d13e36bd..91edd429 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -1360,7 +1360,13 @@ fn readFileLimit(gpa: std.mem.Allocator, path: []const u8, limit: usize) ![]u8 { defer _ = libc.close(fd); const end = libc.lseek(fd, 0, libc.SEEK.END); - if (end < 0 and libc.errno(end) == .SPIPE) return error.NotAFile; + // Not seekable: a pipe or a FIFO is no file; a regular file that is a + // stream (a 9ns mount's log or screen, opened nonseekable) is read to + // its end, as one with no length is. + if (end < 0 and libc.errno(end) == .SPIPE) { + const facts = ninep_io.statNoFollow(path_z) orelse return error.NotAFile; + if (facts.mode & 0o170000 != 0o100000) return error.NotAFile; + } const size: usize = if (end < 0) 0 else @intCast(end); if (end >= 0 and libc.lseek(fd, 0, libc.SEEK.SET) < 0) return error.ReadFailed; if (size == 0) { -- cgit v1.3