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 }