Commit 1072b7f0 authored by lch's avatar lch Committed by Han-Wen Nienhuys

fuse: add functional support for FreeBSD

fuse: merge attr definition of Darwin and FreeBSD

Change-Id: I7229229aed8afad74089bc2ce7eff0b86bd2ccd0
parent 290fbdd1
// Copyright 2016 the Go-FUSE Authors. All rights reserved. //go:build !linux
// Copyright 2024 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
package fuse
import (
"fmt"
"os"
"os/exec"
"strings"
"syscall"
)
func callMountFuseFs(mountPoint string, opts *MountOptions) (fd int, err error) {
bin, err := fusermountBinary()
if err != nil {
return 0, err
}
f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0o000)
if err != nil {
return -1, err
}
cmd := exec.Command(
bin,
"--safe",
"-o", strings.Join(opts.optionsStrings(), ","),
"3",
mountPoint,
)
cmd.Env = []string{"MOUNT_FUSEFS_CALL_BY_LIB=1"}
cmd.ExtraFiles = []*os.File{f}
if err := cmd.Start(); err != nil {
f.Close()
return -1, fmt.Errorf("mount_fusefs: %v", err)
}
if err := cmd.Wait(); err != nil {
// see if we have a better error to report
f.Close()
return -1, fmt.Errorf("mount_fusefs: %v", err)
}
return int(f.Fd()), nil
}
func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, err error) {
// 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).
// Buf for fd, 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")
}
//go:build !darwin
package fuse package fuse
import ( import (
......
package fuse
const outputHeaderSize = 160
const (
_FUSE_KERNEL_VERSION = 7
_MINIMUM_MINOR_VERSION = 12
_OUR_MINOR_VERSION = 28
)
// Copyright 2016 the Go-FUSE Authors. All rights reserved. //go:build !linux
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuse package fuse
import ( import (
"syscall" "golang.org/x/sys/unix"
) )
func (ms *Server) systemWrite(req *request, header []byte) Status { func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 { if req.flatDataSize() == 0 {
err := handleEINTR(func() error { err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header) _, err := unix.Write(ms.mountFd, header)
return err return err
}) })
return ToStatus(err) return ToStatus(err)
......
package fuse
import "fmt"
func (s *Server) setSplice() {
s.canSplice = false
}
func (ms *Server) trySplice(header []byte, req *request, fdData *readResultFd) error {
return fmt.Errorf("unimplemented")
}
...@@ -6,49 +6,10 @@ package fuse ...@@ -6,49 +6,10 @@ package fuse
import ( import (
"bytes" "bytes"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
) )
// TODO - move these into Go's syscall package.
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return
}
func writev(fd int, packet [][]byte) (n int, err error) {
iovecs := make([]syscall.Iovec, 0, len(packet))
for _, v := range packet {
if len(v) == 0 {
continue
}
vec := syscall.Iovec{
Base: &v[0],
}
vec.SetLen(len(v))
iovecs = append(iovecs, vec)
}
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}
func getxattr(path string, attr string, dest []byte) (sz int, errno int) { func getxattr(path string, attr string, dest []byte) (sz int, errno int) {
pathBs := syscall.StringBytePtr(path) pathBs := syscall.StringBytePtr(path)
attrBs := syscall.StringBytePtr(attr) attrBs := syscall.StringBytePtr(attr)
......
...@@ -5,45 +5,10 @@ ...@@ -5,45 +5,10 @@
package fuse package fuse
import ( import (
"os" "golang.org/x/sys/unix"
"syscall"
"unsafe"
) )
// TODO - move these into Go's syscall package.
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return n, err
}
func writev(fd int, packet [][]byte) (n int, err error) { func writev(fd int, packet [][]byte) (n int, err error) {
iovecs := make([]syscall.Iovec, 0, len(packet)) n, err = unix.Writev(fd, packet)
return
for _, v := range packet {
if len(v) == 0 {
continue
}
vec := syscall.Iovec{
Base: &v[0],
}
vec.SetLen(len(v))
iovecs = append(iovecs, vec)
}
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
} }
//go:build !linux
package fuse
import (
"os"
"syscall"
"unsafe"
)
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return n, err
}
// Until golang.orgx/sys/unix provides Writev for Darwin and FreeBSD,
// keep the syscall wrapping funcitons.
func writev(fd int, packet [][]byte) (n int, err error) {
iovecs := make([]syscall.Iovec, 0, len(packet))
for _, v := range packet {
if len(v) == 0 {
continue
}
vec := syscall.Iovec{
Base: &v[0],
}
vec.SetLen(len(v))
iovecs = append(iovecs, vec)
}
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment