Commit cfe6a430 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Split pathfilesystem.go.

parent 1abfc5d4
......@@ -20,7 +20,8 @@ GOFILES=misc.go\
xattr.go \
devnull.go \
pathdebug.go \
opcode.go
opcode.go \
pathops.go \
include $(GOROOT)/src/Make.pkg
package fuse
import (
"bytes"
"fmt"
"log"
"path/filepath"
"strings"
"sync"
......@@ -312,7 +310,6 @@ func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
}
func (me *FileSystemConnector) considerDropInode(n *inode) {
// TODO - this should probably not happen at all.
if n.LookupCount <= 0 && len(n.Children) == 0 && (n.mount == nil || n.mount.unmountPending) &&
n.OpenCount <= 0 {
n.setParent(nil)
......@@ -388,486 +385,3 @@ func EmptyFileSystemConnector() (out *FileSystemConnector) {
out.verify()
return out
}
func NewFileSystemConnector(fs FileSystem) (out *FileSystemConnector) {
out = EmptyFileSystemConnector()
if code := out.Mount("/", fs); code != OK {
panic("root mount failed.")
}
out.verify()
return out
}
func (me *FileSystemConnector) SetOptions(opts FileSystemConnectorOptions) {
me.options = opts
}
func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem) Status {
var node *inode
if mountPoint != "/" {
dirParent, base := filepath.Split(mountPoint)
dirParentNode := me.findInode(dirParent)
// Make sure we know the mount point.
_, _ = me.internalLookup(dirParentNode, base, 0)
}
node = me.findInode(mountPoint)
if !node.IsDir() {
return EINVAL
}
me.lock.Lock()
hasChildren := len(node.Children) > 0
// don't use defer, as we dont want to hold the lock during
// fs.Mount().
me.lock.Unlock()
if hasChildren {
return EBUSY
}
code := fs.Mount(me)
if code != OK {
if me.Debug {
log.Println("Mount error: ", mountPoint, code)
}
return code
}
if me.Debug {
log.Println("Mount: ", fs, "on", mountPoint, node)
}
node.mount = newMount(fs)
me.fileLock.Lock()
defer me.fileLock.Unlock()
node.OpenCount++
return OK
}
func (me *FileSystemConnector) Unmount(path string) Status {
node := me.findInode(path)
if node == nil {
panic(path)
}
mount := node.mount
if mount == nil {
panic(path)
}
// Need to lock to look at node.Children
me.lock.RLock()
defer me.lock.RUnlock()
me.fileLock.Lock()
defer me.fileLock.Unlock()
// 1 = our own mount.
if node.totalOpenCount() > 1 {
log.Println("Umount - busy: ", mount)
return EBUSY
}
if me.Debug {
log.Println("Unmount: ", mount)
}
if len(node.Children) > 0 {
mount.fs.Unmount()
mount.unmountPending = true
} else {
node.mount = nil
}
node.OpenCount--
return OK
}
func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *mountData, node *inode) {
n := me.getInodeData(nodeid)
p, m := n.GetPath()
return p, m, n
}
func (me *FileSystemConnector) Init(h *InHeader, input *InitIn) (*InitOut, Status) {
// TODO ?
return &InitOut{}, OK
}
func (me *FileSystemConnector) Destroy(h *InHeader, input *InitIn) {
// TODO - umount all.
}
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
parent := me.getInodeData(header.NodeId)
return me.internalLookup(parent, name, 1)
}
func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookupCount int) (out *EntryOut, status Status) {
out, status, _ = me.internalLookupWithNode(parent, name, lookupCount)
return out, status
}
func (me *FileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int) (out *EntryOut, status Status, node *inode) {
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath, mount := parent.GetPath()
if mount == nil {
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
fullPath = filepath.Join(fullPath, name)
attr, err := mount.fs.GetAttr(fullPath)
if err == ENOENT && me.options.NegativeTimeout > 0.0 {
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
if err != OK {
return nil, err, nil
}
data := me.lookupUpdate(parent, name, attr.Mode&S_IFDIR != 0)
data.LookupCount += lookupCount
out = &EntryOut{
NodeId: data.NodeId,
Generation: 1, // where to get the generation?
}
SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr
out.Attr.Ino = data.NodeId
return out, OK, data
}
func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
me.forgetUpdate(h.NodeId, int(input.Nlookup))
}
func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
// TODO - do something intelligent with input.Fh.
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
attr, err := mount.fs.GetAttr(fullPath)
if err != OK {
return nil, err
}
out = &AttrOut{
Attr: *attr,
}
out.Attr.Ino = header.NodeId
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
return out, OK
}
func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
stream, err := mount.fs.OpenDir(fullPath)
if err != OK {
return 0, 0, err
}
de := &Dir{
stream: stream,
}
h := me.registerFile(node, de)
return 0, h, OK
}
func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
d := me.getDir(input.Fh)
de, code := d.ReadDir(input)
if code != OK {
return nil, code
}
return de, OK
}
func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f, err := mount.fs.Open(fullPath, input.Flags)
if err != OK {
return 0, 0, err
}
h := me.registerFile(node, f)
return 0, h, OK
}
func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
var err Status = OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
if input.Valid&FATTR_MODE != 0 {
err = mount.fs.Chmod(fullPath, input.Mode)
}
if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) {
// TODO - can we get just FATTR_GID but not FATTR_UID ?
err = mount.fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid))
}
if input.Valid&FATTR_SIZE != 0 {
mount.fs.Truncate(fullPath, input.Size)
}
if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) {
err = mount.fs.Utimens(fullPath,
uint64(input.Atime*1e9)+uint64(input.Atimensec),
uint64(input.Mtime*1e9)+uint64(input.Mtimensec))
}
if err != OK && (input.Valid&FATTR_ATIME_NOW != 0 || input.Valid&FATTR_MTIME_NOW != 0) {
// TODO - should set time to now. Maybe just reuse
// Utimens() ? Go has no UTIME_NOW unfortunately.
}
if err != OK {
return nil, err
}
// TODO - where to get GetAttrIn.Flags / Fh ?
return me.GetAttr(header, &GetAttrIn{})
}
func (me *FileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) {
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
val, err := mount.fs.Readlink(fullPath)
return bytes.NewBufferString(val).Bytes(), err
}
func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
fullPath = filepath.Join(fullPath, name)
err := mount.fs.Mknod(fullPath, input.Mode, uint32(input.Rdev))
if err != OK {
return nil, err
}
return me.internalLookup(node, name, 1)
}
func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
code = mount.fs.Mkdir(filepath.Join(fullPath, name), input.Mode)
if code == OK {
out, code = me.internalLookup(parent, name, 1)
}
return out, code
}
func (me *FileSystemConnector) Unlink(header *InHeader, name string) (code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
code = mount.fs.Unlink(filepath.Join(fullPath, name))
if code == OK {
// Like fuse.c, we update our internal tables.
me.unlinkUpdate(parent, name)
}
return code
}
func (me *FileSystemConnector) Rmdir(header *InHeader, name string) (code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
code = mount.fs.Rmdir(filepath.Join(fullPath, name))
if code == OK {
me.unlinkUpdate(parent, name)
}
return code
}
func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
err := mount.fs.Symlink(pointedTo, filepath.Join(fullPath, linkName))
if err != OK {
return nil, err
}
out, code = me.internalLookup(parent, linkName, 1)
return out, code
}
func (me *FileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) {
oldPath, oldMount, oldParent := me.GetPath(header.NodeId)
newPath, mount, newParent := me.GetPath(input.Newdir)
if mount == nil || oldMount == nil {
return ENOENT
}
if mount != oldMount {
return EXDEV
}
oldPath = filepath.Join(oldPath, oldName)
newPath = filepath.Join(newPath, newName)
code = mount.fs.Rename(oldPath, newPath)
if code == OK {
// It is conceivable that the kernel module will issue a
// forget for the old entry, and a lookup request for the new
// one, but the fuse.c updates its client-side tables on its
// own, so we do this as well.
//
// It should not hurt for us to do it here as well, although
// it remains unclear how we should update Count.
me.renameUpdate(oldParent, oldName, newParent, newName)
}
return code
}
func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) {
orig, mount, _ := me.GetPath(input.Oldnodeid)
newName, newMount, newParent := me.GetPath(header.NodeId)
if mount == nil || newMount == nil {
return nil, ENOENT
}
if mount != newMount {
return nil, EXDEV
}
newName = filepath.Join(newName, filename)
err := mount.fs.Link(orig, newName)
if err != OK {
return nil, err
}
return me.internalLookup(newParent, filename, 1)
}
func (me *FileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) {
p, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.Access(p, input.Mask)
}
func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, h uint64, out *EntryOut, code Status) {
directory, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, nil, ENOENT
}
fullPath := filepath.Join(directory, name)
f, err := mount.fs.Create(fullPath, uint32(input.Flags), input.Mode)
if err != OK {
return 0, 0, nil, err
}
out, code, inode := me.internalLookupWithNode(parent, name, 1)
return 0, me.registerFile(inode, f), out, code
}
func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId)
f := me.unregisterFile(node, input.Fh).(File)
f.Release()
me.considerDropInode(node)
}
func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId)
d := me.unregisterFile(node, input.Fh).(RawDir)
d.Release()
me.considerDropInode(node)
}
func (me *FileSystemConnector) FsyncDir(header *InHeader, input *FsyncIn) (code Status) {
// What the heck is FsyncDir supposed to do?
return OK
}
func (me *FileSystemConnector) GetXAttr(header *InHeader, attribute string) (data []byte, code Status) {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
data, code = mount.fs.GetXAttr(path, attribute)
return data, code
}
func (me *FileSystemConnector) RemoveXAttr(header *InHeader, attr string) Status {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.RemoveXAttr(path, attr)
}
func (me *FileSystemConnector) SetXAttr(header *InHeader, input *SetXAttrIn, attr string, data []byte) Status {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.SetXAttr(path, attr, data, int(input.Flags))
}
func (me *FileSystemConnector) ListXAttr(header *InHeader) (data []byte, code Status) {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
attrs, code := mount.fs.ListXAttr(path)
if code != OK {
return nil, code
}
b := bytes.NewBuffer([]byte{})
for _, v := range attrs {
b.Write([]byte(v))
b.WriteByte(0)
}
return b.Bytes(), code
}
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
f := me.getFile(input.Fh).(File)
return f.Write(input, data)
}
func (me *FileSystemConnector) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
f := me.getFile(input.Fh)
return f.Read(input, bp)
}
// Translation of raw operation to path based operations.
package fuse
import (
"log"
"bytes"
"path/filepath"
)
func NewFileSystemConnector(fs FileSystem) (out *FileSystemConnector) {
out = EmptyFileSystemConnector()
if code := out.Mount("/", fs); code != OK {
panic("root mount failed.")
}
out.verify()
return out
}
func (me *FileSystemConnector) SetOptions(opts FileSystemConnectorOptions) {
me.options = opts
}
func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem) Status {
var node *inode
if mountPoint != "/" {
dirParent, base := filepath.Split(mountPoint)
dirParentNode := me.findInode(dirParent)
// Make sure we know the mount point.
_, _ = me.internalLookup(dirParentNode, base, 0)
}
node = me.findInode(mountPoint)
if !node.IsDir() {
return EINVAL
}
me.lock.Lock()
hasChildren := len(node.Children) > 0
// don't use defer, as we dont want to hold the lock during
// fs.Mount().
me.lock.Unlock()
if hasChildren {
return EBUSY
}
code := fs.Mount(me)
if code != OK {
if me.Debug {
log.Println("Mount error: ", mountPoint, code)
}
return code
}
if me.Debug {
log.Println("Mount: ", fs, "on", mountPoint, node)
}
node.mount = newMount(fs)
me.fileLock.Lock()
defer me.fileLock.Unlock()
node.OpenCount++
return OK
}
func (me *FileSystemConnector) Unmount(path string) Status {
node := me.findInode(path)
if node == nil {
panic(path)
}
mount := node.mount
if mount == nil {
panic(path)
}
// Need to lock to look at node.Children
me.lock.RLock()
defer me.lock.RUnlock()
me.fileLock.Lock()
// don't use defer: we don't want to call out to
// mount.fs.Unmount() with lock held.
ownMount := 1
isBusy := node.totalOpenCount() > ownMount
if !isBusy {
node.OpenCount--
}
me.fileLock.Unlock()
if isBusy {
log.Println("Umount - busy: ", mount)
return EBUSY
}
if me.Debug {
log.Println("Unmount: ", mount)
}
if len(node.Children) > 0 {
mount.fs.Unmount()
mount.unmountPending = true
} else {
node.mount = nil
}
return OK
}
func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *mountData, node *inode) {
n := me.getInodeData(nodeid)
p, m := n.GetPath()
return p, m, n
}
func (me *FileSystemConnector) Init(h *InHeader, input *InitIn) (*InitOut, Status) {
// TODO ?
return &InitOut{}, OK
}
func (me *FileSystemConnector) Destroy(h *InHeader, input *InitIn) {
// TODO - umount all.
}
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
parent := me.getInodeData(header.NodeId)
return me.internalLookup(parent, name, 1)
}
func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookupCount int) (out *EntryOut, status Status) {
out, status, _ = me.internalLookupWithNode(parent, name, lookupCount)
return out, status
}
func (me *FileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int) (out *EntryOut, status Status, node *inode) {
// TODO - fuse.c has special case code for name == "." and
// "..", those lookups happen if FUSE_EXPORT_SUPPORT is set in
// Init.
fullPath, mount := parent.GetPath()
if mount == nil {
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
fullPath = filepath.Join(fullPath, name)
attr, err := mount.fs.GetAttr(fullPath)
if err == ENOENT && me.options.NegativeTimeout > 0.0 {
return NegativeEntry(me.options.NegativeTimeout), OK, nil
}
if err != OK {
return nil, err, nil
}
data := me.lookupUpdate(parent, name, attr.Mode&S_IFDIR != 0)
data.LookupCount += lookupCount
out = &EntryOut{
NodeId: data.NodeId,
Generation: 1, // where to get the generation?
}
SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr
out.Attr.Ino = data.NodeId
return out, OK, data
}
func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
me.forgetUpdate(h.NodeId, int(input.Nlookup))
}
func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
// TODO - do something intelligent with input.Fh.
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
attr, err := mount.fs.GetAttr(fullPath)
if err != OK {
return nil, err
}
out = &AttrOut{
Attr: *attr,
}
out.Attr.Ino = header.NodeId
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
return out, OK
}
func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
stream, err := mount.fs.OpenDir(fullPath)
if err != OK {
return 0, 0, err
}
de := &Dir{
stream: stream,
}
h := me.registerFile(node, de)
return 0, h, OK
}
func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
d := me.getDir(input.Fh)
de, code := d.ReadDir(input)
if code != OK {
return nil, code
}
return de, OK
}
func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, ENOENT
}
// TODO - how to handle return flags, the FUSE open flags?
f, err := mount.fs.Open(fullPath, input.Flags)
if err != OK {
return 0, 0, err
}
h := me.registerFile(node, f)
return 0, h, OK
}
func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
var err Status = OK
// TODO - support Fh. (FSetAttr/FGetAttr/FTruncate.)
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
if input.Valid&FATTR_MODE != 0 {
err = mount.fs.Chmod(fullPath, input.Mode)
}
if err != OK && (input.Valid&FATTR_UID != 0 || input.Valid&FATTR_GID != 0) {
// TODO - can we get just FATTR_GID but not FATTR_UID ?
err = mount.fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid))
}
if input.Valid&FATTR_SIZE != 0 {
mount.fs.Truncate(fullPath, input.Size)
}
if err != OK && (input.Valid&FATTR_ATIME != 0 || input.Valid&FATTR_MTIME != 0) {
err = mount.fs.Utimens(fullPath,
uint64(input.Atime*1e9)+uint64(input.Atimensec),
uint64(input.Mtime*1e9)+uint64(input.Mtimensec))
}
if err != OK && (input.Valid&FATTR_ATIME_NOW != 0 || input.Valid&FATTR_MTIME_NOW != 0) {
// TODO - should set time to now. Maybe just reuse
// Utimens() ? Go has no UTIME_NOW unfortunately.
}
if err != OK {
return nil, err
}
// TODO - where to get GetAttrIn.Flags / Fh ?
return me.GetAttr(header, &GetAttrIn{})
}
func (me *FileSystemConnector) Readlink(header *InHeader) (out []byte, code Status) {
fullPath, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
val, err := mount.fs.Readlink(fullPath)
return bytes.NewBufferString(val).Bytes(), err
}
func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) {
fullPath, mount, node := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
fullPath = filepath.Join(fullPath, name)
err := mount.fs.Mknod(fullPath, input.Mode, uint32(input.Rdev))
if err != OK {
return nil, err
}
return me.internalLookup(node, name, 1)
}
func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
code = mount.fs.Mkdir(filepath.Join(fullPath, name), input.Mode)
if code == OK {
out, code = me.internalLookup(parent, name, 1)
}
return out, code
}
func (me *FileSystemConnector) Unlink(header *InHeader, name string) (code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
code = mount.fs.Unlink(filepath.Join(fullPath, name))
if code == OK {
// Like fuse.c, we update our internal tables.
me.unlinkUpdate(parent, name)
}
return code
}
func (me *FileSystemConnector) Rmdir(header *InHeader, name string) (code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
code = mount.fs.Rmdir(filepath.Join(fullPath, name))
if code == OK {
me.unlinkUpdate(parent, name)
}
return code
}
func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
fullPath, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
err := mount.fs.Symlink(pointedTo, filepath.Join(fullPath, linkName))
if err != OK {
return nil, err
}
out, code = me.internalLookup(parent, linkName, 1)
return out, code
}
func (me *FileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName string, newName string) (code Status) {
oldPath, oldMount, oldParent := me.GetPath(header.NodeId)
newPath, mount, newParent := me.GetPath(input.Newdir)
if mount == nil || oldMount == nil {
return ENOENT
}
if mount != oldMount {
return EXDEV
}
oldPath = filepath.Join(oldPath, oldName)
newPath = filepath.Join(newPath, newName)
code = mount.fs.Rename(oldPath, newPath)
if code == OK {
me.renameUpdate(oldParent, oldName, newParent, newName)
}
return code
}
func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) {
orig, mount, _ := me.GetPath(input.Oldnodeid)
newName, newMount, newParent := me.GetPath(header.NodeId)
if mount == nil || newMount == nil {
return nil, ENOENT
}
if mount != newMount {
return nil, EXDEV
}
newName = filepath.Join(newName, filename)
err := mount.fs.Link(orig, newName)
if err != OK {
return nil, err
}
return me.internalLookup(newParent, filename, 1)
}
func (me *FileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) {
p, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.Access(p, input.Mask)
}
func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, h uint64, out *EntryOut, code Status) {
directory, mount, parent := me.GetPath(header.NodeId)
if mount == nil {
return 0, 0, nil, ENOENT
}
fullPath := filepath.Join(directory, name)
f, err := mount.fs.Create(fullPath, uint32(input.Flags), input.Mode)
if err != OK {
return 0, 0, nil, err
}
out, code, inode := me.internalLookupWithNode(parent, name, 1)
return 0, me.registerFile(inode, f), out, code
}
func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId)
f := me.unregisterFile(node, input.Fh).(File)
f.Release()
me.considerDropInode(node)
}
func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId)
d := me.unregisterFile(node, input.Fh).(RawDir)
d.Release()
me.considerDropInode(node)
}
func (me *FileSystemConnector) FsyncDir(header *InHeader, input *FsyncIn) (code Status) {
// What the heck is FsyncDir supposed to do?
return OK
}
func (me *FileSystemConnector) GetXAttr(header *InHeader, attribute string) (data []byte, code Status) {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
data, code = mount.fs.GetXAttr(path, attribute)
return data, code
}
func (me *FileSystemConnector) RemoveXAttr(header *InHeader, attr string) Status {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.RemoveXAttr(path, attr)
}
func (me *FileSystemConnector) SetXAttr(header *InHeader, input *SetXAttrIn, attr string, data []byte) Status {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return ENOENT
}
return mount.fs.SetXAttr(path, attr, data, int(input.Flags))
}
func (me *FileSystemConnector) ListXAttr(header *InHeader) (data []byte, code Status) {
path, mount, _ := me.GetPath(header.NodeId)
if mount == nil {
return nil, ENOENT
}
attrs, code := mount.fs.ListXAttr(path)
if code != OK {
return nil, code
}
b := bytes.NewBuffer([]byte{})
for _, v := range attrs {
b.Write([]byte(v))
b.WriteByte(0)
}
return b.Bytes(), code
}
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
f := me.getFile(input.Fh).(File)
return f.Write(input, data)
}
func (me *FileSystemConnector) Read(input *ReadIn, bp *BufferPool) ([]byte, Status) {
f := me.getFile(input.Fh)
return f.Read(input, bp)
}
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