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

Move all inode -> path conversions into fsInode.

This further prepares fsInode as an intermediate layer between raw and
path filesystems.
parent 06c1effd
......@@ -171,7 +171,7 @@ type RawFileSystem interface {
Release(header *InHeader, input *ReleaseIn)
Write(*WriteIn, []byte) (written uint32, code Status)
Flush(*FlushIn) Status
Flush(header *InHeader, input *FlushIn) Status
Fsync(*FsyncIn) (code Status)
// Directory handling
......
......@@ -105,7 +105,7 @@ func (me *DefaultRawFileSystem) Write(input *WriteIn, data []byte) (written uint
return 0, ENOSYS
}
func (me *DefaultRawFileSystem) Flush(input *FlushIn) Status {
func (me *DefaultRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
return OK
}
......
......@@ -120,18 +120,32 @@ func NewFile() *MutableDataFile {
return &MutableDataFile{}
}
func TestFSetAttr(t *testing.T) {
fs := &FSetAttrFs{}
dir := MakeTempDir()
defer os.RemoveAll(dir)
func setupFAttrTest(fs FileSystem) (dir string, clean func()) {
dir = MakeTempDir()
state, _, err := MountFileSystem(dir, fs, nil)
CheckSuccess(err)
state.Debug = true
defer state.Unmount()
go state.Loop(false)
// Trigger INIT.
os.Lstat(dir)
if state.KernelSettings().Flags&CAP_FILE_OPS == 0 {
log.Println("Mount does not support file operations")
}
return dir, func() {
if state.Unmount() == nil {
os.RemoveAll(dir)
}
}
}
func TestFSetAttr(t *testing.T) {
fs := &FSetAttrFs{}
dir, clean := setupFAttrTest(fs)
defer clean()
fn := dir + "/file"
f, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY, 0755)
CheckSuccess(err)
......@@ -149,17 +163,6 @@ func TestFSetAttr(t *testing.T) {
t.Error("truncate")
}
if state.KernelSettings().Flags&CAP_FILE_OPS == 0 {
log.Println("Mount does not support file operations")
}
_, err = f.Stat()
CheckSuccess(err)
if !fs.file.GetAttrCalled {
t.Error("Should have called File.GetAttr")
}
err = f.Chmod(024)
CheckSuccess(err)
if fs.file.FileInfo.Mode&07777 != 024 {
......@@ -169,7 +172,8 @@ func TestFSetAttr(t *testing.T) {
err = os.Chtimes(fn, 100e3, 101e3)
CheckSuccess(err)
if fs.file.FileInfo.Atime_ns != 100e3 || fs.file.FileInfo.Mtime_ns != 101e3 {
t.Error("Utimens", fs.file.FileInfo)
t.Errorf("Utimens: atime %d != 100e3 mtime %d != 101e3",
fs.file.FileInfo.Atime_ns, fs.file.FileInfo.Mtime_ns)
}
// TODO - test chown if run as root.
......
package fuse
import (
"log"
"os"
"path/filepath"
)
var _ = log.Println
......@@ -21,13 +23,13 @@ type fsInode struct {
// inode. It returns nil for mount if the file was deleted or the
// filesystem unmounted. This will take the treeLock for the mount,
// so it can not be used in internal methods.
func (me *fsInode) GetPath() (path string, mount *fileSystemMount) {
func (me *fsInode) GetPath() (path string) {
me.inode.treeLock.RLock()
defer me.inode.treeLock.RUnlock()
if me.inode.mount == nil {
// Node from unmounted file system.
return ".deleted", nil
return ".deleted"
}
rev_components := make([]string, 0, 10)
......@@ -36,9 +38,9 @@ func (me *fsInode) GetPath() (path string, mount *fileSystemMount) {
rev_components = append(rev_components, n.Name)
}
if n.mountPoint == nil {
return ".deleted", nil
return ".deleted"
}
return ReverseJoin(rev_components, "/"), n.mountPoint
return ReverseJoin(rev_components, "/")
}
func (me *fsInode) addChild(name string, ch *fsInode) {
......@@ -52,3 +54,171 @@ func (me *fsInode) rmChild(name string, ch *fsInode) {
ch.Name = ".deleted"
ch.Parent = nil
}
////////////////////////////////////////////////////////////////
func (me *fsInode) Readlink(c *Context) ([]byte, Status) {
path := me.GetPath()
val, err := me.inode.mount.fs.Readlink(path, c)
return []byte(val), err
}
func (me *fsInode) Access(mode uint32, context *Context) (code Status) {
p := me.GetPath()
return me.inode.mount.fs.Access(p, mode, context)
}
func (me *fsInode) GetXAttr(attribute string, context *Context) (data []byte, code Status) {
return me.inode.mount.fs.GetXAttr(me.GetPath(), attribute, context)
}
func (me *fsInode) RemoveXAttr(attr string, context *Context) Status {
p := me.GetPath()
return me.inode.mount.fs.RemoveXAttr(p, attr, context)
}
func (me *fsInode) SetXAttr(attr string, data []byte, flags int, context *Context) Status {
return me.inode.mount.fs.SetXAttr(me.GetPath(), attr, data, flags, context)
}
func (me *fsInode) ListXAttr(context *Context) (attrs []string, code Status) {
return me.inode.mount.fs.ListXAttr(me.GetPath(), context)
}
func (me *fsInode) Flush(file File, openFlags uint32, context *Context) (code Status) {
code = file.Flush()
if code.Ok() && openFlags&O_ANYWRITE != 0 {
// We only signal releases to the FS if the
// open could have changed things.
path := me.GetPath()
code = me.inode.mount.fs.Flush(path)
}
return code
}
func (me *fsInode) OpenDir(context *Context) (chan DirEntry, Status) {
return me.inode.mount.fs.OpenDir(me.GetPath(), context)
}
func (me *fsInode) Mknod(name string, mode uint32, dev uint32, context *Context) Status {
p := me.GetPath()
return me.inode.mount.fs.Mknod(filepath.Join(p, name), mode, dev, context)
}
func (me *fsInode) Mkdir(name string, mode uint32, context *Context) (code Status) {
return me.inode.mount.fs.Mkdir(filepath.Join(me.GetPath(), name), mode, context)
}
func (me *fsInode) Unlink(name string, context *Context) (code Status) {
return me.inode.mount.fs.Unlink(filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Rmdir(name string, context *Context) (code Status) {
return me.inode.mount.fs.Rmdir(filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Symlink(name string, content string, context *Context) (code Status) {
return me.inode.mount.fs.Symlink(content, filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Rename(oldName string, newParent *fsInode, newName string, context *Context) (code Status) {
oldPath := filepath.Join(me.GetPath(), oldName)
newPath := filepath.Join(newParent.GetPath(), newName)
return me.inode.mount.fs.Rename(oldPath, newPath, context)
}
func (me *fsInode) Link(name string, existing *fsInode, context *Context) (code Status) {
return me.inode.mount.fs.Link(existing.GetPath(), filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Create(name string, flags uint32, mode uint32, context *Context) (file File, code Status) {
fullPath := filepath.Join(me.GetPath(), name)
return me.inode.mount.fs.Create(fullPath, flags, mode, context)
}
func (me *fsInode) Open(flags uint32, context *Context) (file File, code Status) {
return me.inode.mount.fs.Open(me.GetPath(), flags, context)
}
// TODO: should return fsInode.
func (me *fsInode) Lookup(name string) (fi *os.FileInfo, code Status) {
fullPath := filepath.Join(me.GetPath(), name)
return me.inode.mount.fs.GetAttr(fullPath, nil)
}
func (me *fsInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code Status) {
if file == nil && me.Parent == nil && me.inode.mountPoint == nil {
// called on a deleted files.
file = me.inode.getAnyFile()
}
if file != nil {
fi, code = file.GetAttr()
}
if file == nil || code == ENOSYS {
fi, code = me.inode.mount.fs.GetAttr(me.GetPath(), context)
}
if fi != nil && !fi.IsDirectory() {
fi.Nlink = 1
}
return fi, code
}
func (me *fsInode) Chmod(file File, perms uint32, context *Context) (code Status) {
if file == nil {
file = me.inode.getWritableFile()
}
if file != nil {
// TODO - pass context
code = file.Chmod(perms)
}
if file == nil || code == ENOSYS {
code = me.inode.mount.fs.Chmod(me.GetPath(), perms, context)
}
return code
}
func (me *fsInode) Chown(file File, uid uint32, gid uint32, context *Context) (code Status) {
if file != nil {
// TODO - pass context
code = file.Chown(uid, gid)
}
if file == nil || code == ENOSYS {
// TODO - can we get just FATTR_GID but not FATTR_UID ?
code = me.inode.mount.fs.Chown(me.GetPath(), uid, gid, context)
}
return code
}
func (me *fsInode) Truncate(file File, size uint64, context *Context) (code Status) {
if file == nil {
file = me.inode.getWritableFile()
}
if file != nil {
code = file.Truncate(size)
}
if file == nil || code == ENOSYS {
code = me.inode.mount.fs.Truncate(me.GetPath(), size, context)
}
return code
}
func (me *fsInode) Utimens(file File, atime uint64, mtime uint64, context *Context) (code Status) {
if file == nil {
file = me.inode.getWritableFile()
}
if file != nil {
code = file.Utimens(atime, mtime)
}
if file == nil || code == ENOSYS {
code = me.inode.mount.fs.Utimens(me.GetPath(), atime, mtime, context)
}
return code
}
......@@ -279,9 +279,9 @@ func (me *LockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint
return me.RawFileSystem.Write(input, data)
}
func (me *LockingRawFileSystem) Flush(input *FlushIn) Status {
func (me *LockingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
defer me.locked()()
return me.RawFileSystem.Flush(input)
return me.RawFileSystem.Flush(header, input)
}
func (me *LockingRawFileSystem) Fsync(input *FsyncIn) (code Status) {
......
......@@ -315,6 +315,7 @@ func TestRename(t *testing.T) {
}
}
// Flaky test, due to rename race condition.
func TestDelRename(t *testing.T) {
me := NewTestCase(t)
defer me.Cleanup()
......@@ -342,7 +343,6 @@ func TestDelRename(t *testing.T) {
err = os.Rename(s, d)
CheckSuccess(err)
}
func TestOverwriteRename(t *testing.T) {
......
......@@ -237,7 +237,7 @@ func doRead(state *MountState, req *request) {
}
func doFlush(state *MountState, req *request) {
req.status = state.fileSystem.Flush((*FlushIn)(req.inData))
req.status = state.fileSystem.Flush(req.inHeader, (*FlushIn)(req.inData))
}
func doRelease(state *MountState, req *request) {
......
......@@ -21,6 +21,7 @@ package fuse
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"sync"
......@@ -60,6 +61,24 @@ type fileSystemMount struct {
openFiles HandleMap
}
func (me *fileSystemMount) fileInfoToEntry(fi *os.FileInfo, out *EntryOut) {
SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
if !fi.IsDirectory() {
fi.Nlink = 1
}
CopyFileInfo(fi, &out.Attr)
me.setOwner(&out.Attr)
}
func (me *fileSystemMount) fileInfoToAttr(fi *os.FileInfo, out *AttrOut) {
CopyFileInfo(fi, &out.Attr)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
me.setOwner(&out.Attr)
}
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(DecodeHandle(h)))
return b
......@@ -230,6 +249,29 @@ func (me *inode) getMountDirEntries() (out []DirEntry) {
return out
}
func (me *inode) getAnyFile() (file File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
return f.file
}
return nil
}
// Returns an open writable file for the given inode.
func (me *inode) getWritableFile() (file File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
if f.OpenFlags & O_ANYWRITE != 0 {
return f.file
}
}
return nil
}
const initDirSize = 20
func (me *inode) verify(cur *fileSystemMount) {
......
......@@ -6,11 +6,10 @@ import (
"bytes"
"fmt"
"log"
"path/filepath"
"time"
)
var _ = fmt.Println
var _ = log.Println
func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
me = new(FileSystemConnector)
......@@ -25,41 +24,11 @@ func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSys
return me
}
// Returns an openedFile for the given inode.
func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (opened *openedFile, m *fileSystemMount, p string, node *inode) {
node = me.getInodeData(nodeid)
if fh != 0 {
opened = me.getOpenedFile(fh)
}
path, mount := node.fsInode.GetPath()
if me.Debug {
log.Printf("Node %v = '%s'", nodeid, path)
}
// If the file was deleted, GetPath() will return nil.
if mount != nil {
m = mount
p = path
}
if opened == nil {
node.OpenFilesMutex.Lock()
defer node.OpenFilesMutex.Unlock()
for _, f := range node.OpenFiles {
if f.OpenFlags & O_ANYWRITE != 0 || opened == nil {
opened = f
}
}
}
return
}
func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *fileSystemMount, node *inode) {
n := me.getInodeData(nodeid)
p, m := n.fsInode.GetPath()
return p, m, n
p := n.fsInode.GetPath()
return p, n.mount, n
}
func (me *fileSystemMount) setOwner(attr *Attr) {
......@@ -78,51 +47,45 @@ func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookup
return out, status
}
func (me *FileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int, context *Context) (out *EntryOut, status Status, node *inode) {
mount := me.lookupMount(parent, name, lookupCount)
isMountPoint := (mount != nil)
fullPath := ""
if isMountPoint {
node = mount.mountInode
} else {
fullPath, mount = parent.fsInode.GetPath()
fullPath = filepath.Join(fullPath, name)
func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, lookupCount int) (out *EntryOut, status Status, node *inode) {
fi, err := mount.fs.GetAttr("", nil)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
}
if mount == nil {
timeout := me.rootNode.mountPoint.options.NegativeTimeout
if timeout > 0 {
return NegativeEntry(timeout), OK, nil
} else {
return nil, ENOENT, nil
if !err.Ok() {
return nil, err, mount.mountInode
}
mount.treeLock.Lock()
defer mount.treeLock.Unlock()
mount.mountInode.LookupCount += lookupCount
out = &EntryOut{
NodeId: mount.mountInode.NodeId,
Generation: 1, // where to get the generation?
}
mount.fileInfoToEntry(fi, out)
return out, OK, mount.mountInode
}
func (me *FileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int, context *Context) (out *EntryOut, status Status, node *inode) {
if mount := me.lookupMount(parent, name, lookupCount); mount != nil {
return me.internalMountLookup(mount, lookupCount)
}
fi, err := mount.fs.GetAttr(fullPath, context)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
fi, code := parent.fsInode.Lookup(name)
mount := parent.mount
if code == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
}
if err != OK {
return nil, err, nil
if !code.Ok() {
return nil, code, nil
}
if !isMountPoint {
node = me.lookupUpdate(parent, name, fi.IsDirectory(), lookupCount)
}
out = &EntryOut{
NodeId: node.NodeId,
Generation: 1, // where to get the generation?
}
SplitNs(mount.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(mount.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
if !fi.IsDirectory() {
fi.Nlink = 1
}
CopyFileInfo(fi, &out.Attr)
parent.mount.fileInfoToEntry(fi, out)
out.Attr.Ino = node.NodeId
mount.setOwner(&out.Attr)
return out, OK, node
}
......@@ -131,59 +94,28 @@ func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
}
func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
fh := uint64(0)
if input.Flags&FUSE_GETATTR_FH != 0 {
fh = input.Fh
}
opened, mount, fullPath, node := me.getOpenFileData(header.NodeId, fh)
if mount == nil && opened == nil {
return nil, ENOENT
}
if opened != nil {
fi, err := opened.file.GetAttr()
if err != OK && err != ENOSYS {
return nil, err
}
if fi != nil {
out = &AttrOut{}
CopyFileInfo(fi, &out.Attr)
out.Attr.Ino = header.NodeId
SplitNs(node.mount.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
node := me.getInodeData(header.NodeId)
return out, OK
}
var f File
if input.Flags&FUSE_GETATTR_FH != 0 {
if opened := me.getOpenedFile(input.Fh); opened != nil {
f = opened.file
}
if mount == nil {
return nil, ENOENT
}
fi, err := mount.fs.GetAttr(fullPath, &header.Context)
if err != OK {
return nil, err
fi, code := node.fsInode.GetAttr(f, &header.Context)
if !code.Ok() {
return nil, code
}
out = &AttrOut{}
CopyFileInfo(fi, &out.Attr)
out.Attr.Ino = header.NodeId
if !fi.IsDirectory() {
out.Nlink = 1
}
mount.setOwner(&out.Attr)
SplitNs(mount.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
node.mount.fileInfoToAttr(fi, out)
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
}
stream, err := mount.fs.OpenDir(fullPath, &header.Context)
func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, code Status) {
node := me.getInodeData(header.NodeId)
stream, err := node.fsInode.OpenDir(&header.Context)
if err != OK {
return 0, 0, err
}
......@@ -193,7 +125,7 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u
stream: stream,
}
de.extra = append(de.extra, DirEntry{S_IFDIR, "."}, DirEntry{S_IFDIR, ".."})
h, opened := mount.registerFileHandle(node, de, nil, input.Flags)
h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
// TODO - implement seekable directories
opened.FuseFlags |= FOPEN_NONSEEKABLE
......@@ -210,76 +142,34 @@ func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEnt
}
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
}
f, err := mount.fs.Open(fullPath, input.Flags, &header.Context)
if err != OK {
return 0, 0, err
node := me.getInodeData(header.NodeId)
f, code := node.fsInode.Open(input.Flags, &header.Context)
if !code.Ok() {
return 0, 0, code
}
h, opened := mount.registerFileHandle(node, nil, f, input.Flags)
h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
return opened.FuseFlags, h, OK
}
func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
var err Status = OK
var getAttrIn GetAttrIn
fh := uint64(0)
var f File
if input.Valid&FATTR_FH != 0 {
fh = input.Fh
getAttrIn.Fh = fh
getAttrIn.Flags |= FUSE_GETATTR_FH
}
opened, mount, fullPath, _ := me.getOpenFileData(header.NodeId, fh)
if mount == nil {
return nil, ENOENT
}
if opened != nil && opened.OpenFlags & O_ANYWRITE == 0 {
opened = nil
me.getOpenedFile(input.Fh)
}
fileResult := ENOSYS
if err.Ok() && input.Valid&FATTR_MODE != 0 {
node := me.getInodeData(header.NodeId)
if code.Ok() && input.Valid&FATTR_MODE != 0 {
permissions := uint32(07777) & input.Mode
if opened != nil {
fileResult = opened.file.Chmod(permissions)
}
if fileResult == ENOSYS {
err = mount.fs.Chmod(fullPath, permissions, &header.Context)
} else {
err = fileResult
fileResult = ENOSYS
}
}
if err.Ok() && (input.Valid&(FATTR_UID|FATTR_GID) != 0) {
if opened != nil {
fileResult = opened.file.Chown(uint32(input.Uid), uint32(input.Gid))
}
if fileResult == ENOSYS {
// TODO - can we get just FATTR_GID but not FATTR_UID ?
err = mount.fs.Chown(fullPath, uint32(input.Uid), uint32(input.Gid), &header.Context)
} else {
err = fileResult
fileResult = ENOSYS
code = node.fsInode.Chmod(f, permissions, &header.Context)
}
if code.Ok() && (input.Valid&(FATTR_UID|FATTR_GID) != 0) {
code = node.fsInode.Chown(f, uint32(input.Uid), uint32(input.Gid), &header.Context)
}
if err.Ok() && input.Valid&FATTR_SIZE != 0 {
if opened != nil {
fileResult = opened.file.Truncate(input.Size)
if code.Ok() && input.Valid&FATTR_SIZE != 0 {
code = node.fsInode.Truncate(f, input.Size, &header.Context)
}
if fileResult == ENOSYS {
err = mount.fs.Truncate(fullPath, input.Size, &header.Context)
} else {
err = fileResult
fileResult = ENOSYS
}
}
if err.Ok() && (input.Valid&(FATTR_ATIME|FATTR_MTIME|FATTR_ATIME_NOW|FATTR_MTIME_NOW) != 0) {
if code.Ok() && (input.Valid&(FATTR_ATIME|FATTR_MTIME|FATTR_ATIME_NOW|FATTR_MTIME_NOW) != 0) {
atime := uint64(input.Atime*1e9) + uint64(input.Atimensec)
if input.Valid&FATTR_ATIME_NOW != 0 {
atime = uint64(time.Nanoseconds())
......@@ -290,51 +180,41 @@ func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out
mtime = uint64(time.Nanoseconds())
}
if opened != nil {
fileResult = opened.file.Utimens(atime, mtime)
}
if fileResult == ENOSYS {
err = mount.fs.Utimens(fullPath, atime, mtime, &header.Context)
} else {
err = fileResult
fileResult = ENOSYS
// TODO - if using NOW, mtime and atime may differ.
code = node.fsInode.Utimens(f, atime, mtime, &header.Context)
}
}
if err != OK {
return nil, err
if !code.Ok() {
return nil, code
}
return me.GetAttr(header, &getAttrIn)
fi, code := node.fsInode.GetAttr(f, &header.Context)
out = &AttrOut{}
if fi != nil {
out.Attr.Ino = header.NodeId
node.mount.fileInfoToAttr(fi, out)
}
return out, code
}
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, &header.Context)
return []byte(val), err
n := me.getInodeData(header.NodeId)
return n.fsInode.Readlink(&header.Context)
}
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), &header.Context)
if err != OK {
return nil, err
n := me.getInodeData(header.NodeId)
code = n.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context)
if code.Ok() {
return me.internalLookup(n, name, 1, &header.Context)
}
return me.internalLookup(node, name, 1, &header.Context)
return nil, code
}
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, &header.Context)
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Mkdir(name, input.Mode, &header.Context)
if code.Ok() {
out, code = me.internalLookup(parent, name, 1, &header.Context)
}
......@@ -342,11 +222,8 @@ func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name stri
}
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), &header.Context)
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Unlink(name, &header.Context)
if code.Ok() {
// Like fuse.c, we update our internal tables.
me.unlinkUpdate(parent, name)
......@@ -355,48 +232,38 @@ func (me *FileSystemConnector) Unlink(header *InHeader, name string) (code Statu
}
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), &header.Context)
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Rmdir(name, &header.Context)
if code.Ok() {
// Like fuse.c, we update our internal tables.
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), &header.Context)
if err != OK {
return nil, err
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
if code.Ok() {
return me.internalLookup(parent, linkName, 1, &header.Context)
}
out, code = me.internalLookup(parent, linkName, 1, &header.Context)
return out, code
return nil, 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
}
oldParent := me.getInodeData(header.NodeId)
isMountPoint := me.lookupMount(oldParent, oldName, 0) != nil
if isMountPoint {
return EBUSY
}
if mount != oldMount {
newParent := me.getInodeData(input.Newdir)
if oldParent.mount != newParent.mount {
return EXDEV
}
oldPath = filepath.Join(oldPath, oldName)
newPath = filepath.Join(newPath, newName)
code = mount.fs.Rename(oldPath, newPath, &header.Context)
code = oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &header.Context)
if code.Ok() {
me.renameUpdate(oldParent, oldName, newParent, newName)
}
......@@ -404,51 +271,39 @@ func (me *FileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName
}
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)
existing := me.getInodeData(input.Oldnodeid)
parent := me.getInodeData(header.NodeId)
if mount == nil || newMount == nil {
return nil, ENOENT
}
if mount != newMount {
if existing.mount != parent.mount {
return nil, EXDEV
}
newName = filepath.Join(newName, filename)
err := mount.fs.Link(orig, newName, &header.Context)
if err != OK {
return nil, err
code = parent.fsInode.Link(filename, existing.fsInode, &header.Context)
if !code.Ok() {
return nil, code
}
return me.internalLookup(newParent, filename, 1, &header.Context)
// TODO - revise this for real hardlinks?
return me.internalLookup(parent, filename, 1, &header.Context)
}
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, &header.Context)
n := me.getInodeData(header.NodeId)
return n.fsInode.Access(input.Mask, &header.Context)
}
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, &header.Context)
if err != OK {
return 0, 0, nil, err
parent := me.getInodeData(header.NodeId)
f, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &header.Context)
if !code.Ok() {
return 0, 0, nil, code
}
out, code, inode := me.internalLookupWithNode(parent, name, 1, &header.Context)
if inode == nil {
msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v. code %v", fullPath, code)
msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v, %q. code %v", header.NodeId, name, code)
panic(msg)
}
handle, opened := mount.registerFileHandle(inode, nil, f, input.Flags)
handle, opened := parent.mount.registerFileHandle(inode, nil, f, input.Flags)
return opened.FuseFlags, handle, out, code
}
......@@ -457,22 +312,9 @@ func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
opened.inode.mount.unregisterFileHandle(input.Fh)
}
func (me *FileSystemConnector) Flush(input *FlushIn) Status {
func (me *FileSystemConnector) Flush(header *InHeader, input *FlushIn) Status {
opened := me.getOpenedFile(input.Fh)
code := opened.file.Flush()
if code.Ok() && opened.OpenFlags&O_ANYWRITE != 0 {
// We only signal releases to the FS if the
// open could have changed things.
var path string
var mount *fileSystemMount
path, mount = opened.inode.fsInode.GetPath()
if mount != nil {
code = mount.fs.Flush(path)
}
}
return code
return opened.inode.fsInode.Flush(opened.file, opened.OpenFlags, &header.Context)
}
func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
......@@ -488,40 +330,23 @@ func (me *FileSystemConnector) FsyncDir(header *InHeader, input *FsyncIn) (code
}
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, &header.Context)
return data, code
node := me.getInodeData(header.NodeId)
return node.fsInode.GetXAttr(attribute, &header.Context)
}
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, &header.Context)
node := me.getInodeData(header.NodeId)
return node.fsInode.RemoveXAttr(attr, &header.Context)
}
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), &header.Context)
node := me.getInodeData(header.NodeId)
return node.fsInode.SetXAttr(attr, data, int(input.Flags), &header.Context)
}
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, &header.Context)
node := me.getInodeData(header.NodeId)
attrs, code := node.fsInode.ListXAttr(&header.Context)
if code != OK {
return nil, code
}
......@@ -535,32 +360,21 @@ func (me *FileSystemConnector) ListXAttr(header *InHeader) (data []byte, code St
return b.Bytes(), code
}
func (me *FileSystemConnector) fileDebug(fh uint64, n *inode) {
p, _, _ := me.GetPath(n.NodeId)
log.Printf("Fh %d = %s", fh, p)
}
////////////////
// files.
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
opened := me.getOpenedFile(input.Fh)
if me.Debug {
me.fileDebug(input.Fh, opened.inode)
}
return opened.file.Write(input, data)
}
func (me *FileSystemConnector) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
opened := me.getOpenedFile(input.Fh)
if me.Debug {
me.fileDebug(input.Fh, opened.inode)
}
return opened.file.Read(input, bp)
}
func (me *FileSystemConnector) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, data []byte, code Status) {
opened := me.getOpenedFile(input.Fh)
if me.Debug {
me.fileDebug(input.Fh, opened.inode)
}
return opened.file.Ioctl(input)
}
......
......@@ -146,9 +146,9 @@ func (me *TimingRawFileSystem) Write(input *WriteIn, data []byte) (written uint3
return me.RawFileSystem.Write(input, data)
}
func (me *TimingRawFileSystem) Flush(input *FlushIn) Status {
func (me *TimingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
defer me.startTimer("Flush")()
return me.RawFileSystem.Flush(input)
return me.RawFileSystem.Flush(header, input)
}
func (me *TimingRawFileSystem) Fsync(input *FsyncIn) (code Status) {
......
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