diff --git a/example/loopback/main.go b/example/loopback/main.go index 612110a08..76feb890f 100644 --- a/example/loopback/main.go +++ b/example/loopback/main.go @@ -16,7 +16,6 @@ import ( "path" "runtime/pprof" "syscall" - "time" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" @@ -92,24 +91,16 @@ func main() { log.Fatalf("NewLoopbackRoot(%s): %v\n", orig, err) } - sec := time.Second - opts := &fs.Options{ - // The timeout options are to be compatible with libfuse defaults, - // making benchmarking easier. - AttrTimeout: &sec, - EntryTimeout: &sec, - - NullPermissions: true, // Leave file permissions on "000" files as-is - - MountOptions: fuse.MountOptions{ - AllowOther: *other, - Debug: *debug, - DirectMount: *directmount, - DirectMountStrict: *directmountstrict, - IDMappedMount: *idmap, - FsName: orig, // First column in "df -T": original dir - Name: "loopback", // Second column in "df -T" will be shown as "fuse." + Name - }, + opts := fs.DefaultOptions() + opts.NullPermissions = true // Leave file permissions on "000" files as-is + opts.MountOptions = fuse.MountOptions{ + AllowOther: *other, + Debug: *debug, + DirectMount: *directmount, + DirectMountStrict: *directmountstrict, + IDMappedMount: *idmap, + FsName: orig, // First column in "df -T": original dir + Name: "loopback", // Second column in "df -T" will be shown as "fuse." + Name } if opts.AllowOther { // Make the kernel check file permissions for us diff --git a/example/multizip/main.go b/example/multizip/main.go index f3797dd61..bf223211b 100644 --- a/example/multizip/main.go +++ b/example/multizip/main.go @@ -13,7 +13,6 @@ import ( "fmt" "os" "path/filepath" - "time" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/zipfs" @@ -30,13 +29,9 @@ func main() { } root := &zipfs.MultiZipFs{} - sec := time.Second - opts := fs.Options{ - EntryTimeout: &sec, - AttrTimeout: &sec, - } + opts := fs.DefaultOptions() opts.Debug = *debug - server, err := fs.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) diff --git a/example/winfs/main.go b/example/winfs/main.go index 5be330f02..03a314a69 100644 --- a/example/winfs/main.go +++ b/example/winfs/main.go @@ -142,11 +142,7 @@ func main() { Path: orig, } - sec := time.Second - opts := &fs.Options{ - AttrTimeout: &sec, - EntryTimeout: &sec, - } + opts := fs.DefaultOptions() opts.Debug = *debug opts.MountOptions.Options = append(opts.MountOptions.Options, "fsname="+orig) opts.MountOptions.Name = "winfs" diff --git a/fs/bridge.go b/fs/bridge.go index fa5343cba..7edf9e868 100644 --- a/fs/bridge.go +++ b/fs/bridge.go @@ -10,7 +10,6 @@ import ( "runtime/debug" "sync" "syscall" - "time" "github.com/hanwen/go-fuse/v2/fuse" "github.com/hanwen/go-fuse/v2/internal" @@ -286,24 +285,22 @@ func (b *rawBridge) setAttrTimeout(out *fuse.AttrOut) { // NewNodeFS creates a node based filesystem based on the // InodeEmbedder instance for the root of the tree. +// If nil is given as opts, default settings are +// applied, which are 1 second entry and attribute timeout. func NewNodeFS(root InodeEmbedder, opts *Options) fuse.RawFileSystem { + if opts == nil { + opts = DefaultOptions() + } bridge := &rawBridge{ automaticIno: opts.FirstAutomaticIno, server: opts.ServerCallbacks, nextNodeId: 2, // the root node has nodeid 1 stableAttrs: make(map[StableAttr]*Inode), + options: *opts, } if bridge.automaticIno == 0 { - bridge.automaticIno = 1 << 63 - } - - if opts != nil { - bridge.options = *opts - } else { - oneSec := time.Second - bridge.options.EntryTimeout = &oneSec - bridge.options.AttrTimeout = &oneSec + bridge.automaticIno = DefaultOptions().FirstAutomaticIno } stableAttr := StableAttr{ diff --git a/fs/bridge_test.go b/fs/bridge_test.go index 4ee6a500c..6004f1bb5 100644 --- a/fs/bridge_test.go +++ b/fs/bridge_test.go @@ -279,3 +279,8 @@ func TestNegativeLookupCache(t *testing.T) { } } } + +// NewNodeFS should not crash with opts=nil +func TestNewNodeFSNilOpts(t *testing.T) { + NewNodeFS(&Inode{}, nil) +} diff --git a/fs/default.go b/fs/default.go index e2f7a67c2..897a9b598 100644 --- a/fs/default.go +++ b/fs/default.go @@ -3,3 +3,22 @@ // license that can be found in the LICENSE file. package fs + +import ( + "time" +) + +// DefaultOptions returns the default Options that are used when +// nil is passed for *Options. +// +// When you do want to set something in Options, get the defaults +// from this function and adjust as required. +func DefaultOptions() *Options { + oneSec := time.Second + return &Options{ + // libfuse also uses one second per default + EntryTimeout: &oneSec, + AttrTimeout: &oneSec, + FirstAutomaticIno: 1 << 63, + } +} diff --git a/fs/dir_test.go b/fs/dir_test.go index 4144a4832..666a04b03 100644 --- a/fs/dir_test.go +++ b/fs/dir_test.go @@ -244,8 +244,7 @@ func (n *syncNode) OpendirHandle(ctx context.Context, flags uint32) (FileHandle, func TestFsyncDir(t *testing.T) { root := &syncNode{} - opts := Options{} - mnt, _ := testMount(t, root, &opts) + mnt, _ := testMount(t, root, nil) fd, err := syscall.Open(mnt, syscall.O_DIRECTORY, 0) if err != nil { diff --git a/fs/interrupt_test.go b/fs/interrupt_test.go index 3d7ae99a8..77994f708 100644 --- a/fs/interrupt_test.go +++ b/fs/interrupt_test.go @@ -54,11 +54,7 @@ func (o *interruptOps) Open(ctx context.Context, flags uint32) (FileHandle, uint func TestInterrupt(t *testing.T) { root := &interruptRoot{} - oneSec := time.Second - mntDir, server := testMount(t, root, &Options{ - EntryTimeout: &oneSec, - AttrTimeout: &oneSec, - }) + mntDir, server := testMount(t, root, DefaultOptions()) cmd := exec.Command("cat", mntDir+"/file") if err := cmd.Start(); err != nil { diff --git a/fs/loopback_linux_test.go b/fs/loopback_linux_test.go index 84ec4b221..faa36e308 100644 --- a/fs/loopback_linux_test.go +++ b/fs/loopback_linux_test.go @@ -10,7 +10,6 @@ import ( "sync" "syscall" "testing" - "time" "unsafe" "github.com/hanwen/go-fuse/v2/fuse" @@ -287,11 +286,7 @@ func TestParallelDiropsHang(t *testing.T) { if err != nil { t.Fatalf("NewLoopbackRoot(%s): %v\n", orig, err) } - sec := time.Second - opts := &Options{ - AttrTimeout: &sec, - EntryTimeout: &sec, - } + opts := DefaultOptions() opts.Debug = testutil.VerboseTest() rawFS := NewNodeFS(loopbackRoot, opts) diff --git a/fs/mount.go b/fs/mount.go index 187d6e28a..2a84b3bd5 100644 --- a/fs/mount.go +++ b/fs/mount.go @@ -5,8 +5,6 @@ package fs import ( - "time" - "github.com/hanwen/go-fuse/v2/fuse" ) @@ -15,16 +13,12 @@ import ( // fuse.NewServer. If nil is given as options, default settings are // applied, which are 1 second entry and attribute timeout. func Mount(dir string, root InodeEmbedder, options *Options) (*fuse.Server, error) { - if options == nil { - oneSec := time.Second - options = &Options{ - EntryTimeout: &oneSec, - AttrTimeout: &oneSec, - } - } - rawFS := NewNodeFS(root, options) - server, err := fuse.NewServer(rawFS, dir, &options.MountOptions) + var mountOptions *fuse.MountOptions + if options != nil { + mountOptions = &options.MountOptions + } + server, err := fuse.NewServer(rawFS, dir, mountOptions) if err != nil { return nil, err } diff --git a/fs/windows_example_test.go b/fs/windows_example_test.go index cb076c966..7c51c4872 100644 --- a/fs/windows_example_test.go +++ b/fs/windows_example_test.go @@ -10,7 +10,6 @@ import ( "log" "sync" "syscall" - "time" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" @@ -107,11 +106,7 @@ func Example_loopbackReuse() { Path: origDir, } - sec := time.Second - opts := &fs.Options{ - AttrTimeout: &sec, - EntryTimeout: &sec, - } + opts := fs.DefaultOptions() root := &WindowsNode{ LoopbackNode: &fs.LoopbackNode{