mount: change interface of mount commands to take mount options

This is in preparation of being able to pass mount options to the rc
command "mount/mount"
This commit is contained in:
Nick Craig-Wood 2020-07-23 17:17:01 +01:00
parent e1d34ef427
commit 0272a7f405
15 changed files with 166 additions and 141 deletions

View File

@ -21,7 +21,7 @@ import (
func (r *run) mountFs(t *testing.T, f fs.Fs) {
device := f.Name() + ":" + f.Root()
var options = []fuse.MountOption{
fuse.MaxReadahead(uint32(mountlib.MaxReadAhead)),
fuse.MaxReadahead(uint32(mountlib.Opt.MaxReadAhead)),
fuse.Subtype("rclone"),
fuse.FSName(device), fuse.VolumeName(device),
fuse.NoAppleDouble(),
@ -33,7 +33,7 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) {
c, err := fuse.Mount(r.mntDir, options...)
require.NoError(t, err)
VFS := vfs.New(f, &vfsflags.Opt)
filesys := mount.NewFS(VFS)
filesys := mount.NewFS(VFS, &mountlib.Opt)
server := fusefs.New(c, nil)
// Serve the mount point in the background returning error to errChan

View File

@ -41,7 +41,7 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) {
options := []string{
"-o", "fsname=" + device,
"-o", "subtype=rclone",
"-o", fmt.Sprintf("max_readahead=%d", mountlib.MaxReadAhead),
"-o", fmt.Sprintf("max_readahead=%d", mountlib.Opt.MaxReadAhead),
"-o", "uid=-1",
"-o", "gid=-1",
"-o", "allow_other",

View File

@ -38,29 +38,29 @@ func init() {
}
// mountOptions configures the options from the command line flags
func mountOptions(VFS *vfs.VFS, device string, mountpoint string) (options []string) {
func mountOptions(VFS *vfs.VFS, device string, mountpoint string, opt *mountlib.Options) (options []string) {
// Options
options = []string{
"-o", "fsname=" + device,
"-o", "subtype=rclone",
"-o", fmt.Sprintf("max_readahead=%d", mountlib.MaxReadAhead),
"-o", fmt.Sprintf("attr_timeout=%g", mountlib.AttrTimeout.Seconds()),
"-o", fmt.Sprintf("max_readahead=%d", opt.MaxReadAhead),
"-o", fmt.Sprintf("attr_timeout=%g", opt.AttrTimeout.Seconds()),
// This causes FUSE to supply O_TRUNC with the Open
// call which is more efficient for cmount. However
// it does not work with cgofuse on Windows with
// WinFSP so cmount must work with or without it.
"-o", "atomic_o_trunc",
}
if mountlib.DebugFUSE {
if opt.DebugFUSE {
options = append(options, "-o", "debug")
}
// OSX options
if runtime.GOOS == "darwin" {
if mountlib.NoAppleDouble {
if opt.NoAppleDouble {
options = append(options, "-o", "noappledouble")
}
if mountlib.NoAppleXattr {
if opt.NoAppleXattr {
options = append(options, "-o", "noapplexattr")
}
}
@ -74,35 +74,35 @@ func mountOptions(VFS *vfs.VFS, device string, mountpoint string) (options []str
}
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
if mountlib.VolumeName != "" {
options = append(options, "-o", "volname="+mountlib.VolumeName)
if opt.VolumeName != "" {
options = append(options, "-o", "volname="+opt.VolumeName)
}
}
if mountlib.AllowNonEmpty {
if opt.AllowNonEmpty {
options = append(options, "-o", "nonempty")
}
if mountlib.AllowOther {
if opt.AllowOther {
options = append(options, "-o", "allow_other")
}
if mountlib.AllowRoot {
if opt.AllowRoot {
options = append(options, "-o", "allow_root")
}
if mountlib.DefaultPermissions {
if opt.DefaultPermissions {
options = append(options, "-o", "default_permissions")
}
if VFS.Opt.ReadOnly {
options = append(options, "-o", "ro")
}
if mountlib.WritebackCache {
if opt.WritebackCache {
// FIXME? options = append(options, "-o", WritebackCache())
}
if mountlib.DaemonTimeout != 0 {
options = append(options, "-o", fmt.Sprintf("daemon_timeout=%d", int(mountlib.DaemonTimeout.Seconds())))
if opt.DaemonTimeout != 0 {
options = append(options, "-o", fmt.Sprintf("daemon_timeout=%d", int(opt.DaemonTimeout.Seconds())))
}
for _, option := range mountlib.ExtraOptions {
for _, option := range opt.ExtraOptions {
options = append(options, "-o", option)
}
for _, option := range mountlib.ExtraFlags {
for _, option := range opt.ExtraFlags {
options = append(options, option)
}
return options
@ -128,7 +128,7 @@ 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(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) {
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error, func() error, error) {
f := VFS.Fs()
fs.Debugf(f, "Mounting on %q", mountpoint)
@ -152,7 +152,7 @@ func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error)
host.SetCapCaseInsensitive(f.Features().CaseInsensitive)
// Create options
options := mountOptions(VFS, f.Name()+":"+f.Root(), mountpoint)
options := mountOptions(VFS, f.Name()+":"+f.Root(), mountpoint, opt)
fs.Debugf(f, "Mounting with options: %q", options)
// Serve the mount point in the background returning error to errChan

View File

@ -19,6 +19,7 @@ import (
// Dir represents a directory entry
type Dir struct {
*vfs.Dir
fsys *FS
}
// Check interface satisfied
@ -27,7 +28,7 @@ var _ fusefs.Node = (*Dir)(nil)
// Attr updates the attributes of a directory
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
defer log.Trace(d, "")("attr=%+v, err=%v", a, &err)
a.Valid = mountlib.AttrTimeout
a.Valid = d.fsys.opt.AttrTimeout
a.Gid = d.VFS().Opt.GID
a.Uid = d.VFS().Opt.UID
a.Mode = os.ModeDir | d.VFS().Opt.DirPerms
@ -75,7 +76,7 @@ func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.Lo
if err != nil {
return nil, translateError(err)
}
resp.EntryValid = mountlib.AttrTimeout
resp.EntryValid = d.fsys.opt.AttrTimeout
// Check the mnode to see if it has a fuse Node cached
// We must return the same fuse nodes for vfs Nodes
node, ok := mnode.Sys().(fusefs.Node)
@ -84,9 +85,9 @@ func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.Lo
}
switch x := mnode.(type) {
case *vfs.File:
node = &File{x}
node = &File{x, d.fsys}
case *vfs.Dir:
node = &Dir{x}
node = &Dir{x, d.fsys}
default:
panic("bad type")
}
@ -139,7 +140,7 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr
if err != nil {
return nil, nil, translateError(err)
}
node = &File{file}
node = &File{file, d.fsys}
file.SetSys(node) // cache the FUSE node for later
return node, &FileHandle{fh}, err
}
@ -153,7 +154,7 @@ func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (node fusefs.No
if err != nil {
return nil, translateError(err)
}
node = &Dir{dir}
node = &Dir{dir, d.fsys}
dir.SetSys(node) // cache the FUSE node for later
return node, nil
}

View File

@ -8,7 +8,6 @@ import (
"bazil.org/fuse"
fusefs "bazil.org/fuse/fs"
"github.com/rclone/rclone/cmd/mountlib"
"github.com/rclone/rclone/fs/log"
"github.com/rclone/rclone/vfs"
)
@ -16,6 +15,7 @@ import (
// File represents a file
type File struct {
*vfs.File
fsys *FS
}
// Check interface satisfied
@ -24,7 +24,7 @@ var _ fusefs.Node = (*File)(nil)
// Attr fills out the attributes for the file
func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) {
defer log.Trace(f, "")("a=%+v, err=%v", a, &err)
a.Valid = mountlib.AttrTimeout
a.Valid = f.fsys.opt.AttrTimeout
modTime := f.File.ModTime()
Size := uint64(f.File.Size())
Blocks := (Size + 511) / 512

View File

@ -20,17 +20,19 @@ import (
// FS represents the top level filing system
type FS struct {
*vfs.VFS
f fs.Fs
f fs.Fs
opt *mountlib.Options
}
// Check interface satisfied
var _ fusefs.FS = (*FS)(nil)
// NewFS makes a new FS
func NewFS(VFS *vfs.VFS) *FS {
func NewFS(VFS *vfs.VFS, opt *mountlib.Options) *FS {
fsys := &FS{
VFS: VFS,
f: VFS.Fs(),
opt: opt,
}
return fsys
}
@ -42,7 +44,7 @@ func (f *FS) Root() (node fusefs.Node, err error) {
if err != nil {
return nil, translateError(err)
}
return &Dir{root}, nil
return &Dir{root, f}, nil
}
// Check interface satisfied

View File

@ -20,52 +20,52 @@ func init() {
}
// mountOptions configures the options from the command line flags
func mountOptions(VFS *vfs.VFS, device string) (options []fuse.MountOption) {
func mountOptions(VFS *vfs.VFS, device string, opt *mountlib.Options) (options []fuse.MountOption) {
options = []fuse.MountOption{
fuse.MaxReadahead(uint32(mountlib.MaxReadAhead)),
fuse.MaxReadahead(uint32(opt.MaxReadAhead)),
fuse.Subtype("rclone"),
fuse.FSName(device),
fuse.VolumeName(mountlib.VolumeName),
fuse.VolumeName(opt.VolumeName),
// Options from benchmarking in the fuse module
//fuse.MaxReadahead(64 * 1024 * 1024),
//fuse.WritebackCache(),
}
if mountlib.AsyncRead {
if opt.AsyncRead {
options = append(options, fuse.AsyncRead())
}
if mountlib.NoAppleDouble {
if opt.NoAppleDouble {
options = append(options, fuse.NoAppleDouble())
}
if mountlib.NoAppleXattr {
if opt.NoAppleXattr {
options = append(options, fuse.NoAppleXattr())
}
if mountlib.AllowNonEmpty {
if opt.AllowNonEmpty {
options = append(options, fuse.AllowNonEmptyMount())
}
if mountlib.AllowOther {
if opt.AllowOther {
options = append(options, fuse.AllowOther())
}
if mountlib.AllowRoot {
if opt.AllowRoot {
// options = append(options, fuse.AllowRoot())
fs.Errorf(nil, "Ignoring --allow-root. Support has been removed upstream - see https://github.com/bazil/fuse/issues/144 for more info")
}
if mountlib.DefaultPermissions {
if opt.DefaultPermissions {
options = append(options, fuse.DefaultPermissions())
}
if VFS.Opt.ReadOnly {
options = append(options, fuse.ReadOnly())
}
if mountlib.WritebackCache {
if opt.WritebackCache {
options = append(options, fuse.WritebackCache())
}
if mountlib.DaemonTimeout != 0 {
options = append(options, fuse.DaemonTimeout(fmt.Sprint(int(mountlib.DaemonTimeout.Seconds()))))
if opt.DaemonTimeout != 0 {
options = append(options, fuse.DaemonTimeout(fmt.Sprint(int(opt.DaemonTimeout.Seconds()))))
}
if len(mountlib.ExtraOptions) > 0 {
if len(opt.ExtraOptions) > 0 {
fs.Errorf(nil, "-o/--option not supported with this FUSE backend")
}
if len(mountlib.ExtraFlags) > 0 {
if len(opt.ExtraFlags) > 0 {
fs.Errorf(nil, "--fuse-flag not supported with this FUSE backend")
}
return options
@ -77,8 +77,8 @@ func mountOptions(VFS *vfs.VFS, 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(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) {
if mountlib.DebugFUSE {
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error, func() error, error) {
if opt.DebugFUSE {
fuse.Debug = func(msg interface{}) {
fs.Debugf("fuse", "%v", msg)
}
@ -86,12 +86,12 @@ 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(VFS, f.Name()+":"+f.Root())...)
c, err := fuse.Mount(mountpoint, mountOptions(VFS, f.Name()+":"+f.Root(), opt)...)
if err != nil {
return nil, nil, err
}
filesys := NewFS(VFS)
filesys := NewFS(VFS, opt)
server := fusefs.New(c, nil)
// Serve the mount point in the background returning error to errChan

View File

@ -33,13 +33,15 @@ import (
// FOPEN_DIRECT_IO flag from their `Open` method. See directio_test.go
// for an example.
type FileHandle struct {
h vfs.Handle
h vfs.Handle
fsys *FS
}
// Create a new FileHandle
func newFileHandle(h vfs.Handle) *FileHandle {
func newFileHandle(h vfs.Handle, fsys *FS) *FileHandle {
return &FileHandle{
h: h,
h: h,
fsys: fsys,
}
}
@ -115,7 +117,7 @@ var _ fusefs.FileFsyncer = (*FileHandle)(nil)
// is assumed, and the 'blocks' field is set accordingly.
func (f *FileHandle) Getattr(ctx context.Context, out *fuse.AttrOut) (errno syscall.Errno) {
defer log.Trace(f, "")("attr=%v, errno=%v", &out, &errno)
setAttrOut(f.h.Node(), out)
f.fsys.setAttrOut(f.h.Node(), out)
return 0
}
@ -125,7 +127,7 @@ var _ fusefs.FileGetattrer = (*FileHandle)(nil)
func (f *FileHandle) Setattr(ctx context.Context, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
defer log.Trace(f, "in=%v", in)("attr=%v, errno=%v", &out, &errno)
var err error
setAttrOut(f.h.Node(), out)
f.fsys.setAttrOut(f.h.Node(), out)
size, ok := in.GetSize()
if ok {
err = f.h.Truncate(int64(size))

View File

@ -20,13 +20,15 @@ import (
type FS struct {
VFS *vfs.VFS
f fs.Fs
opt *mountlib.Options
}
// NewFS creates a pathfs.FileSystem from the fs.Fs passed in
func NewFS(VFS *vfs.VFS) *FS {
func NewFS(VFS *vfs.VFS, opt *mountlib.Options) *FS {
fsys := &FS{
VFS: VFS,
f: VFS.Fs(),
opt: opt,
}
return fsys
}
@ -84,16 +86,16 @@ func setAttr(node vfs.Node, attr *fuse.Attr) {
}
// fill in AttrOut from node
func setAttrOut(node vfs.Node, out *fuse.AttrOut) {
func (f *FS) setAttrOut(node vfs.Node, out *fuse.AttrOut) {
setAttr(node, &out.Attr)
out.SetTimeout(mountlib.AttrTimeout)
out.SetTimeout(f.opt.AttrTimeout)
}
// fill in EntryOut from node
func setEntryOut(node vfs.Node, out *fuse.EntryOut) {
func (f *FS) setEntryOut(node vfs.Node, out *fuse.EntryOut) {
setAttr(node, &out.Attr)
out.SetEntryTimeout(mountlib.AttrTimeout)
out.SetAttrTimeout(mountlib.AttrTimeout)
out.SetEntryTimeout(f.opt.AttrTimeout)
out.SetAttrTimeout(f.opt.AttrTimeout)
}
// Translate errors from mountlib into Syscall error numbers

View File

@ -27,12 +27,12 @@ func init() {
func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) {
device := f.Name() + ":" + f.Root()
mountOpts = &fuse.MountOptions{
AllowOther: mountlib.AllowOther,
AllowOther: fsys.opt.AllowOther,
FsName: device,
Name: "rclone",
DisableXAttrs: true,
Debug: mountlib.DebugFUSE,
MaxReadAhead: int(mountlib.MaxReadAhead),
Debug: fsys.opt.DebugFUSE,
MaxReadAhead: int(fsys.opt.MaxReadAhead),
// RememberInodes: true,
// SingleThreaded: true,
@ -96,22 +96,22 @@ func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) {
}
var opts []string
// FIXME doesn't work opts = append(opts, fmt.Sprintf("max_readahead=%d", maxReadAhead))
if mountlib.AllowNonEmpty {
if fsys.opt.AllowNonEmpty {
opts = append(opts, "nonempty")
}
if mountlib.AllowOther {
if fsys.opt.AllowOther {
opts = append(opts, "allow_other")
}
if mountlib.AllowRoot {
if fsys.opt.AllowRoot {
opts = append(opts, "allow_root")
}
if mountlib.DefaultPermissions {
if fsys.opt.DefaultPermissions {
opts = append(opts, "default_permissions")
}
if fsys.VFS.Opt.ReadOnly {
opts = append(opts, "ro")
}
if mountlib.WritebackCache {
if fsys.opt.WritebackCache {
log.Printf("FIXME --write-back-cache not supported")
// FIXME opts = append(opts,fuse.WritebackCache())
}
@ -147,11 +147,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(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error) {
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error, func() error, error) {
f := VFS.Fs()
fs.Debugf(f, "Mounting on %q", mountpoint)
fsys := NewFS(VFS)
fsys := NewFS(VFS, opt)
// nodeFsOpts := &fusefs.PathNodeFsOptions{
// ClientInodes: false,
// Debug: mountlib.DebugFUSE,
@ -171,8 +171,8 @@ func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error)
// FIXME fill out
opts := fusefs.Options{
MountOptions: *mountOpts,
EntryTimeout: &mountlib.AttrTimeout,
AttrTimeout: &mountlib.AttrTimeout,
EntryTimeout: &opt.AttrTimeout,
AttrTimeout: &opt.AttrTimeout,
// UID
// GID
}

View File

@ -111,7 +111,7 @@ var _ = (fusefs.NodeStatfser)((*Node)(nil))
// with the Options.NullPermissions setting. If blksize is unset, 4096
// is assumed, and the 'blocks' field is set accordingly.
func (n *Node) Getattr(ctx context.Context, f fusefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
setAttrOut(n.node, out)
n.fsys.setAttrOut(n.node, out)
return 0
}
@ -121,7 +121,7 @@ var _ = (fusefs.NodeGetattrer)((*Node)(nil))
func (n *Node) Setattr(ctx context.Context, f fusefs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
defer log.Trace(n, "in=%v", in)("out=%#v, errno=%v", &out, &errno)
var err error
setAttrOut(n.node, out)
n.fsys.setAttrOut(n.node, out)
size, ok := in.GetSize()
if ok {
err = n.node.Truncate(int64(size))
@ -158,7 +158,7 @@ func (n *Node) Open(ctx context.Context, flags uint32) (fh fusefs.FileHandle, fu
if entry := n.node.DirEntry(); entry != nil && entry.Size() < 0 {
fuseFlags |= fuse.FOPEN_DIRECT_IO
}
return newFileHandle(handle), fuseFlags, 0
return newFileHandle(handle, n.fsys), fuseFlags, 0
}
var _ = (fusefs.NodeOpener)((*Node)(nil))
@ -197,7 +197,7 @@ func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ino
// FIXME
// out.SetEntryTimeout(dt time.Duration)
// out.SetAttrTimeout(dt time.Duration)
setEntryOut(vfsNode, out)
n.fsys.setEntryOut(vfsNode, out)
return n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode}), 0
}
@ -306,7 +306,7 @@ func (n *Node) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.En
return nil, translateError(err)
}
newNode := newNode(n.fsys, newDir)
setEntryOut(newNode.node, out)
n.fsys.setEntryOut(newNode.node, out)
newInode := n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode})
return newInode, 0
}
@ -333,7 +333,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
if err != nil {
return nil, nil, 0, translateError(err)
}
fh = newFileHandle(handle)
fh = newFileHandle(handle, n.fsys)
// FIXME
// fh = &fusefs.WithFlags{
// File: fh,
@ -346,7 +346,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
if errno != 0 {
return nil, nil, 0, errno
}
setEntryOut(vfsNode, out)
n.fsys.setEntryOut(vfsNode, out)
newNode := newNode(n.fsys, vfsNode)
fs.Debugf(nil, "attr=%#v", out.Attr)
newInode := n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode})

View File

@ -17,37 +17,48 @@ import (
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config"
"github.com/rclone/rclone/fs/config/flags"
"github.com/rclone/rclone/fs/rc"
"github.com/rclone/rclone/lib/atexit"
"github.com/rclone/rclone/vfs"
"github.com/rclone/rclone/vfs/vfsflags"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// Options set by command line flags
var (
DebugFUSE = false
AllowNonEmpty = false
AllowRoot = false
AllowOther = false
DefaultPermissions = false
WritebackCache = false
Daemon = false
MaxReadAhead fs.SizeSuffix = 128 * 1024
// Options for creating the mount
type Options struct {
DebugFUSE bool
AllowNonEmpty bool
AllowRoot bool
AllowOther bool
DefaultPermissions bool
WritebackCache bool
Daemon bool
MaxReadAhead fs.SizeSuffix
ExtraOptions []string
ExtraFlags []string
AttrTimeout = 1 * time.Second // how long the kernel caches attribute for
AttrTimeout time.Duration // how long the kernel caches attribute for
VolumeName string
NoAppleDouble = true // use noappledouble by default
NoAppleXattr = false // do not use noapplexattr by default
NoAppleDouble bool
NoAppleXattr bool
DaemonTimeout time.Duration // OSXFUSE only
AsyncRead = true // do async reads by default
)
AsyncRead bool
}
// DefaultOpt is the default values for creating the mount
var DefaultOpt = Options{
MaxReadAhead: 128 * 1024,
AttrTimeout: 1 * time.Second, // how long the kernel caches attribute for
NoAppleDouble: true, // use noappledouble by default
NoAppleXattr: false, // do not use noapplexattr by default
AsyncRead: true, // do async reads by default
}
type (
// UnmountFn is called to unmount the file system
UnmountFn func() error
// MountFn is called to mount the file system
MountFn func(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error)
MountFn func(VFS *vfs.VFS, mountpoint string, opt *Options) (<-chan error, func() error, error)
)
// Global constants
@ -58,7 +69,35 @@ const (
func init() {
// DaemonTimeout defaults to non zero for macOS
if runtime.GOOS == "darwin" {
DaemonTimeout = 15 * time.Minute
DefaultOpt.DaemonTimeout = 15 * time.Minute
}
}
// Options set by command line flags
var (
Opt = DefaultOpt
)
// AddFlags adds the non filing system specific flags to the command
func AddFlags(flagSet *pflag.FlagSet) {
rc.AddOption("mount", &Opt)
flags.BoolVarP(flagSet, &Opt.DebugFUSE, "debug-fuse", "", Opt.DebugFUSE, "Debug the FUSE internals - needs -v.")
flags.BoolVarP(flagSet, &Opt.AllowNonEmpty, "allow-non-empty", "", Opt.AllowNonEmpty, "Allow mounting over a non-empty directory (not Windows).")
flags.BoolVarP(flagSet, &Opt.AllowRoot, "allow-root", "", Opt.AllowRoot, "Allow access to root user.")
flags.BoolVarP(flagSet, &Opt.AllowOther, "allow-other", "", Opt.AllowOther, "Allow access to other users.")
flags.BoolVarP(flagSet, &Opt.DefaultPermissions, "default-permissions", "", Opt.DefaultPermissions, "Makes kernel enforce access control based on the file mode.")
flags.BoolVarP(flagSet, &Opt.WritebackCache, "write-back-cache", "", Opt.WritebackCache, "Makes kernel buffer writes before sending them to rclone. Without this, writethrough caching is used.")
flags.FVarP(flagSet, &Opt.MaxReadAhead, "max-read-ahead", "", "The number of bytes that can be prefetched for sequential reads.")
flags.DurationVarP(flagSet, &Opt.AttrTimeout, "attr-timeout", "", Opt.AttrTimeout, "Time for which file/directory attributes are cached.")
flags.StringArrayVarP(flagSet, &Opt.ExtraOptions, "option", "o", []string{}, "Option for libfuse/WinFsp. Repeat if required.")
flags.StringArrayVarP(flagSet, &Opt.ExtraFlags, "fuse-flag", "", []string{}, "Flags or arguments to be passed direct to libfuse/WinFsp. Repeat if required.")
flags.BoolVarP(flagSet, &Opt.Daemon, "daemon", "", Opt.Daemon, "Run mount as a daemon (background mode).")
flags.StringVarP(flagSet, &Opt.VolumeName, "volname", "", Opt.VolumeName, "Set the volume name (not supported by all OSes).")
flags.DurationVarP(flagSet, &Opt.DaemonTimeout, "daemon-timeout", "", Opt.DaemonTimeout, "Time limit for rclone to respond to kernel (not supported by all OSes).")
flags.BoolVarP(flagSet, &Opt.AsyncRead, "async-read", "", Opt.AsyncRead, "Use asynchronous reads.")
if runtime.GOOS == "darwin" {
flags.BoolVarP(flagSet, &Opt.NoAppleDouble, "noappledouble", "", Opt.NoAppleDouble, "Sets the OSXFUSE option noappledouble.")
flags.BoolVarP(flagSet, &Opt.NoAppleXattr, "noapplexattr", "", Opt.NoAppleXattr, "Sets the OSXFUSE option noapplexattr.")
}
}
@ -301,7 +340,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
Run: func(command *cobra.Command, args []string) {
cmd.CheckArgs(2, 2, command, args)
if Daemon {
if Opt.Daemon {
config.PassConfigKeyForDaemonization = true
}
@ -321,17 +360,18 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
// Skip checkMountEmpty if --allow-non-empty flag is used or if
// the Operating System is Windows
if !AllowNonEmpty && runtime.GOOS != "windows" {
if !Opt.AllowNonEmpty && runtime.GOOS != "windows" {
err := checkMountEmpty(mountpoint)
if err != nil {
log.Fatalf("Fatal error: %v", err)
}
} else if AllowNonEmpty && runtime.GOOS == "windows" {
} else if Opt.AllowNonEmpty && runtime.GOOS == "windows" {
fs.Logf(nil, "--allow-non-empty flag does nothing on Windows")
}
// Work out the volume name, removing special
// characters from it if necessary
VolumeName := Opt.VolumeName
if VolumeName == "" {
VolumeName = fdst.Name() + ":" + fdst.Root()
}
@ -343,7 +383,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
}
// Start background task if --background is specified
if Daemon {
if Opt.Daemon {
daemonized := startBackgroundMode()
if daemonized {
return
@ -351,7 +391,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
}
VFS := vfs.New(fdst, &vfsflags.Opt)
err := Mount(VFS, mountpoint, mount)
err := Mount(VFS, mountpoint, mount, &Opt)
if err != nil {
log.Fatalf("Fatal error: %v", err)
}
@ -363,28 +403,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
// Add flags
cmdFlags := commandDefinition.Flags()
flags.BoolVarP(cmdFlags, &DebugFUSE, "debug-fuse", "", DebugFUSE, "Debug the FUSE internals - needs -v.")
// mount options
flags.BoolVarP(cmdFlags, &AllowNonEmpty, "allow-non-empty", "", AllowNonEmpty, "Allow mounting over a non-empty directory (not Windows).")
flags.BoolVarP(cmdFlags, &AllowRoot, "allow-root", "", AllowRoot, "Allow access to root user.")
flags.BoolVarP(cmdFlags, &AllowOther, "allow-other", "", AllowOther, "Allow access to other users.")
flags.BoolVarP(cmdFlags, &DefaultPermissions, "default-permissions", "", DefaultPermissions, "Makes kernel enforce access control based on the file mode.")
flags.BoolVarP(cmdFlags, &WritebackCache, "write-back-cache", "", WritebackCache, "Makes kernel buffer writes before sending them to rclone. Without this, writethrough caching is used.")
flags.FVarP(cmdFlags, &MaxReadAhead, "max-read-ahead", "", "The number of bytes that can be prefetched for sequential reads.")
flags.DurationVarP(cmdFlags, &AttrTimeout, "attr-timeout", "", AttrTimeout, "Time for which file/directory attributes are cached.")
flags.StringArrayVarP(cmdFlags, &ExtraOptions, "option", "o", []string{}, "Option for libfuse/WinFsp. Repeat if required.")
flags.StringArrayVarP(cmdFlags, &ExtraFlags, "fuse-flag", "", []string{}, "Flags or arguments to be passed direct to libfuse/WinFsp. Repeat if required.")
flags.BoolVarP(cmdFlags, &Daemon, "daemon", "", Daemon, "Run mount as a daemon (background mode).")
flags.StringVarP(cmdFlags, &VolumeName, "volname", "", VolumeName, "Set the volume name (not supported by all OSes).")
flags.DurationVarP(cmdFlags, &DaemonTimeout, "daemon-timeout", "", DaemonTimeout, "Time limit for rclone to respond to kernel (not supported by all OSes).")
flags.BoolVarP(cmdFlags, &AsyncRead, "async-read", "", AsyncRead, "Use asynchronous reads.")
if runtime.GOOS == "darwin" {
flags.BoolVarP(cmdFlags, &NoAppleDouble, "noappledouble", "", NoAppleDouble, "Sets the OSXFUSE option noappledouble.")
flags.BoolVarP(cmdFlags, &NoAppleXattr, "noapplexattr", "", NoAppleXattr, "Sets the OSXFUSE option noapplexattr.")
}
// Add in the generic flags
AddFlags(cmdFlags)
vfsflags.AddFlags(cmdFlags)
return commandDefinition
@ -416,9 +435,13 @@ func ClipBlocks(b *uint64) {
// Mount mounts the remote at mountpoint.
//
// If noModTime is set then it
func Mount(VFS *vfs.VFS, mountpoint string, mount MountFn) error {
func Mount(VFS *vfs.VFS, mountpoint string, mount MountFn, opt *Options) error {
if opt != nil {
opt = &DefaultOpt
}
// Mount it
errChan, unmount, err := mount(VFS, mountpoint)
errChan, unmount, err := mount(VFS, mountpoint, opt)
if err != nil {
return errors.Wrap(err, "failed to mount FUSE fs")
}

View File

@ -107,7 +107,7 @@ func mountRc(_ context.Context, in rc.Params) (out rc.Params, err error) {
if mountFns[mountType] != nil {
VFS := vfs.New(fdst, &vfsOpt)
_, unmountFn, err := mountFns[mountType](VFS, mountPoint)
_, unmountFn, err := mountFns[mountType](VFS, mountPoint, &Opt)
if err != nil {
log.Printf("mount FAILED: %v", err)

View File

@ -20,6 +20,7 @@ import (
"time"
_ "github.com/rclone/rclone/backend/all" // import all the backends
"github.com/rclone/rclone/cmd/mountlib"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/walk"
"github.com/rclone/rclone/fstest"
@ -30,21 +31,14 @@ import (
"github.com/stretchr/testify/require"
)
type (
// UnmountFn is called to unmount the file system
UnmountFn func() error
// MountFn is called to mount the file system
MountFn func(VFS *vfs.VFS, mountpoint string) (unmountResult <-chan error, unmount func() error, err error)
)
var (
mountFn MountFn
mountFn mountlib.MountFn
)
// RunTests runs all the tests against all the VFS cache modes
//
// If useVFS is set then it runs the tests against a VFS rather than amount
func RunTests(t *testing.T, useVFS bool, fn MountFn) {
func RunTests(t *testing.T, useVFS bool, fn mountlib.MountFn) {
mountFn = fn
flag.Parse()
tests := []struct {
@ -111,7 +105,7 @@ type Run struct {
fremoteName string
cleanRemote func()
umountResult <-chan error
umountFn UnmountFn
umountFn mountlib.UnmountFn
skip bool
}
@ -178,7 +172,7 @@ func (r *Run) mount() {
log.Printf("mount %q %q", r.fremote, r.mountPath)
var err error
r.vfs = vfs.New(r.fremote, &vfsflags.Opt)
r.umountResult, r.umountFn, err = mountFn(r.vfs, r.mountPath)
r.umountResult, r.umountFn, err = mountFn(r.vfs, r.mountPath, &mountlib.Opt)
if err != nil {
log.Printf("mount FAILED: %v", err)
r.skip = true

View File

@ -6,6 +6,7 @@ import (
"testing"
_ "github.com/rclone/rclone/backend/all" // import all the backends
"github.com/rclone/rclone/cmd/mountlib"
"github.com/rclone/rclone/fstest"
"github.com/rclone/rclone/vfs"
"github.com/rclone/rclone/vfs/vfstest"
@ -17,7 +18,7 @@ func TestFunctional(t *testing.T) {
if *fstest.RemoteName != "" {
t.Skip("Skip on non local")
}
vfstest.RunTests(t, true, func(VFS *vfs.VFS, mountpoint string) (unmountResult <-chan error, unmount func() error, err error) {
vfstest.RunTests(t, true, func(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (unmountResult <-chan error, unmount func() error, err error) {
unmountResultChan := make(chan (error), 1)
unmount = func() error {
unmountResultChan <- nil