Filesystem trees
A builder produces one object: an ordinary file or directory, or a filesystem
tree (fs-tree) — bobr’s content-addressed representation of a directory tree,
named by the hash of its manifest (see Concepts). fs-trees are
the building blocks for whole filesystems: the root filesystem of a target
system, or the one a build runs inside (a Sandbox container).
A real filesystem needs files with specific owners and modes — root-owned
files, set-uid binaries. bobr uses a user namespace to create files with these
logical owners and modes without requiring host-root privileges. Regular
files in fs-files/ already carry that ownership and mode in the namespace;
materialization preserves them by hardlinking, not by restoring them from the
manifest.
An fs-tree’s payload is a manifest listing the tree’s entries; regular-file contents live separately as content-addressed fs-files, shared across trees. A complete fs-tree requires both its manifest and all referenced fs-files; the manifest alone is not sufficient to materialize it.
Assembling a real directory from a manifest is fast and space-cheap — identical files are hard-linked into place, sharing one inode — at the cost of one firm rule: such a filesystem is mounted read-only, since writing a shared file would change every tree that references it. Sandboxed builds can write through a separate overlay without changing the read-only lower tree. An fs-tree is immutable.
The manifest lists one entry per path:
- a directory — with its logical
uid,gid, and mode; - a symlink — with its logical
uid,gid, and target; - a regular file — a reference to an fs-file.
A regular file’s bytes, uid, gid, and mode belong to the fs-file it
references, identified by its own hash — not the fsobj-hash
that names objects; an fs-file hash covers one file and folds in its uid,
gid, and mode along with its bytes. Directory and symlink metadata live in the
manifest itself; its exact format is the fs-tree Manifest.
Most operations work on the manifest alone — merging or subsetting trees never
touches the files — and bobr materializes a real directory only when a builder
needs one. fs-trees model only regular files, directories, and symlinks; they
deliberately do not preserve inode topology (so st_ino and st_nlink are not
part of a tree’s identity), nor xattrs, POSIX ACLs, or file capabilities (not
modeled yet).
Among the built-in builders:
FsTreeImportturns an ordinary directory object into an fs-tree,OciExtractproduces one from an OCI image, andSandboxInstallcaptures a sandboxed build’s changes as an additive fs-tree layer;TreeMerge,TreeSubset, andTreeMovetransform fs-trees at the manifest level, without materializing them;SandboxandSandboxInstalluse a materialized fs-tree as the image their build runs on – which is also how a tree is packed into an image (an EROFS blob, an initramfs cpio), by a recipe running the packer over the tree.
A recipe controls materialization by the input name: an input whose name
begins with _ (e.g. _rootfs, _tree) is materialized into a real directory
before the builder runs; any other input is passed as the object itself.
See Request for each builder.