291 lines · 7.1 KB · Go
RawDownload
package mountlib import (	"context"	"log"	"sort"	"sync"	"time" 	"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/vfscommon"	"github.com/rclone/rclone/vfs/vfsflags") // MountInfo defines the configuration for a mounttype MountInfo struct {	unmountFn  UnmountFn	MountPoint string    `json:"MountPoint"`	MountedOn  time.Time `json:"MountedOn"`	Fs         string    `json:"Fs"`	MountOpt   *Options	VFSOpt     *vfscommon.Options} var (	// mutex to protect all the variables in this block	mountMu sync.Mutex	// Mount functions available	mountFns = map[string]MountFn{}	// Map of mounted path => MountInfo	liveMounts = map[string]MountInfo{}) // AddRc adds mount and unmount functionality to rcfunc AddRc(mountUtilName string, mountFunction MountFn) {	mountMu.Lock()	defer mountMu.Unlock()	// rcMount allows the mount command to be run from rc	mountFns[mountUtilName] = mountFunction} func init() {	rc.Add(rc.Call{		Path:         "mount/mount",		AuthRequired: true,		Fn:           mountRc,		Title:        "Create a new mount point",		Help: `rclone allows Linux, FreeBSD, macOS and Windows to mount any ofRclone's cloud storage systems as a file system with FUSE. If no mountType is provided, the priority is given as follows: 1. mount 2.cmount 3.mount2 This takes the following parameters - fs - a remote path to be mounted (required)- mountPoint: valid path on the local machine (required)- mountType: One of the values (mount, cmount, mount2) specifies the mount implementation to use- mountOpt: a JSON object with Mount options in.- vfsOpt: a JSON object with VFS options in. Eg     rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint    rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint mountType=mount    rclone rc mount/mount fs=TestDrive: mountPoint=/mnt/tmp vfsOpt='{"CacheMode": 2}' mountOpt='{"AllowOther": true}' The vfsOpt are as described in options/get and can be seen in the the"vfs" section when running and the mountOpt can be seen in the "mount" section.     rclone rc options/get`,	})} // mountRc allows the mount command to be run from rcfunc mountRc(ctx context.Context, in rc.Params) (out rc.Params, err error) {	mountPoint, err := in.GetString("mountPoint")	if err != nil {		return nil, err	} 	vfsOpt := vfsflags.Opt	err = in.GetStructMissingOK("vfsOpt", &vfsOpt)	if err != nil {		return nil, err	} 	mountOpt := Opt	err = in.GetStructMissingOK("mountOpt", &mountOpt)	if err != nil {		return nil, err	} 	mountType, err := in.GetString("mountType") 	mountMu.Lock()	defer mountMu.Unlock() 	if err != nil || mountType == "" {		if mountFns["mount"] != nil {			mountType = "mount"		} else if mountFns["cmount"] != nil {			mountType = "cmount"		} else if mountFns["mount2"] != nil {			mountType = "mount2"		}	} 	// Get Fs.fs to be mounted from fs parameter in the params	fdst, err := rc.GetFs(ctx, in)	if err != nil {		return nil, err	} 	if mountFns[mountType] != nil {		VFS := vfs.New(fdst, &vfsOpt)		_, unmountFn, err := mountFns[mountType](VFS, mountPoint, &mountOpt) 		if err != nil {			log.Printf("mount FAILED: %v", err)			return nil, err		}		// Add mount to list if mount point was successfully created		liveMounts[mountPoint] = MountInfo{			unmountFn:  unmountFn,			MountedOn:  time.Now(),			Fs:         fdst.Name(),			MountPoint: mountPoint,			VFSOpt:     &vfsOpt,			MountOpt:   &mountOpt,		} 		fs.Debugf(nil, "Mount for %s created at %s using %s", fdst.String(), mountPoint, mountType)		return nil, nil	}	return nil, errors.New("Mount Option specified is not registered, or is invalid")} func init() {	rc.Add(rc.Call{		Path:         "mount/unmount",		AuthRequired: true,		Fn:           unMountRc,		Title:        "Unmount selected active mount",		Help: `rclone allows Linux, FreeBSD, macOS and Windows tomount any of Rclone's cloud storage systems as a file system withFUSE. This takes the following parameters - mountPoint: valid path on the local machine where the mount was created (required) Eg     rclone rc mount/unmount mountPoint=/home/<user>/mountPoint`,	})} // unMountRc allows the umount command to be run from rcfunc unMountRc(_ context.Context, in rc.Params) (out rc.Params, err error) {	mountPoint, err := in.GetString("mountPoint")	if err != nil {		return nil, err	}	mountMu.Lock()	defer mountMu.Unlock()	err = performUnMount(mountPoint)	if err != nil {		return nil, err	}	return nil, nil} func init() {	rc.Add(rc.Call{		Path:         "mount/types",		AuthRequired: true,		Fn:           mountTypesRc,		Title:        "Show all possible mount types",		Help: `This shows all possible mount types and returns them as a list. This takes no parameters and returns - mountTypes: list of mount types The mount types are strings like "mount", "mount2", "cmount" and canbe passed to mount/mount as the mountType parameter. Eg     rclone rc mount/types`,	})} // mountTypesRc returns a list of available mount types.func mountTypesRc(_ context.Context, in rc.Params) (out rc.Params, err error) {	var mountTypes = []string{}	mountMu.Lock()	defer mountMu.Unlock()	for mountType := range mountFns {		mountTypes = append(mountTypes, mountType)	}	sort.Strings(mountTypes)	return rc.Params{		"mountTypes": mountTypes,	}, nil} func init() {	rc.Add(rc.Call{		Path:         "mount/listmounts",		AuthRequired: true,		Fn:           listMountsRc,		Title:        "Show current mount points",		Help: `This shows currently mounted points, which can be used for performing an unmount This takes no parameters and returns - mountPoints: list of current mount points Eg     rclone rc mount/listmounts`,	})} // listMountsRc returns a list of current mountsfunc listMountsRc(_ context.Context, in rc.Params) (out rc.Params, err error) {	var mountTypes = []MountInfo{}	mountMu.Lock()	defer mountMu.Unlock()	for _, a := range liveMounts {		mountTypes = append(mountTypes, a)	}	return rc.Params{		"mountPoints": mountTypes,	}, nil} func init() {	rc.Add(rc.Call{		Path:         "mount/unmountall",		AuthRequired: true,		Fn:           unmountAll,		Title:        "Show current mount points",		Help: `This shows currently mounted points, which can be used for performing an unmount This takes no parameters and returns error if unmount does not succeed. Eg     rclone rc mount/unmountall`,	})} // unmountAll unmounts all the created mountsfunc unmountAll(_ context.Context, in rc.Params) (out rc.Params, err error) {	mountMu.Lock()	defer mountMu.Unlock()	for key, mountInfo := range liveMounts {		err = performUnMount(mountInfo.MountPoint)		if err != nil {			fs.Debugf(nil, "Couldn't unmount : %s", key)			return nil, err		}	}	return nil, nil} // performUnMount unmounts the specified mountPointfunc performUnMount(mountPoint string) (err error) {	mountInfo, ok := liveMounts[mountPoint]	if ok {		err := mountInfo.unmountFn()		if err != nil {			return err		}		delete(liveMounts, mountPoint)	} else {		return errors.New("mount not found")	}	return nil}