feat: implement multi-root virtual filesystem

This commit is contained in:
OpenClaw Agent
2026-09-21 13:29:50 +08:00
parent 8a82e48507
commit 633c833d1c
3 changed files with 149 additions and 11 deletions
+132
View File
@@ -0,0 +1,132 @@
package storage
import (
"os"
"path/filepath"
"strings"
"time"
)
type Multi struct {
Roots []Local
Names []string
}
func NewMulti(paths []string) Multi {
m := Multi{}
for _, p := range paths {
if strings.TrimSpace(p) == "" {
continue
}
abs, _ := filepath.Abs(p)
name := filepath.Base(filepath.Clean(abs))
if name == "." || name == string(filepath.Separator) || name == "" {
name = "root"
}
duplicate := false
for _, existing := range m.Names {
if existing == name {
duplicate = true
break
}
}
if duplicate {
continue
}
m.Roots = append(m.Roots, Local{Root: abs})
m.Names = append(m.Names, name)
}
return m
}
func (m Multi) isVirtualRoot(p string) bool { return strings.Trim(p, "/") == "" }
func (m Multi) find(p string) (Local, string, bool) {
p = strings.Trim(strings.ReplaceAll(p, "\\", "/"), "/")
if p == "" {
return Local{}, "", false
}
parts := strings.SplitN(p, "/", 2)
for i, n := range m.Names {
if parts[0] != n {
continue
}
rel := ""
if len(parts) == 2 {
rel = parts[1]
}
return m.Roots[i], rel, true
}
return Local{}, "", false
}
func (m Multi) Stat(p string) (os.FileInfo, error) {
if m.isVirtualRoot(p) {
return virtualDirInfo{name: "."}, nil
}
r, rel, ok := m.find(p)
if !ok {
return nil, os.ErrNotExist
}
return r.Stat(rel)
}
func (m Multi) Open(p string) (*os.File, error) {
r, rel, ok := m.find(p)
if !ok {
return nil, os.ErrNotExist
}
return r.Open(rel)
}
func (m Multi) Create(p string) (*os.File, error) {
r, rel, ok := m.find(p)
if !ok {
return nil, os.ErrNotExist
}
return r.Create(rel)
}
func (m Multi) Remove(p string) error {
r, rel, ok := m.find(p)
if !ok {
return os.ErrNotExist
}
return r.Remove(rel)
}
func (m Multi) Rename(a, b string) error {
ra, aa, oka := m.find(a)
rb, bb, okb := m.find(b)
if !oka || !okb || ra.Root != rb.Root {
return os.ErrInvalid
}
return ra.Rename(aa, bb)
}
func (m Multi) MkdirAll(p string) error {
r, rel, ok := m.find(p)
if !ok {
return os.ErrNotExist
}
return r.MkdirAll(rel)
}
func (m Multi) List(p string) ([]os.FileInfo, error) {
p = strings.Trim(strings.ReplaceAll(p, "\\", "/"), "/")
if p == "" {
out := make([]os.FileInfo, 0, len(m.Names))
for _, n := range m.Names {
out = append(out, virtualDirInfo{name: n})
}
return out, nil
}
r, rel, ok := m.find(p)
if !ok {
return nil, os.ErrNotExist
}
return r.List(rel)
}
type virtualDirInfo struct{ name string }
func (v virtualDirInfo) Name() string { return v.name }
func (v virtualDirInfo) Size() int64 { return 0 }
func (v virtualDirInfo) Mode() os.FileMode { return os.ModeDir | 0555 }
func (v virtualDirInfo) ModTime() (t time.Time) { return time.Time{} }
func (v virtualDirInfo) IsDir() bool { return true }
func (v virtualDirInfo) Sys() any { return nil }