mirror of
https://github.com/rclone/rclone.git
synced 2025-01-18 12:21:06 +01:00
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:
parent
e1d34ef427
commit
0272a7f405
4
backend/cache/cache_mount_unix_test.go
vendored
4
backend/cache/cache_mount_unix_test.go
vendored
@ -21,7 +21,7 @@ import (
|
|||||||
func (r *run) mountFs(t *testing.T, f fs.Fs) {
|
func (r *run) mountFs(t *testing.T, f fs.Fs) {
|
||||||
device := f.Name() + ":" + f.Root()
|
device := f.Name() + ":" + f.Root()
|
||||||
var options = []fuse.MountOption{
|
var options = []fuse.MountOption{
|
||||||
fuse.MaxReadahead(uint32(mountlib.MaxReadAhead)),
|
fuse.MaxReadahead(uint32(mountlib.Opt.MaxReadAhead)),
|
||||||
fuse.Subtype("rclone"),
|
fuse.Subtype("rclone"),
|
||||||
fuse.FSName(device), fuse.VolumeName(device),
|
fuse.FSName(device), fuse.VolumeName(device),
|
||||||
fuse.NoAppleDouble(),
|
fuse.NoAppleDouble(),
|
||||||
@ -33,7 +33,7 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) {
|
|||||||
c, err := fuse.Mount(r.mntDir, options...)
|
c, err := fuse.Mount(r.mntDir, options...)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
VFS := vfs.New(f, &vfsflags.Opt)
|
VFS := vfs.New(f, &vfsflags.Opt)
|
||||||
filesys := mount.NewFS(VFS)
|
filesys := mount.NewFS(VFS, &mountlib.Opt)
|
||||||
server := fusefs.New(c, nil)
|
server := fusefs.New(c, nil)
|
||||||
|
|
||||||
// Serve the mount point in the background returning error to errChan
|
// Serve the mount point in the background returning error to errChan
|
||||||
|
2
backend/cache/cache_mount_windows_test.go
vendored
2
backend/cache/cache_mount_windows_test.go
vendored
@ -41,7 +41,7 @@ func (r *run) mountFs(t *testing.T, f fs.Fs) {
|
|||||||
options := []string{
|
options := []string{
|
||||||
"-o", "fsname=" + device,
|
"-o", "fsname=" + device,
|
||||||
"-o", "subtype=rclone",
|
"-o", "subtype=rclone",
|
||||||
"-o", fmt.Sprintf("max_readahead=%d", mountlib.MaxReadAhead),
|
"-o", fmt.Sprintf("max_readahead=%d", mountlib.Opt.MaxReadAhead),
|
||||||
"-o", "uid=-1",
|
"-o", "uid=-1",
|
||||||
"-o", "gid=-1",
|
"-o", "gid=-1",
|
||||||
"-o", "allow_other",
|
"-o", "allow_other",
|
||||||
|
@ -38,29 +38,29 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mountOptions configures the options from the command line flags
|
// 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
|
||||||
options = []string{
|
options = []string{
|
||||||
"-o", "fsname=" + device,
|
"-o", "fsname=" + device,
|
||||||
"-o", "subtype=rclone",
|
"-o", "subtype=rclone",
|
||||||
"-o", fmt.Sprintf("max_readahead=%d", mountlib.MaxReadAhead),
|
"-o", fmt.Sprintf("max_readahead=%d", opt.MaxReadAhead),
|
||||||
"-o", fmt.Sprintf("attr_timeout=%g", mountlib.AttrTimeout.Seconds()),
|
"-o", fmt.Sprintf("attr_timeout=%g", opt.AttrTimeout.Seconds()),
|
||||||
// This causes FUSE to supply O_TRUNC with the Open
|
// This causes FUSE to supply O_TRUNC with the Open
|
||||||
// call which is more efficient for cmount. However
|
// call which is more efficient for cmount. However
|
||||||
// it does not work with cgofuse on Windows with
|
// it does not work with cgofuse on Windows with
|
||||||
// WinFSP so cmount must work with or without it.
|
// WinFSP so cmount must work with or without it.
|
||||||
"-o", "atomic_o_trunc",
|
"-o", "atomic_o_trunc",
|
||||||
}
|
}
|
||||||
if mountlib.DebugFUSE {
|
if opt.DebugFUSE {
|
||||||
options = append(options, "-o", "debug")
|
options = append(options, "-o", "debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
// OSX options
|
// OSX options
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
if mountlib.NoAppleDouble {
|
if opt.NoAppleDouble {
|
||||||
options = append(options, "-o", "noappledouble")
|
options = append(options, "-o", "noappledouble")
|
||||||
}
|
}
|
||||||
if mountlib.NoAppleXattr {
|
if opt.NoAppleXattr {
|
||||||
options = append(options, "-o", "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 runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
|
||||||
if mountlib.VolumeName != "" {
|
if opt.VolumeName != "" {
|
||||||
options = append(options, "-o", "volname="+mountlib.VolumeName)
|
options = append(options, "-o", "volname="+opt.VolumeName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mountlib.AllowNonEmpty {
|
if opt.AllowNonEmpty {
|
||||||
options = append(options, "-o", "nonempty")
|
options = append(options, "-o", "nonempty")
|
||||||
}
|
}
|
||||||
if mountlib.AllowOther {
|
if opt.AllowOther {
|
||||||
options = append(options, "-o", "allow_other")
|
options = append(options, "-o", "allow_other")
|
||||||
}
|
}
|
||||||
if mountlib.AllowRoot {
|
if opt.AllowRoot {
|
||||||
options = append(options, "-o", "allow_root")
|
options = append(options, "-o", "allow_root")
|
||||||
}
|
}
|
||||||
if mountlib.DefaultPermissions {
|
if opt.DefaultPermissions {
|
||||||
options = append(options, "-o", "default_permissions")
|
options = append(options, "-o", "default_permissions")
|
||||||
}
|
}
|
||||||
if VFS.Opt.ReadOnly {
|
if VFS.Opt.ReadOnly {
|
||||||
options = append(options, "-o", "ro")
|
options = append(options, "-o", "ro")
|
||||||
}
|
}
|
||||||
if mountlib.WritebackCache {
|
if opt.WritebackCache {
|
||||||
// FIXME? options = append(options, "-o", WritebackCache())
|
// FIXME? options = append(options, "-o", WritebackCache())
|
||||||
}
|
}
|
||||||
if mountlib.DaemonTimeout != 0 {
|
if opt.DaemonTimeout != 0 {
|
||||||
options = append(options, "-o", fmt.Sprintf("daemon_timeout=%d", int(mountlib.DaemonTimeout.Seconds())))
|
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)
|
options = append(options, "-o", option)
|
||||||
}
|
}
|
||||||
for _, option := range mountlib.ExtraFlags {
|
for _, option := range opt.ExtraFlags {
|
||||||
options = append(options, option)
|
options = append(options, option)
|
||||||
}
|
}
|
||||||
return options
|
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
|
// returns an error, and an error channel for the serve process to
|
||||||
// report an error when fusermount is called.
|
// 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()
|
f := VFS.Fs()
|
||||||
fs.Debugf(f, "Mounting on %q", mountpoint)
|
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)
|
host.SetCapCaseInsensitive(f.Features().CaseInsensitive)
|
||||||
|
|
||||||
// Create options
|
// 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)
|
fs.Debugf(f, "Mounting with options: %q", options)
|
||||||
|
|
||||||
// Serve the mount point in the background returning error to errChan
|
// Serve the mount point in the background returning error to errChan
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
// Dir represents a directory entry
|
// Dir represents a directory entry
|
||||||
type Dir struct {
|
type Dir struct {
|
||||||
*vfs.Dir
|
*vfs.Dir
|
||||||
|
fsys *FS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check interface satisfied
|
// Check interface satisfied
|
||||||
@ -27,7 +28,7 @@ var _ fusefs.Node = (*Dir)(nil)
|
|||||||
// Attr updates the attributes of a directory
|
// Attr updates the attributes of a directory
|
||||||
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
||||||
defer log.Trace(d, "")("attr=%+v, err=%v", a, &err)
|
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.Gid = d.VFS().Opt.GID
|
||||||
a.Uid = d.VFS().Opt.UID
|
a.Uid = d.VFS().Opt.UID
|
||||||
a.Mode = os.ModeDir | d.VFS().Opt.DirPerms
|
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 {
|
if err != nil {
|
||||||
return nil, translateError(err)
|
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
|
// Check the mnode to see if it has a fuse Node cached
|
||||||
// We must return the same fuse nodes for vfs Nodes
|
// We must return the same fuse nodes for vfs Nodes
|
||||||
node, ok := mnode.Sys().(fusefs.Node)
|
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) {
|
switch x := mnode.(type) {
|
||||||
case *vfs.File:
|
case *vfs.File:
|
||||||
node = &File{x}
|
node = &File{x, d.fsys}
|
||||||
case *vfs.Dir:
|
case *vfs.Dir:
|
||||||
node = &Dir{x}
|
node = &Dir{x, d.fsys}
|
||||||
default:
|
default:
|
||||||
panic("bad type")
|
panic("bad type")
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, translateError(err)
|
return nil, nil, translateError(err)
|
||||||
}
|
}
|
||||||
node = &File{file}
|
node = &File{file, d.fsys}
|
||||||
file.SetSys(node) // cache the FUSE node for later
|
file.SetSys(node) // cache the FUSE node for later
|
||||||
return node, &FileHandle{fh}, err
|
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 {
|
if err != nil {
|
||||||
return nil, translateError(err)
|
return nil, translateError(err)
|
||||||
}
|
}
|
||||||
node = &Dir{dir}
|
node = &Dir{dir, d.fsys}
|
||||||
dir.SetSys(node) // cache the FUSE node for later
|
dir.SetSys(node) // cache the FUSE node for later
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
fusefs "bazil.org/fuse/fs"
|
fusefs "bazil.org/fuse/fs"
|
||||||
"github.com/rclone/rclone/cmd/mountlib"
|
|
||||||
"github.com/rclone/rclone/fs/log"
|
"github.com/rclone/rclone/fs/log"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
)
|
)
|
||||||
@ -16,6 +15,7 @@ import (
|
|||||||
// File represents a file
|
// File represents a file
|
||||||
type File struct {
|
type File struct {
|
||||||
*vfs.File
|
*vfs.File
|
||||||
|
fsys *FS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check interface satisfied
|
// Check interface satisfied
|
||||||
@ -24,7 +24,7 @@ var _ fusefs.Node = (*File)(nil)
|
|||||||
// Attr fills out the attributes for the file
|
// Attr fills out the attributes for the file
|
||||||
func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
||||||
defer log.Trace(f, "")("a=%+v, err=%v", a, &err)
|
defer log.Trace(f, "")("a=%+v, err=%v", a, &err)
|
||||||
a.Valid = mountlib.AttrTimeout
|
a.Valid = f.fsys.opt.AttrTimeout
|
||||||
modTime := f.File.ModTime()
|
modTime := f.File.ModTime()
|
||||||
Size := uint64(f.File.Size())
|
Size := uint64(f.File.Size())
|
||||||
Blocks := (Size + 511) / 512
|
Blocks := (Size + 511) / 512
|
||||||
|
@ -20,17 +20,19 @@ import (
|
|||||||
// FS represents the top level filing system
|
// FS represents the top level filing system
|
||||||
type FS struct {
|
type FS struct {
|
||||||
*vfs.VFS
|
*vfs.VFS
|
||||||
f fs.Fs
|
f fs.Fs
|
||||||
|
opt *mountlib.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check interface satisfied
|
// Check interface satisfied
|
||||||
var _ fusefs.FS = (*FS)(nil)
|
var _ fusefs.FS = (*FS)(nil)
|
||||||
|
|
||||||
// NewFS makes a new FS
|
// NewFS makes a new FS
|
||||||
func NewFS(VFS *vfs.VFS) *FS {
|
func NewFS(VFS *vfs.VFS, opt *mountlib.Options) *FS {
|
||||||
fsys := &FS{
|
fsys := &FS{
|
||||||
VFS: VFS,
|
VFS: VFS,
|
||||||
f: VFS.Fs(),
|
f: VFS.Fs(),
|
||||||
|
opt: opt,
|
||||||
}
|
}
|
||||||
return fsys
|
return fsys
|
||||||
}
|
}
|
||||||
@ -42,7 +44,7 @@ func (f *FS) Root() (node fusefs.Node, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, translateError(err)
|
return nil, translateError(err)
|
||||||
}
|
}
|
||||||
return &Dir{root}, nil
|
return &Dir{root, f}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check interface satisfied
|
// Check interface satisfied
|
||||||
|
@ -20,52 +20,52 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mountOptions configures the options from the command line flags
|
// 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{
|
options = []fuse.MountOption{
|
||||||
fuse.MaxReadahead(uint32(mountlib.MaxReadAhead)),
|
fuse.MaxReadahead(uint32(opt.MaxReadAhead)),
|
||||||
fuse.Subtype("rclone"),
|
fuse.Subtype("rclone"),
|
||||||
fuse.FSName(device),
|
fuse.FSName(device),
|
||||||
fuse.VolumeName(mountlib.VolumeName),
|
fuse.VolumeName(opt.VolumeName),
|
||||||
|
|
||||||
// Options from benchmarking in the fuse module
|
// Options from benchmarking in the fuse module
|
||||||
//fuse.MaxReadahead(64 * 1024 * 1024),
|
//fuse.MaxReadahead(64 * 1024 * 1024),
|
||||||
//fuse.WritebackCache(),
|
//fuse.WritebackCache(),
|
||||||
}
|
}
|
||||||
if mountlib.AsyncRead {
|
if opt.AsyncRead {
|
||||||
options = append(options, fuse.AsyncRead())
|
options = append(options, fuse.AsyncRead())
|
||||||
}
|
}
|
||||||
if mountlib.NoAppleDouble {
|
if opt.NoAppleDouble {
|
||||||
options = append(options, fuse.NoAppleDouble())
|
options = append(options, fuse.NoAppleDouble())
|
||||||
}
|
}
|
||||||
if mountlib.NoAppleXattr {
|
if opt.NoAppleXattr {
|
||||||
options = append(options, fuse.NoAppleXattr())
|
options = append(options, fuse.NoAppleXattr())
|
||||||
}
|
}
|
||||||
if mountlib.AllowNonEmpty {
|
if opt.AllowNonEmpty {
|
||||||
options = append(options, fuse.AllowNonEmptyMount())
|
options = append(options, fuse.AllowNonEmptyMount())
|
||||||
}
|
}
|
||||||
if mountlib.AllowOther {
|
if opt.AllowOther {
|
||||||
options = append(options, fuse.AllowOther())
|
options = append(options, fuse.AllowOther())
|
||||||
}
|
}
|
||||||
if mountlib.AllowRoot {
|
if opt.AllowRoot {
|
||||||
// options = append(options, fuse.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")
|
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())
|
options = append(options, fuse.DefaultPermissions())
|
||||||
}
|
}
|
||||||
if VFS.Opt.ReadOnly {
|
if VFS.Opt.ReadOnly {
|
||||||
options = append(options, fuse.ReadOnly())
|
options = append(options, fuse.ReadOnly())
|
||||||
}
|
}
|
||||||
if mountlib.WritebackCache {
|
if opt.WritebackCache {
|
||||||
options = append(options, fuse.WritebackCache())
|
options = append(options, fuse.WritebackCache())
|
||||||
}
|
}
|
||||||
if mountlib.DaemonTimeout != 0 {
|
if opt.DaemonTimeout != 0 {
|
||||||
options = append(options, fuse.DaemonTimeout(fmt.Sprint(int(mountlib.DaemonTimeout.Seconds()))))
|
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")
|
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")
|
fs.Errorf(nil, "--fuse-flag not supported with this FUSE backend")
|
||||||
}
|
}
|
||||||
return options
|
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
|
// returns an error, and an error channel for the serve process to
|
||||||
// report an error when fusermount is called.
|
// 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) {
|
||||||
if mountlib.DebugFUSE {
|
if opt.DebugFUSE {
|
||||||
fuse.Debug = func(msg interface{}) {
|
fuse.Debug = func(msg interface{}) {
|
||||||
fs.Debugf("fuse", "%v", msg)
|
fs.Debugf("fuse", "%v", msg)
|
||||||
}
|
}
|
||||||
@ -86,12 +86,12 @@ func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error)
|
|||||||
|
|
||||||
f := VFS.Fs()
|
f := VFS.Fs()
|
||||||
fs.Debugf(f, "Mounting on %q", mountpoint)
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filesys := NewFS(VFS)
|
filesys := NewFS(VFS, opt)
|
||||||
server := fusefs.New(c, nil)
|
server := fusefs.New(c, nil)
|
||||||
|
|
||||||
// Serve the mount point in the background returning error to errChan
|
// Serve the mount point in the background returning error to errChan
|
||||||
|
@ -33,13 +33,15 @@ import (
|
|||||||
// FOPEN_DIRECT_IO flag from their `Open` method. See directio_test.go
|
// FOPEN_DIRECT_IO flag from their `Open` method. See directio_test.go
|
||||||
// for an example.
|
// for an example.
|
||||||
type FileHandle struct {
|
type FileHandle struct {
|
||||||
h vfs.Handle
|
h vfs.Handle
|
||||||
|
fsys *FS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new FileHandle
|
// Create a new FileHandle
|
||||||
func newFileHandle(h vfs.Handle) *FileHandle {
|
func newFileHandle(h vfs.Handle, fsys *FS) *FileHandle {
|
||||||
return &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.
|
// is assumed, and the 'blocks' field is set accordingly.
|
||||||
func (f *FileHandle) Getattr(ctx context.Context, out *fuse.AttrOut) (errno syscall.Errno) {
|
func (f *FileHandle) Getattr(ctx context.Context, out *fuse.AttrOut) (errno syscall.Errno) {
|
||||||
defer log.Trace(f, "")("attr=%v, errno=%v", &out, &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
|
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) {
|
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)
|
defer log.Trace(f, "in=%v", in)("attr=%v, errno=%v", &out, &errno)
|
||||||
var err error
|
var err error
|
||||||
setAttrOut(f.h.Node(), out)
|
f.fsys.setAttrOut(f.h.Node(), out)
|
||||||
size, ok := in.GetSize()
|
size, ok := in.GetSize()
|
||||||
if ok {
|
if ok {
|
||||||
err = f.h.Truncate(int64(size))
|
err = f.h.Truncate(int64(size))
|
||||||
|
@ -20,13 +20,15 @@ import (
|
|||||||
type FS struct {
|
type FS struct {
|
||||||
VFS *vfs.VFS
|
VFS *vfs.VFS
|
||||||
f fs.Fs
|
f fs.Fs
|
||||||
|
opt *mountlib.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFS creates a pathfs.FileSystem from the fs.Fs passed in
|
// 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{
|
fsys := &FS{
|
||||||
VFS: VFS,
|
VFS: VFS,
|
||||||
f: VFS.Fs(),
|
f: VFS.Fs(),
|
||||||
|
opt: opt,
|
||||||
}
|
}
|
||||||
return fsys
|
return fsys
|
||||||
}
|
}
|
||||||
@ -84,16 +86,16 @@ func setAttr(node vfs.Node, attr *fuse.Attr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fill in AttrOut from node
|
// 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)
|
setAttr(node, &out.Attr)
|
||||||
out.SetTimeout(mountlib.AttrTimeout)
|
out.SetTimeout(f.opt.AttrTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill in EntryOut from node
|
// 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)
|
setAttr(node, &out.Attr)
|
||||||
out.SetEntryTimeout(mountlib.AttrTimeout)
|
out.SetEntryTimeout(f.opt.AttrTimeout)
|
||||||
out.SetAttrTimeout(mountlib.AttrTimeout)
|
out.SetAttrTimeout(f.opt.AttrTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate errors from mountlib into Syscall error numbers
|
// Translate errors from mountlib into Syscall error numbers
|
||||||
|
@ -27,12 +27,12 @@ func init() {
|
|||||||
func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) {
|
func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) {
|
||||||
device := f.Name() + ":" + f.Root()
|
device := f.Name() + ":" + f.Root()
|
||||||
mountOpts = &fuse.MountOptions{
|
mountOpts = &fuse.MountOptions{
|
||||||
AllowOther: mountlib.AllowOther,
|
AllowOther: fsys.opt.AllowOther,
|
||||||
FsName: device,
|
FsName: device,
|
||||||
Name: "rclone",
|
Name: "rclone",
|
||||||
DisableXAttrs: true,
|
DisableXAttrs: true,
|
||||||
Debug: mountlib.DebugFUSE,
|
Debug: fsys.opt.DebugFUSE,
|
||||||
MaxReadAhead: int(mountlib.MaxReadAhead),
|
MaxReadAhead: int(fsys.opt.MaxReadAhead),
|
||||||
|
|
||||||
// RememberInodes: true,
|
// RememberInodes: true,
|
||||||
// SingleThreaded: true,
|
// SingleThreaded: true,
|
||||||
@ -96,22 +96,22 @@ func mountOptions(fsys *FS, f fs.Fs) (mountOpts *fuse.MountOptions) {
|
|||||||
}
|
}
|
||||||
var opts []string
|
var opts []string
|
||||||
// FIXME doesn't work opts = append(opts, fmt.Sprintf("max_readahead=%d", maxReadAhead))
|
// FIXME doesn't work opts = append(opts, fmt.Sprintf("max_readahead=%d", maxReadAhead))
|
||||||
if mountlib.AllowNonEmpty {
|
if fsys.opt.AllowNonEmpty {
|
||||||
opts = append(opts, "nonempty")
|
opts = append(opts, "nonempty")
|
||||||
}
|
}
|
||||||
if mountlib.AllowOther {
|
if fsys.opt.AllowOther {
|
||||||
opts = append(opts, "allow_other")
|
opts = append(opts, "allow_other")
|
||||||
}
|
}
|
||||||
if mountlib.AllowRoot {
|
if fsys.opt.AllowRoot {
|
||||||
opts = append(opts, "allow_root")
|
opts = append(opts, "allow_root")
|
||||||
}
|
}
|
||||||
if mountlib.DefaultPermissions {
|
if fsys.opt.DefaultPermissions {
|
||||||
opts = append(opts, "default_permissions")
|
opts = append(opts, "default_permissions")
|
||||||
}
|
}
|
||||||
if fsys.VFS.Opt.ReadOnly {
|
if fsys.VFS.Opt.ReadOnly {
|
||||||
opts = append(opts, "ro")
|
opts = append(opts, "ro")
|
||||||
}
|
}
|
||||||
if mountlib.WritebackCache {
|
if fsys.opt.WritebackCache {
|
||||||
log.Printf("FIXME --write-back-cache not supported")
|
log.Printf("FIXME --write-back-cache not supported")
|
||||||
// FIXME opts = append(opts,fuse.WritebackCache())
|
// 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
|
// returns an error, and an error channel for the serve process to
|
||||||
// report an error when fusermount is called.
|
// 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()
|
f := VFS.Fs()
|
||||||
fs.Debugf(f, "Mounting on %q", mountpoint)
|
fs.Debugf(f, "Mounting on %q", mountpoint)
|
||||||
|
|
||||||
fsys := NewFS(VFS)
|
fsys := NewFS(VFS, opt)
|
||||||
// nodeFsOpts := &fusefs.PathNodeFsOptions{
|
// nodeFsOpts := &fusefs.PathNodeFsOptions{
|
||||||
// ClientInodes: false,
|
// ClientInodes: false,
|
||||||
// Debug: mountlib.DebugFUSE,
|
// Debug: mountlib.DebugFUSE,
|
||||||
@ -171,8 +171,8 @@ func mount(VFS *vfs.VFS, mountpoint string) (<-chan error, func() error, error)
|
|||||||
// FIXME fill out
|
// FIXME fill out
|
||||||
opts := fusefs.Options{
|
opts := fusefs.Options{
|
||||||
MountOptions: *mountOpts,
|
MountOptions: *mountOpts,
|
||||||
EntryTimeout: &mountlib.AttrTimeout,
|
EntryTimeout: &opt.AttrTimeout,
|
||||||
AttrTimeout: &mountlib.AttrTimeout,
|
AttrTimeout: &opt.AttrTimeout,
|
||||||
// UID
|
// UID
|
||||||
// GID
|
// GID
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ var _ = (fusefs.NodeStatfser)((*Node)(nil))
|
|||||||
// with the Options.NullPermissions setting. If blksize is unset, 4096
|
// with the Options.NullPermissions setting. If blksize is unset, 4096
|
||||||
// is assumed, and the 'blocks' field is set accordingly.
|
// is assumed, and the 'blocks' field is set accordingly.
|
||||||
func (n *Node) Getattr(ctx context.Context, f fusefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
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
|
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) {
|
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)
|
defer log.Trace(n, "in=%v", in)("out=%#v, errno=%v", &out, &errno)
|
||||||
var err error
|
var err error
|
||||||
setAttrOut(n.node, out)
|
n.fsys.setAttrOut(n.node, out)
|
||||||
size, ok := in.GetSize()
|
size, ok := in.GetSize()
|
||||||
if ok {
|
if ok {
|
||||||
err = n.node.Truncate(int64(size))
|
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 {
|
if entry := n.node.DirEntry(); entry != nil && entry.Size() < 0 {
|
||||||
fuseFlags |= fuse.FOPEN_DIRECT_IO
|
fuseFlags |= fuse.FOPEN_DIRECT_IO
|
||||||
}
|
}
|
||||||
return newFileHandle(handle), fuseFlags, 0
|
return newFileHandle(handle, n.fsys), fuseFlags, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = (fusefs.NodeOpener)((*Node)(nil))
|
var _ = (fusefs.NodeOpener)((*Node)(nil))
|
||||||
@ -197,7 +197,7 @@ func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ino
|
|||||||
// FIXME
|
// FIXME
|
||||||
// out.SetEntryTimeout(dt time.Duration)
|
// out.SetEntryTimeout(dt time.Duration)
|
||||||
// out.SetAttrTimeout(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
|
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)
|
return nil, translateError(err)
|
||||||
}
|
}
|
||||||
newNode := newNode(n.fsys, newDir)
|
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})
|
newInode := n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode})
|
||||||
return newInode, 0
|
return newInode, 0
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, translateError(err)
|
return nil, nil, 0, translateError(err)
|
||||||
}
|
}
|
||||||
fh = newFileHandle(handle)
|
fh = newFileHandle(handle, n.fsys)
|
||||||
// FIXME
|
// FIXME
|
||||||
// fh = &fusefs.WithFlags{
|
// fh = &fusefs.WithFlags{
|
||||||
// File: fh,
|
// File: fh,
|
||||||
@ -346,7 +346,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
|
|||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return nil, nil, 0, errno
|
return nil, nil, 0, errno
|
||||||
}
|
}
|
||||||
setEntryOut(vfsNode, out)
|
n.fsys.setEntryOut(vfsNode, out)
|
||||||
newNode := newNode(n.fsys, vfsNode)
|
newNode := newNode(n.fsys, vfsNode)
|
||||||
fs.Debugf(nil, "attr=%#v", out.Attr)
|
fs.Debugf(nil, "attr=%#v", out.Attr)
|
||||||
newInode := n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode})
|
newInode := n.NewInode(ctx, newNode, fusefs.StableAttr{Mode: out.Attr.Mode})
|
||||||
|
@ -17,37 +17,48 @@ import (
|
|||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/fs/config"
|
"github.com/rclone/rclone/fs/config"
|
||||||
"github.com/rclone/rclone/fs/config/flags"
|
"github.com/rclone/rclone/fs/config/flags"
|
||||||
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/lib/atexit"
|
"github.com/rclone/rclone/lib/atexit"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options set by command line flags
|
// Options for creating the mount
|
||||||
var (
|
type Options struct {
|
||||||
DebugFUSE = false
|
DebugFUSE bool
|
||||||
AllowNonEmpty = false
|
AllowNonEmpty bool
|
||||||
AllowRoot = false
|
AllowRoot bool
|
||||||
AllowOther = false
|
AllowOther bool
|
||||||
DefaultPermissions = false
|
DefaultPermissions bool
|
||||||
WritebackCache = false
|
WritebackCache bool
|
||||||
Daemon = false
|
Daemon bool
|
||||||
MaxReadAhead fs.SizeSuffix = 128 * 1024
|
MaxReadAhead fs.SizeSuffix
|
||||||
ExtraOptions []string
|
ExtraOptions []string
|
||||||
ExtraFlags []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
|
VolumeName string
|
||||||
NoAppleDouble = true // use noappledouble by default
|
NoAppleDouble bool
|
||||||
NoAppleXattr = false // do not use noapplexattr by default
|
NoAppleXattr bool
|
||||||
DaemonTimeout time.Duration // OSXFUSE only
|
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 (
|
type (
|
||||||
// UnmountFn is called to unmount the file system
|
// UnmountFn is called to unmount the file system
|
||||||
UnmountFn func() error
|
UnmountFn func() error
|
||||||
// MountFn is called to mount the file system
|
// 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
|
// Global constants
|
||||||
@ -58,7 +69,35 @@ const (
|
|||||||
func init() {
|
func init() {
|
||||||
// DaemonTimeout defaults to non zero for macOS
|
// DaemonTimeout defaults to non zero for macOS
|
||||||
if runtime.GOOS == "darwin" {
|
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) {
|
Run: func(command *cobra.Command, args []string) {
|
||||||
cmd.CheckArgs(2, 2, command, args)
|
cmd.CheckArgs(2, 2, command, args)
|
||||||
|
|
||||||
if Daemon {
|
if Opt.Daemon {
|
||||||
config.PassConfigKeyForDaemonization = true
|
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
|
// Skip checkMountEmpty if --allow-non-empty flag is used or if
|
||||||
// the Operating System is Windows
|
// the Operating System is Windows
|
||||||
if !AllowNonEmpty && runtime.GOOS != "windows" {
|
if !Opt.AllowNonEmpty && runtime.GOOS != "windows" {
|
||||||
err := checkMountEmpty(mountpoint)
|
err := checkMountEmpty(mountpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fatal error: %v", err)
|
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")
|
fs.Logf(nil, "--allow-non-empty flag does nothing on Windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Work out the volume name, removing special
|
// Work out the volume name, removing special
|
||||||
// characters from it if necessary
|
// characters from it if necessary
|
||||||
|
VolumeName := Opt.VolumeName
|
||||||
if VolumeName == "" {
|
if VolumeName == "" {
|
||||||
VolumeName = fdst.Name() + ":" + fdst.Root()
|
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
|
// Start background task if --background is specified
|
||||||
if Daemon {
|
if Opt.Daemon {
|
||||||
daemonized := startBackgroundMode()
|
daemonized := startBackgroundMode()
|
||||||
if daemonized {
|
if daemonized {
|
||||||
return
|
return
|
||||||
@ -351,7 +391,7 @@ be copied to the vfs cache before opening with --vfs-cache-mode full.
|
|||||||
}
|
}
|
||||||
|
|
||||||
VFS := vfs.New(fdst, &vfsflags.Opt)
|
VFS := vfs.New(fdst, &vfsflags.Opt)
|
||||||
err := Mount(VFS, mountpoint, mount)
|
err := Mount(VFS, mountpoint, mount, &Opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fatal error: %v", err)
|
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
|
// Add flags
|
||||||
cmdFlags := commandDefinition.Flags()
|
cmdFlags := commandDefinition.Flags()
|
||||||
flags.BoolVarP(cmdFlags, &DebugFUSE, "debug-fuse", "", DebugFUSE, "Debug the FUSE internals - needs -v.")
|
AddFlags(cmdFlags)
|
||||||
// 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
|
|
||||||
vfsflags.AddFlags(cmdFlags)
|
vfsflags.AddFlags(cmdFlags)
|
||||||
|
|
||||||
return commandDefinition
|
return commandDefinition
|
||||||
@ -416,9 +435,13 @@ func ClipBlocks(b *uint64) {
|
|||||||
// Mount mounts the remote at mountpoint.
|
// Mount mounts the remote at mountpoint.
|
||||||
//
|
//
|
||||||
// If noModTime is set then it
|
// 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
|
// Mount it
|
||||||
errChan, unmount, err := mount(VFS, mountpoint)
|
errChan, unmount, err := mount(VFS, mountpoint, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to mount FUSE fs")
|
return errors.Wrap(err, "failed to mount FUSE fs")
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func mountRc(_ context.Context, in rc.Params) (out rc.Params, err error) {
|
|||||||
|
|
||||||
if mountFns[mountType] != nil {
|
if mountFns[mountType] != nil {
|
||||||
VFS := vfs.New(fdst, &vfsOpt)
|
VFS := vfs.New(fdst, &vfsOpt)
|
||||||
_, unmountFn, err := mountFns[mountType](VFS, mountPoint)
|
_, unmountFn, err := mountFns[mountType](VFS, mountPoint, &Opt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("mount FAILED: %v", err)
|
log.Printf("mount FAILED: %v", err)
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
_ "github.com/rclone/rclone/backend/all" // import all the backends
|
_ "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"
|
||||||
"github.com/rclone/rclone/fs/walk"
|
"github.com/rclone/rclone/fs/walk"
|
||||||
"github.com/rclone/rclone/fstest"
|
"github.com/rclone/rclone/fstest"
|
||||||
@ -30,21 +31,14 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"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 (
|
var (
|
||||||
mountFn MountFn
|
mountFn mountlib.MountFn
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunTests runs all the tests against all the VFS cache modes
|
// 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
|
// 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
|
mountFn = fn
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -111,7 +105,7 @@ type Run struct {
|
|||||||
fremoteName string
|
fremoteName string
|
||||||
cleanRemote func()
|
cleanRemote func()
|
||||||
umountResult <-chan error
|
umountResult <-chan error
|
||||||
umountFn UnmountFn
|
umountFn mountlib.UnmountFn
|
||||||
skip bool
|
skip bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +172,7 @@ func (r *Run) mount() {
|
|||||||
log.Printf("mount %q %q", r.fremote, r.mountPath)
|
log.Printf("mount %q %q", r.fremote, r.mountPath)
|
||||||
var err error
|
var err error
|
||||||
r.vfs = vfs.New(r.fremote, &vfsflags.Opt)
|
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 {
|
if err != nil {
|
||||||
log.Printf("mount FAILED: %v", err)
|
log.Printf("mount FAILED: %v", err)
|
||||||
r.skip = true
|
r.skip = true
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
_ "github.com/rclone/rclone/backend/all" // import all the backends
|
_ "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/fstest"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfstest"
|
"github.com/rclone/rclone/vfs/vfstest"
|
||||||
@ -17,7 +18,7 @@ func TestFunctional(t *testing.T) {
|
|||||||
if *fstest.RemoteName != "" {
|
if *fstest.RemoteName != "" {
|
||||||
t.Skip("Skip on non local")
|
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)
|
unmountResultChan := make(chan (error), 1)
|
||||||
unmount = func() error {
|
unmount = func() error {
|
||||||
unmountResultChan <- nil
|
unmountResultChan <- nil
|
||||||
|
Loading…
Reference in New Issue
Block a user