Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
09a3c381
Commit
09a3c381
authored
Dec 21, 2020
by
midchildan
Committed by
Han-Wen Nienhuys
Jan 04, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fuse: support the new macFUSE mount protocol
Closes #379. Change-Id: Ieb821fe7e68a3b7822306ad620dcdf834b5dfc12
parent
da0be912
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
90 additions
and
54 deletions
+90
-54
fuse/mount_darwin.go
fuse/mount_darwin.go
+90
-54
No files found.
fuse/mount_darwin.go
View file @
09a3c381
...
@@ -9,89 +9,125 @@ import (
...
@@ -9,89 +9,125 @@ import (
"fmt"
"fmt"
"os"
"os"
"os/exec"
"os/exec"
"path/filepath"
"strings"
"strings"
"syscall"
"syscall"
"unsafe"
)
)
func
openFUSEDevice
()
(
*
os
.
File
,
error
)
{
func
unixgramSocketpair
()
(
l
,
r
*
os
.
File
,
err
error
)
{
f
s
,
err
:=
filepath
.
Glob
(
"/dev/osxfuse*"
)
f
d
,
err
:=
syscall
.
Socketpair
(
syscall
.
AF_UNIX
,
syscall
.
SOCK_STREAM
,
0
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
os
.
NewSyscallError
(
"socketpair"
,
err
.
(
syscall
.
Errno
))
}
}
if
len
(
fs
)
==
0
{
l
=
os
.
NewFile
(
uintptr
(
fd
[
0
]),
"socketpair-half1"
)
bin
:=
oldLoadBin
r
=
os
.
NewFile
(
uintptr
(
fd
[
1
]),
"socketpair-half2"
)
if
_
,
err
:=
os
.
Stat
(
newLoadBin
);
err
==
nil
{
return
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"
// Create a FUSE FS on the specified mount point. The returned
const
newLoadBin
=
"/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse"
// mount point is always absolute.
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
)
{
func
mount
(
mountPoint
string
,
opts
*
MountOptions
,
ready
chan
<-
error
)
(
fd
int
,
err
error
)
{
f
,
err
:=
openFUSEDevice
()
local
,
remote
,
err
:=
unixgramSocketpair
()
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
}
}
bin
:=
oldMountBin
defer
local
.
Close
()
if
_
,
err
:=
os
.
Stat
(
newMountBin
);
err
==
nil
{
defer
remote
.
Close
()
bin
=
newMountBin
bin
,
err
:=
fusermountBinary
()
if
err
!=
nil
{
return
0
,
err
}
}
cmd
:=
exec
.
Command
(
bin
,
"-o"
,
strings
.
Join
(
opts
.
optionsStrings
(),
","
),
"-o"
,
fmt
.
Sprintf
(
"iosize=%d"
,
opts
.
MaxWrite
),
"3"
,
mountPoint
)
cmd
:=
exec
.
Command
(
bin
,
cmd
.
ExtraFiles
=
[]
*
os
.
File
{
f
}
"-o"
,
strings
.
Join
(
opts
.
optionsStrings
(),
","
),
cmd
.
Env
=
append
(
os
.
Environ
(),
"MOUNT_FUSEFS_CALL_BY_LIB="
,
"MOUNT_OSXFUSE_CALL_BY_LIB="
,
"-o"
,
fmt
.
Sprintf
(
"iosize=%d"
,
opts
.
MaxWrite
),
"MOUNT_OSXFUSE_DAEMON_PATH="
+
os
.
Args
[
0
],
mountPoint
)
"MOUNT_FUSEFS_DAEMON_PATH="
+
os
.
Args
[
0
])
cmd
.
ExtraFiles
=
[]
*
os
.
File
{
remote
}
// fd would be (index + 3)
cmd
.
Env
=
append
(
os
.
Environ
(),
"_FUSE_CALL_BY_LIB="
,
"_FUSE_DAEMON_PATH="
+
os
.
Args
[
0
],
"_FUSE_COMMFD=3"
,
"_FUSE_COMMVERS=2"
,
"MOUNT_OSXFUSE_CALL_BY_LIB="
,
"MOUNT_OSXFUSE_DAEMON_PATH="
+
os
.
Args
[
0
])
var
out
,
errOut
bytes
.
Buffer
var
out
,
errOut
bytes
.
Buffer
cmd
.
Stdout
=
&
out
cmd
.
Stdout
=
&
out
cmd
.
Stderr
=
&
errOut
cmd
.
Stderr
=
&
errOut
if
err
:=
cmd
.
Start
();
err
!=
nil
{
if
err
=
cmd
.
Start
();
err
!=
nil
{
f
.
Close
()
return
return
0
,
err
}
}
fd
,
err
=
getConnection
(
local
)
if
err
!=
nil
{
return
-
1
,
err
}
go
func
()
{
go
func
()
{
err
:=
cmd
.
Wait
()
// wait inside a goroutine or otherwise it would block forever for unknown reasons
if
err
!=
nil
{
if
err
:=
cmd
.
Wait
();
err
!=
nil
{
err
=
fmt
.
Errorf
(
"mount_osxfusefs failed: %v. Stderr: %s, Stdout: %s"
,
err
,
errOut
.
String
(),
out
.
String
())
err
=
fmt
.
Errorf
(
"mount_osxfusefs failed: %v. Stderr: %s, Stdout: %s"
,
err
,
errOut
.
String
(),
out
.
String
())
}
}
ready
<-
err
ready
<-
err
close
(
ready
)
close
(
ready
)
}()
}()
// The finalizer for f will close its fd so we return a dup.
// golang sets CLOEXEC on file descriptors when they are
defer
f
.
Close
()
// acquired through normal operations (e.g. open).
return
syscall
.
Dup
(
int
(
f
.
Fd
()))
// Buf for fd, we have to set CLOEXEC manually
syscall
.
CloseOnExec
(
fd
)
return
fd
,
err
}
}
func
unmount
(
dir
string
,
opts
*
MountOptions
)
error
{
func
unmount
(
dir
string
,
opts
*
MountOptions
)
error
{
return
syscall
.
Unmount
(
dir
,
0
)
return
syscall
.
Unmount
(
dir
,
0
)
}
}
func
getConnection
(
local
*
os
.
File
)
(
int
,
error
)
{
var
data
[
4
]
byte
control
:=
make
([]
byte
,
4
*
256
)
// n, oobn, recvflags, from, errno - todo: error checking.
_
,
oobn
,
_
,
_
,
err
:=
syscall
.
Recvmsg
(
int
(
local
.
Fd
()),
data
[
:
],
control
[
:
],
0
)
if
err
!=
nil
{
return
0
,
err
}
message
:=
*
(
*
syscall
.
Cmsghdr
)(
unsafe
.
Pointer
(
&
control
[
0
]))
fd
:=
*
(
*
int32
)(
unsafe
.
Pointer
(
uintptr
(
unsafe
.
Pointer
(
&
control
[
0
]))
+
syscall
.
SizeofCmsghdr
))
if
message
.
Type
!=
syscall
.
SCM_RIGHTS
{
return
0
,
fmt
.
Errorf
(
"getConnection: recvmsg returned wrong control type: %d"
,
message
.
Type
)
}
if
oobn
<=
syscall
.
SizeofCmsghdr
{
return
0
,
fmt
.
Errorf
(
"getConnection: too short control message. Length: %d"
,
oobn
)
}
if
fd
<
0
{
return
0
,
fmt
.
Errorf
(
"getConnection: fd < 0: %d"
,
fd
)
}
return
int
(
fd
),
nil
}
func
fusermountBinary
()
(
string
,
error
)
{
binPaths
:=
[]
string
{
"/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfuse"
,
"/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"
,
}
for
_
,
path
:=
range
binPaths
{
if
_
,
err
:=
os
.
Stat
(
path
);
err
==
nil
{
return
path
,
nil
}
}
return
""
,
fmt
.
Errorf
(
"no FUSE mount utility found"
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment