ADR 0328 supersedes ADR 0325: shared data is a library with one home, kept usable by its group rather than by ACL entries. The engine now makes each library's group and each module's user in its libraries' groups; keeps a library's root and requested sub-paths in its group with group write and setgid on its home, making missing sub-paths as the root is; waits for the operator's word before touching a root that holds data, and on the take act walks it by descriptor (no link, same filesystem, bounded and resumed, files with other names left); holds the containers of a library whose disk or mount is not there; and puts the tool runner's account in the group. The ACL keeping, mask repair and watch are gone; an access is again as before ADR 0325.
55 lines
2.6 KiB
Go
55 lines
2.6 KiB
Go
package apply
|
|
|
|
import (
|
|
"errors"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// A bounded walk under a library's root (novox/hq ADR 0328 §7, issue 567).
|
|
//
|
|
// **Walked by descriptor.** The root is opened as a mesh directory is (meshWalk: no link another account could
|
|
// make, the root 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 root's is not entered, and an entry opened is checked
|
|
// to be the one that was looked at. An entry's group and mode are set through its own descriptor, so a name
|
|
// swapped for a link between the look and the change changes nothing.
|
|
//
|
|
// **Bounded, and resumed.** A 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 root, kept in the engine's state and never said) and the
|
|
// next goes on from there, in the order of the names, so successive walks cover the library whole.
|
|
|
|
// WalkLimits bound one walk under a root: how many entries it reads, and for how long.
|
|
type WalkLimits struct {
|
|
Entries int
|
|
Time time.Duration
|
|
}
|
|
|
|
// ActLimits bound one walk of the take act; one stopped at its bound goes on from its cursor at the next look.
|
|
var ActLimits = WalkLimits{Entries: 5_000_000, Time: 30 * time.Minute}
|
|
|
|
// WalkCounts is what one walk did or found. Counts only: never a path below the root.
|
|
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, Shared files with another name elsewhere left as they are.
|
|
Links, Other, Mounts, Shared int
|
|
// Read is every entry looked at; Failed the entries that could not be changed (an immutable file, say).
|
|
Read, Failed 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")
|
|
|
|
// keptPath refuses a root 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 errors.New("the root is not stated as the engine states one (absolute, no `..`, no doubled or " +
|
|
"trailing separator); nothing was changed")
|
|
}
|
|
return nil
|
|
}
|