From 2871268505f5b7d33d6365005fe8e368cd8f7984 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 22 Jul 2020 17:58:49 +0100 Subject: [PATCH] mount: change interface of mount commands to take VFS This is in preparation of being able to pass options to the rc command "mount/mount" --- backend/cache/cache_mount_unix_test.go | 5 +++- backend/cache/cache_mount_windows_test.go | 5 +++- cmd/cmount/fs.go | 7 +++--- cmd/cmount/mount.go | 28 +++++++++++------------ cmd/mount/fs.go | 7 +++--- cmd/mount/mount.go | 26 ++++++++++----------- cmd/mount2/fs.go | 7 +++--- cmd/mount2/mount.go | 23 ++++++++++--------- cmd/mountlib/mount.go | 9 +++++--- cmd/mountlib/rc.go | 5 +++- vfs/vfstest/fs.go | 6 +++-- vfs/vfstest_test.go | 6 ++--- 12 files changed, 72 insertions(+), 62 deletions(-) diff --git a/backend/cache/cache_mount_unix_test.go b/backend/cache/cache_mount_unix_test.go index b91f4bc9e..ea7e7bdbb 100644 --- a/backend/cache/cache_mount_unix_test.go +++ b/backend/cache/cache_mount_unix_test.go @@ -13,6 +13,8 @@ import ( "github.com/rclone/rclone/cmd/mount" "github.com/rclone/rclone/cmd/mountlib" "github.com/rclone/rclone/fs" + "github.com/rclone/rclone/vfs" + "github.com/rclone/rclone/vfs/vfsflags" "github.com/stretchr/testify/require" ) @@ -30,7 +32,8 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) { require.NoError(t, err) c, err := fuse.Mount(r.mntDir, options...) require.NoError(t, err) - filesys := mount.NewFS(f) + VFS := vfs.New(f, &vfsflags.Opt) + filesys := mount.NewFS(VFS) server := fusefs.New(c, nil) // Serve the mount point in the background returning error to errChan diff --git a/backend/cache/cache_mount_windows_test.go b/backend/cache/cache_mount_windows_test.go index 0210209dc..17c6a2c5a 100644 --- a/backend/cache/cache_mount_windows_test.go +++ b/backend/cache/cache_mount_windows_test.go @@ -14,6 +14,8 @@ import ( "github.com/rclone/rclone/cmd/cmount" "github.com/rclone/rclone/cmd/mountlib" "github.com/rclone/rclone/fs" + "github.com/rclone/rclone/vfs" + "github.com/rclone/rclone/vfs/vfsflags" "github.com/stretchr/testify/require" ) @@ -51,7 +53,8 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) { "--FileSystemName=rclone", } - fsys := cmount.NewFS(f) + VFS := vfs.New(f, &vfsflags.Opt) + fsys := cmount.NewFS(VFS) host := fuse.NewFileSystemHost(fsys) // Serve the mount point in the background returning error to errChan diff --git a/cmd/cmount/fs.go b/cmd/cmount/fs.go index 0a35edc59..c558eaf7a 100644 --- a/cmd/cmount/fs.go +++ b/cmd/cmount/fs.go @@ -17,7 +17,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/vfs" - "github.com/rclone/rclone/vfs/vfsflags" ) const fhUnset = ^uint64(0) @@ -32,10 +31,10 @@ type FS struct { } // NewFS makes a new FS -func NewFS(f fs.Fs) *FS { +func NewFS(VFS *vfs.VFS) *FS { fsys := &FS{ - VFS: vfs.New(f, &vfsflags.Opt), - f: f, + VFS: VFS, + f: VFS.Fs(), ready: make(chan (struct{})), } return fsys diff --git a/cmd/cmount/mount.go b/cmd/cmount/mount.go index 881542b2e..2ddb65f9c 100644 --- a/cmd/cmount/mount.go +++ b/cmd/cmount/mount.go @@ -23,7 +23,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/vfs" - "github.com/rclone/rclone/vfs/vfsflags" ) const ( @@ -45,7 +44,7 @@ func init() { } // mountOptions configures the options from the command line flags -func mountOptions(device string, mountpoint string) (options []string) { +func mountOptions(VFS *vfs.VFS, device string, mountpoint string) (options []string) { // Options options = []string{ "-o", "fsname=" + device, @@ -97,7 +96,7 @@ func mountOptions(device string, mountpoint string) (options []string) { if mountlib.DefaultPermissions { options = append(options, "-o", "default_permissions") } - if vfsflags.Opt.ReadOnly { + if VFS.Opt.ReadOnly { options = append(options, "-o", "ro") } if mountlib.WritebackCache { @@ -135,22 +134,23 @@ func waitFor(fn func() bool) (ok bool) { // // returns an error, and an error channel for the serve process to // report an error when fusermount is called. -func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, error) { +func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) { + f := VFS.Fs() fs.Debugf(f, "Mounting on %q", mountpoint) // Check the mountpoint - in Windows the mountpoint mustn't exist before the mount if runtime.GOOS != "windows" { fi, err := os.Stat(mountpoint) if err != nil { - return nil, nil, nil, errors.Wrap(err, "mountpoint") + return nil, nil, errors.Wrap(err, "mountpoint") } if !fi.IsDir() { - return nil, nil, nil, errors.New("mountpoint is not a directory") + return nil, nil, errors.New("mountpoint is not a directory") } } // Create underlying FS - fsys := NewFS(f) + fsys := NewFS(VFS) host := fuse.NewFileSystemHost(fsys) if usingReaddirPlus { host.SetCapReaddirPlus(true) @@ -158,7 +158,7 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er host.SetCapCaseInsensitive(f.Features().CaseInsensitive) // Create options - options := mountOptions(f.Name()+":"+f.Root(), mountpoint) + options := mountOptions(VFS, f.Name()+":"+f.Root(), mountpoint) fs.Debugf(f, "Mounting with options: %q", options) // Serve the mount point in the background returning error to errChan @@ -199,7 +199,7 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er select { case err := <-errChan: err = errors.Wrap(err, "mount stopped before calling Init") - return nil, nil, nil, err + return nil, nil, err case <-fsys.ready: } @@ -214,15 +214,15 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er } } - return fsys.VFS, errChan, unmount, nil + return errChan, unmount, nil } // Mount mounts the remote at mountpoint. // // If noModTime is set then it -func Mount(f fs.Fs, mountpoint string) error { +func Mount(VFS *vfs.VFS, mountpoint string) error { // Mount it - FS, errChan, unmount, err := mount(f, mountpoint) + errChan, unmount, err := mount(VFS, mountpoint) if err != nil { return errors.Wrap(err, "failed to mount FUSE fs") } @@ -248,9 +248,9 @@ waitloop: break waitloop // user sent SIGHUP to clear the cache case <-sigHup: - root, err := FS.Root() + root, err := VFS.Root() if err != nil { - fs.Errorf(f, "Error reading root: %v", err) + fs.Errorf(VFS.Fs(), "Error reading root: %v", err) } else { root.ForgetAll() } diff --git a/cmd/mount/fs.go b/cmd/mount/fs.go index 0292db99b..0fb384397 100644 --- a/cmd/mount/fs.go +++ b/cmd/mount/fs.go @@ -15,7 +15,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/vfs" - "github.com/rclone/rclone/vfs/vfsflags" ) // FS represents the top level filing system @@ -28,10 +27,10 @@ type FS struct { var _ fusefs.FS = (*FS)(nil) // NewFS makes a new FS -func NewFS(f fs.Fs) *FS { +func NewFS(VFS *vfs.VFS) *FS { fsys := &FS{ - VFS: vfs.New(f, &vfsflags.Opt), - f: f, + VFS: VFS, + f: VFS.Fs(), } return fsys } diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go index 34da286c6..7e34af28d 100644 --- a/cmd/mount/mount.go +++ b/cmd/mount/mount.go @@ -18,7 +18,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/vfs" - "github.com/rclone/rclone/vfs/vfsflags" ) func init() { @@ -28,7 +27,7 @@ func init() { } // mountOptions configures the options from the command line flags -func mountOptions(device string) (options []fuse.MountOption) { +func mountOptions(VFS *vfs.VFS, device string) (options []fuse.MountOption) { options = []fuse.MountOption{ fuse.MaxReadahead(uint32(mountlib.MaxReadAhead)), fuse.Subtype("rclone"), @@ -61,7 +60,7 @@ func mountOptions(device string) (options []fuse.MountOption) { if mountlib.DefaultPermissions { options = append(options, fuse.DefaultPermissions()) } - if vfsflags.Opt.ReadOnly { + if VFS.Opt.ReadOnly { options = append(options, fuse.ReadOnly()) } if mountlib.WritebackCache { @@ -85,14 +84,15 @@ func mountOptions(device string) (options []fuse.MountOption) { // // returns an error, and an error channel for the serve process to // report an error when fusermount is called. -func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, error) { +func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) { + f := VFS.Fs() fs.Debugf(f, "Mounting on %q", mountpoint) - c, err := fuse.Mount(mountpoint, mountOptions(f.Name()+":"+f.Root())...) + c, err := fuse.Mount(mountpoint, mountOptions(VFS, f.Name()+":"+f.Root())...) if err != nil { - return nil, nil, nil, err + return nil, nil, err } - filesys := NewFS(f) + filesys := NewFS(VFS) server := fusefs.New(c, nil) // Serve the mount point in the background returning error to errChan @@ -109,7 +109,7 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er // check if the mount process has an error to report <-c.Ready if err := c.MountError; err != nil { - return nil, nil, nil, err + return nil, nil, err } unmount := func() error { @@ -118,13 +118,13 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er return fuse.Unmount(mountpoint) } - return filesys.VFS, errChan, unmount, nil + return errChan, unmount, nil } // Mount mounts the remote at mountpoint. // // If noModTime is set then it -func Mount(f fs.Fs, mountpoint string) error { +func Mount(VFS *vfs.VFS, mountpoint string) error { if mountlib.DebugFUSE { fuse.Debug = func(msg interface{}) { fs.Debugf("fuse", "%v", msg) @@ -132,7 +132,7 @@ func Mount(f fs.Fs, mountpoint string) error { } // Mount it - FS, errChan, unmount, err := mount(f, mountpoint) + errChan, unmount, err := mount(VFS, mountpoint) if err != nil { return errors.Wrap(err, "failed to mount FUSE fs") } @@ -162,9 +162,9 @@ waitloop: break waitloop // user sent SIGHUP to clear the cache case <-sigHup: - root, err := FS.Root() + root, err := VFS.Root() if err != nil { - fs.Errorf(f, "Error reading root: %v", err) + fs.Errorf(VFS.Fs(), "Error reading root: %v", err) } else { root.ForgetAll() } diff --git a/cmd/mount2/fs.go b/cmd/mount2/fs.go index 0a24580e9..e359d79f6 100644 --- a/cmd/mount2/fs.go +++ b/cmd/mount2/fs.go @@ -14,7 +14,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/vfs" - "github.com/rclone/rclone/vfs/vfsflags" ) // FS represents the top level filing system @@ -24,10 +23,10 @@ type FS struct { } // NewFS creates a pathfs.FileSystem from the fs.Fs passed in -func NewFS(f fs.Fs) *FS { +func NewFS(VFS *vfs.VFS) *FS { fsys := &FS{ - VFS: vfs.New(f, &vfsflags.Opt), - f: f, + VFS: VFS, + f: VFS.Fs(), } return fsys } diff --git a/cmd/mount2/mount.go b/cmd/mount2/mount.go index b2b13d306..148abb25b 100644 --- a/cmd/mount2/mount.go +++ b/cmd/mount2/mount.go @@ -156,10 +156,11 @@ func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) { // // returns an error, and an error channel for the serve process to // report an error when fusermount is called. -func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, error) { +func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) { + f := VFS.Fs() fs.Debugf(f, "Mounting on %q", mountpoint) - fsys := NewFS(f) + fsys := NewFS(VFS) // nodeFsOpts := &fusefs.PathNodeFsOptions{ // ClientInodes: false, // Debug: mountlib.DebugFUSE, @@ -187,20 +188,20 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er root, err := fsys.Root() if err != nil { - return nil, nil, nil, err + return nil, nil, err } rawFS := fusefs.NewNodeFS(root, &opts) server, err := fuse.NewServer(rawFS, mountpoint, &opts.MountOptions) if err != nil { - return nil, nil, nil, err + return nil, nil, err } //mountOpts := &fuse.MountOptions{} //server, err := fusefs.Mount(mountpoint, fsys, &opts) // server, err := fusefs.Mount(mountpoint, root, &opts) // if err != nil { - // return nil, nil, nil, err + // return nil, nil, err // } umount := func() error { @@ -222,19 +223,19 @@ func mount(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, er fs.Debugf(f, "Waiting for the mount to start...") err = server.WaitMount() if err != nil { - return nil, nil, nil, err + return nil, nil, err } fs.Debugf(f, "Mount started") - return fsys.VFS, errs, umount, nil + return errs, umount, nil } // Mount mounts the remote at mountpoint. // // If noModTime is set then it -func Mount(f fs.Fs, mountpoint string) error { +func Mount(VFS *vfs.VFS, mountpoint string) error { // Mount it - vfs, errChan, unmount, err := mount(f, mountpoint) + errChan, unmount, err := mount(VFS, mountpoint) if err != nil { return errors.Wrap(err, "failed to mount FUSE fs") } @@ -263,9 +264,9 @@ waitloop: break waitloop // user sent SIGHUP to clear the cache case <-sigHup: - root, err := vfs.Root() + root, err := VFS.Root() if err != nil { - fs.Errorf(f, "Error reading root: %v", err) + fs.Errorf(VFS.Fs(), "Error reading root: %v", err) } else { root.ForgetAll() } diff --git a/cmd/mountlib/mount.go b/cmd/mountlib/mount.go index 6cb45f83a..c76abe637 100644 --- a/cmd/mountlib/mount.go +++ b/cmd/mountlib/mount.go @@ -43,7 +43,9 @@ type ( // UnmountFn is called to unmount the file system UnmountFn func() error // MountFn is called to mount the file system - MountFn func(f fs.Fs, mountpoint string) (*vfs.VFS, <-chan error, func() error, error) + MountFn func(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) + // MountBlockingFn is called to mount the file system and block + MountBlockingFn func(VFS *vfs.VFS, mountpoint string) error ) // Global constants @@ -106,7 +108,7 @@ func checkMountpointOverlap(root, mountpoint string) error { } // NewMountCommand makes a mount command with the given name and Mount function -func NewMountCommand(commandName string, hidden bool, Mount func(f fs.Fs, mountpoint string) error) *cobra.Command { +func NewMountCommand(commandName string, hidden bool, Mount MountBlockingFn) *cobra.Command { var commandDefinition = &cobra.Command{ Use: commandName + " remote:path /path/to/mountpoint", Hidden: hidden, @@ -346,7 +348,8 @@ be copied to the vfs cache before opening with --vfs-cache-mode full. } } - err := Mount(fdst, mountpoint) + VFS := vfs.New(fdst, &vfsflags.Opt) + err := Mount(VFS, mountpoint) if err != nil { log.Fatalf("Fatal error: %v", err) } diff --git a/cmd/mountlib/rc.go b/cmd/mountlib/rc.go index ebd545613..843380333 100644 --- a/cmd/mountlib/rc.go +++ b/cmd/mountlib/rc.go @@ -10,6 +10,8 @@ import ( "github.com/pkg/errors" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/rc" + "github.com/rclone/rclone/vfs" + "github.com/rclone/rclone/vfs/vfsflags" ) // MountInfo defines the configuration for a mount @@ -91,7 +93,8 @@ func mountRc(_ context.Context, in rc.Params) (out rc.Params, err error) { } if mountFns[mountType] != nil { - _, _, unmountFn, err := mountFns[mountType](fdst, mountPoint) + VFS := vfs.New(fdst, &vfsflags.Opt) + _, unmountFn, err := mountFns[mountType](VFS, mountPoint) if err != nil { log.Printf("mount FAILED: %v", err) diff --git a/vfs/vfstest/fs.go b/vfs/vfstest/fs.go index 11be32a34..cd90e199d 100644 --- a/vfs/vfstest/fs.go +++ b/vfs/vfstest/fs.go @@ -25,6 +25,7 @@ import ( "github.com/rclone/rclone/fstest" "github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs/vfscommon" + "github.com/rclone/rclone/vfs/vfsflags" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -33,7 +34,7 @@ type ( // UnmountFn is called to unmount the file system UnmountFn func() error // MountFn is called to mount the file system - MountFn func(f fs.Fs, mountpoint string) (vfs *vfs.VFS, unmountResult <-chan error, unmount func() error, err error) + MountFn func(VFS *vfs.VFS, mountpoint string) (unmountResult <-chan error, unmount func() error, err error) ) var ( @@ -176,7 +177,8 @@ found: func (r *Run) mount() { log.Printf("mount %q %q", r.fremote, r.mountPath) var err error - r.vfs, r.umountResult, r.umountFn, err = mountFn(r.fremote, r.mountPath) + r.vfs = vfs.New(r.fremote, &vfsflags.Opt) + r.umountResult, r.umountFn, err = mountFn(r.vfs, r.mountPath) if err != nil { log.Printf("mount FAILED: %v", err) r.skip = true diff --git a/vfs/vfstest_test.go b/vfs/vfstest_test.go index 35612c92e..fbf17f3b2 100644 --- a/vfs/vfstest_test.go +++ b/vfs/vfstest_test.go @@ -6,7 +6,6 @@ import ( "testing" _ "github.com/rclone/rclone/backend/all" // import all the backends - "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fstest" "github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs/vfstest" @@ -18,13 +17,12 @@ func TestFunctional(t *testing.T) { if *fstest.RemoteName != "" { t.Skip("Skip on non local") } - vfstest.RunTests(t, true, func(f fs.Fs, mountpoint string) (VFS *vfs.VFS, unmountResult <-chan error, unmount func() error, err error) { + vfstest.RunTests(t, true, func(VFS *vfs.VFS, mountpoint string) (unmountResult <-chan error, unmount func() error, err error) { unmountResultChan := make(chan (error), 1) unmount = func() error { unmountResultChan <- nil return nil } - VFS = vfs.New(f, nil) - return VFS, unmountResultChan, unmount, nil + return unmountResultChan, unmount, nil }) }