Commit 625c7706 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fs: use loopbackNode for the root node too

This leaves only one type to implement for the loopback file system,
which will simplify extending the loopback functionality.

Change-Id: I8906755f3bdf2ea63557d5bb25f50651521364c7
parent 0f51f708
...@@ -14,14 +14,33 @@ import ( ...@@ -14,14 +14,33 @@ import (
) )
type loopbackRoot struct { type loopbackRoot struct {
loopbackNode
rootPath string rootPath string
rootDev uint64 rootDev uint64
} }
func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) StableAttr {
// We compose an inode number by the underlying inode, and
// mixing in the device number. In traditional filesystems,
// the inode numbers are small. The device numbers are also
// small (typically 16 bit). Finally, we mask out the root
// device number of the root, so a loopback FS that does not
// encompass multiple mounts will reflect the inode numbers of
// the underlying filesystem
swapped := (uint64(st.Dev) << 32) | (uint64(st.Dev) >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return StableAttr{
Mode: uint32(st.Mode),
Gen: 1,
// This should work well for traditional backing FSes,
// not so much for other go-fuse FS-es
Ino: (swapped ^ swappedRootDev) ^ st.Ino,
}
}
type loopbackNode struct { type loopbackNode struct {
Inode Inode
rootData *loopbackRoot
} }
var _ = (NodeStatfser)((*loopbackNode)(nil)) var _ = (NodeStatfser)((*loopbackNode)(nil))
...@@ -55,23 +74,9 @@ func (n *loopbackNode) Statfs(ctx context.Context, out *fuse.StatfsOut) syscall. ...@@ -55,23 +74,9 @@ func (n *loopbackNode) Statfs(ctx context.Context, out *fuse.StatfsOut) syscall.
return OK return OK
} }
func (r *loopbackRoot) Getattr(ctx context.Context, f FileHandle, out *fuse.AttrOut) syscall.Errno {
st := syscall.Stat_t{}
err := syscall.Stat(r.rootPath, &st)
if err != nil {
return ToErrno(err)
}
out.FromStat(&st)
return OK
}
func (n *loopbackNode) root() *loopbackRoot {
return n.Root().Operations().(*loopbackRoot)
}
func (n *loopbackNode) path() string { func (n *loopbackNode) path() string {
path := n.Path(n.Root()) path := n.Path(n.Root())
return filepath.Join(n.root().rootPath, path) return filepath.Join(n.rootData.rootPath, path)
} }
func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) { func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) {
...@@ -84,8 +89,8 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO ...@@ -84,8 +89,8 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO
} }
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
return ch, 0 return ch, 0
} }
...@@ -117,8 +122,8 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32 ...@@ -117,8 +122,8 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
return ch, 0 return ch, 0
} }
...@@ -138,8 +143,8 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out ...@@ -138,8 +143,8 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
return ch, 0 return ch, 0
} }
...@@ -156,45 +161,18 @@ func (n *loopbackNode) Unlink(ctx context.Context, name string) syscall.Errno { ...@@ -156,45 +161,18 @@ func (n *loopbackNode) Unlink(ctx context.Context, name string) syscall.Errno {
return ToErrno(err) return ToErrno(err)
} }
func toLoopbackNode(op InodeEmbedder) *loopbackNode {
if r, ok := op.(*loopbackRoot); ok {
return &r.loopbackNode
}
return op.(*loopbackNode)
}
func (n *loopbackNode) Rename(ctx context.Context, name string, newParent InodeEmbedder, newName string, flags uint32) syscall.Errno { func (n *loopbackNode) Rename(ctx context.Context, name string, newParent InodeEmbedder, newName string, flags uint32) syscall.Errno {
newParentLoopback := toLoopbackNode(newParent)
if flags&RENAME_EXCHANGE != 0 { if flags&RENAME_EXCHANGE != 0 {
return n.renameExchange(name, newParentLoopback, newName) return n.renameExchange(name, newParent, newName)
} }
p1 := filepath.Join(n.path(), name) p1 := filepath.Join(n.path(), name)
p2 := filepath.Join(newParentLoopback.path(), newName) p2 := filepath.Join(n.rootData.rootPath, newParent.EmbeddedInode().Path(nil), newName)
err := syscall.Rename(p1, p2) err := syscall.Rename(p1, p2)
return ToErrno(err) return ToErrno(err)
} }
func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) StableAttr {
// We compose an inode number by the underlying inode, and
// mixing in the device number. In traditional filesystems,
// the inode numbers are small. The device numbers are also
// small (typically 16 bit). Finally, we mask out the root
// device number of the root, so a loopback FS that does not
// encompass multiple mounts will reflect the inode numbers of
// the underlying filesystem
swapped := (uint64(st.Dev) << 32) | (uint64(st.Dev) >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return StableAttr{
Mode: uint32(st.Mode),
Gen: 1,
// This should work well for traditional backing FSes,
// not so much for other go-fuse FS-es
Ino: (swapped ^ swappedRootDev) ^ st.Ino,
}
}
var _ = (NodeCreater)((*loopbackNode)(nil)) var _ = (NodeCreater)((*loopbackNode)(nil))
func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (inode *Inode, fh FileHandle, fuseFlags uint32, errno syscall.Errno) { func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (inode *Inode, fh FileHandle, fuseFlags uint32, errno syscall.Errno) {
...@@ -211,8 +189,8 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -211,8 +189,8 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
return nil, nil, 0, ToErrno(err) return nil, nil, 0, ToErrno(err)
} }
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
lf := NewLoopbackFile(fd) lf := NewLoopbackFile(fd)
out.FromStat(&st) out.FromStat(&st)
...@@ -231,8 +209,8 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu ...@@ -231,8 +209,8 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu
syscall.Unlink(p) syscall.Unlink(p)
return nil, ToErrno(err) return nil, ToErrno(err)
} }
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, 0 return ch, 0
...@@ -241,8 +219,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu ...@@ -241,8 +219,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu
func (n *loopbackNode) Link(ctx context.Context, target InodeEmbedder, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) { func (n *loopbackNode) Link(ctx context.Context, target InodeEmbedder, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) {
p := filepath.Join(n.path(), name) p := filepath.Join(n.path(), name)
targetNode := toLoopbackNode(target) err := syscall.Link(filepath.Join(n.rootData.rootPath, target.EmbeddedInode().Path(nil)), p)
err := syscall.Link(targetNode.path(), p)
if err != nil { if err != nil {
return nil, ToErrno(err) return nil, ToErrno(err)
} }
...@@ -251,8 +228,8 @@ func (n *loopbackNode) Link(ctx context.Context, target InodeEmbedder, name stri ...@@ -251,8 +228,8 @@ func (n *loopbackNode) Link(ctx context.Context, target InodeEmbedder, name stri
syscall.Unlink(p) syscall.Unlink(p)
return nil, ToErrno(err) return nil, ToErrno(err)
} }
node := &loopbackNode{} node := &loopbackNode{rootData: n.rootData}
ch := n.NewInode(ctx, node, n.root().idFromStat(&st)) ch := n.NewInode(ctx, node, n.rootData.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, 0 return ch, 0
...@@ -302,11 +279,17 @@ func (n *loopbackNode) Getattr(ctx context.Context, f FileHandle, out *fuse.Attr ...@@ -302,11 +279,17 @@ func (n *loopbackNode) Getattr(ctx context.Context, f FileHandle, out *fuse.Attr
if f != nil { if f != nil {
return f.(FileGetattrer).Getattr(ctx, out) return f.(FileGetattrer).Getattr(ctx, out)
} }
p := n.path() p := n.path()
var err error var err error
st := syscall.Stat_t{} st := syscall.Stat_t{}
if &n.Inode == n.Root() {
err = syscall.Stat(p, &st)
} else {
err = syscall.Lstat(p, &st) err = syscall.Lstat(p, &st)
}
if err != nil { if err != nil {
return ToErrno(err) return ToErrno(err)
} }
...@@ -390,16 +373,20 @@ func (n *loopbackNode) Setattr(ctx context.Context, f FileHandle, in *fuse.SetAt ...@@ -390,16 +373,20 @@ func (n *loopbackNode) Setattr(ctx context.Context, f FileHandle, in *fuse.SetAt
// NewLoopbackRoot returns a root node for a loopback file system whose // NewLoopbackRoot returns a root node for a loopback file system whose
// root is at the given root. This node implements all NodeXxxxer // root is at the given root. This node implements all NodeXxxxer
// operations available. // operations available.
func NewLoopbackRoot(root string) (InodeEmbedder, error) { func NewLoopbackRoot(rootPath string) (InodeEmbedder, error) {
var st syscall.Stat_t var st syscall.Stat_t
err := syscall.Stat(root, &st) err := syscall.Stat(rootPath, &st)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n := &loopbackRoot{ root := &loopbackRoot{
rootPath: root, rootPath: rootPath,
rootDev: uint64(st.Dev), rootDev: uint64(st.Dev),
} }
n := &loopbackNode{
rootData: root,
}
return n, nil return n, nil
} }
...@@ -32,7 +32,7 @@ func (n *loopbackNode) Listxattr(ctx context.Context, dest []byte) (uint32, sysc ...@@ -32,7 +32,7 @@ func (n *loopbackNode) Listxattr(ctx context.Context, dest []byte) (uint32, sysc
return 0, syscall.ENOSYS return 0, syscall.ENOSYS
} }
func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newName string) syscall.Errno { func (n *loopbackNode) renameExchange(name string, newparent InodeEmbedder, newName string) syscall.Errno {
return syscall.ENOSYS return syscall.ENOSYS
} }
......
...@@ -8,6 +8,7 @@ package fs ...@@ -8,6 +8,7 @@ package fs
import ( import (
"context" "context"
"path/filepath"
"syscall" "syscall"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
...@@ -33,13 +34,14 @@ func (n *loopbackNode) Listxattr(ctx context.Context, dest []byte) (uint32, sysc ...@@ -33,13 +34,14 @@ func (n *loopbackNode) Listxattr(ctx context.Context, dest []byte) (uint32, sysc
return uint32(sz), ToErrno(err) return uint32(sz), ToErrno(err)
} }
func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newName string) syscall.Errno { func (n *loopbackNode) renameExchange(name string, newparent InodeEmbedder, newName string) syscall.Errno {
fd1, err := syscall.Open(n.path(), syscall.O_DIRECTORY, 0) fd1, err := syscall.Open(n.path(), syscall.O_DIRECTORY, 0)
if err != nil { if err != nil {
return ToErrno(err) return ToErrno(err)
} }
defer syscall.Close(fd1) defer syscall.Close(fd1)
fd2, err := syscall.Open(newparent.path(), syscall.O_DIRECTORY, 0) p2 := filepath.Join(n.rootData.rootPath, newparent.EmbeddedInode().Path(nil))
fd2, err := syscall.Open(p2, syscall.O_DIRECTORY, 0)
defer syscall.Close(fd2) defer syscall.Close(fd2)
if err != nil { if err != nil {
return ToErrno(err) return ToErrno(err)
...@@ -52,15 +54,15 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN ...@@ -52,15 +54,15 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN
// Double check that nodes didn't change from under us. // Double check that nodes didn't change from under us.
inode := &n.Inode inode := &n.Inode
if inode.Root() != inode && inode.StableAttr().Ino != n.root().idFromStat(&st).Ino { if inode.Root() != inode && inode.StableAttr().Ino != n.rootData.idFromStat(&st).Ino {
return syscall.EBUSY return syscall.EBUSY
} }
if err := syscall.Fstat(fd2, &st); err != nil { if err := syscall.Fstat(fd2, &st); err != nil {
return ToErrno(err) return ToErrno(err)
} }
newinode := &newparent.Inode newinode := newparent.EmbeddedInode()
if newinode.Root() != newinode && newinode.StableAttr().Ino != n.root().idFromStat(&st).Ino { if newinode.Root() != newinode && newinode.StableAttr().Ino != n.rootData.idFromStat(&st).Ino {
return syscall.EBUSY return syscall.EBUSY
} }
......
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