A module's containers ran as whatever their image chose and shared folders were made writable by putting accounts in the folder's group (ADR 0312), which ADR 0325 supersedes. The engine now makes each declared module identity as a system account with the controller's numbers, runs a container declaring `identity` as it, and keeps each placed shared folder usable through one POSIX ACL entry per user, set through the kernel's xattrs on descriptors it opened itself. A folder holding data is kept only after the operator's warrant (the take act); a missing folder is made where its data lives and waits where its disk is not; root's data is never kept. A watch and a bounded sweep put back what an app narrows. The group grant is removed, and what it put an account in is taken back. Reuses the descriptor walks, the create act, the missing-path wait and the warrant- backed act message from the paused issue 567 branch.
68 lines
3.2 KiB
Go
68 lines
3.2 KiB
Go
package apply
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// A bounded walk under a kept folder (novox/hq ADR 0325 §8, §10, issue 567).
|
|
//
|
|
// **Walked by descriptor.** The folder is opened as a mesh directory is (meshWalk: no link another account could
|
|
// make, the folder itself no link), and everything under it is reached from its parent's descriptor with
|
|
// O_NOFOLLOW: a link met is passed by, a folder whose device is not the kept folder's is not entered, and an entry
|
|
// opened is checked to be the one that was looked at. An entry's ACL is read and written through its own
|
|
// descriptor, so a name swapped for a link between the look and the change changes nothing.
|
|
//
|
|
// **Bounded, and resumed.** A media library is millions of files, and a walk that never ends is a machine that
|
|
// cannot say what it did. Each walk reads at most so many entries for at most so long; one that meets its bound
|
|
// says how far it got (a cursor, the names of each level below the folder, kept in the engine's state and never
|
|
// said) and the next goes on from there, in the order of the names, so successive looks cover a folder whole.
|
|
|
|
// WalkLimits bound one walk under a folder: how many entries it reads, and for how long.
|
|
type WalkLimits struct {
|
|
Entries int
|
|
Time time.Duration
|
|
}
|
|
|
|
// ActLimits bound the take act and the walk that adds or drops a user's entries. One stopped goes on at the next
|
|
// apply, from the start: what already has its entries is passed quickly.
|
|
var ActLimits = WalkLimits{Entries: 5_000_000, Time: 30 * time.Minute}
|
|
|
|
// SweepLimits bound the sweep of one kept folder on one look (ADR 0325 §10): the look must come back within its
|
|
// own bound whatever the folder holds.
|
|
var SweepLimits = WalkLimits{Entries: 2000, Time: 2 * time.Second}
|
|
|
|
// WalkCounts is what one walk did or found. Counts only: never a path below the folder.
|
|
type WalkCounts struct {
|
|
// Folders and Files are the entries changed; Kept the ones that already had what they need.
|
|
Folders, Files, Kept int
|
|
// Links are links passed by, Other entries neither a file nor a folder, Mounts folders on another
|
|
// filesystem not entered.
|
|
Links, Other, Mounts int
|
|
// Read is every entry looked at.
|
|
Read int
|
|
// Narrowed is the entries that gave a user less than its right (judged by entry and mask together) and
|
|
// were put back; Unrepaired the ones that could not be — the owner's bits, which the mesh never changes.
|
|
Narrowed, Unrepaired int
|
|
}
|
|
|
|
// ErrWalkBound is a walk that met its bound before it was through: what it did stays, and the cursor says where
|
|
// the next one goes on.
|
|
var ErrWalkBound = errors.New("the walk met its bound")
|
|
|
|
// ErrNoACL is a filesystem that allows no ACLs here (ENOTSUP): a ZFS dataset whose acltype is off, say. The access
|
|
// waits for the take act, which sets it where it can (ADR 0325 §8).
|
|
var ErrNoACL = errors.New("the filesystem allows no access entries")
|
|
|
|
// keptPath refuses a folder that is not stated exactly: absolute and clean, so `..` and a doubled separator
|
|
// never name it.
|
|
func keptPath(path string) error {
|
|
if !filepath.IsAbs(path) || filepath.Clean(path) != path {
|
|
return fmt.Errorf("%q is not an access's folder as the engine states it (absolute, no `..`, no doubled or "+
|
|
"trailing separator); nothing was changed", path)
|
|
}
|
|
return nil
|
|
}
|