Documentation
¶
Overview ¶
Package rootfs is a container's root filesystem: an in-memory tree that image layers are applied to, frozen as a read-only lower, and cloned per container into a copy-on-write upper.
It is deliberately free of any WebAssembly runtime type, so the native executor (wazero) and the browser executor can both adapt the same tree.
The tree lives entirely in memory and every path is resolved inside it: absolute symlink targets are relative to the tree's root and ".." stops at the root, so nothing a container or a layer does can reach the host.
Index ¶
- Constants
- Variables
- func ModulePath(title string) string
- type Budget
- type Change
- type DirEntry
- type FS
- func (f *FS) AddExternal(p string, r io.ReaderAt, size int64) error
- func (f *FS) ApplyDiff(r io.Reader, u Usage, lim Limits) error
- func (f *FS) ApplyLayer(r io.Reader, mediaType, title string, b *Budget) error
- func (f *FS) ApplyTar(r io.Reader, b *Budget) error
- func (f *FS) ApplyWasm(r io.Reader, title string, b *Budget) (string, error)
- func (f *FS) Changes() uint64
- func (f *FS) Chmod(p string, mode fs.FileMode) error
- func (f *FS) Chtimes(p string, mtime time.Time, follow bool) error
- func (f *FS) Clone(q Quota) *FS
- func (f *FS) Diff() []Change
- func (f *FS) Extract(dst string, r io.Reader, lim Limits, noOverwriteDirNonDir bool) error
- func (f *FS) Freeze()
- func (f *FS) IOFS() fs.FS
- func (f *FS) Link(oldPath, newPath string) error
- func (f *FS) Lstat(p string) (*Info, error)
- func (f *FS) Mkdir(p string, perm fs.FileMode) error
- func (f *FS) MkdirAll(p string, perm fs.FileMode) error
- func (f *FS) OpenFile(p string, flag Flag, perm fs.FileMode) (*File, error)
- func (f *FS) ReadDir(p string) ([]DirEntry, error)
- func (f *FS) ReadFile(p string) ([]byte, error)
- func (f *FS) Readlink(p string) (string, error)
- func (f *FS) Remove(p string) error
- func (f *FS) Rename(from, to string) error
- func (f *FS) Rmdir(p string) error
- func (f *FS) Stat(p string) (*Info, error)
- func (f *FS) Symlink(target, linkPath string) error
- func (f *FS) Usage() (bytes int64, files int)
- func (f *FS) WriteDiff(w io.Writer) (Usage, error)
- func (f *FS) WriteFile(p string, data []byte, perm fs.FileMode) error
- func (f *FS) WriteLayer(w io.Writer) (Usage, error)
- func (f *FS) WriteTar(src string, w io.Writer) error
- func (f *FS) Written() int64
- type File
- func (h *File) Chtimes(mtime time.Time) error
- func (h *File) Close() error
- func (h *File) Entries(n int) ([]DirEntry, error)
- func (h *File) Info() (*Info, error)
- func (h *File) IsAppend() bool
- func (h *File) IsDir() bool
- func (h *File) Name() string
- func (h *File) Read(p []byte) (int, error)
- func (h *File) ReadAt(p []byte, off int64) (int, error)
- func (h *File) ReadDir(n int) ([]fs.DirEntry, error)
- func (h *File) Seek(offset int64, whence int) (int64, error)
- func (h *File) SetAppend(on bool)
- func (h *File) Stat() (fs.FileInfo, error)
- func (h *File) Truncate(size int64) error
- func (h *File) Write(p []byte) (int, error)
- func (h *File) WriteAt(p []byte, off int64) (int, error)
- type Flag
- type Info
- type LayerReader
- type Limits
- type Quota
- type Usage
Constants ¶
const ( Modified = 0 // C Added = 1 // A Deleted = 2 // D )
Change kinds, as the Docker Engine API numbers them.
const MaxZstdWindow = 64 << 20
MaxZstdWindow bounds a zstd layer's window, which is what the decoder allocates: zstd's levels 1-19 use at most 8 MiB, --long up to 128 MiB.
Variables ¶
var ( ErrNotDir = errors.New("not a directory") ErrIsDir = errors.New("is a directory") ErrNotEmpty = errors.New("directory not empty") ErrLoop = errors.New("too many levels of symbolic links") ErrNoSpace = errors.New("no space left on device") ErrReadOnly = errors.New("read-only file system") ErrNameTooLong = errors.New("file name too long") ErrBadFile = errors.New("bad file descriptor") ErrCrossLink = errors.New("invalid cross-device link") )
Errors beyond those io/fs defines.
var DefaultLimits = Limits{
MaxBytes: 1 << 30,
MaxFiles: 1 << 17,
MaxRatio: 200,
MaxPathLen: 4096,
MaxDepth: 128,
}
DefaultLimits fit wasm images with a wide margin.
var ErrArchive = errors.New("rootfs: archive")
ErrArchive is wrapped by every refusal of an archive (PUT/GET /containers/{id}/archive).
var ErrLayer = errors.New("unsafe or invalid layer")
ErrLayer is wrapped by every refusal of layer content.
var ErrWhiteoutName = errors.New("rootfs: a file name beginning with .wh. cannot be written to an image layer")
ErrWhiteoutName is returned by WriteLayer for a changed path whose name begins with ".wh.": an OCI layer would read it as a whiteout.
Functions ¶
func ModulePath ¶
ModulePath is where a bare wasm module layer is placed: "/" plus its title when that is a plain, safe file name, otherwise "/module.wasm".
Types ¶
type DirEntry ¶
type DirEntry struct {
// contains filtered or unexported fields
}
DirEntry is one directory entry. It implements fs.DirEntry.
type FS ¶
type FS struct {
// contains filtered or unexported fields
}
FS is an in-memory filesystem tree. It is safe for concurrent use.
func Build ¶
func Build(layers []LayerReader, lim Limits) (*FS, error)
Build applies layers in order to a new tree and freezes it.
func (*FS) AddExternal ¶ added in v0.33.0
AddExternal adds a read-only regular file at p (parents are created) whose content is read from r on demand: nothing is copied into memory and nothing is charged to the quota. Every write, truncation or open for writing of it fails with ErrReadOnly, in this tree and in its clones.
func (*FS) ApplyDiff ¶ added in v0.4.0
ApplyDiff applies WriteDiff's output to f, a fresh clone of the same base, and restores the usage it recorded (bounded by f's quota). The changeset is untrusted (it comes back from storage): it is checked as an image layer is, under lim.
func (*FS) ApplyLayer ¶
ApplyLayer applies one layer blob of the given media type to f. title is the layer's org.opencontainers.image.title annotation, used to name a bare wasm module.
func (*FS) ApplyTar ¶
ApplyTar applies an uncompressed tar changeset to f, per the OCI layer specification: opaque whiteouts first, then explicit whiteouts, both against what lower layers left; then additions in archive order, so a whiteout never hides an entry of its own layer.
Refused outright: absolute names, "..", names under a non-directory (which is how a symlink planted by one entry redirects the next), symlink targets that climb above the root, hard links to anything but an existing regular file, and anything over the budget.
func (*FS) ApplyWasm ¶
ApplyWasm writes a single wasm module (a CNCF wasm artifact layer) into the tree and returns its path.
func (*FS) Changes ¶ added in v0.4.0
Changes counts this tree's mutations: equal counts, equal trees.
func (*FS) Clone ¶
Clone returns a writable copy-on-write view of f: f's nodes are shared until the clone writes to them, at which point the clone copies them up. Writing to f afterwards (if it is not frozen) copies up as well, so neither ever sees the other's changes.
func (*FS) Diff ¶ added in v0.4.0
Diff lists what this tree changed relative to its base, sorted by path, as `docker diff` does: a changed directory is Modified and its changed entries follow; everything under a new directory is Added.
func (*FS) Extract ¶ added in v0.12.0
Extract writes a tar into the directory dst of the tree, as `docker cp` into a container does. The tar is untrusted: names must be relative and clean (no "..", no absolute path), hard links must name an entry inside dst, devices and FIFOs are refused, and the entries, each file and the total are bounded by lim. Every write goes through the tree's own operations, so paths resolve inside the root (a symlink cannot lead out) and the tree's quota applies. With noOverwriteDirNonDir, an entry that would replace a directory with a non-directory, or the reverse, is refused.
func (*FS) Freeze ¶
func (f *FS) Freeze()
Freeze makes the tree read-only: every later mutation fails with ErrReadOnly. Clones of a frozen tree are writable.
func (*FS) IOFS ¶
IOFS returns a read-only io/fs view of the tree, with fs.FS's strict path rules (unrooted, slash-separated, no "." or ".." elements), so the tree can be handed to anything that reads an fs.FS, fstest included.
func (*FS) WriteDiff ¶ added in v0.4.0
WriteDiff writes what this tree changed relative to the tree it was cloned from as a tar changeset that ApplyDiff, on a fresh clone of the same base, turns back into an equal tree: added and changed entries in full, removed ones as whiteouts, a directory removed and made again as opaque. A tree that is not a clone is written whole. Hard links among the written entries are kept; a link to an entry left unchanged in the base is written as a copy.
func (*FS) WriteLayer ¶ added in v0.12.0
WriteLayer writes what this tree changed relative to its base as an OCI image layer (an uncompressed tar changeset): added and changed entries in full, removed ones as ".wh.<name>" entries, a directory removed and made again followed by ".wh..wh..opq". It is what `commit` stores. A tree that is not a clone is written whole.
type File ¶
type File struct {
// contains filtered or unexported fields
}
File is an open file or directory.
func (*File) ReadDir ¶
ReadDir implements fs.ReadDirFile: with n > 0 it returns at most n entries and io.EOF at the end; with n <= 0 all remaining entries.
type LayerReader ¶
type LayerReader struct {
MediaType string
Title string
Open func() (io.ReadCloser, error)
}
LayerReader is one layer to build from.
type Limits ¶
type Limits struct {
// MaxBytes bounds the total uncompressed bytes of file content.
MaxBytes int64
// MaxFiles bounds the total number of entries.
MaxFiles int
// MaxRatio bounds decompressed/compressed bytes of a compressed layer.
MaxRatio int64
// MaxPathLen bounds an entry name or link target.
MaxPathLen int
// MaxDepth bounds the number of components of an entry name.
MaxDepth int
}
Limits bounds what unpacking an image's layers may produce. A Budget spends one Limits across all the layers of an image.