Initial commit
Proof-of-concept implementation. Bugs will occur.
This commit is contained in:
146
vendor/github.com/hanwen/go-fuse/v2/fuse/mount_freebsd.go
generated
vendored
Normal file
146
vendor/github.com/hanwen/go-fuse/v2/fuse/mount_freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
package fuse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func getMaxWrite() int {
|
||||
return 1 << 20
|
||||
}
|
||||
|
||||
func callMountFuseFs(mountPoint string, opts *MountOptions) (devFuseFd int, err error) {
|
||||
bin, err := fusermountBinary()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// Convenience for cleaning up open FDs in the event of an error.
|
||||
closeFd := func(fd int) {
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
}
|
||||
}
|
||||
|
||||
// Use syscall.Open instead of os.OpenFile to avoid Go garbage collecting an
|
||||
// [os.File], which will close the FD later, but we need to keep it open for
|
||||
// the life of the FUSE mount.
|
||||
const devFuse = "/dev/fuse"
|
||||
devFuseFd, err = syscall.Open(devFuse, syscall.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf(
|
||||
"failed to get a RDWR file descriptor for %s: %w",
|
||||
devFuse, err)
|
||||
}
|
||||
defer closeFd(devFuseFd)
|
||||
// We will also defensively direct the forked process's stdin to the null
|
||||
// device to prevent any unintended side effects.
|
||||
devNullFd, err := syscall.Open(os.DevNull, syscall.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf(
|
||||
"failed to get a RDONLY file descriptor for %s: %w",
|
||||
os.DevNull, err)
|
||||
}
|
||||
defer closeFd(devNullFd)
|
||||
|
||||
// Use syscall.ForkExec directly instead of exec.Command because we need to
|
||||
// pass raw file descriptors to the child, rather than a garbage collected
|
||||
// os.File.
|
||||
env := []string{"MOUNT_FUSEFS_CALL_BY_LIB=1"}
|
||||
argv := []string{
|
||||
bin,
|
||||
"--safe",
|
||||
"-o", strings.Join(opts.optionsStrings(), ","),
|
||||
"3",
|
||||
mountPoint,
|
||||
}
|
||||
fds := []uintptr{
|
||||
uintptr(devNullFd),
|
||||
uintptr(os.Stdout.Fd()),
|
||||
uintptr(os.Stderr.Fd()),
|
||||
uintptr(devFuseFd),
|
||||
}
|
||||
pid, err := syscall.ForkExec(bin, argv, &syscall.ProcAttr{
|
||||
Env: env,
|
||||
Files: fds,
|
||||
})
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("failed to fork mount_fusefs: %w", err)
|
||||
}
|
||||
|
||||
var ws syscall.WaitStatus
|
||||
_, err = syscall.Wait4(pid, &ws, 0, nil)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf(
|
||||
"failed to wait for exit status of mount_fusefs: %w", err)
|
||||
}
|
||||
if ws.ExitStatus() != 0 {
|
||||
return -1, fmt.Errorf(
|
||||
"mount_fusefs: exited with status %d", ws.ExitStatus())
|
||||
}
|
||||
|
||||
return devFuseFd, nil
|
||||
}
|
||||
|
||||
func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, err error) {
|
||||
// Note: opts.DirectMount is not supported in FreeBSD, but the intended
|
||||
// behavior is to *attempt* a direct mount when it's set, not to return an
|
||||
// error. So in this case, we just ignore it and use the binary from
|
||||
// fusermountBinary().
|
||||
|
||||
// Using the same logic from libfuse to prevent chaos
|
||||
for {
|
||||
f, err := os.OpenFile("/dev/null", os.O_RDWR, 0o000)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if f.Fd() > 2 {
|
||||
f.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Magic `/dev/fd/N` mountpoint. See the docs for NewServer() for how this
|
||||
// works.
|
||||
|
||||
fd = parseFuseFd(mountPoint)
|
||||
if fd >= 0 {
|
||||
if opts.Debug {
|
||||
opts.Logger.Printf("mount: magic mountpoint %q, using fd %d", mountPoint, fd)
|
||||
}
|
||||
} else {
|
||||
// Usual case: mount via the `fusermount` suid helper
|
||||
fd, err = callMountFuseFs(mountPoint, opts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// golang sets CLOEXEC on file descriptors when they are
|
||||
// acquired through normal operations (e.g. open).
|
||||
// However, for raw FDs, we have to set CLOEXEC manually.
|
||||
syscall.CloseOnExec(fd)
|
||||
|
||||
close(ready)
|
||||
return fd, err
|
||||
}
|
||||
|
||||
func unmount(mountPoint string, opts *MountOptions) (err error) {
|
||||
_ = opts
|
||||
return syscall.Unmount(mountPoint, 0)
|
||||
}
|
||||
|
||||
func fusermountBinary() (string, error) {
|
||||
binPaths := []string{
|
||||
"/sbin/mount_fusefs",
|
||||
}
|
||||
|
||||
for _, path := range binPaths {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no FUSE mount utility found")
|
||||
}
|
||||
Reference in New Issue
Block a user