oprimized, working
This commit is contained in:
parent
2b39afca3b
commit
0350ecba9a
38 changed files with 1809 additions and 826 deletions
src/host/vfs
|
@ -3,27 +3,27 @@ package vfs
|
|||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ResolveFS struct {
|
||||
osDir string
|
||||
osFS *OsFS
|
||||
rootFS Filesystem
|
||||
resolver *resolver
|
||||
}
|
||||
|
||||
func NewResolveFS(osDir string, factories map[string]FsFactory) *ResolveFS {
|
||||
func NewResolveFS(rootFs Filesystem, factories map[string]FsFactory) *ResolveFS {
|
||||
return &ResolveFS{
|
||||
osDir: osDir,
|
||||
osFS: NewOsFs(osDir),
|
||||
rootFS: rootFs,
|
||||
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)
|
||||
fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.rootFS.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ func (r *ResolveFS) Open(filename string) (File, error) {
|
|||
return nestedFs.Open(nestedFsPath)
|
||||
}
|
||||
|
||||
return r.osFS.Open(fsPath)
|
||||
return r.rootFS.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)
|
||||
func (r *ResolveFS) ReadDir(dir string) ([]fs.DirEntry, error) {
|
||||
fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(dir, r.rootFS.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -44,7 +44,32 @@ func (r *ResolveFS) ReadDir(dir string) (map[string]File, error) {
|
|||
return nestedFs.ReadDir(nestedFsPath)
|
||||
}
|
||||
|
||||
return r.osFS.ReadDir(fsPath)
|
||||
entries, err := r.rootFS.ReadDir(fsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]fs.DirEntry, 0, len(entries))
|
||||
for _, e := range entries {
|
||||
if r.resolver.isNestedFs(e.Name()) {
|
||||
out = append(out, newDirInfo(e.Name()))
|
||||
} else {
|
||||
out = append(out, e)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Stat implements Filesystem.
|
||||
func (r *ResolveFS) Stat(filename string) (fs.FileInfo, error) {
|
||||
fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.rootFS.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nestedFs != nil {
|
||||
return nestedFs.Stat(nestedFsPath)
|
||||
}
|
||||
|
||||
return r.rootFS.Stat(fsPath)
|
||||
}
|
||||
|
||||
var _ Filesystem = &ResolveFS{}
|
||||
|
@ -69,8 +94,18 @@ type resolver struct {
|
|||
|
||||
type openFile func(path string) (File, error)
|
||||
|
||||
func (r *resolver) isNestedFs(f string) bool {
|
||||
for ext := range r.factories {
|
||||
if strings.HasSuffix(f, ext) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// open requeue raw open, without resolver call
|
||||
func (r *resolver) resolvePath(name string, rawOpen openFile) (fsPath string, nestedFs Filesystem, nestedFsPath string, err error) {
|
||||
name = path.Clean(name)
|
||||
name = strings.TrimPrefix(name, Separator)
|
||||
parts := strings.Split(name, Separator)
|
||||
|
||||
|
@ -89,11 +124,12 @@ PARTS_LOOP:
|
|||
}
|
||||
|
||||
if nestOn == -1 {
|
||||
return clean(name), nil, "", nil
|
||||
return AbsPath(name), nil, "", nil
|
||||
}
|
||||
|
||||
fsPath = clean(strings.Join(parts[:nestOn], Separator))
|
||||
nestedFsPath = clean(strings.Join(parts[nestOn:], Separator))
|
||||
fsPath = AbsPath(path.Join(parts[:nestOn]...))
|
||||
|
||||
nestedFsPath = AbsPath(path.Join(parts[nestOn:]...))
|
||||
|
||||
// we dont need lock until now
|
||||
// it must be before fsmap read to exclude race condition:
|
||||
|
@ -123,9 +159,8 @@ PARTS_LOOP:
|
|||
var ErrNotExist = fs.ErrNotExist
|
||||
|
||||
func getFile[F File](m map[string]F, name string) (File, error) {
|
||||
name = clean(name)
|
||||
if name == Separator {
|
||||
return &Dir{}, nil
|
||||
return &dir{}, nil
|
||||
}
|
||||
|
||||
f, ok := m[name]
|
||||
|
@ -135,27 +170,30 @@ func getFile[F File](m map[string]F, name string) (File, error) {
|
|||
|
||||
for p := range m {
|
||||
if strings.HasPrefix(p, name) {
|
||||
return &Dir{}, nil
|
||||
return &dir{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotExist
|
||||
}
|
||||
|
||||
func listFilesInDir[F File](m map[string]F, name string) (map[string]File, error) {
|
||||
name = clean(name)
|
||||
|
||||
out := map[string]File{}
|
||||
func listDirFromFiles[F File](m map[string]F, name string) ([]fs.DirEntry, error) {
|
||||
out := make([]fs.DirEntry, 0, len(m))
|
||||
name = AddTrailSlash(name)
|
||||
for p, f := range m {
|
||||
if strings.HasPrefix(p, name) {
|
||||
parts := strings.Split(trimRelPath(p, name), Separator)
|
||||
if len(parts) == 1 {
|
||||
out[parts[0]] = f
|
||||
out = append(out, newFileInfo(parts[0], f.Size()))
|
||||
} else {
|
||||
out[parts[0]] = &Dir{}
|
||||
out = append(out, newDirInfo(parts[0]))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
out = slices.CompactFunc(out, func(de1, de2 fs.DirEntry) bool {
|
||||
return de1.Name() == de2.Name()
|
||||
})
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue