rework 2 (working)
This commit is contained in:
parent
5a77fa5e9c
commit
d30ef6cc9c
48 changed files with 1340 additions and 1747 deletions
src/host/vfs
146
src/host/vfs/resolver.go
Normal file
146
src/host/vfs/resolver.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package vfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ResolveFS struct {
|
||||
osDir string
|
||||
osFS *OsFS
|
||||
resolver *resolver
|
||||
}
|
||||
|
||||
func NewResolveFS(osDir string, factories map[string]FsFactory) *ResolveFS {
|
||||
return &ResolveFS{
|
||||
osDir: osDir,
|
||||
osFS: NewOsFs(osDir),
|
||||
resolver: newResolver(factories),
|
||||
}
|
||||
}
|
||||
|
||||
// Open implements Filesystem.
|
||||
func (r *ResolveFS) Open(filename string) (File, error) {
|
||||
fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.osFS.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nestedFs != nil {
|
||||
return nestedFs.Open(nestedFsPath)
|
||||
}
|
||||
|
||||
return r.osFS.Open(fsPath)
|
||||
}
|
||||
|
||||
// ReadDir implements Filesystem.
|
||||
func (r *ResolveFS) ReadDir(dir string) (map[string]File, error) {
|
||||
fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(dir, r.osFS.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nestedFs != nil {
|
||||
return nestedFs.ReadDir(nestedFsPath)
|
||||
}
|
||||
|
||||
return r.osFS.ReadDir(fsPath)
|
||||
}
|
||||
|
||||
var _ Filesystem = &ResolveFS{}
|
||||
|
||||
type FsFactory func(f File) (Filesystem, error)
|
||||
|
||||
const Separator = "/"
|
||||
|
||||
func newResolver(factories map[string]FsFactory) *resolver {
|
||||
return &resolver{
|
||||
factories: factories,
|
||||
fsmap: map[string]Filesystem{},
|
||||
}
|
||||
}
|
||||
|
||||
type resolver struct {
|
||||
m sync.Mutex
|
||||
factories map[string]FsFactory
|
||||
fsmap map[string]Filesystem // filesystem cache
|
||||
// TODO: add fsmap clean
|
||||
}
|
||||
|
||||
type openFile func(path string) (File, error)
|
||||
|
||||
// open requeue raw open, without resolver call
|
||||
func (r *resolver) resolvePath(name string, rawOpen openFile) (fsPath string, nestedFs Filesystem, nestedFsPath string, err error) {
|
||||
name = strings.TrimPrefix(name, Separator)
|
||||
parts := strings.Split(name, Separator)
|
||||
|
||||
nestOn := -1
|
||||
var nestFactory FsFactory
|
||||
|
||||
PARTS_LOOP:
|
||||
for i, part := range parts {
|
||||
for ext, factory := range r.factories {
|
||||
if strings.HasSuffix(part, ext) {
|
||||
nestOn = i + 1
|
||||
nestFactory = factory
|
||||
break PARTS_LOOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nestOn == -1 {
|
||||
return name, nil, "", nil
|
||||
}
|
||||
|
||||
fsPath = Clean(strings.Join(parts[:nestOn], Separator))
|
||||
nestedFsPath = Clean(strings.Join(parts[nestOn:], Separator))
|
||||
|
||||
// we dont need lock until now
|
||||
// it must be before fsmap read to exclude race condition:
|
||||
// read -> write
|
||||
// read -> write
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
if nestedFs, ok := r.fsmap[fsPath]; ok {
|
||||
return fsPath, nestedFs, nestedFsPath, nil
|
||||
} else {
|
||||
fsFile, err := rawOpen(fsPath)
|
||||
if err != nil {
|
||||
return "", nil, "", fmt.Errorf("error opening filesystem file: %s with error: %w", fsPath, err)
|
||||
}
|
||||
nestedFs, err := nestFactory(fsFile)
|
||||
if err != nil {
|
||||
return "", nil, "", fmt.Errorf("error creating filesystem from file: %s with error: %w", fsPath, err)
|
||||
}
|
||||
r.fsmap[fsPath] = nestedFs
|
||||
|
||||
return fsPath, nestedFs, nestedFsPath, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// func (r *resolver) resolveFile(name string, fs Filesystem) (File, error) {
|
||||
// fsPath, nestedFs, nestedFsPath, err := r.resolvePath(name, fs)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// if nestedFs == nil {
|
||||
// return fs.Open(fsPath)
|
||||
// }
|
||||
|
||||
// return nestedFs.Open(nestedFsPath)
|
||||
// }
|
||||
|
||||
// func (r *resolver) resolveDir(name string, fs Filesystem) (map[string]File, error) {
|
||||
// fsPath, nestedFs, nestedFsPath, err := r.resolvePath(name, fs)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// if nestedFs == nil {
|
||||
// return fs.ReadDir(fsPath)
|
||||
// }
|
||||
|
||||
// return nestedFs.ReadDir(nestedFsPath)
|
||||
// }
|
Loading…
Add table
Add a link
Reference in a new issue