Commit 7c7b66b4 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Drop SwitchFileSystem.

parent 51207b6e
......@@ -30,7 +30,6 @@ MANUAL_GOFILES=api.go \
fsops.go \
readonlyfs.go \
request.go \
switchfs.go \
typeprint.go \
types.go \
version.go \
......
package fuse
import (
"os"
"path/filepath"
"sort"
"strings"
)
// SwitchFileSystem construct the union of a set of filesystems, and
// select them by prefix. Consider the traditional Unix file system:
// different parts have different characteristics, eg. "/usr" is
// read-only, while "/home/user" is read/write. Similarly, "/tmp"
// does not need to be persistent and "/dev" is totally unlike a file
// system.
//
// With SwitchFileSystem, you can write filesystems for each of these
// parts separately, and combine them using SwitchFileSystem. This is
// a simpler and less efficient alternative to in-process mounts, but
// it also works if the encompassing file system already has the
// mounted directory.
type SwitchFileSystem struct {
DefaultFileSystem
fileSystems SwitchedFileSystems
}
// This is the definition of one member of SwitchedFileSystems.
type SwitchedFileSystem struct {
Prefix string
FileSystem
StripPrefix bool
}
type SwitchedFileSystems []*SwitchedFileSystem
func (p SwitchedFileSystems) Len() int {
return len(p)
}
func (p SwitchedFileSystems) Less(i, j int) bool {
// Invert order, so we get more specific prefixes first.
return p[i].Prefix > p[j].Prefix
}
func (p SwitchedFileSystems) Swap(i, j int) {
swFs := p[i]
p[i] = p[j]
p[j] = swFs
}
func NewSwitchFileSystem(fsMap []SwitchedFileSystem) *SwitchFileSystem {
me := &SwitchFileSystem{}
for _, inSwFs := range fsMap {
swFs := inSwFs
swFs.Prefix = strings.TrimLeft(swFs.Prefix, string(filepath.Separator))
swFs.Prefix = strings.TrimRight(swFs.Prefix, string(filepath.Separator))
me.fileSystems = append(me.fileSystems, &swFs)
}
sort.Sort(me.fileSystems)
return me
}
// TODO - use binary search. This is inefficient if there are large
// numbers of switched filesystems.
func (me *SwitchFileSystem) findFileSystem(path string) (string, *SwitchedFileSystem) {
for _, swFs := range me.fileSystems {
if swFs.Prefix == "" || swFs.Prefix == path || strings.HasPrefix(path, swFs.Prefix+string(filepath.Separator)) {
if swFs.StripPrefix {
path = strings.TrimLeft(path[len(swFs.Prefix):], string(filepath.Separator))
}
return path, swFs
}
}
return "", nil
}
func (me *SwitchFileSystem) GetAttr(name string, context *Context) (*os.FileInfo, Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.GetAttr(name, context)
}
func (me *SwitchFileSystem) Readlink(name string, context *Context) (string, Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return "", ENOENT
}
return fs.FileSystem.Readlink(name, context)
}
func (me *SwitchFileSystem) Mknod(name string, mode uint32, dev uint32, context *Context) Status {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Mknod(name, mode, dev, context)
}
func (me *SwitchFileSystem) Mkdir(name string, mode uint32, context *Context) Status {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Mkdir(name, mode, context)
}
func (me *SwitchFileSystem) Unlink(name string, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Unlink(name, context)
}
func (me *SwitchFileSystem) Rmdir(name string, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Rmdir(name, context)
}
func (me *SwitchFileSystem) Symlink(value string, linkName string, context *Context) (code Status) {
linkName, fs := me.findFileSystem(linkName)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Symlink(value, linkName, context)
}
func (me *SwitchFileSystem) Rename(oldName string, newName string, context *Context) (code Status) {
oldName, fs1 := me.findFileSystem(oldName)
newName, fs2 := me.findFileSystem(newName)
if fs1 != fs2 {
return EXDEV
}
if fs1 == nil {
return ENOENT
}
return fs1.Rename(oldName, newName, context)
}
func (me *SwitchFileSystem) Link(oldName string, newName string, context *Context) (code Status) {
oldName, fs1 := me.findFileSystem(oldName)
newName, fs2 := me.findFileSystem(newName)
if fs1 != fs2 {
return EXDEV
}
if fs1 == nil {
return ENOENT
}
return fs1.Link(oldName, newName, context)
}
func (me *SwitchFileSystem) Chmod(name string, mode uint32, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Chmod(name, mode, context)
}
func (me *SwitchFileSystem) Chown(name string, uid uint32, gid uint32, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Chown(name, uid, gid, context)
}
func (me *SwitchFileSystem) Truncate(name string, offset uint64, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Truncate(name, offset, context)
}
func (me *SwitchFileSystem) Open(name string, flags uint32, context *Context) (file File, code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.Open(name, flags, context)
}
func (me *SwitchFileSystem) OpenDir(name string, context *Context) (stream chan DirEntry, status Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.OpenDir(name, context)
}
func (me *SwitchFileSystem) OnMount(nodeFs *PathNodeFs) {
for _, fs := range me.fileSystems {
fs.FileSystem.OnMount(nodeFs)
}
}
func (me *SwitchFileSystem) OnUnmount() {
for _, fs := range me.fileSystems {
fs.FileSystem.OnUnmount()
}
}
func (me *SwitchFileSystem) Access(name string, mode uint32, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Access(name, mode, context)
}
func (me *SwitchFileSystem) Create(name string, flags uint32, mode uint32, context *Context) (file File, code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.Create(name, flags, mode, context)
}
func (me *SwitchFileSystem) Utimens(name string, AtimeNs uint64, CtimeNs uint64, context *Context) (code Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.Utimens(name, AtimeNs, CtimeNs, context)
}
func (me *SwitchFileSystem) GetXAttr(name string, attr string, context *Context) ([]byte, Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.GetXAttr(name, attr, context)
}
func (me *SwitchFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *Context) Status {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.SetXAttr(name, attr, data, flags, context)
}
func (me *SwitchFileSystem) ListXAttr(name string, context *Context) ([]string, Status) {
name, fs := me.findFileSystem(name)
if fs == nil {
return nil, ENOENT
}
return fs.FileSystem.ListXAttr(name, context)
}
func (me *SwitchFileSystem) RemoveXAttr(name string, attr string, context *Context) Status {
name, fs := me.findFileSystem(name)
if fs == nil {
return ENOENT
}
return fs.FileSystem.RemoveXAttr(name, attr, context)
}
package fuse
import (
"testing"
)
func TestSwitchFsSlash(t *testing.T) {
fsMap := []SwitchedFileSystem{
SwitchedFileSystem{Prefix: ""},
SwitchedFileSystem{Prefix: "/home"},
SwitchedFileSystem{Prefix: "usr/"},
}
sfs := NewSwitchFileSystem(fsMap)
for path, expectPrefix := range map[string]string{
"home/foo/bar": "home",
"usr/local": "usr",
} {
_, fs := sfs.findFileSystem(path)
if fs.Prefix != expectPrefix {
t.Errorf("Mismatch %s - '%s' != '%s'", path, fs.Prefix, expectPrefix)
}
}
}
func TestSwitchFs(t *testing.T) {
fsMap := []SwitchedFileSystem{
SwitchedFileSystem{Prefix: ""},
SwitchedFileSystem{Prefix: "home/foo"},
SwitchedFileSystem{Prefix: "home"},
SwitchedFileSystem{Prefix: "usr"},
}
sfs := NewSwitchFileSystem(fsMap)
for path, expectPrefix := range map[string]string{
"xyz": "",
"home/foo/bar": "home/foo",
"home/fooz/bar": "home",
"home/efg": "home",
"lib": "",
"abc": "",
"usr/local": "usr",
} {
_, fs := sfs.findFileSystem(path)
if fs.Prefix != expectPrefix {
t.Errorf("Mismatch %s %s %v", path, fs.Prefix, expectPrefix)
}
}
}
func TestSwitchFsStrip(t *testing.T) {
fsMap := []SwitchedFileSystem{
SwitchedFileSystem{Prefix: ""},
SwitchedFileSystem{Prefix: "dev", StripPrefix: true},
SwitchedFileSystem{Prefix: "home", StripPrefix: false},
}
sfs := NewSwitchFileSystem(fsMap)
// Don't check for inputs ending in '/' since Go-FUSE never
// generates them.
for path, expectPath := range map[string]string{
"xyz": "xyz",
"home/foo/bar": "home/foo/bar",
"home": "home",
"dev/null": "null",
"dev": "",
} {
stripPath, _ := sfs.findFileSystem(path)
if stripPath != expectPath {
t.Errorf("Mismatch %s %s %v", path, stripPath, expectPath)
}
}
}
func TestSwitchFsApi(t *testing.T) {
var fs FileSystem
fs = &SwitchedFileSystem{}
_ = fs
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment