rclone/vendor/github.com/hanwen/go-fuse/v2/fuse/mount_darwin.go

97 lines
2.2 KiB
Go

// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
)
func openFUSEDevice() (*os.File, error) {
fs, err := filepath.Glob("/dev/osxfuse*")
if err != nil {
return nil, err
}
if len(fs) == 0 {
bin := oldLoadBin
if _, err := os.Stat(newLoadBin); err == nil {
bin = newLoadBin
}
cmd := exec.Command(bin)
if err := cmd.Run(); err != nil {
return nil, err
}
fs, err = filepath.Glob("/dev/osxfuse*")
if err != nil {
return nil, err
}
}
for _, fn := range fs {
f, err := os.OpenFile(fn, os.O_RDWR, 0)
if err != nil {
continue
}
return f, nil
}
return nil, fmt.Errorf("all FUSE devices busy")
}
const oldLoadBin = "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs"
const newLoadBin = "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse"
const oldMountBin = "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
const newMountBin = "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"
func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, err error) {
f, err := openFUSEDevice()
if err != nil {
return 0, err
}
bin := oldMountBin
if _, err := os.Stat(newMountBin); err == nil {
bin = newMountBin
}
cmd := exec.Command(bin, "-o", strings.Join(opts.optionsStrings(), ","), "-o", fmt.Sprintf("iosize=%d", opts.MaxWrite), "3", mountPoint)
cmd.ExtraFiles = []*os.File{f}
cmd.Env = append(os.Environ(), "MOUNT_FUSEFS_CALL_BY_LIB=", "MOUNT_OSXFUSE_CALL_BY_LIB=",
"MOUNT_OSXFUSE_DAEMON_PATH="+os.Args[0],
"MOUNT_FUSEFS_DAEMON_PATH="+os.Args[0])
var out, errOut bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errOut
if err := cmd.Start(); err != nil {
f.Close()
return 0, err
}
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("mount_osxfusefs failed: %v. Stderr: %s, Stdout: %s", err, errOut.String(), out.String())
}
ready <- err
close(ready)
}()
// The finalizer for f will close its fd so we return a dup.
defer f.Close()
return syscall.Dup(int(f.Fd()))
}
func unmount(dir string) error {
return syscall.Unmount(dir, 0)
}