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

fs: rename from nodefs

The new naming makes clear that this is the One True API for Go-FUSE
parent 6aed6515
......@@ -17,16 +17,16 @@ import (
"testing"
"time"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
)
func setupFs(fs nodefs.InodeEmbedder, N int) (string, func()) {
opts := &nodefs.Options{}
func setupFs(node fs.InodeEmbedder, N int) (string, func()) {
opts := &fs.Options{}
opts.Debug = testutil.VerboseTest()
mountPoint := testutil.TempDir()
server, err := nodefs.Mount(mountPoint, fs, opts)
server, err := fs.Mount(mountPoint, node, opts)
if err != nil {
log.Panicf("cannot mount %v", err)
}
......
......@@ -10,17 +10,17 @@ import (
"strings"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
type StatFS struct {
nodefs.Inode
fs.Inode
files map[string]fuse.Attr
}
var _ = (nodefs.NodeOnAdder)((*StatFS)(nil))
var _ = (fs.NodeOnAdder)((*StatFS)(nil))
func (r *StatFS) OnAdd(ctx context.Context) {
for nm, a := range r.files {
......@@ -50,8 +50,8 @@ func (r *StatFS) addFile(name string, a fuse.Attr) {
ch := p.GetChild(component)
if ch == nil {
// Create a directory
ch = p.NewPersistentInode(context.Background(), &nodefs.Inode{},
nodefs.StableAttr{Mode: syscall.S_IFDIR})
ch = p.NewPersistentInode(context.Background(), &fs.Inode{},
fs.StableAttr{Mode: syscall.S_IFDIR})
// Add it
p.AddChild(component, ch, true)
}
......@@ -60,10 +60,10 @@ func (r *StatFS) addFile(name string, a fuse.Attr) {
}
// Create the file
child := p.NewPersistentInode(context.Background(), &nodefs.MemRegularFile{
child := p.NewPersistentInode(context.Background(), &fs.MemRegularFile{
Data: make([]byte, a.Size),
Attr: a,
}, nodefs.StableAttr{})
}, fs.StableAttr{})
// And add it
p.AddChild(base, child, true)
......
......@@ -12,32 +12,32 @@ import (
"log"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
type HelloRoot struct {
nodefs.Inode
fs.Inode
}
func (r *HelloRoot) OnAdd(ctx context.Context) {
ch := r.NewPersistentInode(
ctx, &nodefs.MemRegularFile{
ctx, &fs.MemRegularFile{
Data: []byte("file.txt"),
Attr: fuse.Attr{
Mode: 0644,
},
}, nodefs.StableAttr{Ino: 2})
}, fs.StableAttr{Ino: 2})
r.AddChild("file.txt", ch, false)
}
func (r *HelloRoot) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
func (r *HelloRoot) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
out.Mode = 0755
return 0
}
var _ = (nodefs.NodeGetattrer)((*HelloRoot)(nil))
var _ = (nodefs.NodeOnAdder)((*HelloRoot)(nil))
var _ = (fs.NodeGetattrer)((*HelloRoot)(nil))
var _ = (fs.NodeOnAdder)((*HelloRoot)(nil))
func main() {
debug := flag.Bool("debug", false, "print debug data")
......@@ -45,9 +45,9 @@ func main() {
if len(flag.Args()) < 1 {
log.Fatal("Usage:\n hello MOUNTPOINT")
}
opts := &nodefs.Options{}
opts := &fs.Options{}
opts.Debug = *debug
server, err := nodefs.Mount(flag.Arg(0), &HelloRoot{}, opts)
server, err := fs.Mount(flag.Arg(0), &HelloRoot{}, opts)
if err != nil {
log.Fatalf("Mount fail: %v\n", err)
}
......
......@@ -18,7 +18,7 @@ import (
"syscall"
"time"
"github.com/hanwen/go-fuse/nodefs"
"github.com/hanwen/go-fuse/fs"
)
func writeMemProfile(fn string, sigs <-chan os.Signal) {
......@@ -75,13 +75,13 @@ func main() {
}
orig := flag.Arg(1)
loopbackRoot, err := nodefs.NewLoopbackRoot(orig)
loopbackRoot, err := fs.NewLoopbackRoot(orig)
if err != nil {
log.Fatalf("NewLoopbackRoot(%s): %v\n", orig, err)
}
sec := time.Second
opts := &nodefs.Options{
opts := &fs.Options{
// These options are to be compatible with libfuse defaults,
// making benchmarking easier.
AttrTimeout: &sec,
......@@ -89,7 +89,7 @@ func main() {
}
opts.Debug = *debug
opts.AllowOther = *other
server, err := nodefs.Mount(flag.Arg(0), loopbackRoot, opts)
server, err := fs.Mount(flag.Arg(0), loopbackRoot, opts)
if err != nil {
log.Fatalf("Mount fail: %v\n", err)
}
......
......@@ -11,7 +11,7 @@ import (
"path/filepath"
"time"
"github.com/hanwen/go-fuse/nodefs"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/zipfs"
)
......@@ -25,15 +25,15 @@ func main() {
os.Exit(2)
}
fs := &zipfs.MultiZipFs{}
root := &zipfs.MultiZipFs{}
sec := time.Second
opts := nodefs.Options{
opts := fs.Options{
EntryTimeout: &sec,
AttrTimeout: &sec,
DefaultPermissions: true,
}
opts.Debug = *debug
server, err := nodefs.Mount(flag.Arg(0), fs, &opts)
server, err := fs.Mount(flag.Arg(0), root, &opts)
if err != nil {
fmt.Printf("Mount fail: %v\n", err)
os.Exit(1)
......
......@@ -18,8 +18,8 @@ import (
"time"
"github.com/hanwen/go-fuse/benchmark"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
func main() {
......@@ -50,18 +50,18 @@ func main() {
}
}
fs := &benchmark.StatFS{}
root := &benchmark.StatFS{}
lines := benchmark.ReadLines(flag.Arg(1))
for _, l := range lines {
fs.AddFile(strings.TrimSpace(l),
root.AddFile(strings.TrimSpace(l),
fuse.Attr{Mode: syscall.S_IFREG})
}
opts := &nodefs.Options{
opts := &fs.Options{
AttrTimeout: ttl,
EntryTimeout: ttl,
}
opts.Debug = *debug
server, err := nodefs.Mount(flag.Arg(0), fs, opts)
server, err := fs.Mount(flag.Arg(0), root, opts)
if err != nil {
log.Fatalf("Mount fail: %v\n", err)
}
......
......@@ -16,7 +16,7 @@ import (
"strings"
"time"
"github.com/hanwen/go-fuse/nodefs"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/zipfs"
)
......@@ -54,13 +54,13 @@ func main() {
os.Exit(1)
}
opts := &nodefs.Options{
opts := &fs.Options{
AttrTimeout: ttl,
EntryTimeout: ttl,
DefaultPermissions: true,
}
opts.Debug = *debug
server, err := nodefs.Mount(flag.Arg(0), root, opts)
server, err := fs.Mount(flag.Arg(0), root, opts)
if err != nil {
fmt.Printf("Mount fail: %v\n", err)
os.Exit(1)
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package nodefs provides infrastructure to build tree-organized filesystems.
// Package fs provides infrastructure to build tree-organized filesystems.
//
// A tree-organized filesystem is similar to UNIX or Plan 9 filesystem: it
// consists of nodes with each node being either a file or a directory. Files
......@@ -71,7 +71,7 @@
// Locks for networked filesystems are supported through the suite of
// Getlk, Setlk and Setlkw methods. They alllow locks on regions of
// regular files.
package nodefs
package fs
import (
"context"
......@@ -88,8 +88,8 @@ import (
// read-only filesystem with a predefined tree structure. See
// zipfs_test.go for an example. A example is in zip_test.go
type InodeEmbedder interface {
// populateInode and inode are used by nodefs internally to
// link Inode to a Node.
// populateInode and inode are used internally to link Inode
// to a Node.
//
// See Inode() for the public API to retrieve an inode from Node.
embed() *Inode
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"bytes"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"syscall"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import "syscall"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import "syscall"
......
......@@ -2,4 +2,4 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"bytes"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"syscall"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"io"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"sync"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs_test
package fs_test
import (
"fmt"
......@@ -10,19 +10,19 @@ import (
"log"
"os"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// mountLoopback mounts dir under the given mountpoint
func mountLoopback(dir, mntPoint string) (*fuse.Server, error) {
root, err := nodefs.NewLoopbackRoot(dir)
root, err := fs.NewLoopbackRoot(dir)
if err != nil {
return nil, err
}
// Make the root available under mntDir
return nodefs.Mount(mntPoint, root, &nodefs.Options{
return fs.Mount(mntPoint, root, &fs.Options{
MountOptions: fuse.MountOptions{Debug: true},
})
}
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs_test
package fs_test
import (
"context"
......@@ -12,8 +12,8 @@ import (
"strings"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// files contains the files we will expose as a file system
......@@ -24,11 +24,11 @@ var files = map[string]string{
// inMemoryFS is the root of the tree
type inMemoryFS struct {
nodefs.Inode
fs.Inode
}
// Ensure that we implement NodeOnAdder
var _ = (nodefs.NodeOnAdder)((*inMemoryFS)(nil))
var _ = (fs.NodeOnAdder)((*inMemoryFS)(nil))
// OnAdd is called on mounting the file system. Use it to populate
// the file system tree.
......@@ -46,8 +46,8 @@ func (root *inMemoryFS) OnAdd(ctx context.Context) {
ch := p.GetChild(component)
if ch == nil {
// Create a directory
ch = p.NewPersistentInode(ctx, &nodefs.Inode{},
nodefs.StableAttr{Mode: syscall.S_IFDIR})
ch = p.NewPersistentInode(ctx, &fs.Inode{},
fs.StableAttr{Mode: syscall.S_IFDIR})
// Add it
p.AddChild(component, ch, true)
}
......@@ -58,9 +58,9 @@ func (root *inMemoryFS) OnAdd(ctx context.Context) {
// Create the file. The Inode must be persistent,
// because its life time is not under control of the
// kernel.
child := p.NewPersistentInode(ctx, &nodefs.MemRegularFile{
child := p.NewPersistentInode(ctx, &fs.MemRegularFile{
Data: []byte(content),
}, nodefs.StableAttr{})
}, fs.StableAttr{})
// And add it
p.AddChild(base, child, true)
......@@ -73,7 +73,7 @@ func Example() {
mntDir, _ := ioutil.TempDir("", "")
root := &inMemoryFS{}
server, err := nodefs.Mount(mntDir, root, &nodefs.Options{
server, err := fs.Mount(mntDir, root, &fs.Options{
MountOptions: fuse.MountOptions{Debug: true},
// This adds read permissions to the files and
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"bytes"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"bytes"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"time"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"context"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"fmt"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
package fs
import (
"syscall"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs_test
package fs_test
import (
"archive/zip"
......@@ -16,8 +16,8 @@ import (
"syscall"
"testing"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
var testData = map[string]string{
......@@ -66,7 +66,7 @@ func TestZipFS(t *testing.T) {
if err != nil {
t.Fatal(err)
}
server, err := nodefs.Mount(mntDir, root, nil)
server, err := fs.Mount(mntDir, root, nil)
if err != nil {
t.Fatal(err)
}
......@@ -110,15 +110,15 @@ func TestZipFSOnAdd(t *testing.T) {
zr := &zipRoot{zr: r}
root := &nodefs.Inode{}
root := &fs.Inode{}
mnt, err := ioutil.TempDir("", "ZipFS")
if err != nil {
t.Fatal(err)
}
server, err := nodefs.Mount(mnt, root, &nodefs.Options{
server, err := fs.Mount(mnt, root, &fs.Options{
OnAdd: func(ctx context.Context) {
root.AddChild("sub",
root.NewPersistentInode(ctx, zr, nodefs.StableAttr{Mode: syscall.S_IFDIR}), false)
root.NewPersistentInode(ctx, zr, fs.StableAttr{Mode: syscall.S_IFDIR}), false)
},
})
if err != nil {
......@@ -137,25 +137,25 @@ func TestZipFSOnAdd(t *testing.T) {
// zipFile is a file read from a zip archive.
type zipFile struct {
nodefs.Inode
fs.Inode
file *zip.File
mu sync.Mutex
data []byte
}
var _ = (nodefs.NodeOpener)((*zipFile)(nil))
var _ = (nodefs.NodeGetattrer)((*zipFile)(nil))
var _ = (fs.NodeOpener)((*zipFile)(nil))
var _ = (fs.NodeGetattrer)((*zipFile)(nil))
// Getattr sets the minimum, which is the size. A more full-featured
// FS would also set timestamps and permissions.
func (zf *zipFile) Getattr(ctx context.Context, f nodefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
func (zf *zipFile) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
out.Size = zf.file.UncompressedSize64
return 0
}
// Open lazily unpacks zip data
func (zf *zipFile) Open(ctx context.Context, flags uint32) (nodefs.FileHandle, uint32, syscall.Errno) {
func (zf *zipFile) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
zf.mu.Lock()
defer zf.mu.Unlock()
if zf.data == nil {
......@@ -174,27 +174,27 @@ func (zf *zipFile) Open(ctx context.Context, flags uint32) (nodefs.FileHandle, u
// We don't return a filehandle since we don't really need
// one. The file content is immutable, so hint the kernel to
// cache the data.
return nil, fuse.FOPEN_KEEP_CACHE, nodefs.OK
return nil, fuse.FOPEN_KEEP_CACHE, fs.OK
}
// Read simply returns the data that was already unpacked in the Open call
func (zf *zipFile) Read(ctx context.Context, f nodefs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
func (zf *zipFile) Read(ctx context.Context, f fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
end := int(off) + len(dest)
if end > len(zf.data) {
end = len(zf.data)
}
return fuse.ReadResultData(zf.data[off:end]), nodefs.OK
return fuse.ReadResultData(zf.data[off:end]), fs.OK
}
// zipRoot is the root of the Zip filesystem. Its only functionality
// is populating the filesystem.
type zipRoot struct {
nodefs.Inode
fs.Inode
zr *zip.Reader
}
var _ = (nodefs.NodeOnAdder)((*zipRoot)(nil))
var _ = (fs.NodeOnAdder)((*zipRoot)(nil))
func (zr *zipRoot) OnAdd(ctx context.Context) {
// OnAdd is called once we are attached to an Inode. We can
......@@ -211,14 +211,14 @@ func (zr *zipRoot) OnAdd(ctx context.Context) {
}
ch := p.GetChild(component)
if ch == nil {
ch = p.NewPersistentInode(ctx, &nodefs.Inode{},
nodefs.StableAttr{Mode: fuse.S_IFDIR})
ch = p.NewPersistentInode(ctx, &fs.Inode{},
fs.StableAttr{Mode: fuse.S_IFDIR})
p.AddChild(component, ch, true)
}
p = ch
}
ch := p.NewPersistentInode(ctx, &zipFile{file: f}, nodefs.StableAttr{})
ch := p.NewPersistentInode(ctx, &zipFile{file: f}, fs.StableAttr{})
p.AddChild(base, ch, true)
}
}
......@@ -13,8 +13,8 @@ import (
"path/filepath"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
func filePathHash(path string) string {
......@@ -32,7 +32,7 @@ type unionFSRoot struct {
}
type unionFSNode struct {
nodefs.Inode
fs.Inode
}
const delDir = "DELETIONS"
......@@ -42,7 +42,7 @@ var delDirHash = filePathHash(delDir)
func (r *unionFSRoot) allMarkers(result map[string]struct{}) syscall.Errno {
dir := filepath.Join(r.roots[0], delDir)
ds, errno := nodefs.NewLoopbackDirStream(dir)
ds, errno := fs.NewLoopbackDirStream(dir)
if errno != 0 {
return errno
}
......@@ -85,7 +85,7 @@ func (r *unionFSRoot) writeMarker(name string) syscall.Errno {
dest := r.markerPath(name)
err := ioutil.WriteFile(dest, []byte(name), 0644)
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
func (r *unionFSRoot) markerPath(name string) string {
......@@ -102,25 +102,25 @@ func (n *unionFSNode) root() *unionFSRoot {
return n.Root().Operations().(*unionFSRoot)
}
var _ = (nodefs.NodeSetattrer)((*unionFSNode)(nil))
var _ = (fs.NodeSetattrer)((*unionFSNode)(nil))
func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
func (n *unionFSNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
if errno := n.promote(); errno != 0 {
return errno
}
if fh != nil {
return fh.(nodefs.FileSetattrer).Setattr(ctx, in, out)
return fh.(fs.FileSetattrer).Setattr(ctx, in, out)
}
p := filepath.Join(n.root().roots[0], n.Path(nil))
fsa, ok := fh.(nodefs.FileSetattrer)
fsa, ok := fh.(fs.FileSetattrer)
if ok && fsa != nil {
fsa.Setattr(ctx, in, out)
} else {
if m, ok := in.GetMode(); ok {
if err := syscall.Chmod(p, m); err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
}
......@@ -136,7 +136,7 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus
sgid = int(gid)
}
if err := syscall.Chown(p, suid, sgid); err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
}
......@@ -158,34 +158,34 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus
ts[1] = fuse.UtimeToTimespec(mp)
if err := syscall.UtimesNano(p, ts[:]); err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
}
if sz, ok := in.GetSize(); ok {
if err := syscall.Truncate(p, int64(sz)); err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
}
}
fga, ok := fh.(nodefs.FileGetattrer)
fga, ok := fh.(fs.FileGetattrer)
if ok && fga != nil {
fga.Getattr(ctx, out)
} else {
st := syscall.Stat_t{}
err := syscall.Lstat(p, &st)
if err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
out.FromStat(&st)
}
return 0
}
var _ = (nodefs.NodeCreater)((*unionFSNode)(nil))
var _ = (fs.NodeCreater)((*unionFSNode)(nil))
func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*nodefs.Inode, nodefs.FileHandle, uint32, syscall.Errno) {
func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*fs.Inode, fs.FileHandle, uint32, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, nil, 0, syscall.EPERM
}
......@@ -217,15 +217,15 @@ func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mod
return nil, nil, 0, err.(syscall.Errno)
}
ch := n.NewInode(ctx, &unionFSNode{}, nodefs.StableAttr{Mode: st.Mode, Ino: st.Ino})
ch := n.NewInode(ctx, &unionFSNode{}, fs.StableAttr{Mode: st.Mode, Ino: st.Ino})
out.FromStat(&st)
return ch, nodefs.NewLoopbackFile(fd), 0, 0
return ch, fs.NewLoopbackFile(fd), 0, 0
}
var _ = (nodefs.NodeOpener)((*unionFSNode)(nil))
var _ = (fs.NodeOpener)((*unionFSNode)(nil))
func (n *unionFSNode) Open(ctx context.Context, flags uint32) (nodefs.FileHandle, uint32, syscall.Errno) {
func (n *unionFSNode) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
isWR := (flags&syscall.O_RDWR != 0) || (flags&syscall.O_WRONLY != 0)
var st syscall.Stat_t
......@@ -242,12 +242,12 @@ func (n *unionFSNode) Open(ctx context.Context, flags uint32) (nodefs.FileHandle
return nil, 0, err.(syscall.Errno)
}
return nodefs.NewLoopbackFile(fd), 0, 0
return fs.NewLoopbackFile(fd), 0, 0
}
var _ = (nodefs.NodeGetattrer)((*unionFSNode)(nil))
var _ = (fs.NodeGetattrer)((*unionFSNode)(nil))
func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
func (n *unionFSNode) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
var st syscall.Stat_t
_, idx := n.getBranch(&st)
if idx < 0 {
......@@ -258,9 +258,9 @@ func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fu
return 0
}
var _ = (nodefs.NodeLookuper)((*unionFSNode)(nil))
var _ = (fs.NodeLookuper)((*unionFSNode)(nil))
func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) {
func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, syscall.ENOENT
}
......@@ -271,7 +271,7 @@ func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOu
idx := n.root().getBranch(p, &st)
if idx >= 0 {
// XXX use idx in Ino?
ch := n.NewInode(ctx, &unionFSNode{}, nodefs.StableAttr{Mode: st.Mode, Ino: st.Ino})
ch := n.NewInode(ctx, &unionFSNode{}, fs.StableAttr{Mode: st.Mode, Ino: st.Ino})
out.FromStat(&st)
out.Mode |= 0111
return ch, 0
......@@ -279,21 +279,21 @@ func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOu
return nil, syscall.ENOENT
}
var _ = (nodefs.NodeUnlinker)((*unionFSNode)(nil))
var _ = (fs.NodeUnlinker)((*unionFSNode)(nil))
func (n *unionFSNode) Unlink(ctx context.Context, name string) syscall.Errno {
return n.root().delPath(filepath.Join(n.Path(nil), name))
}
var _ = (nodefs.NodeRmdirer)((*unionFSNode)(nil))
var _ = (fs.NodeRmdirer)((*unionFSNode)(nil))
func (n *unionFSNode) Rmdir(ctx context.Context, name string) syscall.Errno {
return n.root().delPath(filepath.Join(n.Path(nil), name))
}
var _ = (nodefs.NodeSymlinker)((*unionFSNode)(nil))
var _ = (fs.NodeSymlinker)((*unionFSNode)(nil))
func (n *unionFSNode) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) {
func (n *unionFSNode) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
n.promote()
path := filepath.Join(n.root().roots[0], n.Path(nil), name)
err := syscall.Symlink(target, path)
......@@ -309,14 +309,14 @@ func (n *unionFSNode) Symlink(ctx context.Context, target, name string, out *fus
out.FromStat(&st)
ch := n.NewInode(ctx, &unionFSNode{}, nodefs.StableAttr{
ch := n.NewInode(ctx, &unionFSNode{}, fs.StableAttr{
Mode: syscall.S_IFLNK,
Ino: st.Ino,
})
return ch, 0
}
var _ = (nodefs.NodeReadlinker)((*unionFSNode)(nil))
var _ = (fs.NodeReadlinker)((*unionFSNode)(nil))
func (n *unionFSNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
nm, idx := n.getBranch(nil)
......@@ -330,9 +330,9 @@ func (n *unionFSNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
return buf[:count], 0
}
var _ = (nodefs.NodeReaddirer)((*unionFSNode)(nil))
var _ = (fs.NodeReaddirer)((*unionFSNode)(nil))
func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Errno) {
func (n *unionFSNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
root := n.root()
markers := map[string]struct{}{delDirHash: struct{}{}}
......@@ -358,11 +358,11 @@ func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Er
})
}
return nodefs.NewListDirStream(result), 0
return fs.NewListDirStream(result), 0
}
func readRoot(root string, dir string, result map[string]uint32) {
ds, errno := nodefs.NewLoopbackDirStream(filepath.Join(root, dir))
ds, errno := fs.NewLoopbackDirStream(filepath.Join(root, dir))
if errno != 0 {
return
}
......@@ -412,7 +412,7 @@ func (n *unionFSRoot) delPath(p string) syscall.Errno {
if idx == 0 {
err := syscall.Unlink(filepath.Join(r.roots[idx], p))
if err != nil {
return nodefs.ToErrno(err)
return fs.ToErrno(err)
}
idx = r.getBranch(p, &st)
}
......
......@@ -13,9 +13,9 @@ import (
"syscall"
"testing"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
"github.com/hanwen/go-fuse/posixtest"
)
......@@ -50,7 +50,7 @@ func newTestCase(t *testing.T, populate bool) *testCase {
}
}
opts := nodefs.Options{}
opts := fs.Options{}
opts.Debug = testutil.VerboseTest()
tc := &testCase{
dir: dir,
......@@ -62,7 +62,7 @@ func newTestCase(t *testing.T, populate bool) *testCase {
roots: []string{tc.rw, tc.ro},
}
server, err := nodefs.Mount(tc.mnt, tc.root, &opts)
server, err := fs.Mount(tc.mnt, tc.root, &opts)
if err != nil {
t.Fatal("Mount", err)
}
......
Objective
=========
A high-performance FUSE API that minimizes pitfalls with writing
correct filesystems.
Decisions
=========
* Nodes contain references to their children. This is useful
because most filesystems will need to construct tree-like
structures.
* Nodes contain references to their parents. As a result, we can
derive the path for each Inode, and there is no need for a
separate PathFS.
* Nodes can be "persistent", meaning their lifetime is not under
control of the kernel. This is useful for constructing FS trees
in advance, rather than driven by LOOKUP.
* The NodeID for FS tree node must be defined on creation and are
immutable. By contrast, reusing NodeIds (eg. rsc/bazil FUSE, as
well as old go-fuse/fuse/nodefs) needs extra synchronization to
avoid races with notify and FORGET, and makes handling the inode
Generation more complicated.
* The mode of an Inode is defined on creation. Files cannot change
type during their lifetime. This also prevents the common error
of forgetting to return the filetype in Lookup/GetAttr.
* The NodeID (used for communicating with kernel) is equal to
Attr.Ino (value shown in Stat and Lstat return values.).
* No global treelock, to ensure scalability.
* Support for hard links. libfuse doesn't support this in the
high-level API. Extra care for race conditions is needed when
looking up the same file through different paths.
* do not issue Notify{Entry,Delete} as part of
AddChild/RmChild/MvChild: because NodeIDs are unique and
immutable, there is no confusion about which nodes are
invalidated, and the notification doesn't have to happen under
lock.
* Directory reading uses the DirStream. Semantics for rewinding
directory reads, and adding files after opening (but before
reading) are handled automatically. No support for directory
seeks.
* Method names are based on syscall names. Where there is no
syscall (eg. "open directory"), we bias towards writing
everything together (Opendir)
To do/To decide
=========
* decide on a final package name
* handle less open/create.
* Symlink []byte vs string.
......@@ -19,27 +19,27 @@ import (
"log"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// MultiZipFs is a filesystem that mounts zipfiles.
type MultiZipFs struct {
nodefs.Inode
fs.Inode
}
func (fs *MultiZipFs) OnAdd(ctx context.Context) {
n := fs.NewPersistentInode(ctx, &configRoot{}, nodefs.StableAttr{Mode: syscall.S_IFDIR})
func (root *MultiZipFs) OnAdd(ctx context.Context) {
n := root.NewPersistentInode(ctx, &configRoot{}, fs.StableAttr{Mode: syscall.S_IFDIR})
fs.AddChild("config", n, false)
root.AddChild("config", n, false)
}
type configRoot struct {
nodefs.Inode
fs.Inode
}
var _ = (nodefs.NodeUnlinker)((*configRoot)(nil))
var _ = (nodefs.NodeSymlinker)((*configRoot)(nil))
var _ = (fs.NodeUnlinker)((*configRoot)(nil))
var _ = (fs.NodeSymlinker)((*configRoot)(nil))
func (r *configRoot) Unlink(ctx context.Context, basename string) syscall.Errno {
if r.GetChild(basename) == nil {
......@@ -64,7 +64,7 @@ func (r *configRoot) Unlink(ctx context.Context, basename string) syscall.Errno
return 0
}
func (r *configRoot) Symlink(ctx context.Context, target string, base string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) {
func (r *configRoot) Symlink(ctx context.Context, target string, base string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
root, err := NewArchiveFileSystem(target)
if err != nil {
log.Println("NewZipArchiveFileSystem failed.", err)
......@@ -72,12 +72,12 @@ func (r *configRoot) Symlink(ctx context.Context, target string, base string, ou
}
_, parent := r.Parent()
ch := r.NewPersistentInode(ctx, root, nodefs.StableAttr{Mode: syscall.S_IFDIR})
ch := r.NewPersistentInode(ctx, root, fs.StableAttr{Mode: syscall.S_IFDIR})
parent.AddChild(base, ch, false)
link := r.NewPersistentInode(ctx, &nodefs.MemSymlink{
link := r.NewPersistentInode(ctx, &fs.MemSymlink{
Data: []byte(target),
}, nodefs.StableAttr{Mode: syscall.S_IFLNK})
}, fs.StableAttr{Mode: syscall.S_IFLNK})
r.AddChild(base, link, false)
return link, 0
}
......@@ -10,9 +10,9 @@ import (
"testing"
"time"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
)
const testTtl = 100 * time.Millisecond
......@@ -22,13 +22,13 @@ func setupMzfs(t *testing.T) (mountPoint string, state *fuse.Server, cleanup fun
mountPoint = testutil.TempDir()
dt := testTtl
opts := &nodefs.Options{
opts := &fs.Options{
EntryTimeout: &dt,
AttrTimeout: &dt,
}
opts.Debug = testutil.VerboseTest()
server, err := nodefs.Mount(mountPoint, root, opts)
server, err := fs.Mount(mountPoint, root, opts)
if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err)
}
......
......@@ -17,8 +17,8 @@ import (
"strings"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// TODO - handle symlinks.
......@@ -32,7 +32,7 @@ func HeaderToFileInfo(out *fuse.Attr, h *tar.Header) {
}
type tarRoot struct {
nodefs.Inode
fs.Inode
rc io.ReadCloser
}
......@@ -77,8 +77,8 @@ func (r *tarRoot) OnAdd(ctx context.Context) {
ch := p.GetChild(comp)
if ch == nil {
ch = p.NewPersistentInode(ctx,
&nodefs.Inode{},
nodefs.StableAttr{Mode: syscall.S_IFDIR})
&fs.Inode{},
fs.StableAttr{Mode: syscall.S_IFDIR})
p.AddChild(comp, ch, false)
}
p = ch
......@@ -88,37 +88,37 @@ func (r *tarRoot) OnAdd(ctx context.Context) {
HeaderToFileInfo(&attr, hdr)
switch hdr.Typeflag {
case tar.TypeSymlink:
l := &nodefs.MemSymlink{
l := &fs.MemSymlink{
Data: []byte(hdr.Linkname),
}
l.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, l, nodefs.StableAttr{Mode: syscall.S_IFLNK}), false)
p.AddChild(base, r.NewPersistentInode(ctx, l, fs.StableAttr{Mode: syscall.S_IFLNK}), false)
case tar.TypeLink:
log.Println("don't know how to handle Typelink")
case tar.TypeChar:
rf := &nodefs.MemRegularFile{}
rf := &fs.MemRegularFile{}
rf.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, rf, nodefs.StableAttr{Mode: syscall.S_IFCHR}), false)
p.AddChild(base, r.NewPersistentInode(ctx, rf, fs.StableAttr{Mode: syscall.S_IFCHR}), false)
case tar.TypeBlock:
rf := &nodefs.MemRegularFile{}
rf := &fs.MemRegularFile{}
rf.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, rf, nodefs.StableAttr{Mode: syscall.S_IFBLK}), false)
p.AddChild(base, r.NewPersistentInode(ctx, rf, fs.StableAttr{Mode: syscall.S_IFBLK}), false)
case tar.TypeDir:
rf := &nodefs.MemRegularFile{}
rf := &fs.MemRegularFile{}
rf.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, rf, nodefs.StableAttr{Mode: syscall.S_IFDIR}), false)
p.AddChild(base, r.NewPersistentInode(ctx, rf, fs.StableAttr{Mode: syscall.S_IFDIR}), false)
case tar.TypeFifo:
rf := &nodefs.MemRegularFile{}
rf := &fs.MemRegularFile{}
rf.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, rf, nodefs.StableAttr{Mode: syscall.S_IFIFO}), false)
p.AddChild(base, r.NewPersistentInode(ctx, rf, fs.StableAttr{Mode: syscall.S_IFIFO}), false)
case tar.TypeReg, tar.TypeRegA:
df := &nodefs.MemRegularFile{
df := &fs.MemRegularFile{
Data: buf.Bytes(),
}
df.Attr = attr
p.AddChild(base, r.NewPersistentInode(ctx, df, nodefs.StableAttr{}), false)
p.AddChild(base, r.NewPersistentInode(ctx, df, fs.StableAttr{}), false)
default:
log.Printf("entry %q: unsupported type '%c'", hdr.Name, hdr.Typeflag)
}
......@@ -134,7 +134,7 @@ func (rc *readCloser) Close() error {
return rc.close()
}
func NewTarCompressedTree(name string, format string) (nodefs.InodeEmbedder, error) {
func NewTarCompressedTree(name string, format string) (fs.InodeEmbedder, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
......
......@@ -16,8 +16,8 @@ import (
"testing"
"time"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
)
var tarContents = map[string]string{
......@@ -69,9 +69,9 @@ func TestTar(t *testing.T) {
mnt := testutil.TempDir()
defer os.Remove(mnt)
opts := &nodefs.Options{}
opts.Debug = true
s, err := nodefs.Mount(mnt, root, opts)
opts := &fs.Options{}
opts.Debug = testutil.VerboseTest()
s, err := fs.Mount(mnt, root, opts)
if err != nil {
t.Errorf("Mount: %v", err)
}
......
......@@ -15,17 +15,17 @@ import (
"sync"
"syscall"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
type zipRoot struct {
nodefs.Inode
fs.Inode
zr *zip.ReadCloser
}
var _ = (nodefs.NodeOnAdder)((*zipRoot)(nil))
var _ = (fs.NodeOnAdder)((*zipRoot)(nil))
func (zr *zipRoot) OnAdd(ctx context.Context) {
for _, f := range zr.zr.File {
......@@ -41,20 +41,20 @@ func (zr *zipRoot) OnAdd(ctx context.Context) {
}
ch := p.GetChild(component)
if ch == nil {
ch = p.NewPersistentInode(ctx, &nodefs.Inode{},
nodefs.StableAttr{Mode: fuse.S_IFDIR})
ch = p.NewPersistentInode(ctx, &fs.Inode{},
fs.StableAttr{Mode: fuse.S_IFDIR})
p.AddChild(component, ch, true)
}
p = ch
}
ch := p.NewPersistentInode(ctx, &zipFile{file: f}, nodefs.StableAttr{})
ch := p.NewPersistentInode(ctx, &zipFile{file: f}, fs.StableAttr{})
p.AddChild(base, ch, true)
}
}
// NewZipTree creates a new file-system for the zip file named name.
func NewZipTree(name string) (nodefs.InodeEmbedder, error) {
func NewZipTree(name string) (fs.InodeEmbedder, error) {
r, err := zip.OpenReader(name)
if err != nil {
return nil, err
......@@ -65,19 +65,19 @@ func NewZipTree(name string) (nodefs.InodeEmbedder, error) {
// zipFile is a file read from a zip archive.
type zipFile struct {
nodefs.Inode
fs.Inode
file *zip.File
mu sync.Mutex
data []byte
}
var _ = (nodefs.NodeOpener)((*zipFile)(nil))
var _ = (nodefs.NodeGetattrer)((*zipFile)(nil))
var _ = (fs.NodeOpener)((*zipFile)(nil))
var _ = (fs.NodeGetattrer)((*zipFile)(nil))
// Getattr sets the minimum, which is the size. A more full-featured
// FS would also set timestamps and permissions.
func (zf *zipFile) Getattr(ctx context.Context, f nodefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
func (zf *zipFile) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
out.Mode = uint32(zf.file.Mode()) & 07777
out.Nlink = 1
out.Mtime = uint64(zf.file.ModTime().Unix())
......@@ -89,7 +89,7 @@ func (zf *zipFile) Getattr(ctx context.Context, f nodefs.FileHandle, out *fuse.A
}
// Open lazily unpacks zip data
func (zf *zipFile) Open(ctx context.Context, flags uint32) (nodefs.FileHandle, uint32, syscall.Errno) {
func (zf *zipFile) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
zf.mu.Lock()
defer zf.mu.Unlock()
if zf.data == nil {
......@@ -112,7 +112,7 @@ func (zf *zipFile) Open(ctx context.Context, flags uint32) (nodefs.FileHandle, u
}
// Read simply returns the data that was already unpacked in the Open call
func (zf *zipFile) Read(ctx context.Context, f nodefs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
func (zf *zipFile) Read(ctx context.Context, f fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
end := int(off) + len(dest)
if end > len(zf.data) {
end = len(zf.data)
......@@ -120,9 +120,9 @@ func (zf *zipFile) Read(ctx context.Context, f nodefs.FileHandle, dest []byte, o
return fuse.ReadResultData(zf.data[off:end]), 0
}
var _ = (nodefs.NodeOnAdder)((*zipRoot)(nil))
var _ = (fs.NodeOnAdder)((*zipRoot)(nil))
func NewArchiveFileSystem(name string) (root nodefs.InodeEmbedder, err error) {
func NewArchiveFileSystem(name string) (root fs.InodeEmbedder, err error) {
switch {
case strings.HasSuffix(name, ".zip"):
root, err = NewZipTree(name)
......
......@@ -13,9 +13,9 @@ import (
"testing"
"time"
"github.com/hanwen/go-fuse/fs"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
)
func testZipFile() string {
......@@ -34,9 +34,9 @@ func setupZipfs(t *testing.T) (mountPoint string, cleanup func()) {
}
mountPoint = testutil.TempDir()
opts := &nodefs.Options{}
opts := &fs.Options{}
opts.Debug = testutil.VerboseTest()
server, err := nodefs.Mount(mountPoint, root, opts)
server, err := fs.Mount(mountPoint, root, opts)
return mountPoint, func() {
server.Unmount()
......
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