Documentation
¶
Overview ¶
Package fs is the file capability: the kernel I/O tier's file boundary. Reading a file crosses a system call out of the process's shared memory, so a service reads files from the host only through a capability granted by the binary that owns the process.
A binary constructs a HostFiles for one directory and passes it, as an IFiles, to whatever needs it; a service receives the capability in its constructor and never calls os.Open, os.ReadFile or os.DirFS itself. Files compiled into the binary with go:embed cross no boundary and need no capability. The interface has the standard library's io/fs shape, so an in-memory tree (testing/fstest.MapFS) or an embedded one (embed.FS, or an io/fs.Sub of either) is granted the same way.
The capability is read-only: it has no operation that creates, writes, renames or removes a file. HostFiles also reads symbolic links (io/fs.ReadLinkFS), which a process table granted as /proc needs.
Index ¶
- Variables
- type Change
- type ChangeOp
- type HostFiles
- func (files *HostFiles) Directory() string
- func (files *HostFiles) Lstat(name string) (stdfs.FileInfo, error)
- func (files *HostFiles) Open(name string) (stdfs.File, error)
- func (files *HostFiles) ReadDir(name string) ([]stdfs.DirEntry, error)
- func (files *HostFiles) ReadFile(name string) ([]byte, error)
- func (files *HostFiles) ReadLink(name string) (string, error)
- type HostWatcher
- type IFiles
- type IWatcher
- type Watch
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoDirectory is returned by [NewHostFiles] for an empty directory // name, which would otherwise silently grant the working directory. ErrNoDirectory = errors.New("ipc/fs: no directory named") // ErrNotDirectory is returned by [NewHostFiles] for a path that exists // but is not a directory. ErrNotDirectory = errors.New("ipc/fs: not a directory") // ErrNotGranted is returned by every operation on a HostFiles that // [NewHostFiles] did not construct, such as a nil pointer or a zero value. ErrNotGranted = errors.New("ipc/fs: no directory granted; construct HostFiles with NewHostFiles") )
var ErrWatchClosed = errors.New("ipc/fs: the watch has ended")
ErrWatchClosed is returned by Watch.Add once the watch has ended.
Functions ¶
This section is empty.
Types ¶
type Change ¶
Change is one notification from the kernel: the slash-separated, unrooted name of the file or directory beneath the granted directory, as IFiles spells names, and what happened to it. Err, when set, reports that the kernel's queue failed and the watch has ended; it is the last Change the watch delivers before its channel closes.
type ChangeOp ¶
type ChangeOp uint8
ChangeOp is what happened to a watched name.
The operations a watch reports. One kernel notification is one Change; a consumer that cares only that something happened reads the name alone.
type HostFiles ¶
type HostFiles struct {
// contains filtered or unexported fields
}
HostFiles is one directory of this host's filesystem, granted as a read-only capability over os.DirFS. Names are resolved beneath the directory and io/fs rejects ".." and rooted names with io/fs.ErrInvalid; like os.DirFS it follows symbolic links, so whoever grants a directory vouches for the links inside it. It holds no open descriptor and needs no closing.
func NewHostFiles ¶
NewHostFiles grants read access to directory, which must exist and be a directory. A relative directory is resolved against the working directory once, here, so a later change of working directory does not move the grant.
func (*HostFiles) Directory ¶
Directory is the absolute host directory the capability reads, or empty when nothing was granted.
type HostWatcher ¶
type HostWatcher struct {
// contains filtered or unexported fields
}
HostWatcher is one directory of this host's filesystem, granted as a change-notification capability over the kernel's inotify queue. Like HostFiles it holds no open descriptor itself: each Watch opens its own queue and closes it when its context ends.
func NewHostWatcher ¶
func NewHostWatcher(directory string) (*HostWatcher, error)
NewHostWatcher grants change notification beneath directory, which must exist and be a directory; the same checks NewHostFiles makes, so a binary grants both capabilities over one directory with the same argument.
func (*HostWatcher) Directory ¶
func (watcher *HostWatcher) Directory() string
Directory is the absolute host directory the capability watches, or empty when nothing was granted.
func (*HostWatcher) Watch ¶
func (watcher *HostWatcher) Watch(ctx context.Context) (*Watch, error)
Watch opens one inotify queue and delivers its notifications until ctx ends. The goroutine it starts is owned here: it exits on ctx, closes the queue and then the channel, so a consumer joins it by draining Changes.
type IFiles ¶
type IFiles interface {
stdfs.ReadFileFS
stdfs.ReadDirFS
}
IFiles is read-only access to one tree of files, addressed by the slash-separated, unrooted names io/fs defines: opening a file, reading a whole file and listing a directory.
type IWatcher ¶
type IWatcher interface {
// Watch opens one subscription bounded by ctx.
Watch(ctx context.Context) (*Watch, error)
}
IWatcher is change notification for files beneath one host directory: the kernel I/O tier's second file boundary, beside IFiles. A service that reacts to files changing receives it in its constructor and never opens the kernel's notification queue itself; a test grants a double whose channel it feeds.
type Watch ¶
Watch is one open subscription. Changes delivers every notification under every directory added to it, in kernel order, and is closed when the context the watch was opened with ends or the watch fails. Add watches one more directory beneath the granted directory; a watch reports changes to the entries of a watched directory, not to the entries of its subdirectories, so a consumer adds each directory it reads.
It is a value of two fields rather than an interface: a channel and a function are data, and nothing dispatches on them.