Provide passive per-source resource contexts
This commit is contained in:
132
internal/engine/resource_context.go
Normal file
132
internal/engine/resource_context.go
Normal file
@@ -0,0 +1,132 @@
|
||||
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) || strings.Contains(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) {
|
||||
if !fs.ValidPath(name) || strings.Contains(name, "\\") {
|
||||
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, filepath.FromSlash(name)))
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user