summaryrefslogtreecommitdiff
path: root/9proc/src/scratch.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-20 01:47:28 -0300
committerGabriel Schneider <[email protected]>2026-09-20 01:47:29 -0300
commit66f2e492c348677ab3050f5e378b9eb4c04c98ce (patch)
treecf06b32309eace8eb573925e9cf14e3dfc27bd66 /9proc/src/scratch.zig
parent65209217b5b68f56bc0bd5bc6c4dce33911ded59 (diff)
downloadcloud9-66f2e492c348677ab3050f5e378b9eb4c04c98ce.tar.gz
cloud9-66f2e492c348677ab3050f5e378b9eb4c04c98ce.zip
9proc core becomes a backend of cloud9.fs; engine gains optional features
9proc's own fid table, walk loop and dir-read engine are replaced by cloud9.fs.Server; the tree (static, vars, providers) is served through the engine's Req/Reply contract with node ids that keep the old qid scheme. Providers may answer later by returning error.Again (parked in the engine, retried each step, Tflush -> EINTR); no new files are exposed. Engine (backward compatible, all opt-in via Backend.features / Options): create, remove, wstat, reference accounting for backends that count handles, a salted fid index, name_capacity 0 (names from getattr), Reply.ename for backend-chosen error text, Attr.path/version/atime. Engine-level error strings and the 217-byte msize floor now apply to 9proc; tests updated accordingly. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to '9proc/src/scratch.zig')
-rw-r--r--9proc/src/scratch.zig30
1 files changed, 16 insertions, 14 deletions
diff --git a/9proc/src/scratch.zig b/9proc/src/scratch.zig
index 2163a28..f666afb 100644
--- a/9proc/src/scratch.zig
+++ b/9proc/src/scratch.zig
@@ -7,6 +7,7 @@
//! the root is handle 0. Not internally synchronized (like `Shared`).
const std = @import("std");
const cloud9 = @import("cloud9");
+const fs = cloud9.fs;
const core = @import("core.zig");
const Allocator = std.mem.Allocator;
const Provider = core.Provider;
@@ -374,8 +375,7 @@ const Fixture = struct {
}
fn nodeOf(x: *Fixture, fid: u32) *Node {
- for (x.h.conn.fids) |f| if (f.used and f.id == fid) return x.scratch.node(f.node.prov.h);
- unreachable;
+ return x.scratch.node(x.h.conn.providerHandle(fid).?);
}
};
@@ -429,7 +429,7 @@ test "scratch create/write/read/rename/truncate/remove" {
_ = try x.h.ok(.{ .clunk = .{ .fid = 5 } });
try x.h.walkTo(6, &.{ "scratch", "d" });
try x.h.expectFail(.{ .remove = .{ .fid = 6 } }, "directory not empty");
- try x.h.expectFail(.{ .clunk = .{ .fid = 6 } }, "unknown fid"); // remove always clunks
+ try x.h.expectFail(.{ .clunk = .{ .fid = 6 } }, fs.e_unknown_fid); // remove always clunks
try x.h.walkTo(7, &.{ "scratch", "d", "inner" });
_ = try x.h.ok(.{ .remove = .{ .fid = 7 } });
try x.h.walkTo(8, &.{ "scratch", "d" });
@@ -469,7 +469,7 @@ test "walk of a missing name and walking a file" {
// a walk that fails past the first element is a partial Rwalk that leaves newfid unused
const r = try x.h.ok(.{ .walk = .{ .fid = 0, .newfid = 4, .names = &.{ "scratch", "nope", "x" } } });
try testing.expectEqual(@as(u16, 1), r.walk.nwqid);
- try x.h.expectFail(.{ .clunk = .{ .fid = 4 } }, "unknown fid");
+ try x.h.expectFail(.{ .clunk = .{ .fid = 4 } }, fs.e_unknown_fid);
// .. from a file is not a directory; .. from the scratch root reaches the server root
try x.h.expectFail(.{ .walk = .{ .fid = 3, .newfid = 5, .names = &.{".."} } }, "not a directory");
try x.h.walkTo(5, &.{"scratch"});
@@ -504,10 +504,9 @@ test "directory read across consecutive offsets returns every record exactly onc
seen[idx] = true;
}
for (seen) |s| try testing.expect(s);
- try x.h.expectFail(.{ .read = .{ .fid = 2, .offset = 7, .count = 200 } }, "bad offset");
- // a read that cannot fit even one record returns nothing rather than splitting it
- const tiny = try x.h.ok(.{ .read = .{ .fid = 2, .offset = 0, .count = 30 } });
- try testing.expectEqual(@as(usize, 0), tiny.read.len);
+ try x.h.expectFail(.{ .read = .{ .fid = 2, .offset = 7, .count = 200 } }, fs.e_bad_offset);
+ // a read that cannot fit even one record is refused rather than splitting it
+ try x.h.expectFail(.{ .read = .{ .fid = 2, .offset = 0, .count = 30 } }, fs.e_count_small);
_ = try x.h.ok(.{ .clunk = .{ .fid = 2 } });
// Tversion resets every fid and every reference
try x.h.version(8192);
@@ -592,13 +591,16 @@ test "wstat with every field equal to the current stat changes nothing" {
try x.h.walkTo(1, &.{"scratch"});
_ = try x.h.ok(.{ .create = .{ .fid = 1, .name = "same", .perm = 0o640, .mode = cloud9.oread } });
const before = (try x.h.ok(.{ .stat = .{ .fid = 1 } })).stat;
- var copy = before;
+ // The engine owns type, dev, qid, atime and the owner names: those must
+ // be "don't care"; name, mode, mtime and length equal to the current
+ // stat reach the provider and change nothing.
+ var copy = dontcare;
var name_buf: [core.max_name]u8 = undefined;
@memcpy(name_buf[0..before.name.len], before.name);
copy.name = name_buf[0..before.name.len];
- copy.uid = "tester";
- copy.gid = "tester";
- copy.muid = "tester";
+ copy.mode = before.mode;
+ copy.mtime = before.mtime;
+ copy.length = before.length;
_ = try x.h.ok(.{ .wstat = .{ .fid = 1, .stat = copy } });
const after = (try x.h.ok(.{ .stat = .{ .fid = 1 } })).stat;
try testing.expectEqual(before.qid, after.qid);
@@ -619,7 +621,7 @@ test "wstat with every field equal to the current stat changes nothing" {
// the mode's directory bit is immutable, mtime is settable
st = dontcare;
st.mode = cloud9.dmdir | 0o640;
- try x.h.expectFail(.{ .wstat = .{ .fid = 2, .stat = st } }, "permission denied");
+ try x.h.expectFail(.{ .wstat = .{ .fid = 2, .stat = st } }, fs.e_wstat);
st = dontcare;
st.mtime = 12345;
_ = try x.h.ok(.{ .wstat = .{ .fid = 2, .stat = st } });
@@ -651,7 +653,7 @@ test "ORCLOSE removes on clunk and removed files stay readable through open fids
_ = try x.h.ok(.{ .clunk = .{ .fid = 3 } });
try x.h.walkTo(6, &.{"scratch"});
try x.h.expectFail(.{ .walk = .{ .fid = 6, .newfid = 7, .names = &.{"d"} } }, "file does not exist");
- try x.h.expectFail(.{ .create = .{ .fid = 5, .name = "x", .perm = 0o644, .mode = cloud9.oread } }, "unknown fid"); // remove clunked it
+ try x.h.expectFail(.{ .create = .{ .fid = 5, .name = "x", .perm = 0o644, .mode = cloud9.oread } }, fs.e_unknown_fid); // remove clunked it
}
test "qid paths are stable identities, not addresses: remove + recreate differ" {