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"
This commit is contained in:
Nick Craig-Wood 2020-07-22 17:58:49 +01:00
parent 744828a4de
commit 2871268505
12 changed files with 72 additions and 62 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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

View File

@ -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
})
}