Commit 1f1c157d authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Allow different PathFilesystems to be mounted within directories of

PathFileSystemConnector file system.
parent 9d51ae3f
*~ *~
*.6 *.6
8.out
.nfs* .nfs*
_* _*
...@@ -21,9 +21,9 @@ func main() { ...@@ -21,9 +21,9 @@ func main() {
} }
orig := flag.Arg(0) orig := flag.Arg(0)
pt := examplelib.NewPassThroughFuse(orig) fs := examplelib.NewPassThroughFuse(orig)
fs := fuse.NewPathFileSystemConnector(pt) conn := fuse.NewPathFileSystemConnector(fs)
state := fuse.NewMountState(fs) state := fuse.NewMountState(conn)
state.Debug = *debug state.Debug = *debug
mountPoint := flag.Arg(1) mountPoint := flag.Arg(1)
......
...@@ -7,7 +7,8 @@ DEPS=../fuse ...@@ -7,7 +7,8 @@ DEPS=../fuse
GOFILES=dummyfuse.go\ GOFILES=dummyfuse.go\
passthrough.go\ passthrough.go\
stackfs.go stackfs.go\
misc.go
include $(GOROOT)/src/Make.pkg include $(GOROOT)/src/Make.pkg
...@@ -194,11 +194,11 @@ func (self *DummyPathFuse) OpenDir(name string) (dir fuse.RawFuseDir, code fuse. ...@@ -194,11 +194,11 @@ func (self *DummyPathFuse) OpenDir(name string) (dir fuse.RawFuseDir, code fuse.
return nil, fuse.ENOSYS return nil, fuse.ENOSYS
} }
func (self *DummyPathFuse) Init() (*fuse.InitOut, fuse.Status) { func (self *DummyPathFuse) Mount(conn *fuse.PathFileSystemConnector) (fuse.Status) {
return nil, fuse.ENOSYS return fuse.OK
} }
func (self *DummyPathFuse) Destroy() { func (self *DummyPathFuse) Unmount() {
} }
func (self *DummyPathFuse) Access(name string, mode uint32) (code fuse.Status) { func (self *DummyPathFuse) Access(name string, mode uint32) (code fuse.Status) {
...@@ -213,6 +213,3 @@ func (self *DummyPathFuse) Utimens(name string, AtimeNs uint64, CtimeNs uint64) ...@@ -213,6 +213,3 @@ func (self *DummyPathFuse) Utimens(name string, AtimeNs uint64, CtimeNs uint64)
return fuse.ENOSYS return fuse.ENOSYS
} }
func (self *DummyPathFuse) SetOptions(*fuse.PathFileSystemConnectorOptions) {
}
package examplelib
import "os"
////////////////
func IsDir(name string) bool {
fi, _ := os.Lstat(name)
return fi != nil && fi.IsDirectory()
}
func IsFile(name string) bool {
fi, _ := os.Lstat(name)
return fi != nil && fi.IsRegular()
}
func FileExists(name string) bool {
_, err := os.Lstat(name)
return err == nil
}
...@@ -25,11 +25,11 @@ func NewPassThroughFuse(root string) (out *PassThroughFuse) { ...@@ -25,11 +25,11 @@ func NewPassThroughFuse(root string) (out *PassThroughFuse) {
return out return out
} }
func (self *PassThroughFuse) Init() (*fuse.InitOut, fuse.Status) { func (self *PassThroughFuse) Mount(conn *fuse.PathFileSystemConnector) (fuse.Status) {
return new(fuse.InitOut), fuse.OK return fuse.OK
} }
func (self *PassThroughFuse) Destroy() { func (self *PassThroughFuse) Unmount() {
} }
......
...@@ -16,23 +16,6 @@ import ( ...@@ -16,23 +16,6 @@ import (
var _ = strings.Join var _ = strings.Join
var _ = log.Println var _ = log.Println
////////////////
func IsDir(name string) bool {
fi, _ := os.Lstat(name)
return fi != nil && fi.IsDirectory()
}
func IsFile(name string) bool {
fi, _ := os.Lstat(name)
return fi != nil && fi.IsRegular()
}
func FileExists(name string) bool {
_, err := os.Lstat(name)
return err == nil
}
//////////////// ////////////////
// state for our testcase, mostly constants // state for our testcase, mostly constants
...@@ -50,6 +33,7 @@ type testCase struct { ...@@ -50,6 +33,7 @@ type testCase struct {
origSubfile string origSubfile string
tester *testing.T tester *testing.T
state *fuse.MountState state *fuse.MountState
connector *fuse.PathFileSystemConnector
} }
// Create and mount filesystem. // Create and mount filesystem.
...@@ -69,9 +53,10 @@ func (self *testCase) Setup(t *testing.T) { ...@@ -69,9 +53,10 @@ func (self *testCase) Setup(t *testing.T) {
self.origSubdir = path.Join(self.origDir, subdir) self.origSubdir = path.Join(self.origDir, subdir)
self.origSubfile = path.Join(self.origSubdir, "subfile") self.origSubfile = path.Join(self.origSubdir, "subfile")
fs := fuse.NewPathFileSystemConnector(NewPassThroughFuse(self.origDir)) pfs := NewPassThroughFuse(self.origDir)
self.connector = fuse.NewPathFileSystemConnector(pfs)
self.state = fuse.NewMountState(fs) self.connector.Debug = true
self.state = fuse.NewMountState(self.connector)
self.state.Mount(self.mountPoint) self.state.Mount(self.mountPoint)
//self.state.Debug = false //self.state.Debug = false
...@@ -610,3 +595,44 @@ func TestMount(t *testing.T) { ...@@ -610,3 +595,44 @@ func TestMount(t *testing.T) {
ts.testLargeDirRead() ts.testLargeDirRead()
ts.Cleanup() ts.Cleanup()
} }
func TestRecursiveMount(t *testing.T) {
ts := new(testCase)
ts.Setup(t)
f, err := os.Open(path.Join(ts.mountPoint, "hello.txt"),
os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
t.Errorf("open write err %v", err)
}
f.WriteString("bla")
f.Close()
pfs2 := NewPassThroughFuse(ts.origDir)
code := ts.connector.Mount("/hello.txt", pfs2)
if code != fuse.EINVAL {
t.Error("expect EINVAL", code)
}
submnt := path.Join(ts.mountPoint, "mnt")
err = os.Mkdir(submnt, 0777)
if err != nil {
t.Errorf("mkdir")
}
code = ts.connector.Mount("/mnt", pfs2)
if code != fuse.OK {
t.Errorf("mkdir")
}
_, err = os.Lstat(submnt)
if err != nil {
t.Error("lstat submount", err)
}
_, err = os.Lstat(path.Join(submnt, "hello.txt"))
if err != nil {
t.Error("lstat submount/file", err)
}
ts.Cleanup()
}
...@@ -31,7 +31,7 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool { ...@@ -31,7 +31,7 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool {
dirent.Off = de.offset dirent.Off = de.offset
dirent.Ino = inode dirent.Ino = inode
dirent.NameLen = uint32(len(name)) dirent.NameLen = uint32(len(name))
dirent.Typ = (mode & 0170000) >> 12 dirent.Typ = ModeToType(mode)
err := binary.Write(&de.buf, binary.LittleEndian, dirent) err := binary.Write(&de.buf, binary.LittleEndian, dirent)
if err != nil { if err != nil {
......
...@@ -291,3 +291,7 @@ func NegativeEntry(time float64) *EntryOut { ...@@ -291,3 +291,7 @@ func NegativeEntry(time float64) *EntryOut {
SplitNs(time, &out.EntryValid, &out.EntryValidNsec) SplitNs(time, &out.EntryValid, &out.EntryValidNsec)
return out return out
} }
func ModeToType(mode uint32) uint32 {
return (mode & 0170000) >> 12
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"sync" "sync"
"fmt" "fmt"
"log"
"path" "path"
"strings" "strings"
) )
...@@ -15,8 +16,15 @@ type inodeData struct { ...@@ -15,8 +16,15 @@ type inodeData struct {
Name string Name string
LookupCount int LookupCount int
Type uint32
// Number of inodeData that have this as parent. // Number of inodeData that have this as parent.
RefCount int RefCount int
// If non-nil the file system mounted here.
Mounted PathFilesystem
// If yes, we are looking to unmount the mounted fs.
unmountPending bool
} }
// Should implement some hash table method instead? // Should implement some hash table method instead?
...@@ -33,18 +41,22 @@ func (self *inodeData) Key() string { ...@@ -33,18 +41,22 @@ func (self *inodeData) Key() string {
return inodeDataKey(p, self.Name) return inodeDataKey(p, self.Name)
} }
func (self *inodeData) GetPath() string { func (self *inodeData) GetPath() (path string, fs PathFilesystem) {
// TODO - softcode this. // TODO - softcode this.
var components [100]string var components [100]string
j := len(components) j := len(components)
for p := self; p != nil && p.NodeId != FUSE_ROOT_ID; p = p.Parent { inode := self
for ; inode != nil && inode.Mounted == nil; inode = inode.Parent {
j-- j--
components[j] = p.Name components[j] = inode.Name
} }
fullPath := strings.Join(components[j:], "/") fullPath := strings.Join(components[j:], "/")
return fullPath if !inode.unmountPending {
fs = inode.Mounted
}
return fullPath, fs
} }
type TimeoutOptions struct { type TimeoutOptions struct {
...@@ -66,8 +78,6 @@ type PathFileSystemConnectorOptions struct { ...@@ -66,8 +78,6 @@ type PathFileSystemConnectorOptions struct {
} }
type PathFileSystemConnector struct { type PathFileSystemConnector struct {
fileSystem PathFilesystem
// Protects the hashmap, its contents and the nextFreeInode counter. // Protects the hashmap, its contents and the nextFreeInode counter.
lock sync.RWMutex lock sync.RWMutex
...@@ -86,6 +96,7 @@ type PathFileSystemConnector struct { ...@@ -86,6 +96,7 @@ type PathFileSystemConnector struct {
nextFreeInode uint64 nextFreeInode uint64
options PathFileSystemConnectorOptions options PathFileSystemConnectorOptions
Debug bool
} }
// Must be called with lock held. // Must be called with lock held.
...@@ -156,7 +167,7 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int ...@@ -156,7 +167,7 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int
data, ok := self.inodePathMapByInode[nodeId] data, ok := self.inodePathMapByInode[nodeId]
if ok { if ok {
data.LookupCount -= forgetCount data.LookupCount -= forgetCount
if data.LookupCount <= 0 && data.RefCount <= 0 { if data.LookupCount <= 0 && data.RefCount <= 0 && (data.Mounted == nil || data.unmountPending) {
self.inodePathMap[data.Key()] = nil, false self.inodePathMap[data.Key()] = nil, false
} }
} }
...@@ -219,6 +230,29 @@ func (self *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) { ...@@ -219,6 +230,29 @@ func (self *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) {
} }
} }
// Walk the file system starting from the root.
func (self *PathFileSystemConnector) findInode(fullPath string) *inodeData {
fullPath = strings.TrimLeft(path.Clean(fullPath), "/")
comps := strings.Split(fullPath, "/", -1)
self.lock.RLock()
defer self.lock.RUnlock()
node := self.inodePathMapByInode[FUSE_ROOT_ID]
for i, component := range(comps) {
if len(component) == 0 {
continue
}
key := inodeDataKey(node.NodeId, component)
node = self.inodePathMap[key]
if node == nil {
panic(fmt.Sprintf("findInode: %v %v", i, fullPath))
}
}
return node
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Below routines should not access inodePathMap(ByInode) directly, // Below routines should not access inodePathMap(ByInode) directly,
// and there need no locking. // and there need no locking.
...@@ -227,10 +261,10 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector ...@@ -227,10 +261,10 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
out = new(PathFileSystemConnector) out = new(PathFileSystemConnector)
out.inodePathMap = make(map[string]*inodeData) out.inodePathMap = make(map[string]*inodeData)
out.inodePathMapByInode = make(map[uint64]*inodeData) out.inodePathMapByInode = make(map[uint64]*inodeData)
out.fileSystem = fs
rootData := new(inodeData) rootData := new(inodeData)
rootData.NodeId = FUSE_ROOT_ID rootData.NodeId = FUSE_ROOT_ID
rootData.Type = ModeToType(S_IFDIR)
out.inodePathMap[rootData.Key()] = rootData out.inodePathMap[rootData.Key()] = rootData
out.inodePathMapByInode[FUSE_ROOT_ID] = rootData out.inodePathMapByInode[FUSE_ROOT_ID] = rootData
...@@ -240,21 +274,79 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector ...@@ -240,21 +274,79 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
out.options.AttrTimeout = 1.0 out.options.AttrTimeout = 1.0
out.options.EntryTimeout = 1.0 out.options.EntryTimeout = 1.0
fs.SetOptions(&out.options) if code := out.Mount("/", fs); code != OK {
panic("root mount failed.")
}
return out return out
} }
func (self *PathFileSystemConnector) GetPath(nodeid uint64) string { func (self *PathFileSystemConnector) SetOptions(opts PathFileSystemConnectorOptions) {
self.options = opts
}
func (self *PathFileSystemConnector) Mount(path string, fs PathFilesystem) Status {
node := self.findInode(path)
// TODO - check that fs was not mounted elsewhere.
if node.RefCount > 0 {
return EBUSY
}
if node.Type & ModeToType(S_IFDIR) == 0 {
return EINVAL
}
code := fs.Mount(self)
if code != OK {
if self.Debug {
log.Println("Mount error: ", path, code)
}
return code
}
if self.Debug {
log.Println("Mount: ", fs, "on", path, node)
}
// TODO - this is technically a race-condition.
node.Mounted = fs
node.unmountPending = false
return OK
}
func (self *PathFileSystemConnector) Unmount(path string) Status {
node := self.findInode(path)
if node == nil || node.Mounted == nil {
panic(path)
}
// TODO - check if we have open files.
if self.Debug {
log.Println("Unmount: ", node)
}
// node manipulations are racy?
if node.RefCount > 0 {
node.Mounted.Unmount()
node.unmountPending = true
} else {
node.Mounted = nil
}
return OK
}
func (self *PathFileSystemConnector) GetPath(nodeid uint64) (path string, fs PathFilesystem) {
return self.getInodeData(nodeid).GetPath() return self.getInodeData(nodeid).GetPath()
} }
func (self *PathFileSystemConnector) Init(h *InHeader, input *InitIn) (*InitOut, Status) { func (self *PathFileSystemConnector) Init(h *InHeader, input *InitIn) (*InitOut, Status) {
return self.fileSystem.Init() // TODO ?
return new(InitOut), OK
} }
func (self *PathFileSystemConnector) Destroy(h *InHeader, input *InitIn) { func (self *PathFileSystemConnector) Destroy(h *InHeader, input *InitIn) {
self.fileSystem.Destroy() // TODO - umount all.
} }
func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) { func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
...@@ -263,8 +355,14 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -263,8 +355,14 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
// TODO - fuse.c has special case code for name == "." and // TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in // "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init. // Init.
fullPath := path.Join(parent.GetPath(), name) fullPath, fs := parent.GetPath()
attr, err := self.fileSystem.GetAttr(fullPath) if fs == nil {
return NegativeEntry(self.options.NegativeTimeout), OK
}
fullPath = path.Join(fullPath, name)
attr, err := fs.GetAttr(fullPath)
if err == ENOENT && self.options.NegativeTimeout > 0.0 { if err == ENOENT && self.options.NegativeTimeout > 0.0 {
return NegativeEntry(self.options.NegativeTimeout), OK return NegativeEntry(self.options.NegativeTimeout), OK
} }
...@@ -274,6 +372,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -274,6 +372,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
} }
data := self.lookupUpdate(header.NodeId, name) data := self.lookupUpdate(header.NodeId, name)
data.Type = ModeToType(attr.Mode)
out = new(EntryOut) out = new(EntryOut)
out.NodeId = data.NodeId out.NodeId = data.NodeId
...@@ -282,7 +381,6 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -282,7 +381,6 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
SplitNs(self.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec) SplitNs(self.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr out.Attr = *attr
return out, OK return out, OK
} }
...@@ -291,7 +389,12 @@ func (self *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) { ...@@ -291,7 +389,12 @@ func (self *PathFileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
} }
func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) { func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
attr, err := self.fileSystem.GetAttr(self.GetPath(header.NodeId)) // TODO - should we update inodeData.Type?
fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return nil, ENOENT
}
attr, err := fs.GetAttr(fullPath)
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -305,8 +408,12 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) ...@@ -305,8 +408,12 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn)
} }
func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status) { func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseDir, status Status) {
fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return 0, nil, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags? // TODO - how to handle return flags, the FUSE open flags?
f, err := self.fileSystem.OpenDir(self.GetPath(header.NodeId)) f, err := fs.OpenDir(fullPath)
if err != OK { if err != OK {
return 0, nil, err return 0, nil, err
} }
...@@ -315,8 +422,12 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f ...@@ -315,8 +422,12 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f
} }
func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) { func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return 0, nil, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags? // TODO - how to handle return flags, the FUSE open flags?
f, err := self.fileSystem.Open(self.GetPath(header.NodeId), input.Flags) f, err := fs.Open(fullPath, input.Flags)
if err != OK { if err != OK {
return 0, nil, err return 0, nil, err
} }
...@@ -327,19 +438,23 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) ...@@ -327,19 +438,23 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
var err Status = OK var err Status = OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.) // TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath := self.GetPath(header.NodeId) fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return nil, ENOENT
}
if input.Valid&FATTR_MODE != 0 { if input.Valid&FATTR_MODE != 0 {
err = self.fileSystem.Chmod(fullPath, input.Mode) err = fs.Chmod(fullPath, input.Mode)
} }
if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) { if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) {
// TODO - can we get just FATTR_GID but not FATTR_UID ? // TODO - can we get just FATTR_GID but not FATTR_UID ?
err = self.fileSystem.Chown(fullPath, uint32(input.Uid), uint32(input.Gid)) err = fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid))
} }
if input.Valid&FATTR_SIZE != 0 { if input.Valid&FATTR_SIZE != 0 {
self.fileSystem.Truncate(fullPath, input.Size) fs.Truncate(fullPath, input.Size)
} }
if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) { if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) {
err = self.fileSystem.Utimens(fullPath, err = fs.Utimens(fullPath,
uint64(input.Atime*1e9)+uint64(input.Atimensec), uint64(input.Atime*1e9)+uint64(input.Atimensec),
uint64(input.Mtime*1e9)+uint64(input.Mtimensec)) uint64(input.Mtime*1e9)+uint64(input.Mtimensec))
} }
...@@ -356,14 +471,21 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) ...@@ -356,14 +471,21 @@ func (self *PathFileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn)
} }
func (self *PathFileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) { func (self *PathFileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) {
fullPath := self.GetPath(header.NodeId) fullPath, fs := self.GetPath(header.NodeId)
val, err := self.fileSystem.Readlink(fullPath) if fs == nil {
return nil, ENOENT
}
val, err := fs.Readlink(fullPath)
return bytes.NewBufferString(val).Bytes(), err return bytes.NewBufferString(val).Bytes(), err
} }
func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) {
fullPath := path.Join(self.GetPath(header.NodeId), name) fullPath, fs := self.GetPath(header.NodeId)
err := self.fileSystem.Mknod(fullPath, input.Mode, uint32(input.Rdev)) if fs == nil {
return nil, ENOENT
}
fullPath = path.Join(fullPath, name)
err := fs.Mknod(fullPath, input.Mode, uint32(input.Rdev))
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -371,7 +493,11 @@ func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, nam ...@@ -371,7 +493,11 @@ func (self *PathFileSystemConnector) Mknod(header *InHeader, input *MknodIn, nam
} }
func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
err := self.fileSystem.Mkdir(path.Join(self.GetPath(header.NodeId), name), input.Mode) fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return nil, ENOENT
}
err := fs.Mkdir(path.Join(fullPath, name), input.Mode)
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -380,7 +506,11 @@ func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, nam ...@@ -380,7 +506,11 @@ func (self *PathFileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, nam
} }
func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code Status) { func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code Status) {
code = self.fileSystem.Unlink(path.Join(self.GetPath(header.NodeId), name)) fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return ENOENT
}
code = fs.Unlink(path.Join(fullPath, name))
// Like fuse.c, we update our internal tables. // Like fuse.c, we update our internal tables.
self.unlinkUpdate(header.NodeId, name) self.unlinkUpdate(header.NodeId, name)
...@@ -389,13 +519,21 @@ func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code ...@@ -389,13 +519,21 @@ func (self *PathFileSystemConnector) Unlink(header *InHeader, name string) (code
} }
func (self *PathFileSystemConnector) Rmdir(header *InHeader, name string) (code Status) { func (self *PathFileSystemConnector) Rmdir(header *InHeader, name string) (code Status) {
code = self.fileSystem.Rmdir(path.Join(self.GetPath(header.NodeId), name)) fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return ENOENT
}
code = fs.Rmdir(path.Join(fullPath, name))
self.unlinkUpdate(header.NodeId, name) self.unlinkUpdate(header.NodeId, name)
return code return code
} }
func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
err := self.fileSystem.Symlink(pointedTo, path.Join(self.GetPath(header.NodeId), linkName)) fullPath, fs := self.GetPath(header.NodeId)
if fs == nil {
return nil, ENOENT
}
err := fs.Symlink(pointedTo, path.Join(fullPath, linkName))
if err != OK { if err != OK {
return nil, err return nil, err
} }
...@@ -405,10 +543,18 @@ func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string, ...@@ -405,10 +543,18 @@ func (self *PathFileSystemConnector) Symlink(header *InHeader, pointedTo string,
} }
func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) { func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) {
oldPath := path.Join(self.GetPath(header.NodeId), oldName) oldPath, oldFs := self.GetPath(header.NodeId)
newPath := path.Join(self.GetPath(input.Newdir), newName) newPath, fs := self.GetPath(input.Newdir)
if fs == nil || oldFs == nil {
return ENOENT
}
if fs != oldFs {
return EXDEV
}
code = self.fileSystem.Rename(oldPath, newPath) oldPath = path.Join(oldPath, oldName)
newPath = path.Join(newPath, newName)
code = fs.Rename(oldPath, newPath)
if code != OK { if code != OK {
return return
} }
...@@ -425,9 +571,18 @@ func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, o ...@@ -425,9 +571,18 @@ func (self *PathFileSystemConnector) Rename(header *InHeader, input *RenameIn, o
} }
func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) { func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) {
orig := self.GetPath(input.Oldnodeid) orig, fs := self.GetPath(input.Oldnodeid)
newName := path.Join(self.GetPath(header.NodeId), filename) newName, newFs := self.GetPath(header.NodeId)
err := self.fileSystem.Link(orig, newName)
if fs == nil || newFs == nil {
return nil, ENOENT
}
if newFs != fs {
return nil, EXDEV
}
newName = path.Join(newName, filename)
err := fs.Link(orig, newName)
if err != OK { if err != OK {
return nil, err return nil, err
...@@ -437,14 +592,21 @@ func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filen ...@@ -437,14 +592,21 @@ func (self *PathFileSystemConnector) Link(header *InHeader, input *LinkIn, filen
} }
func (self *PathFileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) { func (self *PathFileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) {
return self.fileSystem.Access(self.GetPath(header.NodeId), input.Mask) p, fs := self.GetPath(header.NodeId)
if fs == nil {
return ENOENT
}
return fs.Access(p, input.Mask)
} }
func (self *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) { func (self *PathFileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, fuseFile RawFuseFile, out *EntryOut, code Status) {
directory := self.GetPath(header.NodeId) directory, fs := self.GetPath(header.NodeId)
if fs == nil {
return 0, nil, nil, ENOENT
}
fullPath := path.Join(directory, name) fullPath := path.Join(directory, name)
f, err := self.fileSystem.Create(fullPath, uint32(input.Flags), input.Mode) f, err := fs.Create(fullPath, uint32(input.Flags), input.Mode)
if err != OK { if err != OK {
return 0, nil, nil, err return 0, nil, nil, err
} }
......
...@@ -92,6 +92,9 @@ const ( ...@@ -92,6 +92,9 @@ const (
ENOTDIR = Status(syscall.ENOTDIR) ENOTDIR = Status(syscall.ENOTDIR)
EACCES = Status(syscall.EACCES) EACCES = Status(syscall.EACCES)
EPERM = Status(syscall.EPERM) EPERM = Status(syscall.EPERM)
EBUSY = Status(syscall.EBUSY)
EINVAL = Status(syscall.EINVAL)
EXDEV = Status(syscall.EXDEV)
) )
type Opcode int type Opcode int
...@@ -568,14 +571,12 @@ type PathFilesystem interface { ...@@ -568,14 +571,12 @@ type PathFilesystem interface {
OpenDir(name string) (dir RawFuseDir, code Status) OpenDir(name string) (dir RawFuseDir, code Status)
// TODO - what is a good interface? // TODO - what is a good interface?
Init() (*InitOut, Status) Mount(connector *PathFileSystemConnector) Status
Destroy() Unmount()
Access(name string, mode uint32) (code Status) Access(name string, mode uint32) (code Status)
Create(name string, flags uint32, mode uint32) (file RawFuseFile, code Status) Create(name string, flags uint32, mode uint32) (file RawFuseFile, code Status)
Utimens(name string, AtimeNs uint64, CtimeNs uint64) (code Status) Utimens(name string, AtimeNs uint64, CtimeNs uint64) (code Status)
// unimplemented: poll, ioctl, bmap. // unimplemented: poll, ioctl, bmap.
SetOptions(*PathFileSystemConnectorOptions)
} }
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