overlay

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2026 License: BSD-3-Clause Imports: 10 Imported by: 1

Documentation

Overview

Package overlay makes a read-only filesystem writable without rewriting it on every change.

The problem it solves

An archive is a read-only filesystem: iso9660, squashfs, zip and tar all answer reads and refuse writes, because there is nothing to mutate in place. Offering a writable Filesystem over one anyway means every WriteFile rewrites the whole container -- a DeleteFile on three gigabytes moving three gigabytes -- and the interface then promises something cheap that is not. The caller finds out by watching a disk.

So changes are accumulated instead. A write lands in a spool directory and costs what that write costs; the container is rewritten ONCE, by Overlay.Seal, at a moment the caller chose and named. The interface stops lying: mutation is cheap, and the expensive thing has its own name.

What is copied

Only what changed. An entry nobody touched is read from the base and, at seal time, handed to the builder straight from the base -- so an archive of three gigabytes with one small file replaced spools that one small file.

Losing changes

Unsealed changes live in the spool and nowhere else. Overlay.Close discards them, on purpose and loudly: a Close that sealed in passing would commit a rewrite nobody asked for, and a Close that silently kept a spool would leave gigabytes in a temporary directory for the next reboot to collect. Seal is the commit.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned for a path that is in neither layer, or that a
	// deletion has shadowed.
	ErrNotFound = errors.New("overlay: path not found")
	// ErrNotDirectory is returned when a directory operation names a file.
	ErrNotDirectory = errors.New("overlay: not a directory")
	// ErrIsDirectory is returned when a file operation names a directory.
	ErrIsDirectory = errors.New("overlay: is a directory")
	// ErrClosed is returned once the overlay has been closed.
	ErrClosed = errors.New("overlay: closed")
	// ErrExists is returned by MkDir for a path already taken.
	ErrExists = errors.New("overlay: already exists")
)

Errors this package returns.

Functions

This section is empty.

Types

type Builder

type Builder interface {
	// AddDir records a directory. A format with no directory entries may
	// ignore it.
	AddDir(name string, perm os.FileMode) error
	// AddFile records a file and reads its contents from r.
	AddFile(name string, perm os.FileMode, r io.Reader) error
}

Builder is what a format offers for authoring one: iso9660's Builder, a zip writer, this org's sevenzip writer. Seal drives it and knows nothing else about the format.

type Option

type Option func(*Overlay)

Option configures an Overlay.

func WithSpool

func WithSpool(dir string) Option

WithSpool puts the working copies in dir instead of a temporary directory. The caller then owns it: Close leaves it alone.

type Overlay

type Overlay struct {
	// contains filtered or unexported fields
}

Overlay is a read-only filesystem plus the changes made to it.

func New

func New(base filesystem.Filesystem, opts ...Option) (*Overlay, error)

New wraps base. Nothing is read from it until something asks.

func (*Overlay) Close

func (o *Overlay) Close() error

func (*Overlay) DeleteDir

func (o *Overlay) DeleteDir(p string) error

DeleteDir shadows a directory and everything under it.

func (*Overlay) DeleteFile

func (o *Overlay) DeleteFile(p string) error

DeleteFile shadows a path. The base keeps it; the overlay stops answering for it, and Seal leaves it out.

func (*Overlay) ListDir

func (o *Overlay) ListDir(dir string) ([]filesystem.DirEntry, error)

ListDir merges the two layers: what the base holds, minus what is shadowed, plus what was added.

func (*Overlay) MkDir

func (o *Overlay) MkDir(p string, perm os.FileMode) error

MkDir records a directory. Nothing is created in the base, which has no idea this happened until Seal.

func (*Overlay) OpenFile

func (o *Overlay) OpenFile(p string) (filesystem.File, error)

OpenFile hands out a handle. A working copy is opened from the spool; an untouched entry is asked of the base, if the base offers handles at all.

func (*Overlay) ReadFile

func (o *Overlay) ReadFile(p string) ([]byte, error)

ReadFile reads the working copy when there is one, and the base otherwise.

func (o *Overlay) ReadLink(p string) (string, error)

ReadLink asks the base: nothing in the upper layer makes links.

func (*Overlay) Rename

func (o *Overlay) Rename(from, to string) error

Rename is a read and two writes, which is what it costs here: the point of the spool is that those are cheap.

func (*Overlay) Seal

func (o *Overlay) Seal(b Builder) error

Seal hands the merged view to a builder, once.

Entries are offered in path order, directories before what is inside them, because a builder that has to create a parent before its children can then rely on that rather than sorting for itself.

An entry nobody touched is streamed from the BASE. Only what changed was ever copied, which is what keeps a small edit to a large archive small: the spool holds the edit, and the rest goes straight through.

func (*Overlay) SealToFile

func (o *Overlay) SealToFile(target string, mk func(io.WriteSeeker) (Builder, error)) error

SealToFile seals into target, and does it by RENAME.

The new archive is written beside the target and moved over it at the end, so an interrupted seal -- a full disk, a signal, a power cut -- leaves the original exactly as it was. Sealing in place would destroy the archive in order to write it, which turns every interruption into data loss, and the window is the whole rewrite.

func (*Overlay) Spool

func (o *Overlay) Spool() string

Spool is where working copies are kept, so a caller can say how much room the changes are taking.

func (*Overlay) Stat

func (o *Overlay) Stat(p string) (filesystem.Stat, error)

Stat answers from the upper layer first.

func (*Overlay) WriteFile

func (o *Overlay) WriteFile(p string, data []byte, perm os.FileMode) error

WriteFile is the cheap operation this package exists for: it writes to the spool, and the container is untouched until Seal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL