Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  • FsTreeImport turns an ordinary directory object into an fs-tree, OciExtract produces one from an OCI image, and SandboxInstall captures a sandboxed build’s changes as an additive fs-tree layer;
  • TreeMerge, TreeSubset, and TreeMove transform fs-trees at the manifest level, without materializing them;
  • Sandbox and SandboxInstall use 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.