Commit 570a84cd authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fuse/nodefs: mount root node.Node directly.

This obviates the nodefs.FileSystem type. To adjust for this API change,

  * call nodefs.MountRoot() on the Root() node of a to-be-mounted
    filesystem.

  * Move OnMount/OnUnmount methods to the type of the root node.

  * Stop embedding NewDefaultFileSystem() into file system
    objects. Usually FS objects no longer have to be exposed.
parent 8b78faac
...@@ -24,7 +24,7 @@ func setupFs(fs pathfs.FileSystem) (string, func()) { ...@@ -24,7 +24,7 @@ func setupFs(fs pathfs.FileSystem) (string, func()) {
} }
mountPoint, _ := ioutil.TempDir("", "stat_test") mountPoint, _ := ioutil.TempDir("", "stat_test")
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(mountPoint, nfs, opts) state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), opts)
if err != nil { if err != nil {
panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods. panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods.
} }
......
...@@ -55,7 +55,7 @@ func main() { ...@@ -55,7 +55,7 @@ func main() {
} }
gofs := unionfs.NewAutoUnionFs(flag.Arg(1), options) gofs := unionfs.NewAutoUnionFs(flag.Arg(1), options)
pathfs := pathfs.NewPathNodeFs(gofs, nil) pathfs := pathfs.NewPathNodeFs(gofs, nil)
state, conn, err := nodefs.MountFileSystem(flag.Arg(0), pathfs, &fsOpts) state, conn, err := nodefs.MountRoot(flag.Arg(0), pathfs.Root(), &fsOpts)
if err != nil { if err != nil {
fmt.Printf("Mount fail: %v\n", err) fmt.Printf("Mount fail: %v\n", err)
os.Exit(1) os.Exit(1)
......
...@@ -53,7 +53,7 @@ func main() { ...@@ -53,7 +53,7 @@ func main() {
log.Fatal("Usage:\n hello MOUNTPOINT") log.Fatal("Usage:\n hello MOUNTPOINT")
} }
nfs := pathfs.NewPathNodeFs(&HelloFs{FileSystem: pathfs.NewDefaultFileSystem()}, nil) nfs := pathfs.NewPathNodeFs(&HelloFs{FileSystem: pathfs.NewDefaultFileSystem()}, nil)
server, _, err := nodefs.MountFileSystem(flag.Arg(0), nfs, nil) server, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
if err != nil { if err != nil {
log.Fatal("Mount fail: %v\n", err) log.Fatal("Mount fail: %v\n", err)
} }
......
...@@ -38,7 +38,7 @@ func main() { ...@@ -38,7 +38,7 @@ func main() {
EntryTimeout: time.Second, EntryTimeout: time.Second,
} }
pathFs := pathfs.NewPathNodeFs(finalFs, nil) pathFs := pathfs.NewPathNodeFs(finalFs, nil)
conn := nodefs.NewFileSystemConnector(pathFs, opts) conn := nodefs.NewFileSystemConnector(pathFs.Root(), opts)
mountPoint := flag.Arg(0) mountPoint := flag.Arg(0)
mOpts := &fuse.MountOptions{ mOpts := &fuse.MountOptions{
AllowOther: *other, AllowOther: *other,
......
...@@ -23,8 +23,8 @@ func main() { ...@@ -23,8 +23,8 @@ func main() {
mountPoint := flag.Arg(0) mountPoint := flag.Arg(0)
prefix := flag.Arg(1) prefix := flag.Arg(1)
fs := nodefs.NewMemNodeFs(prefix) root := nodefs.NewMemNodeFSRoot(prefix)
conn := nodefs.NewFileSystemConnector(fs, nil) conn := nodefs.NewFileSystemConnector(root, nil)
server, err := fuse.NewServer(conn.RawFS(), mountPoint, nil) server, err := fuse.NewServer(conn.RawFS(), mountPoint, nil)
if err != nil { if err != nil {
fmt.Printf("Mount fail: %v\n", err) fmt.Printf("Mount fail: %v\n", err)
......
...@@ -23,7 +23,7 @@ func main() { ...@@ -23,7 +23,7 @@ func main() {
fs := zipfs.NewMultiZipFs() fs := zipfs.NewMultiZipFs()
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(flag.Arg(0), nfs, nil) state, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
if err != nil { if err != nil {
fmt.Printf("Mount fail: %v\n", err) fmt.Printf("Mount fail: %v\n", err)
os.Exit(1) os.Exit(1)
......
...@@ -48,7 +48,7 @@ func main() { ...@@ -48,7 +48,7 @@ func main() {
NegativeTimeout: time.Duration(*negative_ttl * float64(time.Second)), NegativeTimeout: time.Duration(*negative_ttl * float64(time.Second)),
PortableInodes: *portable, PortableInodes: *portable,
} }
mountState, _, err := nodefs.MountFileSystem(flag.Arg(0), nodeFs, &mOpts) mountState, _, err := nodefs.MountRoot(flag.Arg(0), nodeFs.Root(), &mOpts)
if err != nil { if err != nil {
log.Fatal("Mount fail:", err) log.Fatal("Mount fail:", err)
} }
......
...@@ -44,8 +44,7 @@ func main() { ...@@ -44,8 +44,7 @@ func main() {
} }
} }
var fs nodefs.FileSystem root, err := zipfs.NewArchiveFileSystem(flag.Arg(1))
fs, err = zipfs.NewArchiveFileSystem(flag.Arg(1))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "NewArchiveFileSystem failed: %v\n", err) fmt.Fprintf(os.Stderr, "NewArchiveFileSystem failed: %v\n", err)
os.Exit(1) os.Exit(1)
...@@ -55,7 +54,7 @@ func main() { ...@@ -55,7 +54,7 @@ func main() {
AttrTimeout: time.Duration(*ttl * float64(time.Second)), AttrTimeout: time.Duration(*ttl * float64(time.Second)),
EntryTimeout: time.Duration(*ttl * float64(time.Second)), EntryTimeout: time.Duration(*ttl * float64(time.Second)),
} }
state, _, err := nodefs.MountFileSystem(flag.Arg(0), fs, opts) state, _, err := nodefs.MountRoot(flag.Arg(0), root, opts)
if err != nil { if err != nil {
fmt.Printf("Mount fail: %v\n", err) fmt.Printf("Mount fail: %v\n", err)
os.Exit(1) os.Exit(1)
......
...@@ -11,24 +11,11 @@ import ( ...@@ -11,24 +11,11 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
// The FileSystem is the unit that can be mounted. It's essential // This is a legacy type.
// function is the Root() method, which provides access to the file
// system tree.
type FileSystem interface { type FileSystem interface {
// Root should return the inode for root of this file system. // Root should return the inode for root of this file system.
Root() Node Root() Node
// OnMount is called just after a mount is executed, either
// when the root is mounted, or when other filesystem are
// mounted in-process. The passed-in FileSystemConnector gives
// access to Notify methods and Debug settings.
OnMount(conn *FileSystemConnector)
// OnUnmount is executed just before a submount is removed,
// and when the process receives a forget for the FUSE root
// node.
OnUnmount()
// Used for debug outputs // Used for debug outputs
String() string String() string
...@@ -46,6 +33,18 @@ type Node interface { ...@@ -46,6 +33,18 @@ type Node interface {
Inode() *Inode Inode() *Inode
SetInode(node *Inode) SetInode(node *Inode)
// OnMount is called on the root node just after a mount is
// executed, either when the actual root is mounted, or when a
// filesystem is mounted in-process. The passed-in
// FileSystemConnector gives access to Notify methods and
// Debug settings.
OnMount(conn *FileSystemConnector)
// OnUnmount is executed just before a submount is removed,
// and when the process receives a forget for the FUSE root
// node.
OnUnmount()
// Lookup finds a child node to this node; it is only called // Lookup finds a child node to this node; it is only called
// for directory Nodes. // for directory Nodes.
Lookup(out *fuse.Attr, name string, context *fuse.Context) (node Node, code fuse.Status) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node Node, code fuse.Status)
......
...@@ -6,33 +6,6 @@ import ( ...@@ -6,33 +6,6 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
// NewDefaultNodeFileSystem returns a dummy implementation of
// NodeFileSystem, for embedding in structs.
func NewDefaultFileSystem() FileSystem {
return (*defaultFileSystem)(nil)
}
type defaultFileSystem struct {
}
func (fs *defaultFileSystem) OnUnmount() {
}
func (fs *defaultFileSystem) OnMount(conn *FileSystemConnector) {
}
func (fs *defaultFileSystem) Root() Node {
return NewDefaultNode()
}
func (fs *defaultFileSystem) String() string {
return "defaultFileSystem"
}
func (fs *defaultFileSystem) SetDebug(dbg bool) {
}
// NewDefaultNode returns an implementation of Node that returns // NewDefaultNode returns an implementation of Node that returns
// ENOSYS for all operations. // ENOSYS for all operations.
func NewDefaultNode() Node { func NewDefaultNode() Node {
...@@ -43,6 +16,12 @@ type defaultNode struct { ...@@ -43,6 +16,12 @@ type defaultNode struct {
inode *Inode inode *Inode
} }
func (fs *defaultNode) OnUnmount() {
}
func (fs *defaultNode) OnMount(conn *FileSystemConnector) {
}
func (n *defaultNode) StatFs() *fuse.StatfsOut { func (n *defaultNode) StatFs() *fuse.StatfsOut {
return nil return nil
} }
......
...@@ -31,8 +31,6 @@ type FileSystemConnector struct { ...@@ -31,8 +31,6 @@ type FileSystemConnector struct {
// Callbacks for talking back to the kernel. // Callbacks for talking back to the kernel.
server *fuse.Server server *fuse.Server
nodeFs FileSystem
// Translate between uint64 handles and *Inode. // Translate between uint64 handles and *Inode.
inodeMap handleMap inodeMap handleMap
...@@ -53,20 +51,19 @@ func NewOptions() *Options { ...@@ -53,20 +51,19 @@ func NewOptions() *Options {
// NewFileSystemConnector creates a FileSystemConnector with the given // NewFileSystemConnector creates a FileSystemConnector with the given
// options. // options.
func NewFileSystemConnector(nodeFs FileSystem, opts *Options) (c *FileSystemConnector) { func NewFileSystemConnector(root Node, opts *Options) (c *FileSystemConnector) {
c = new(FileSystemConnector) c = new(FileSystemConnector)
if opts == nil { if opts == nil {
opts = NewOptions() opts = NewOptions()
} }
c.nodeFs = nodeFs
c.inodeMap = newHandleMap(opts.PortableInodes) c.inodeMap = newHandleMap(opts.PortableInodes)
c.rootNode = newInode(true, nodeFs.Root()) c.rootNode = newInode(true, root)
// Make sure we don't reuse generation numbers. // Make sure we don't reuse generation numbers.
c.generation = uint64(time.Now().UnixNano()) c.generation = uint64(time.Now().UnixNano())
c.verify() c.verify()
c.mountRoot(nodeFs, opts) c.mountRoot(opts)
// FUSE does not issue a LOOKUP for 1 (obviously), but it does // FUSE does not issue a LOOKUP for 1 (obviously), but it does
// issue a forget. This lookupUpdate is to make the counts match. // issue a forget. This lookupUpdate is to make the counts match.
...@@ -130,7 +127,7 @@ func (c *FileSystemConnector) lookupUpdate(node *Inode) (id uint64) { ...@@ -130,7 +127,7 @@ func (c *FileSystemConnector) lookupUpdate(node *Inode) (id uint64) {
// Must run outside treeLock. // Must run outside treeLock.
func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) { func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) {
if nodeID == fuse.FUSE_ROOT_ID { if nodeID == fuse.FUSE_ROOT_ID {
c.nodeFs.OnUnmount() c.rootNode.Node().OnUnmount()
// We never got a lookup for root, so don't try to // We never got a lookup for root, so don't try to
// forget root. // forget root.
...@@ -250,10 +247,10 @@ func (c *FileSystemConnector) LookupNode(parent *Inode, path string) *Inode { ...@@ -250,10 +247,10 @@ func (c *FileSystemConnector) LookupNode(parent *Inode, path string) *Inode {
return parent return parent
} }
func (c *FileSystemConnector) mountRoot(nodeFs FileSystem, opts *Options) { func (c *FileSystemConnector) mountRoot(opts *Options) {
c.rootNode.mountFs(nodeFs, opts) c.rootNode.mountFs(opts)
c.rootNode.mount.connector = c c.rootNode.mount.connector = c
nodeFs.OnMount(c) c.rootNode.Node().OnMount(c)
c.verify() c.verify()
} }
...@@ -264,7 +261,7 @@ func (c *FileSystemConnector) mountRoot(nodeFs FileSystem, opts *Options) { ...@@ -264,7 +261,7 @@ func (c *FileSystemConnector) mountRoot(nodeFs FileSystem, opts *Options) {
// //
// It returns ENOENT if the directory containing the mount point does // It returns ENOENT if the directory containing the mount point does
// not exist, and EBUSY if the intended mount point already exists. // not exist, and EBUSY if the intended mount point already exists.
func (c *FileSystemConnector) Mount(parent *Inode, name string, nodeFs FileSystem, opts *Options) fuse.Status { func (c *FileSystemConnector) Mount(parent *Inode, name string, root Node, opts *Options) fuse.Status {
defer c.verify() defer c.verify()
parent.mount.treeLock.Lock() parent.mount.treeLock.Lock()
defer parent.mount.treeLock.Unlock() defer parent.mount.treeLock.Unlock()
...@@ -273,21 +270,21 @@ func (c *FileSystemConnector) Mount(parent *Inode, name string, nodeFs FileSyste ...@@ -273,21 +270,21 @@ func (c *FileSystemConnector) Mount(parent *Inode, name string, nodeFs FileSyste
return fuse.EBUSY return fuse.EBUSY
} }
node = newInode(true, nodeFs.Root()) node = newInode(true, root)
if opts == nil { if opts == nil {
opts = c.rootNode.mountPoint.options opts = c.rootNode.mountPoint.options
} }
node.mountFs(nodeFs, opts) node.mountFs(opts)
node.mount.connector = c node.mount.connector = c
parent.addChild(name, node) parent.addChild(name, node)
node.mountPoint.parentInode = parent node.mountPoint.parentInode = parent
if c.debug { if c.debug {
log.Println("Mount: ", nodeFs, "on subdir", name, log.Printf("Mount %T on subdir %s, parent %d", node,
"parent", c.inodeMap.Handle(&parent.handled)) name, c.inodeMap.Handle(&parent.handled))
} }
nodeFs.OnMount(c) node.Node().OnMount(c)
return fuse.OK return fuse.OK
} }
...@@ -328,7 +325,7 @@ func (c *FileSystemConnector) Unmount(node *Inode) fuse.Status { ...@@ -328,7 +325,7 @@ func (c *FileSystemConnector) Unmount(node *Inode) fuse.Status {
} }
delete(parentNode.children, name) delete(parentNode.children, name)
mount.fs.OnUnmount() node.Node().OnUnmount()
parentId := c.inodeMap.Handle(&parentNode.handled) parentId := c.inodeMap.Handle(&parentNode.handled)
if parentNode == c.rootNode { if parentNode == c.rootNode {
......
...@@ -18,9 +18,6 @@ type openedFile struct { ...@@ -18,9 +18,6 @@ type openedFile struct {
} }
type fileSystemMount struct { type fileSystemMount struct {
// The file system we mounted here.
fs FileSystem
// Node that we were mounted on. // Node that we were mounted on.
mountInode *Inode mountInode *Inode
......
...@@ -41,12 +41,8 @@ func (c *rawBridge) String() string { ...@@ -41,12 +41,8 @@ func (c *rawBridge) String() string {
return "go-fuse:unmounted" return "go-fuse:unmounted"
} }
fs := c.rootNode.mount.fs name := fmt.Sprintf("%T", c.rootNode.Node())
name := fs.String()
if name == "DefaultNodeFileSystem" {
name = fmt.Sprintf("%T", fs)
name = strings.TrimLeft(name, "*") name = strings.TrimLeft(name, "*")
}
return name return name
} }
...@@ -55,7 +51,7 @@ func (c *rawBridge) Init(s *fuse.Server) { ...@@ -55,7 +51,7 @@ func (c *rawBridge) Init(s *fuse.Server) {
} }
func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) { func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) {
code = mount.fs.Root().GetAttr(out, nil, nil) code = mount.mountInode.Node().GetAttr(out, nil, nil)
if !code.Ok() { if !code.Ok() {
log.Println("Root getattr should not return error", code) log.Println("Root getattr should not return error", code)
out.Mode = fuse.S_IFDIR | 0755 out.Mode = fuse.S_IFDIR | 0755
......
...@@ -4,11 +4,17 @@ import ( ...@@ -4,11 +4,17 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
func MountFileSystem(mountpoint string, nodeFs FileSystem, opts *Options) (*fuse.Server, *FileSystemConnector, error) { // Mounts a filesystem with the given root node on the given directory
conn := NewFileSystemConnector(nodeFs, opts) func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) {
conn := NewFileSystemConnector(root, opts)
s, err := fuse.NewServer(conn.RawFS(), mountpoint, nil) s, err := fuse.NewServer(conn.RawFS(), mountpoint, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s, conn, nil return s, conn, nil
} }
// Mounts a filesystem on the given directory
func MountFileSystem(mountpoint string, fs FileSystem, opts *Options) (*fuse.Server, *FileSystemConnector, error) {
return MountRoot(mountpoint, fs.Root(), opts)
}
...@@ -173,10 +173,9 @@ func (n *Inode) rmChild(name string) (ch *Inode) { ...@@ -173,10 +173,9 @@ func (n *Inode) rmChild(name string) (ch *Inode) {
return ch return ch
} }
// Can only be called on untouched inodes. // Can only be called on untouched root inodes.
func (n *Inode) mountFs(fs FileSystem, opts *Options) { func (n *Inode) mountFs(opts *Options) {
n.mountPoint = &fileSystemMount{ n.mountPoint = &fileSystemMount{
fs: fs,
openFiles: newHandleMap(false), openFiles: newHandleMap(false),
mountInode: n, mountInode: n,
options: opts, options: opts,
......
...@@ -10,14 +10,14 @@ import ( ...@@ -10,14 +10,14 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
// NewMemNodeFs creates an in-memory node-based filesystem. Files are // NewMemNodeFSRoot creates an in-memory node-based filesystem. Files
// written into a backing store under the given prefix. // are written into a backing store under the given prefix.
func NewMemNodeFs(prefix string) FileSystem { func NewMemNodeFSRoot(prefix string) Node {
fs := &memNodeFs{ fs := &memNodeFs{
backingStorePrefix: prefix, backingStorePrefix: prefix,
} }
fs.root = fs.newNode() fs.root = fs.newNode()
return fs return fs.root
} }
type memNodeFs struct { type memNodeFs struct {
......
...@@ -11,18 +11,18 @@ import ( ...@@ -11,18 +11,18 @@ import (
const testTtl = 100 * time.Millisecond const testTtl = 100 * time.Millisecond
func setupMemNodeTest(t *testing.T) (wd string, fs FileSystem, clean func()) { func setupMemNodeTest(t *testing.T) (wd string, root Node, clean func()) {
tmp, err := ioutil.TempDir("", "go-fuse-memnode_test") tmp, err := ioutil.TempDir("", "go-fuse-memnode_test")
if err != nil { if err != nil {
t.Fatalf("TempDir failed: %v", err) t.Fatalf("TempDir failed: %v", err)
} }
back := tmp + "/backing" back := tmp + "/backing"
os.Mkdir(back, 0700) os.Mkdir(back, 0700)
fs = NewMemNodeFs(back) root = NewMemNodeFSRoot(back)
mnt := tmp + "/mnt" mnt := tmp + "/mnt"
os.Mkdir(mnt, 0700) os.Mkdir(mnt, 0700)
connector := NewFileSystemConnector(fs, connector := NewFileSystemConnector(root,
&Options{ &Options{
EntryTimeout: testTtl, EntryTimeout: testTtl,
AttrTimeout: testTtl, AttrTimeout: testTtl,
...@@ -39,7 +39,7 @@ func setupMemNodeTest(t *testing.T) (wd string, fs FileSystem, clean func()) { ...@@ -39,7 +39,7 @@ func setupMemNodeTest(t *testing.T) (wd string, fs FileSystem, clean func()) {
// Unthreaded, but in background. // Unthreaded, but in background.
go state.Serve() go state.Serve()
return mnt, fs, func() { return mnt, root, func() {
state.Unmount() state.Unmount()
os.RemoveAll(tmp) os.RemoveAll(tmp)
} }
......
...@@ -35,7 +35,7 @@ func setupOwnerTest(t *testing.T, opts *nodefs.Options) (workdir string, cleanup ...@@ -35,7 +35,7 @@ func setupOwnerTest(t *testing.T, opts *nodefs.Options) (workdir string, cleanup
fs := &ownerFs{NewDefaultFileSystem()} fs := &ownerFs{NewDefaultFileSystem()}
nfs := NewPathNodeFs(fs, nil) nfs := NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(wd, nfs, opts) state, _, err := nodefs.MountRoot(wd, nfs.Root(), opts)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -47,7 +47,7 @@ func (fs *PathNodeFs) SetDebug(dbg bool) { ...@@ -47,7 +47,7 @@ func (fs *PathNodeFs) SetDebug(dbg bool) {
fs.debug = dbg fs.debug = dbg
} }
func (fs *PathNodeFs) Mount(path string, nodeFs nodefs.FileSystem, opts *nodefs.Options) fuse.Status { func (fs *PathNodeFs) Mount(path string, root nodefs.Node, opts *nodefs.Options) fuse.Status {
dir, name := filepath.Split(path) dir, name := filepath.Split(path)
if dir != "" { if dir != "" {
dir = filepath.Clean(dir) dir = filepath.Clean(dir)
...@@ -56,7 +56,7 @@ func (fs *PathNodeFs) Mount(path string, nodeFs nodefs.FileSystem, opts *nodefs. ...@@ -56,7 +56,7 @@ func (fs *PathNodeFs) Mount(path string, nodeFs nodefs.FileSystem, opts *nodefs.
if parent == nil { if parent == nil {
return fuse.ENOENT return fuse.ENOENT
} }
return fs.connector.Mount(parent, name, nodeFs, opts) return fs.connector.Mount(parent, name, root, opts)
} }
// Forgets all known information on client inodes. // Forgets all known information on client inodes.
...@@ -91,9 +91,6 @@ func (fs *PathNodeFs) Unmount(path string) fuse.Status { ...@@ -91,9 +91,6 @@ func (fs *PathNodeFs) Unmount(path string) fuse.Status {
return fs.connector.Unmount(node) return fs.connector.Unmount(node)
} }
func (fs *PathNodeFs) OnUnmount() {
}
func (fs *PathNodeFs) String() string { func (fs *PathNodeFs) String() string {
name := fs.fs.String() name := fs.fs.String()
if name == "defaultFileSystem" { if name == "defaultFileSystem" {
...@@ -107,11 +104,6 @@ func (fs *PathNodeFs) Connector() *nodefs.FileSystemConnector { ...@@ -107,11 +104,6 @@ func (fs *PathNodeFs) Connector() *nodefs.FileSystemConnector {
return fs.connector return fs.connector
} }
func (fs *PathNodeFs) OnMount(conn *nodefs.FileSystemConnector) {
fs.connector = conn
fs.fs.OnMount(fs)
}
func (fs *PathNodeFs) Node(name string) *nodefs.Inode { func (fs *PathNodeFs) Node(name string) *nodefs.Inode {
n, rest := fs.LastNode(name) n, rest := fs.LastNode(name)
if len(rest) > 0 { if len(rest) > 0 {
...@@ -206,6 +198,14 @@ type pathInode struct { ...@@ -206,6 +198,14 @@ type pathInode struct {
inode *nodefs.Inode inode *nodefs.Inode
} }
func (n *pathInode) OnMount(conn *nodefs.FileSystemConnector) {
n.pathFs.connector = conn
n.pathFs.fs.OnMount(n.pathFs)
}
func (n *pathInode) OnUnmount() {
}
// Drop all known client inodes. Must have the treeLock. // Drop all known client inodes. Must have the treeLock.
func (n *pathInode) forgetClientInodes() { func (n *pathInode) forgetClientInodes() {
n.clientInode = 0 n.clientInode = 0
......
...@@ -112,7 +112,7 @@ func xattrTestCase(t *testing.T, nm string) (mountPoint string, cleanup func()) ...@@ -112,7 +112,7 @@ func xattrTestCase(t *testing.T, nm string) (mountPoint string, cleanup func())
} }
nfs := NewPathNodeFs(xfs, nil) nfs := NewPathNodeFs(xfs, nil)
state, _, err := nodefs.MountFileSystem(mountPoint, nfs, nil) state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("TempDir failed: %v", err) t.Fatalf("TempDir failed: %v", err)
} }
......
...@@ -40,7 +40,7 @@ func setupCacheTest(t *testing.T) (string, *pathfs.PathNodeFs, func()) { ...@@ -40,7 +40,7 @@ func setupCacheTest(t *testing.T) (string, *pathfs.PathNodeFs, func()) {
pathfs.NewLoopbackFileSystem(dir + "/orig"), pathfs.NewLoopbackFileSystem(dir + "/orig"),
} }
pfs := pathfs.NewPathNodeFs(fs, nil) pfs := pathfs.NewPathNodeFs(fs, nil)
state, conn, err := nodefs.MountFileSystem(dir+"/mnt", pfs, nil) state, conn, err := nodefs.MountRoot(dir+"/mnt", pfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
...@@ -140,7 +140,7 @@ func TestNonseekable(t *testing.T) { ...@@ -140,7 +140,7 @@ func TestNonseekable(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(dir, nfs, nil) state, _, err := nodefs.MountRoot(dir, nfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("failed: %v", err) t.Fatalf("failed: %v", err)
} }
...@@ -173,7 +173,7 @@ func TestGetAttrRace(t *testing.T) { ...@@ -173,7 +173,7 @@ func TestGetAttrRace(t *testing.T) {
fs := pathfs.NewLoopbackFileSystem(dir + "/orig") fs := pathfs.NewLoopbackFileSystem(dir + "/orig")
pfs := pathfs.NewPathNodeFs(fs, nil) pfs := pathfs.NewPathNodeFs(fs, nil)
state, conn, err := nodefs.MountFileSystem(dir+"/mnt", pfs, state, conn, err := nodefs.MountRoot(dir+"/mnt", pfs.Root(),
&nodefs.Options{}) &nodefs.Options{})
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
......
...@@ -41,7 +41,7 @@ func defaultReadTest(t *testing.T) (root string, cleanup func()) { ...@@ -41,7 +41,7 @@ func defaultReadTest(t *testing.T) (root string, cleanup func()) {
t.Fatalf("TempDir failed: %v", err) t.Fatalf("TempDir failed: %v", err)
} }
pathfs := pathfs.NewPathNodeFs(fs, nil) pathfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(dir, pathfs, nil) state, _, err := nodefs.MountRoot(dir, pathfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -34,8 +34,8 @@ func TestDeleteNotify(t *testing.T) { ...@@ -34,8 +34,8 @@ func TestDeleteNotify(t *testing.T) {
t.Fatalf("TempDir failed %v", err) t.Fatalf("TempDir failed %v", err)
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
fs := nodefs.NewMemNodeFs(dir + "/backing") root := nodefs.NewMemNodeFSRoot(dir + "/backing")
conn := nodefs.NewFileSystemConnector(fs, conn := nodefs.NewFileSystemConnector(root,
&nodefs.Options{PortableInodes: true}) &nodefs.Options{PortableInodes: true})
mnt := dir + "/mnt" mnt := dir + "/mnt"
err = os.Mkdir(mnt, 0755) err = os.Mkdir(mnt, 0755)
...@@ -51,18 +51,18 @@ func TestDeleteNotify(t *testing.T) { ...@@ -51,18 +51,18 @@ func TestDeleteNotify(t *testing.T) {
go state.Serve() go state.Serve()
defer state.Unmount() defer state.Unmount()
_, code := fs.Root().Mkdir("testdir", 0755, nil) _, code := root.Mkdir("testdir", 0755, nil)
if !code.Ok() { if !code.Ok() {
t.Fatal(code) t.Fatal(code)
} }
ch := fs.Root().Inode().RmChild("testdir") ch := root.Inode().RmChild("testdir")
ch.Node().SetInode(nil) ch.Node().SetInode(nil)
flip := flipNode{ flip := flipNode{
Node: ch.Node(), Node: ch.Node(),
ok: make(chan int), ok: make(chan int),
} }
fs.Root().Inode().NewChild("testdir", true, &flip) root.Inode().NewChild("testdir", true, &flip)
err = ioutil.WriteFile(mnt+"/testdir/testfile", []byte{42}, 0644) err = ioutil.WriteFile(mnt+"/testdir/testfile", []byte{42}, 0644)
if err != nil { if err != nil {
...@@ -99,12 +99,12 @@ func TestDeleteNotify(t *testing.T) { ...@@ -99,12 +99,12 @@ func TestDeleteNotify(t *testing.T) {
// Simulate deletion+mkdir coming from the network // Simulate deletion+mkdir coming from the network
close(flip.ok) close(flip.ok)
oldCh := fs.Root().Inode().RmChild("testdir") oldCh := root.Inode().RmChild("testdir")
_, code = fs.Root().Inode().Node().Mkdir("testdir", 0755, nil) _, code = root.Inode().Node().Mkdir("testdir", 0755, nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("mkdir status", code) t.Fatal("mkdir status", code)
} }
conn.DeleteNotify(fs.Root().Inode(), oldCh, "testdir") conn.DeleteNotify(root.Inode(), oldCh, "testdir")
_, err = os.Lstat(mnt + "/testdir") _, err = os.Lstat(mnt + "/testdir")
if err != nil { if err != nil {
......
...@@ -138,7 +138,7 @@ func setupFAttrTest(t *testing.T, fs pathfs.FileSystem) (dir string, clean func( ...@@ -138,7 +138,7 @@ func setupFAttrTest(t *testing.T, fs pathfs.FileSystem) (dir string, clean func(
t.Fatalf("TempDir failed: %v", err) t.Fatalf("TempDir failed: %v", err)
} }
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(dir, nfs, nil) state, _, err := nodefs.MountRoot(dir, nfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -70,7 +70,7 @@ func NewTestCase(t *testing.T) *testCase { ...@@ -70,7 +70,7 @@ func NewTestCase(t *testing.T) *testCase {
me.pathFs = pathfs.NewPathNodeFs(pfs, &pathfs.PathNodeFsOptions{ me.pathFs = pathfs.NewPathNodeFs(pfs, &pathfs.PathNodeFsOptions{
ClientInodes: true}) ClientInodes: true})
me.connector = nodefs.NewFileSystemConnector(me.pathFs, me.connector = nodefs.NewFileSystemConnector(me.pathFs.Root(),
&nodefs.Options{ &nodefs.Options{
EntryTimeout: testTtl, EntryTimeout: testTtl,
AttrTimeout: testTtl, AttrTimeout: testTtl,
...@@ -923,7 +923,7 @@ func TestOriginalIsSymlink(t *testing.T) { ...@@ -923,7 +923,7 @@ func TestOriginalIsSymlink(t *testing.T) {
fs := pathfs.NewLoopbackFileSystem(link) fs := pathfs.NewLoopbackFileSystem(link)
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(mnt, nfs, nil) state, _, err := nodefs.MountRoot(mnt, nfs.Root(), nil)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -20,7 +20,7 @@ func TestMountOnExisting(t *testing.T) { ...@@ -20,7 +20,7 @@ func TestMountOnExisting(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Mkdir failed: %v", err) t.Fatalf("Mkdir failed: %v", err)
} }
nfs := nodefs.NewDefaultFileSystem() nfs := nodefs.NewDefaultNode()
code := ts.connector.Mount(ts.rootNode(), "mnt", nfs, nil) code := ts.connector.Mount(ts.rootNode(), "mnt", nfs, nil)
if code != fuse.EBUSY { if code != fuse.EBUSY {
t.Fatal("expect EBUSY:", code) t.Fatal("expect EBUSY:", code)
...@@ -46,7 +46,7 @@ func TestMountRename(t *testing.T) { ...@@ -46,7 +46,7 @@ func TestMountRename(t *testing.T) {
defer ts.Cleanup() defer ts.Cleanup()
fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil) fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil)
code := ts.connector.Mount(ts.rootNode(), "mnt", fs, nil) code := ts.connector.Mount(ts.rootNode(), "mnt", fs.Root(), nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("mount should succeed") t.Fatal("mount should succeed")
} }
...@@ -62,7 +62,7 @@ func TestMountReaddir(t *testing.T) { ...@@ -62,7 +62,7 @@ func TestMountReaddir(t *testing.T) {
defer ts.Cleanup() defer ts.Cleanup()
fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil) fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil)
code := ts.connector.Mount(ts.rootNode(), "mnt", fs, nil) code := ts.connector.Mount(ts.rootNode(), "mnt", fs.Root(), nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("mount should succeed") t.Fatal("mount should succeed")
} }
...@@ -87,7 +87,7 @@ func TestRecursiveMount(t *testing.T) { ...@@ -87,7 +87,7 @@ func TestRecursiveMount(t *testing.T) {
} }
fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil) fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil)
code := ts.connector.Mount(ts.rootNode(), "mnt", fs, nil) code := ts.connector.Mount(ts.rootNode(), "mnt", fs.Root(), nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("mount should succeed") t.Fatal("mount should succeed")
} }
...@@ -129,7 +129,7 @@ func TestDeletedUnmount(t *testing.T) { ...@@ -129,7 +129,7 @@ func TestDeletedUnmount(t *testing.T) {
submnt := filepath.Join(ts.mnt, "mnt") submnt := filepath.Join(ts.mnt, "mnt")
pfs2 := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil) pfs2 := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil)
code := ts.connector.Mount(ts.rootNode(), "mnt", pfs2, nil) code := ts.connector.Mount(ts.rootNode(), "mnt", pfs2.Root(), nil)
if !code.Ok() { if !code.Ok() {
t.Fatal("Mount error", code) t.Fatal("Mount error", code)
} }
...@@ -163,38 +163,21 @@ func TestDeletedUnmount(t *testing.T) { ...@@ -163,38 +163,21 @@ func TestDeletedUnmount(t *testing.T) {
} }
} }
type defaultFS struct {
nodefs.FileSystem
root nodefs.Node
}
func (fs *defaultFS) Root() nodefs.Node {
return fs.root
}
func TestDefaultNodeMount(t *testing.T) { func TestDefaultNodeMount(t *testing.T) {
fs := &defaultFS{
nodefs.NewDefaultFileSystem(),
nodefs.NewDefaultNode(),
}
dir, err := ioutil.TempDir("", "go-fuse") dir, err := ioutil.TempDir("", "go-fuse")
if err != nil { if err != nil {
t.Fatalf("TempDir: %v", err) t.Fatalf("TempDir: %v", err)
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
s, conn, err := nodefs.MountFileSystem(dir, fs, nil) root := nodefs.NewDefaultNode()
s, conn, err := nodefs.MountRoot(dir, root, nil)
if err != nil { if err != nil {
t.Fatalf("MountFileSystem: %v", err) t.Fatalf("MountRoot: %v", err)
} }
go s.Serve() go s.Serve()
defer s.Unmount() defer s.Unmount()
sub := &defaultFS{ if err := conn.Mount(root.Inode(), "sub", nodefs.NewDefaultNode(), nil); !err.Ok() {
nodefs.NewDefaultFileSystem(),
nodefs.NewDefaultNode(),
}
if err := conn.Mount(fs.Root().Inode(), "sub", sub, nil); !err.Ok() {
t.Fatalf("Mount: %v", err) t.Fatalf("Mount: %v", err)
} }
......
...@@ -87,7 +87,7 @@ func NewNotifyTest(t *testing.T) *NotifyTest { ...@@ -87,7 +87,7 @@ func NewNotifyTest(t *testing.T) *NotifyTest {
} }
me.pathfs = pathfs.NewPathNodeFs(me.fs, nil) me.pathfs = pathfs.NewPathNodeFs(me.fs, nil)
me.state, me.connector, err = nodefs.MountFileSystem(me.dir, me.pathfs, opts) me.state, me.connector, err = nodefs.MountRoot(me.dir, me.pathfs.Root(), opts)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -131,7 +131,7 @@ func (fs *autoUnionFs) createFs(name string, roots []string) fuse.Status { ...@@ -131,7 +131,7 @@ func (fs *autoUnionFs) createFs(name string, roots []string) fuse.Status {
log.Printf("Adding workspace %v for roots %v", name, ufs.String()) log.Printf("Adding workspace %v for roots %v", name, ufs.String())
nfs := pathfs.NewPathNodeFs(ufs, &fs.options.PathNodeFsOptions) nfs := pathfs.NewPathNodeFs(ufs, &fs.options.PathNodeFsOptions)
code := fs.nodeFs.Mount(name, nfs, &fs.options.Options) code := fs.nodeFs.Mount(name, nfs.Root(), &fs.options.Options)
if code.Ok() { if code.Ok() {
fs.knownFileSystems[name] = knownFs{ fs.knownFileSystems[name] = knownFs{
ufs, ufs,
......
...@@ -54,7 +54,7 @@ func setup(t *testing.T) (workdir string, cleanup func()) { ...@@ -54,7 +54,7 @@ func setup(t *testing.T) (workdir string, cleanup func()) {
fs := NewAutoUnionFs(wd+"/store", testAOpts) fs := NewAutoUnionFs(wd+"/store", testAOpts)
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(wd+"/mnt", nfs, &testAOpts.Options) state, _, err := nodefs.MountRoot(wd+"/mnt", nfs.Root(), &testAOpts.Options)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -93,7 +93,7 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) { ...@@ -93,7 +93,7 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) {
pathfs := pathfs.NewPathNodeFs(ufs, pathfs := pathfs.NewPathNodeFs(ufs,
&pathfs.PathNodeFsOptions{ClientInodes: true}) &pathfs.PathNodeFsOptions{ClientInodes: true})
state, conn, err := nodefs.MountFileSystem(wd+"/mnt", pathfs, opts) state, conn, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
...@@ -1159,7 +1159,7 @@ func TestUnionFsDisappearing(t *testing.T) { ...@@ -1159,7 +1159,7 @@ func TestUnionFsDisappearing(t *testing.T) {
} }
nfs := pathfs.NewPathNodeFs(ufs, nil) nfs := pathfs.NewPathNodeFs(ufs, nil)
state, _, err := nodefs.MountFileSystem(wd+"/mnt", nfs, opts) state, _, err := nodefs.MountRoot(wd+"/mnt", nfs.Root(), opts)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -64,7 +64,7 @@ func TestXAttrCaching(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestXAttrCaching(t *testing.T) {
pathfs := pathfs.NewPathNodeFs(ufs, pathfs := pathfs.NewPathNodeFs(ufs,
&pathfs.PathNodeFsOptions{ClientInodes: true}) &pathfs.PathNodeFsOptions{ClientInodes: true})
server, conn, err := nodefs.MountFileSystem(wd+"/mnt", pathfs, opts) server, conn, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts)
if err != nil { if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err) t.Fatalf("MountNodeFileSystem failed: %v", err)
} }
......
...@@ -16,38 +16,47 @@ type MemFile interface { ...@@ -16,38 +16,47 @@ type MemFile interface {
type memNode struct { type memNode struct {
nodefs.Node nodefs.Node
file MemFile file MemFile
fs *MemTreeFs
} }
// MemTreeFs creates a tree of internal Inodes. Since the tree is // memTreeFs creates a tree of internal Inodes. Since the tree is
// loaded in memory completely at startup, it does not need to inode // loaded in memory completely at startup, it does not need inode
// discovery through Lookup() at serve time. // discovery through Lookup() at serve time.
type MemTreeFs struct { type MemTreeFs struct {
nodefs.FileSystem root *memNode
root memNode
files map[string]MemFile files map[string]MemFile
Name string Name string
} }
func NewMemTreeFs() *MemTreeFs { func NewMemTreeFs(files map[string]MemFile) *MemTreeFs {
return &MemTreeFs{ fs := &MemTreeFs{
FileSystem: nodefs.NewDefaultFileSystem(), root: &memNode{Node: nodefs.NewDefaultNode()},
root: memNode{Node: nodefs.NewDefaultNode()}, files: files,
} }
fs.root.fs = fs
return fs
} }
func (fs *MemTreeFs) String() string { func (fs *MemTreeFs) String() string {
return fs.Name return fs.Name
} }
func (fs *MemTreeFs) OnMount(conn *nodefs.FileSystemConnector) { func (fs *MemTreeFs) SetDebug(bool) {
}
func (fs *MemTreeFs) Root() nodefs.Node {
return fs.root
}
func (fs *MemTreeFs) onMount() {
for k, v := range fs.files { for k, v := range fs.files {
fs.addFile(k, v) fs.addFile(k, v)
} }
fs.files = nil fs.files = nil
} }
func (fs *MemTreeFs) Root() nodefs.Node { func (n *memNode) OnMount(c *nodefs.FileSystemConnector) {
return &fs.root n.fs.onMount()
} }
func (n *memNode) Print(indent int) { func (n *memNode) Print(indent int) {
...@@ -114,7 +123,10 @@ func (n *MemTreeFs) addFile(name string, f MemFile) { ...@@ -114,7 +123,10 @@ func (n *MemTreeFs) addFile(name string, f MemFile) {
for i, c := range comps { for i, c := range comps {
child := node.GetChild(c) child := node.GetChild(c)
if child == nil { if child == nil {
fsnode := &memNode{Node: nodefs.NewDefaultNode()} fsnode := &memNode{
Node: nodefs.NewDefaultNode(),
fs: n,
}
if i == len(comps)-1 { if i == len(comps)-1 {
fsnode.file = f fsnode.file = f
} }
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"sync" "sync"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/fuse/pathfs"
) )
...@@ -28,7 +29,7 @@ const ( ...@@ -28,7 +29,7 @@ const (
// MultiZipFs is a path filesystem that mounts zipfiles. // MultiZipFs is a path filesystem that mounts zipfiles.
type MultiZipFs struct { type MultiZipFs struct {
lock sync.RWMutex lock sync.RWMutex
zips map[string]*MemTreeFs zips map[string]nodefs.Node
dirZipFileMap map[string]string dirZipFileMap map[string]string
nodeFs *pathfs.PathNodeFs nodeFs *pathfs.PathNodeFs
...@@ -37,7 +38,7 @@ type MultiZipFs struct { ...@@ -37,7 +38,7 @@ type MultiZipFs struct {
func NewMultiZipFs() *MultiZipFs { func NewMultiZipFs() *MultiZipFs {
m := &MultiZipFs{ m := &MultiZipFs{
zips: make(map[string]*MemTreeFs), zips: make(map[string]nodefs.Node),
dirZipFileMap: make(map[string]string), dirZipFileMap: make(map[string]string),
FileSystem: pathfs.NewDefaultFileSystem(), FileSystem: pathfs.NewDefaultFileSystem(),
} }
...@@ -116,9 +117,9 @@ func (fs *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Stat ...@@ -116,9 +117,9 @@ func (fs *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Stat
fs.lock.Lock() fs.lock.Lock()
defer fs.lock.Unlock() defer fs.lock.Unlock()
zfs, ok := fs.zips[basename] root, ok := fs.zips[basename]
if ok { if ok {
code = fs.nodeFs.UnmountNode(zfs.Root().Inode()) code = fs.nodeFs.UnmountNode(root.Inode())
if !code.Ok() { if !code.Ok() {
return code return code
} }
...@@ -162,18 +163,18 @@ func (fs *MultiZipFs) Symlink(value string, linkName string, context *fuse.Conte ...@@ -162,18 +163,18 @@ func (fs *MultiZipFs) Symlink(value string, linkName string, context *fuse.Conte
return fuse.EBUSY return fuse.EBUSY
} }
afs, err := NewArchiveFileSystem(value) root, err := NewArchiveFileSystem(value)
if err != nil { if err != nil {
log.Println("NewZipArchiveFileSystem failed.", err) log.Println("NewZipArchiveFileSystem failed.", err)
return fuse.EINVAL return fuse.EINVAL
} }
code = fs.nodeFs.Mount(base, afs, nil) code = fs.nodeFs.Mount(base, root, nil)
if !code.Ok() { if !code.Ok() {
return code return code
} }
fs.dirZipFileMap[base] = value fs.dirZipFileMap[base] = value
fs.zips[base] = afs fs.zips[base] = root
return fuse.OK return fuse.OK
} }
...@@ -23,7 +23,7 @@ func setupMzfs(t *testing.T) (mountPoint string, cleanup func()) { ...@@ -23,7 +23,7 @@ func setupMzfs(t *testing.T) (mountPoint string, cleanup func()) {
fs := NewMultiZipFs() fs := NewMultiZipFs()
mountPoint, _ = ioutil.TempDir("", "") mountPoint, _ = ioutil.TempDir("", "")
nfs := pathfs.NewPathNodeFs(fs, nil) nfs := pathfs.NewPathNodeFs(fs, nil)
state, _, err := nodefs.MountFileSystem(mountPoint, nfs, &nodefs.Options{ state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), &nodefs.Options{
EntryTimeout: testTtl, EntryTimeout: testTtl,
AttrTimeout: testTtl, AttrTimeout: testTtl,
NegativeTimeout: 0.0, NegativeTimeout: 0.0,
......
...@@ -3,13 +3,14 @@ package zipfs ...@@ -3,13 +3,14 @@ package zipfs
import ( import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"errors"
"fmt" "fmt"
"github.com/hanwen/go-fuse/fuse"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
) )
type ZipFile struct { type ZipFile struct {
...@@ -57,33 +58,30 @@ func NewZipTree(name string) (map[string]MemFile, error) { ...@@ -57,33 +58,30 @@ func NewZipTree(name string) (map[string]MemFile, error) {
return out, nil return out, nil
} }
func NewArchiveFileSystem(name string) (mfs *MemTreeFs, err error) { func NewArchiveFileSystem(name string) (root nodefs.Node, err error) {
mfs = NewMemTreeFs() var files map[string]MemFile
mfs.Name = fmt.Sprintf("fs(%s)", name) switch {
case strings.HasSuffix(name, ".zip"):
if strings.HasSuffix(name, ".zip") { files, err = NewZipTree(name)
mfs.files, err = NewZipTree(name) case strings.HasSuffix(name, ".tar.gz"):
} files, err = NewTarCompressedTree(name, "gz")
if strings.HasSuffix(name, ".tar.gz") { case strings.HasSuffix(name, ".tar.bz2"):
mfs.files, err = NewTarCompressedTree(name, "gz") files, err = NewTarCompressedTree(name, "bz2")
} case strings.HasSuffix(name, ".tar"):
if strings.HasSuffix(name, ".tar.bz2") {
mfs.files, err = NewTarCompressedTree(name, "bz2")
}
if strings.HasSuffix(name, ".tar") {
f, err := os.Open(name) f, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mfs.files = NewTarTree(f) files = NewTarTree(f)
default:
return nil, fmt.Errorf("unknown archive format %q", name)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
if mfs.files == nil { mfs := NewMemTreeFs(files)
return nil, errors.New(fmt.Sprintf("Unknown type for %v", name)) mfs.Name = fmt.Sprintf("fs(%s)", name)
} return mfs.Root(), nil
return mfs, nil
} }
...@@ -21,13 +21,13 @@ func testZipFile() string { ...@@ -21,13 +21,13 @@ func testZipFile() string {
} }
func setupZipfs(t *testing.T) (mountPoint string, cleanup func()) { func setupZipfs(t *testing.T) (mountPoint string, cleanup func()) {
zfs, err := NewArchiveFileSystem(testZipFile()) root, err := NewArchiveFileSystem(testZipFile())
if err != nil { if err != nil {
t.Fatalf("NewArchiveFileSystem failed: %v", err) t.Fatalf("NewArchiveFileSystem failed: %v", err)
} }
mountPoint, _ = ioutil.TempDir("", "") mountPoint, _ = ioutil.TempDir("", "")
state, _, err := nodefs.MountFileSystem(mountPoint, zfs, nil) state, _, err := nodefs.MountRoot(mountPoint, root, nil)
state.SetDebug(VerboseTest()) state.SetDebug(VerboseTest())
go state.Serve() go state.Serve()
......
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