ef2ef8ef84
Summary: In cases where cmount is not available in macOS, we alias nfsmount to mount command and transparently start the NFS server and mount it to the target dir. The NFS server is started on localhost on a random port so it is reasonably secure. Test Plan: ``` go run rclone.go mount --http-url https://beta.rclone.org :http: nfs-test ``` Added mount tests: ``` go test ./cmd/nfsmount ```
69 lines
1.9 KiB
Go
69 lines
1.9 KiB
Go
//go:build darwin && !cmount
|
|
// +build darwin,!cmount
|
|
|
|
// Package nfsmount implements mounting functionality using serve nfs command
|
|
//
|
|
// NFS mount is only needed for macOS since it has no
|
|
// support for FUSE-based file systems
|
|
package nfsmount
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"os/exec"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/rclone/rclone/cmd/mountlib"
|
|
"github.com/rclone/rclone/cmd/serve/nfs"
|
|
"github.com/rclone/rclone/vfs"
|
|
)
|
|
|
|
func init() {
|
|
cmd := mountlib.NewMountCommand("mount", false, mount)
|
|
cmd.Aliases = append(cmd.Aliases, "nfsmount")
|
|
mountlib.AddRc("nfsmount", mount)
|
|
}
|
|
|
|
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors <-chan error, unmount func() error, err error) {
|
|
s, err := nfs.NewServer(context.Background(), VFS, &nfs.Options{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
errChan := make(chan error, 1)
|
|
go func() {
|
|
errChan <- s.Serve()
|
|
}()
|
|
// The port is always picked at random after the NFS server has started
|
|
// we need to query the server for the port number so we can mount it
|
|
_, port, err := net.SplitHostPort(s.Addr().String())
|
|
if err != nil {
|
|
err = fmt.Errorf("cannot find port number in %s", s.Addr().String())
|
|
return
|
|
}
|
|
optionsString := strings.Join(opt.ExtraOptions, ",")
|
|
err = exec.Command("mount", fmt.Sprintf("-oport=%s,mountport=%s,%s", port, port, optionsString), "localhost:", mountpoint).Run()
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to mount NFS volume %e", err)
|
|
return
|
|
}
|
|
asyncerrors = errChan
|
|
unmount = func() error {
|
|
var umountErr error
|
|
if runtime.GOOS == "darwin" {
|
|
umountErr = exec.Command("diskutil", "umount", "force", mountpoint).Run()
|
|
} else {
|
|
umountErr = exec.Command("umount", "-f", mountpoint).Run()
|
|
}
|
|
shutdownErr := s.Shutdown()
|
|
VFS.Shutdown()
|
|
if umountErr != nil {
|
|
return fmt.Errorf("failed to umount the NFS volume %e", umountErr)
|
|
} else if shutdownErr != nil {
|
|
return fmt.Errorf("failed to shutdown NFS server: %e", shutdownErr)
|
|
}
|
|
return nil
|
|
}
|
|
return
|
|
}
|