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) }