Deleted fuseshim.
parent
8ce082c8b9
commit
ed2ae82923
|
@ -1,39 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/jacobsa/fuse/internal/fusekernel"
|
||||
)
|
||||
|
||||
// Buffer provides a mechanism for constructing a message from multiple
|
||||
// segments.
|
||||
type Buffer []byte
|
||||
|
||||
// alloc allocates size bytes and returns a pointer to the new
|
||||
// segment.
|
||||
func (w *Buffer) Alloc(size uintptr) unsafe.Pointer {
|
||||
s := int(size)
|
||||
if len(*w)+s > cap(*w) {
|
||||
old := *w
|
||||
*w = make([]byte, len(*w), 2*cap(*w)+s)
|
||||
copy(*w, old)
|
||||
}
|
||||
l := len(*w)
|
||||
*w = (*w)[:l+s]
|
||||
return unsafe.Pointer(&(*w)[l])
|
||||
}
|
||||
|
||||
// reset clears out the contents of the buffer.
|
||||
func (w *Buffer) reset() {
|
||||
for i := range (*w)[:cap(*w)] {
|
||||
(*w)[i] = 0
|
||||
}
|
||||
*w = (*w)[:0]
|
||||
}
|
||||
|
||||
func NewBuffer(extra uintptr) (buf Buffer) {
|
||||
const hdrSize = unsafe.Sizeof(fusekernel.OutHeader{})
|
||||
buf = make(Buffer, hdrSize, hdrSize+extra)
|
||||
return
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,131 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// OS X appears to cap the size of writes to 1 MiB. This constant is also used
|
||||
// for sizing receive buffers, so make it as small as it can be without
|
||||
// limiting write sizes.
|
||||
const maxWrite = 1 << 20
|
||||
|
||||
var errNoAvail = errors.New("no available fuse devices")
|
||||
|
||||
var errNotLoaded = errors.New("osxfusefs is not loaded")
|
||||
|
||||
func loadOSXFUSE() error {
|
||||
cmd := exec.Command("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs")
|
||||
cmd.Dir = "/"
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
return err
|
||||
}
|
||||
|
||||
func openOSXFUSEDev() (*os.File, error) {
|
||||
var f *os.File
|
||||
var err error
|
||||
for i := uint64(0); ; i++ {
|
||||
path := "/dev/osxfuse" + strconv.FormatUint(i, 10)
|
||||
f, err = os.OpenFile(path, os.O_RDWR, 0000)
|
||||
if os.IsNotExist(err) {
|
||||
if i == 0 {
|
||||
// not even the first device was found -> fuse is not loaded
|
||||
return nil, errNotLoaded
|
||||
}
|
||||
|
||||
// we've run out of kernel-provided devices
|
||||
return nil, errNoAvail
|
||||
}
|
||||
|
||||
if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
|
||||
// try the next one
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
func callMount(dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
|
||||
bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
|
||||
|
||||
for k, v := range conf.options {
|
||||
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
||||
// Silly limitation but the mount helper does not
|
||||
// understand any escaping. See TestMountOptionCommaError.
|
||||
return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v)
|
||||
}
|
||||
}
|
||||
cmd := exec.Command(
|
||||
bin,
|
||||
"-o", conf.getOptions(),
|
||||
// Tell osxfuse-kext how large our buffer is. It must split
|
||||
// writes larger than this into multiple writes.
|
||||
//
|
||||
// OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
|
||||
// this instead.
|
||||
"-o", "iosize="+strconv.FormatUint(maxWrite, 10),
|
||||
// refers to fd passed in cmd.ExtraFiles
|
||||
"3",
|
||||
dir,
|
||||
)
|
||||
cmd.ExtraFiles = []*os.File{f}
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
|
||||
// TODO this is used for fs typenames etc, let app influence it
|
||||
cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_DAEMON_PATH="+bin)
|
||||
var buf bytes.Buffer
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
err := cmd.Wait()
|
||||
if err != nil {
|
||||
if buf.Len() > 0 {
|
||||
output := buf.Bytes()
|
||||
output = bytes.TrimRight(output, "\n")
|
||||
msg := err.Error() + ": " + string(output)
|
||||
err = errors.New(msg)
|
||||
}
|
||||
}
|
||||
*errp = err
|
||||
close(ready)
|
||||
}()
|
||||
return err
|
||||
}
|
||||
|
||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
||||
f, err := openOSXFUSEDev()
|
||||
if err == errNotLoaded {
|
||||
err = loadOSXFUSE()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// try again
|
||||
f, err = openOSXFUSEDev()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = callMount(dir, conf, f, ready, errp)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Maximum file write size we are prepared to receive from the kernel.
|
||||
const maxWrite = 128 * 1024
|
||||
|
||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
||||
for k, v := range conf.options {
|
||||
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
||||
// Silly limitation but the mount helper does not
|
||||
// understand any escaping. See TestMountOptionCommaError.
|
||||
return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000)
|
||||
if err != nil {
|
||||
*errp = err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"/sbin/mount_fusefs",
|
||||
"--safe",
|
||||
"-o", conf.getOptions(),
|
||||
"3",
|
||||
dir,
|
||||
)
|
||||
cmd.ExtraFiles = []*os.File{f}
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mount_fusefs: %q, %v", out, err)
|
||||
}
|
||||
|
||||
close(ready)
|
||||
return f, nil
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Maximum file write size we are prepared to receive from the kernel. Linux
|
||||
// appears to limit writes to 128 KiB.
|
||||
const maxWrite = 128 * 1024
|
||||
|
||||
func lineLogger(wg *sync.WaitGroup, prefix string, r io.ReadCloser) {
|
||||
defer wg.Done()
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
switch line := scanner.Text(); line {
|
||||
case `fusermount: failed to open /etc/fuse.conf: Permission denied`:
|
||||
// Silence this particular message, it occurs way too
|
||||
// commonly and isn't very relevant to whether the mount
|
||||
// succeeds or not.
|
||||
continue
|
||||
default:
|
||||
log.Printf("%s: %s", prefix, line)
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Printf("%s, error reading: %v", prefix, err)
|
||||
}
|
||||
}
|
||||
|
||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
|
||||
// linux mount is never delayed
|
||||
close(ready)
|
||||
|
||||
fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("socketpair error: %v", err)
|
||||
}
|
||||
|
||||
writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
|
||||
defer writeFile.Close()
|
||||
|
||||
readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
|
||||
defer readFile.Close()
|
||||
|
||||
cmd := exec.Command(
|
||||
"fusermount",
|
||||
"-o", conf.getOptions(),
|
||||
"--",
|
||||
dir,
|
||||
)
|
||||
cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
|
||||
|
||||
cmd.ExtraFiles = []*os.File{writeFile}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("fusermount: %v", err)
|
||||
}
|
||||
wg.Add(2)
|
||||
go lineLogger(&wg, "mount helper output", stdout)
|
||||
go lineLogger(&wg, "mount helper error", stderr)
|
||||
wg.Wait()
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("fusermount: %v", err)
|
||||
}
|
||||
|
||||
c, err := net.FileConn(readFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uc, ok := c.(*net.UnixConn)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c)
|
||||
}
|
||||
|
||||
buf := make([]byte, 32) // expect 1 byte
|
||||
oob := make([]byte, 32) // expect 24 bytes
|
||||
_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
|
||||
scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
|
||||
}
|
||||
if len(scms) != 1 {
|
||||
return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
|
||||
}
|
||||
scm := scms[0]
|
||||
gotFds, err := syscall.ParseUnixRights(&scm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
|
||||
}
|
||||
if len(gotFds) != 1 {
|
||||
return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
|
||||
}
|
||||
f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
|
||||
return f, nil
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/jacobsa/fuse/internal/fusekernel"
|
||||
)
|
||||
|
||||
func dummyOption(conf *mountConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mountConfig holds the configuration for a mount operation.
|
||||
// Use it by passing MountOption values to Mount.
|
||||
type mountConfig struct {
|
||||
options map[string]string
|
||||
maxReadahead uint32
|
||||
initFlags fusekernel.InitFlags
|
||||
}
|
||||
|
||||
func escapeComma(s string) string {
|
||||
s = strings.Replace(s, `\`, `\\`, -1)
|
||||
s = strings.Replace(s, `,`, `\,`, -1)
|
||||
return s
|
||||
}
|
||||
|
||||
// getOptions makes a string of options suitable for passing to FUSE
|
||||
// mount flag `-o`. Returns an empty string if no options were set.
|
||||
// Any platform specific adjustments should happen before the call.
|
||||
func (m *mountConfig) getOptions() string {
|
||||
var opts []string
|
||||
for k, v := range m.options {
|
||||
k = escapeComma(k)
|
||||
if v != "" {
|
||||
k += "=" + escapeComma(v)
|
||||
}
|
||||
opts = append(opts, k)
|
||||
}
|
||||
return strings.Join(opts, ",")
|
||||
}
|
||||
|
||||
type mountOption func(*mountConfig) error
|
||||
|
||||
// MountOption is passed to Mount to change the behavior of the mount.
|
||||
type MountOption mountOption
|
||||
|
||||
// FSName sets the file system name (also called source) that is
|
||||
// visible in the list of mounted file systems.
|
||||
//
|
||||
// FreeBSD ignores this option.
|
||||
func FSName(name string) MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options["fsname"] = name
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Subtype sets the subtype of the mount. The main type is always
|
||||
// `fuse`. The type in a list of mounted file systems will look like
|
||||
// `fuse.foo`.
|
||||
//
|
||||
// OS X ignores this option.
|
||||
// FreeBSD ignores this option.
|
||||
func Subtype(fstype string) MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options["subtype"] = fstype
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// LocalVolume sets the volume to be local (instead of network),
|
||||
// changing the behavior of Finder, Spotlight, and such.
|
||||
//
|
||||
// OS X only. Others ignore this option.
|
||||
func LocalVolume() MountOption {
|
||||
return localVolume
|
||||
}
|
||||
|
||||
// VolumeName sets the volume name shown in Finder.
|
||||
//
|
||||
// OS X only. Others ignore this option.
|
||||
func VolumeName(name string) MountOption {
|
||||
return volumeName(name)
|
||||
}
|
||||
|
||||
var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
|
||||
|
||||
// AllowOther allows other users to access the file system.
|
||||
//
|
||||
// Only one of AllowOther or AllowRoot can be used.
|
||||
func AllowOther() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
if _, ok := conf.options["allow_root"]; ok {
|
||||
return ErrCannotCombineAllowOtherAndAllowRoot
|
||||
}
|
||||
conf.options["allow_other"] = ""
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AllowRoot allows other users to access the file system.
|
||||
//
|
||||
// Only one of AllowOther or AllowRoot can be used.
|
||||
//
|
||||
// FreeBSD ignores this option.
|
||||
func AllowRoot() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
if _, ok := conf.options["allow_other"]; ok {
|
||||
return ErrCannotCombineAllowOtherAndAllowRoot
|
||||
}
|
||||
conf.options["allow_root"] = ""
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultPermissions makes the kernel enforce access control based on
|
||||
// the file mode (as in chmod).
|
||||
//
|
||||
// Without this option, the Node itself decides what is and is not
|
||||
// allowed. This is normally ok because FUSE file systems cannot be
|
||||
// accessed by other users without AllowOther/AllowRoot.
|
||||
//
|
||||
// FreeBSD ignores this option.
|
||||
func DefaultPermissions() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options["default_permissions"] = ""
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Set the supplied arbitrary (key, value) pair in the "-o" argument to the
|
||||
// fuse mount binary, overriding any previous setting for the key. If value is
|
||||
// empty, the '=' will be omitted from the argument.
|
||||
func SetOption(key, value string) MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options[key] = value
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReadOnly makes the mount read-only.
|
||||
func ReadOnly() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options["ro"] = ""
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MaxReadahead sets the number of bytes that can be prefetched for
|
||||
// sequential reads. The kernel can enforce a maximum value lower than
|
||||
// this.
|
||||
//
|
||||
// This setting makes the kernel perform speculative reads that do not
|
||||
// originate from any client process. This usually tremendously
|
||||
// improves read performance.
|
||||
func MaxReadahead(n uint32) MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.maxReadahead = n
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AsyncRead enables multiple outstanding read requests for the same
|
||||
// handle. Without this, there is at most one request in flight at a
|
||||
// time.
|
||||
func AsyncRead() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.initFlags |= fusekernel.InitAsyncRead
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WritebackCache enables the kernel to buffer writes before sending
|
||||
// them to the FUSE server. Without this, writethrough caching is
|
||||
// used.
|
||||
func WritebackCache() MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.initFlags |= fusekernel.InitWritebackCache
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
func localVolume(conf *mountConfig) error {
|
||||
conf.options["local"] = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func volumeName(name string) MountOption {
|
||||
return func(conf *mountConfig) error {
|
||||
conf.options["volname"] = name
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
func localVolume(conf *mountConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func volumeName(name string) MountOption {
|
||||
return dummyOption
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
// for TestMountOptionCommaError
|
||||
func ForTestSetMountOption(k, v string) MountOption {
|
||||
fn := func(conf *mountConfig) error {
|
||||
conf.options[k] = v
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
func localVolume(conf *mountConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func volumeName(name string) MountOption {
|
||||
return dummyOption
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
package fuseshim_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
fuse "github.com/jacobsa/bazilfuse"
|
||||
"github.com/jacobsa/bazilfuse/fs"
|
||||
"github.com/jacobsa/bazilfuse/fs/fstestutil"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fstestutil.DebugByDefault()
|
||||
}
|
||||
|
||||
func TestMountOptionFSName(t *testing.T) {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.Skip("FreeBSD does not support FSName")
|
||||
}
|
||||
t.Parallel()
|
||||
const name = "FuseTestMarker"
|
||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||
fuse.FSName(name),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer mnt.Close()
|
||||
|
||||
info, err := fstestutil.GetMountInfo(mnt.Dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if g, e := info.FSName, name; g != e {
|
||||
t.Errorf("wrong FSName: %q != %q", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
func testMountOptionFSNameEvil(t *testing.T, evil string) {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.Skip("FreeBSD does not support FSName")
|
||||
}
|
||||
t.Parallel()
|
||||
var name = "FuseTest" + evil + "Marker"
|
||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||
fuse.FSName(name),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer mnt.Close()
|
||||
|
||||
info, err := fstestutil.GetMountInfo(mnt.Dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if g, e := info.FSName, name; g != e {
|
||||
t.Errorf("wrong FSName: %q != %q", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilComma(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// see TestMountOptionCommaError for a test that enforces we
|
||||
// at least give a nice error, instead of corrupting the mount
|
||||
// options
|
||||
t.Skip("TODO: OS X gets this wrong, commas in mount options cannot be escaped at all")
|
||||
}
|
||||
testMountOptionFSNameEvil(t, ",")
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilSpace(t *testing.T) {
|
||||
testMountOptionFSNameEvil(t, " ")
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilTab(t *testing.T) {
|
||||
testMountOptionFSNameEvil(t, "\t")
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilNewline(t *testing.T) {
|
||||
testMountOptionFSNameEvil(t, "\n")
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilBackslash(t *testing.T) {
|
||||
testMountOptionFSNameEvil(t, `\`)
|
||||
}
|
||||
|
||||
func TestMountOptionFSNameEvilBackslashDouble(t *testing.T) {
|
||||
// catch double-unescaping, if it were to happen
|
||||
testMountOptionFSNameEvil(t, `\\`)
|
||||
}
|
||||
|
||||
func TestMountOptionSubtype(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Skip("OS X does not support Subtype")
|
||||
}
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.Skip("FreeBSD does not support Subtype")
|
||||
}
|
||||
t.Parallel()
|
||||
const name = "FuseTestMarker"
|
||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||
fuse.Subtype(name),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer mnt.Close()
|
||||
|
||||
info, err := fstestutil.GetMountInfo(mnt.Dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if g, e := info.Type, "fuse."+name; g != e {
|
||||
t.Errorf("wrong Subtype: %q != %q", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO test LocalVolume
|
||||
|
||||
// TODO test AllowOther; hard because needs system-level authorization
|
||||
|
||||
func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||
fuse.AllowOther(),
|
||||
fuse.AllowRoot(),
|
||||
)
|
||||
if err == nil {
|
||||
mnt.Close()
|
||||
}
|
||||
if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
|
||||
t.Fatalf("wrong error: %v != %v", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO test AllowRoot; hard because needs system-level authorization
|
||||
|
||||
func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
|
||||
t.Parallel()
|
||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||
fuse.AllowRoot(),
|
||||
fuse.AllowOther(),
|
||||
)
|
||||
if err == nil {
|
||||
mnt.Close()
|
||||
}
|
||||
if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
|
||||
t.Fatalf("wrong error: %v != %v", g, e)
|
||||
}
|
||||
}
|
||||
|
||||
type unwritableFile struct{}
|
||||
|
||||
func (f unwritableFile) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||
a.Mode = 0000
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMountOptionDefaultPermissions(t *testing.T) {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.Skip("FreeBSD does not support DefaultPermissions")
|
||||
}
|
||||
t.Parallel()
|
||||
mnt, err := fstestutil.MountedT(t,
|
||||
fstestutil.SimpleFS{
|
||||
&fstestutil.ChildMap{"child": unwritableFile{}},
|
||||
},
|
||||
nil,
|
||||
fuse.DefaultPermissions(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer mnt.Close()
|
||||
|
||||
// This will be prevented by kernel-level access checking when
|
||||
// DefaultPermissions is used.
|
||||
f, err := os.OpenFile(mnt.Dir+"/child", os.O_WRONLY, 0000)
|
||||
if err == nil {
|
||||
f.Close()
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
if !os.IsPermission(err) {
|
||||
t.Fatalf("expected a permission error, got %T: %v", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
type createrDir struct {
|
||||
fstestutil.Dir
|
||||
}
|
||||
|
||||
var _ fs.NodeCreater = createrDir{}
|
||||
|
||||
func (createrDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
|
||||
// pick a really distinct error, to identify it later
|
||||
return nil, nil, fuse.Errno(syscall.ENAMETOOLONG)
|
||||
}
|
||||
|
||||
func TestMountOptionReadOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
mnt, err := fstestutil.MountedT(t,
|
||||
fstestutil.SimpleFS{createrDir{}},
|
||||
nil,
|
||||
fuse.ReadOnly(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer mnt.Close()
|
||||
|
||||
// This will be prevented by kernel-level access checking when
|
||||
// ReadOnly is used.
|
||||
f, err := os.Create(mnt.Dir + "/child")
|
||||
if err == nil {
|
||||
f.Close()
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
perr, ok := err.(*os.PathError)
|
||||
if !ok {
|
||||
t.Fatalf("expected PathError, got %T: %v", err, err)
|
||||
}
|
||||
if perr.Err != syscall.EROFS {
|
||||
t.Fatalf("expected EROFS, got %T: %v", err, err)
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
// Unmount tries to unmount the filesystem mounted at dir.
|
||||
func Unmount(dir string) error {
|
||||
return unmount(dir)
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package fuseshim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func unmount(dir string) error {
|
||||
cmd := exec.Command("fusermount", "-u", dir)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
if len(output) > 0 {
|
||||
output = bytes.TrimRight(output, "\n")
|
||||
msg := err.Error() + ": " + string(output)
|
||||
err = errors.New(msg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
package fuseshim
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func unmount(dir string) error {
|
||||
err := syscall.Unmount(dir, 0)
|
||||
if err != nil {
|
||||
err = &os.PathError{Op: "unmount", Path: dir, Err: err}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue