Files
ConfigKit/internal/engine/resource_context.go

134 lines
3.4 KiB
Go

package engine
import (
"errors"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
)
// ResourceContext is a passive copy of one acquired source's rooted filesystem
// and slash-relative base directory. FS is borrowed and opens resources only
// when the application explicitly requests them.
type ResourceContext struct {
FS fs.FS
BaseDir string
}
func cloneResourceContexts(contexts map[string]ResourceContext) map[string]ResourceContext {
if contexts == nil {
return nil
}
cloned := make(map[string]ResourceContext, len(contexts))
for id, context := range contexts {
cloned[id] = context
}
return cloned
}
// rootedNativeFS borrows a namespace without invoking SubFS or opening it at
// query time. All resource names remain relative to its configured root.
type rootedNativeFS struct {
filesystem fs.FS
root string
}
func (r rootedNativeFS) name(name string) (string, error) {
if !fs.ValidPath(name) {
return "", &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
}
joined := path.Join(r.root, name)
if !fs.ValidPath(joined) || r.root != "." && joined != r.root && !strings.HasPrefix(joined, r.root+"/") {
return "", &fs.PathError{Op: "open", Path: name, Err: fs.ErrPermission}
}
return joined, nil
}
func (r rootedNativeFS) Open(name string) (fs.File, error) {
joined, err := r.name(name)
if err != nil {
return nil, err
}
return r.filesystem.Open(joined)
}
func (r rootedNativeFS) ReadDir(name string) ([]fs.DirEntry, error) {
joined, err := r.name(name)
if err != nil {
return nil, err
}
return fs.ReadDir(r.filesystem, joined)
}
// rootedHostFS stores only a canonical root path. No os.Root is retained after
// loading or created by a SourceContext query.
type hostResourceRoot interface {
Open(string) (*os.File, error)
Close() error
}
type rootedHostFS struct {
root string
openRoot func(string) (hostResourceRoot, error)
}
func (r rootedHostFS) Open(name string) (fs.File, error) {
localName, err := filepath.Localize(name)
if err != nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
}
opener := r.openRoot
if opener == nil {
opener = func(name string) (hostResourceRoot, error) { return os.OpenRoot(name) }
}
root, err := opener(r.root)
if err != nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
}
canonical, err := canonicalExistingPath(filepath.Join(r.root, localName))
if err != nil {
_ = root.Close()
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
}
if !containedPath(r.root, canonical) {
_ = root.Close()
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrPermission}
}
relative, err := filepath.Rel(r.root, canonical)
if err != nil {
_ = root.Close()
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
}
file, err := root.Open(relative)
if err != nil {
_ = root.Close()
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
}
owned := rootedHostFile{File: file, root: root}
var opened fs.File = file
if directory, ok := opened.(fs.ReadDirFile); ok {
return &rootedHostDirFile{rootedHostFile: owned, directory: directory}, nil
}
return &owned, nil
}
type rootedHostFile struct {
fs.File
root hostResourceRoot
}
func (f *rootedHostFile) Close() error {
return errors.Join(f.File.Close(), f.root.Close())
}
type rootedHostDirFile struct {
rootedHostFile
directory fs.ReadDirFile
}
func (f *rootedHostDirFile) ReadDir(count int) ([]fs.DirEntry, error) {
return f.directory.ReadDir(count)
}