Implements the source PDF's prescribed model for directory structure:
'treat the CZYX cube as the only persistent store, with system calls that
operate on CZYX records and Null-space flags rather than paths and inodes.'
Nested dirs are RECONSTRUCTED from a per-record `path` metatag, so the
filesystem does not need recursive inode trees.
- cubecoords: add CubeHeader.path (Option<String>) + HAS_PATH flag bit (1<<8);
refresh_flags() sets it. Cubestore TLV codec now serializes/deserializes the
path as tag 13 (persists across checkpoint/reopen).
- cubestore: scan_by_path (exact), scan_by_path_prefix (dir listing by path
prefix; bare '/etc' normalized to '/etc/'), plus query_by_path/_prefix
returning decoded (coord,header,body).
- cubesys: `put` verb gains path=<p>;
new `query-path <dir>` verb reconstructs a directory listing from metatags.
- ConcurrentStore: query_by_path(_prefix) delegate to inner CubeStore.
Verified live in VM: migrated /etc/passwd, /etc/network/interfaces, /usr/bin/ls
at unrelated coordinates; 'query-path /etc' returns the two /etc files,
'/usr/bin/ls' correctly excluded. cubestore 8/8 tests pass.
Refs: OS-in-CUBE migration, query-layer prototype.
Implements the source PDF's 'put(C,Z,Y,X,bytes,flags)' + 'scan_by_flag'
associative-storage API so records are discoverable by WHAT they are
(event type / doc_type metatag) rather than WHERE they live (coordinate
path) — the 'log lookup by query' the OS layers want.
cubestore:
- CubeStore::scan_by_flag(u16) / scan_by_type(&str): predicate scans
over decoded CubeHeader (not prefix scans).
- CubeStore::query_by_flag / query_by_type: same, but also return the
decoded (label, header, body) so a query tool can present results.
- get_record's raw/un-enveloped fallback now refresh_flags() so
synthesized headers carry SIZE_BYTES and are visible to flag queries.
- regression tests: scan_by_flag_finds_typed_records,
scan_by_type_event_lookup.
cubesys (daemon):
- new 'put' verb: enveloped write with optional doc_type=/title=
metatags (the PDF's put API). rawput remains for bulk/append payloads.
- ConcurrentStore::query_doc_type was already the backing predicate the
'query <doc_type>' verb uses; it now matches these typed records.
Proven end-to-end in the VM: 'cubec query klog' returns the kernel-log
index record (doc_type=klog) published by cube-os-klog.sh, and
'cubec query fn' returns the 8 pre-existing typed program records.
get_record() previously returned None for any payload lacking a TLV envelope
(4-byte header-len | header | body). Records written through the raw path
(put_raw / the daemon's 'rawput' verb, used by every OS-layer service) carry
no envelope, so callers such as cubefs getattr/read and the 'stat' verb mapped
that None to size 0 / empty file: real bytes became SILENTLY INVISIBLE through
the filesystem while rawget still returned them.
This broke the OS-in-CUBE migration (2026-08-13): every rawput OS record listed
as a 0-byte file in /cubefs, which also surface-invalidated the 'the OS boots
from cube' resume path.
Now a payload that is not a well-formed envelope is surfaced as a raw body under
a synthesized header whose size_bytes reports the true length. Enveloped records
still decode their real header (no behavior change on the record path). Adds two
regression tests: get_record_surfaces_raw_unenveloped_payloads and
get_record_still_prefers_the_real_envelope (cargo test -p cubestore: 5/5).
Keep CubeBackend::put returning () for source compat across cubesys/cubecrypt/
cube-bench; add put_checked() (default Ok(())) letting DaemonBackend report a
real socket error. FUSE create/write/truncate now call put_record_checked and
map the failure to FsError::WriteFailed -> errno 5 (EIO).
Verified: ./check (fmt+test+clippy) green; canonical ./check mount 57/57.
The cubefs-mount --socket path was never actually built: CubeFs<B> is
generic, so the --socket (DaemonBackend) and default (HashBackend) arms
of the match were incompatible types (E0308), and --features mount failed
to compile. The running binary was therefore the in-memory build, so
--socket was silently ignored and every FUSE write went to RAM and never
reached the daemon (rawget/rawkeys returned none / 0 keys, WAL stayed 0).
Fix: type-erase the backend. Add (forwards to inner) in cubestore, and build
in cubefs-mount via
Box::new(DaemonBackend::new(p)) / Box::new(HashBackend::new()). Keeps
cubefs free of a cubesys dep (acyclic graph).
Verified end-to-end on host (shared code path as the VM): a FUSE write
via lands in the daemon store (rawget returns the
record, 5 keys present, WAL grows), and survives a of the
daemon + relaunch with the same --store (byte-identical read-back).
Also includes (from RESUME-cubefs-daemon.md): cubesys raw* command family
(rawget/rawput/rawdel/rawkeys/rawscan + parse/hex helpers) and the
DaemonBackend client + smoke tests. Report/verification docs added.
Note: VM cubefs.service still mounts in-memory (no --socket); update the
unit to as a
follow-up so the deployed VM FUSE is durable too.
Integrates Packages 3-5 over a single shared CubeStore, the literal
CUBELinux premise (data addressed by coordinate, not path). Adds the
cubesys crate (lib + cube CLI + cube-demo) proving two end-to-end
properties: a cubefs path IS a runnable code cell at the same coordinate,
and a sealed record reopens and runs on the same store.
Two latent cross-crate bugs surfaced and fixed while integrating:
- cubecoords: refresh_flags() now preserves out-of-band flag bits
(8..=15), so cubecrypt's HEADER_FLAG_ENCRYPTED survives refresh.
- cubestore: record codec now serializes raw flag bits (TLV tag 12) so
the encrypted bit survives the store round-trip.
All gates green (./check, incl. cubefs --features mount).
Implements the PDF's Package 3 with new code:
- path: bijective POSIX path <-> Czyx mapping (/c001/z002/y003/x004).
Axis-letter + 3-digit zero-padded canonical names so lexical order equals
numeric order and each coordinate has exactly one spelling. Inode IS the
packed u32 coordinate — no inode side table.
- nullspace: the PDF's 'use Null cubes for ACLs, xattrs, journaling, volume
metadata', with the Z-plane allocation fixed and documented (Z=1 volume,
Z=2 ACL, Z=3 xattr, Z=4 journal ring). ACL/xattr tables are FNV
hash-bucketed with exact-match resolution inside the bucket, because 4
axes of subject cannot injectively mirror into 2 axes of Null space.
Journal is a bounded ring; wraps are detectable via a monotonic counter.
- vfs: the whole filesystem, kernel-free and unit-testable — lookup,
readdir, create/read/write/truncate/unlink, mkdir/rmdir, ACL enforcement,
xattrs, journaling, POSIX errno mapping.
- fuse (feature 'mount'): thin kernel adapter, zero TTL (the store is
writable out-of-band, so cached metadata would go stale).
- cubestore: added the PDF's 'optional scanning primitives' (keys,
scan_prefix) and the Package 2 association API (associate, linked_to)
that cubefs needs for directory listings.
Two defects were found by LIVE MOUNT testing and fixed, not by unit tests:
1. mkdir succeeded then the kernel's revalidating lookup returned ENOENT,
so 'mkdir -p' could never reach depth 4. Directories were purely
inferred from records, making an empty directory unrepresentable. Fixed
with an explicit Null-space directory marker; rmdir removes it; readdir
merges markers in. 5 regression tests added.
2. Multi-user ACL behaviour was untestable because the mount lacked
AllowOther — the kernel returned EACCES at the mountpoint before any
request reached us. Added --allow-other.
Verified: 58 unit tests pass; clippy clean; live mount exercised with cat,
echo, dd, truncate, cp, chmod, chown, getfattr/setfattr, mkdir -p, rmdir,
find, a 200-record write loop, and cross-user reads/writes as luulu.