github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/mount/mount.go (about)

     1  //go:build linux
     2  
     3  // Package mount implements a FUSE mounting system for rclone remotes.
     4  package mount
     5  
     6  import (
     7  	"fmt"
     8  	"runtime"
     9  
    10  	"bazil.org/fuse"
    11  	fusefs "bazil.org/fuse/fs"
    12  	"github.com/rclone/rclone/cmd/mountlib"
    13  	"github.com/rclone/rclone/fs"
    14  	"github.com/rclone/rclone/vfs"
    15  )
    16  
    17  func init() {
    18  	mountlib.NewMountCommand("mount", false, mount)
    19  	mountlib.AddRc("mount", mount)
    20  }
    21  
    22  // mountOptions configures the options from the command line flags
    23  func mountOptions(VFS *vfs.VFS, device string, opt *mountlib.Options) (options []fuse.MountOption) {
    24  	options = []fuse.MountOption{
    25  		fuse.MaxReadahead(uint32(opt.MaxReadAhead)),
    26  		fuse.Subtype("rclone"),
    27  		fuse.FSName(device),
    28  
    29  		// Options from benchmarking in the fuse module
    30  		//fuse.MaxReadahead(64 * 1024 * 1024),
    31  		//fuse.WritebackCache(),
    32  	}
    33  	if opt.AsyncRead {
    34  		options = append(options, fuse.AsyncRead())
    35  	}
    36  	if opt.AllowOther {
    37  		options = append(options, fuse.AllowOther())
    38  	}
    39  	if opt.AllowRoot {
    40  		// options = append(options, fuse.AllowRoot())
    41  		fs.Errorf(nil, "Ignoring --allow-root. Support has been removed upstream - see https://github.com/bazil/fuse/issues/144 for more info")
    42  	}
    43  	if opt.DefaultPermissions {
    44  		options = append(options, fuse.DefaultPermissions())
    45  	}
    46  	if VFS.Opt.ReadOnly {
    47  		options = append(options, fuse.ReadOnly())
    48  	}
    49  	if opt.WritebackCache {
    50  		options = append(options, fuse.WritebackCache())
    51  	}
    52  	if opt.DaemonTimeout != 0 {
    53  		options = append(options, fuse.DaemonTimeout(fmt.Sprint(int(opt.DaemonTimeout.Seconds()))))
    54  	}
    55  	if len(opt.ExtraOptions) > 0 {
    56  		fs.Errorf(nil, "-o/--option not supported with this FUSE backend")
    57  	}
    58  	if len(opt.ExtraFlags) > 0 {
    59  		fs.Errorf(nil, "--fuse-flag not supported with this FUSE backend")
    60  	}
    61  	return options
    62  }
    63  
    64  // mount the file system
    65  //
    66  // The mount point will be ready when this returns.
    67  //
    68  // returns an error, and an error channel for the serve process to
    69  // report an error when fusermount is called.
    70  func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error, func() error, error) {
    71  	f := VFS.Fs()
    72  	if runtime.GOOS == "darwin" {
    73  		fs.Logf(nil, "macOS users: please try \"rclone cmount\" as it will be the default in v1.54")
    74  	}
    75  	if err := mountlib.CheckOverlap(f, mountpoint); err != nil {
    76  		return nil, nil, err
    77  	}
    78  	if err := mountlib.CheckAllowNonEmpty(mountpoint, opt); err != nil {
    79  		return nil, nil, err
    80  	}
    81  	fs.Debugf(f, "Mounting on %q", mountpoint)
    82  
    83  	if opt.DebugFUSE {
    84  		fuse.Debug = func(msg interface{}) {
    85  			fs.Debugf("fuse", "%v", msg)
    86  		}
    87  	}
    88  
    89  	c, err := fuse.Mount(mountpoint, mountOptions(VFS, opt.DeviceName, opt)...)
    90  	if err != nil {
    91  		return nil, nil, err
    92  	}
    93  
    94  	filesys := NewFS(VFS, opt)
    95  	filesys.server = fusefs.New(c, nil)
    96  
    97  	// Serve the mount point in the background returning error to errChan
    98  	errChan := make(chan error, 1)
    99  	go func() {
   100  		err := filesys.server.Serve(filesys)
   101  		closeErr := c.Close()
   102  		if err == nil {
   103  			err = closeErr
   104  		}
   105  		errChan <- err
   106  	}()
   107  
   108  	unmount := func() error {
   109  		// Shutdown the VFS
   110  		filesys.VFS.Shutdown()
   111  		return fuse.Unmount(mountpoint)
   112  	}
   113  
   114  	return errChan, unmount, nil
   115  }