e2afd00118
See: #6234
225 lines
6.1 KiB
Go
225 lines
6.1 KiB
Go
//go:build linux || (darwin && amd64)
|
|
// +build linux darwin,amd64
|
|
|
|
// Package mount2 implements a FUSE mounting system for rclone remotes.
|
|
package mount2
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"runtime"
|
|
|
|
fusefs "github.com/hanwen/go-fuse/v2/fs"
|
|
"github.com/hanwen/go-fuse/v2/fuse"
|
|
"github.com/rclone/rclone/cmd/mountlib"
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/vfs"
|
|
)
|
|
|
|
func init() {
|
|
mountlib.NewMountCommand("mount2", true, mount)
|
|
mountlib.AddRc("mount2", mount)
|
|
}
|
|
|
|
// mountOptions configures the options from the command line flags
|
|
//
|
|
// man mount.fuse for more info and note the -o flag for other options
|
|
func mountOptions(fsys *FS, f fs.Fs, opt *mountlib.Options) (mountOpts *fuse.MountOptions) {
|
|
mountOpts = &fuse.MountOptions{
|
|
AllowOther: fsys.opt.AllowOther,
|
|
FsName: opt.DeviceName,
|
|
Name: "rclone",
|
|
DisableXAttrs: true,
|
|
Debug: fsys.opt.DebugFUSE,
|
|
MaxReadAhead: int(fsys.opt.MaxReadAhead),
|
|
|
|
// RememberInodes: true,
|
|
// SingleThreaded: true,
|
|
|
|
/*
|
|
AllowOther bool
|
|
|
|
// Options are passed as -o string to fusermount.
|
|
Options []string
|
|
|
|
// Default is _DEFAULT_BACKGROUND_TASKS, 12. This numbers
|
|
// controls the allowed number of requests that relate to
|
|
// async I/O. Concurrency for synchronous I/O is not limited.
|
|
MaxBackground int
|
|
|
|
// Write size to use. If 0, use default. This number is
|
|
// capped at the kernel maximum.
|
|
MaxWrite int
|
|
|
|
// Max read ahead to use. If 0, use default. This number is
|
|
// capped at the kernel maximum.
|
|
MaxReadAhead int
|
|
|
|
// If IgnoreSecurityLabels is set, all security related xattr
|
|
// requests will return NO_DATA without passing through the
|
|
// user defined filesystem. You should only set this if you
|
|
// file system implements extended attributes, and you are not
|
|
// interested in security labels.
|
|
IgnoreSecurityLabels bool // ignoring labels should be provided as a fusermount mount option.
|
|
|
|
// If RememberInodes is set, we will never forget inodes.
|
|
// This may be useful for NFS.
|
|
RememberInodes bool
|
|
|
|
// Values shown in "df -T" and friends
|
|
// First column, "Filesystem"
|
|
FsName string
|
|
|
|
// Second column, "Type", will be shown as "fuse." + Name
|
|
Name string
|
|
|
|
// If set, wrap the file system in a single-threaded locking wrapper.
|
|
SingleThreaded bool
|
|
|
|
// If set, return ENOSYS for Getxattr calls, so the kernel does not issue any
|
|
// Xattr operations at all.
|
|
DisableXAttrs bool
|
|
|
|
// If set, print debugging information.
|
|
Debug bool
|
|
|
|
// If set, ask kernel to forward file locks to FUSE. If using,
|
|
// you must implement the GetLk/SetLk/SetLkw methods.
|
|
EnableLocks bool
|
|
|
|
// If set, ask kernel not to do automatic data cache invalidation.
|
|
// The filesystem is fully responsible for invalidating data cache.
|
|
ExplicitDataCacheControl bool
|
|
*/
|
|
|
|
}
|
|
var opts []string
|
|
// FIXME doesn't work opts = append(opts, fmt.Sprintf("max_readahead=%d", maxReadAhead))
|
|
if fsys.opt.AllowOther {
|
|
opts = append(opts, "allow_other")
|
|
}
|
|
if fsys.opt.AllowRoot {
|
|
opts = append(opts, "allow_root")
|
|
}
|
|
if fsys.opt.DefaultPermissions {
|
|
opts = append(opts, "default_permissions")
|
|
}
|
|
if fsys.VFS.Opt.ReadOnly {
|
|
opts = append(opts, "ro")
|
|
}
|
|
if fsys.opt.WritebackCache {
|
|
log.Printf("FIXME --write-back-cache not supported")
|
|
// FIXME opts = append(opts,fuse.WritebackCache())
|
|
}
|
|
// Some OS X only options
|
|
if runtime.GOOS == "darwin" {
|
|
opts = append(opts,
|
|
// VolumeName sets the volume name shown in Finder.
|
|
fmt.Sprintf("volname=%s", opt.VolumeName),
|
|
|
|
// NoAppleXattr makes OSXFUSE disallow extended attributes with the
|
|
// prefix "com.apple.". This disables persistent Finder state and
|
|
// other such information.
|
|
"noapplexattr",
|
|
|
|
// NoAppleDouble makes OSXFUSE disallow files with names used by OS X
|
|
// to store extended attributes on file systems that do not support
|
|
// them natively.
|
|
//
|
|
// Such file names are:
|
|
//
|
|
// ._*
|
|
// .DS_Store
|
|
"noappledouble",
|
|
)
|
|
}
|
|
mountOpts.Options = opts
|
|
return mountOpts
|
|
}
|
|
|
|
// mount the file system
|
|
//
|
|
// The mount point will be ready when this returns.
|
|
//
|
|
// returns an error, and an error channel for the serve process to
|
|
// report an error when fusermount is called.
|
|
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error, func() error, error) {
|
|
f := VFS.Fs()
|
|
if err := mountlib.CheckOverlap(f, mountpoint); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := mountlib.CheckAllowNonEmpty(mountpoint, opt); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
fs.Debugf(f, "Mounting on %q", mountpoint)
|
|
|
|
fsys := NewFS(VFS, opt)
|
|
|
|
// nodeFsOpts := &fusefs.PathNodeFsOptions{
|
|
// ClientInodes: false,
|
|
// Debug: mountlib.DebugFUSE,
|
|
// }
|
|
// nodeFs := fusefs.NewPathNodeFs(fsys, nodeFsOpts)
|
|
|
|
//mOpts := fusefs.NewOptions() // default options
|
|
// FIXME
|
|
// mOpts.EntryTimeout = 10 * time.Second
|
|
// mOpts.AttrTimeout = 10 * time.Second
|
|
// mOpts.NegativeTimeout = 10 * time.Second
|
|
//mOpts.Debug = mountlib.DebugFUSE
|
|
|
|
//conn := fusefs.NewFileSystemConnector(nodeFs.Root(), mOpts)
|
|
mountOpts := mountOptions(fsys, f, opt)
|
|
|
|
// FIXME fill out
|
|
opts := fusefs.Options{
|
|
MountOptions: *mountOpts,
|
|
EntryTimeout: &opt.AttrTimeout,
|
|
AttrTimeout: &opt.AttrTimeout,
|
|
// UID
|
|
// GID
|
|
}
|
|
|
|
root, err := fsys.Root()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
rawFS := fusefs.NewNodeFS(root, &opts)
|
|
server, err := fuse.NewServer(rawFS, mountpoint, &opts.MountOptions)
|
|
if err != nil {
|
|
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, err
|
|
// }
|
|
|
|
umount := func() error {
|
|
// Shutdown the VFS
|
|
fsys.VFS.Shutdown()
|
|
return server.Unmount()
|
|
}
|
|
|
|
// serverSettings := server.KernelSettings()
|
|
// fs.Debugf(f, "Server settings %+v", serverSettings)
|
|
|
|
// Serve the mount point in the background returning error to errChan
|
|
errs := make(chan error, 1)
|
|
go func() {
|
|
server.Serve()
|
|
errs <- nil
|
|
}()
|
|
|
|
fs.Debugf(f, "Waiting for the mount to start...")
|
|
err = server.WaitMount()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
fs.Debugf(f, "Mount started")
|
|
return errs, umount, nil
|
|
}
|