fix dep, impl nonempty
This commit is contained in:
parent
c8c18403e4
commit
a5d237df2a
24 changed files with 286 additions and 215 deletions
6
Gopkg.lock
generated
6
Gopkg.lock
generated
|
|
@ -8,6 +8,7 @@
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/hanwen/go-fuse"
|
name = "github.com/hanwen/go-fuse"
|
||||||
packages = [
|
packages = [
|
||||||
"fuse",
|
"fuse",
|
||||||
|
|
@ -15,8 +16,7 @@
|
||||||
"fuse/pathfs",
|
"fuse/pathfs",
|
||||||
"splice"
|
"splice"
|
||||||
]
|
]
|
||||||
revision = "5690be47d614355a22931c129e1075c25a62e9ac"
|
revision = "a9ddcb8a4b609500fc59c89ccc9ee05f00a5fefd"
|
||||||
version = "v20170619"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/inconshreveable/mousetrap"
|
name = "github.com/inconshreveable/mousetrap"
|
||||||
|
|
@ -60,6 +60,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "b608e0349a7dfcc18e5882f75da5d116cf8986b1bc9d87d9b2808093698cd439"
|
inputs-digest = "9bee1a4379bcd4b9176976a3cedac4a5c846c42ebdc54c623d3fb551c6921aa9"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
||||||
|
|
@ -28,3 +28,7 @@
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/hanwen/go-fuse"
|
||||||
|
branch = "master"
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,15 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
hostport string
|
hostport string
|
||||||
|
nonempty bool
|
||||||
|
readonly bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(serveCmd)
|
rootCmd.AddCommand(serveCmd)
|
||||||
serveCmd.PersistentFlags().StringVar(&hostport, "listen", "0.0.0.0:8889", "Host and port to listen on")
|
serveCmd.PersistentFlags().StringVar(&hostport, "listen", "0.0.0.0:8889", "Host and port to listen on")
|
||||||
|
serveCmd.PersistentFlags().BoolVar(&nonempty, "nonempty", false, "Allow mounting over a nonempty directory (default behavior in libfuse 3.x)")
|
||||||
|
serveCmd.PersistentFlags().BoolVar(&readonly, "readonly", false, "Mount read-only")
|
||||||
}
|
}
|
||||||
|
|
||||||
var serveCmd = &cobra.Command{
|
var serveCmd = &cobra.Command{
|
||||||
|
|
@ -29,5 +33,9 @@ func serveRun(cmd *cobra.Command, args []string) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
dir := args[0]
|
dir := args[0]
|
||||||
kubelwagen.Serve(hostport, dir)
|
opts := &kubelwagen.WsFsOpts{
|
||||||
|
ReadOnly: readonly,
|
||||||
|
NonEmpty: nonempty,
|
||||||
|
}
|
||||||
|
kubelwagen.Serve(hostport, dir, opts)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ type WsFs struct {
|
||||||
|
|
||||||
type WsFsOpts struct {
|
type WsFsOpts struct {
|
||||||
ReadOnly bool
|
ReadOnly bool
|
||||||
|
NonEmpty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWsFs(opts WsFsOpts, req chan RequestCallback, closer chan bool) *pathfs.PathNodeFs {
|
func NewWsFs(opts WsFsOpts, req chan RequestCallback, closer chan bool) *pathfs.PathNodeFs {
|
||||||
|
|
|
||||||
23
fuse.go
23
fuse.go
|
|
@ -1,16 +1,18 @@
|
||||||
package kubelwagen
|
package kubelwagen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
"github.com/hanwen/go-fuse/fuse/nodefs"
|
"github.com/hanwen/go-fuse/fuse/nodefs"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveFuse(dir string, req chan RequestCallback, closer chan bool) error {
|
func serveFuse(dir string, req chan RequestCallback, opts WsFsOpts, closer chan bool) error {
|
||||||
opts := WsFsOpts{
|
|
||||||
ReadOnly: true,
|
|
||||||
}
|
|
||||||
nfs := NewWsFs(opts, req, closer)
|
nfs := NewWsFs(opts, req, closer)
|
||||||
server, _, err := nodefs.MountRoot(dir, nfs.Root(), nil)
|
|
||||||
|
mountOpts := mkMountOpts(opts)
|
||||||
|
conn := nodefs.NewFileSystemConnector(nfs.Root(), &nodefs.Options{})
|
||||||
|
|
||||||
|
server, err := fuse.NewServer(conn.RawFS(), dir, mountOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatalln("cannot mount:", err)
|
logrus.Fatalln("cannot mount:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -19,3 +21,14 @@ func serveFuse(dir string, req chan RequestCallback, closer chan bool) error {
|
||||||
<-closer
|
<-closer
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mkMountOpts(opts WsFsOpts) *fuse.MountOptions {
|
||||||
|
var fusermountopts []string
|
||||||
|
if opts.NonEmpty {
|
||||||
|
fusermountopts = append(fusermountopts, "nonempty")
|
||||||
|
}
|
||||||
|
mountOpts := &fuse.MountOptions{
|
||||||
|
Options: fusermountopts,
|
||||||
|
}
|
||||||
|
return mountOpts
|
||||||
|
}
|
||||||
|
|
|
||||||
4
serve.go
4
serve.go
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Serve(hostport string, dir string) {
|
func Serve(hostport string, dir string, opts *WsFsOpts) {
|
||||||
closer := make(chan bool)
|
closer := make(chan bool)
|
||||||
|
|
||||||
signalChan := make(chan os.Signal, 1)
|
signalChan := make(chan os.Signal, 1)
|
||||||
|
|
@ -25,7 +25,7 @@ func Serve(hostport string, dir string) {
|
||||||
req := make(chan RequestCallback, 5)
|
req := make(chan RequestCallback, 5)
|
||||||
|
|
||||||
go func(dir string, closer chan bool) {
|
go func(dir string, closer chan bool) {
|
||||||
err := serveFuse(dir, req, closer)
|
err := serveFuse(dir, req, *opts, closer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatalf("Error serving FUSE: %s", err)
|
logrus.Fatalf("Error serving FUSE: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
vendor/github.com/hanwen/go-fuse/AUTHORS
generated
vendored
1
vendor/github.com/hanwen/go-fuse/AUTHORS
generated
vendored
|
|
@ -11,5 +11,6 @@ Logan Hanks <logan@bitcasa.com>
|
||||||
Nick Cooper <gh@smoogle.org>
|
Nick Cooper <gh@smoogle.org>
|
||||||
Patrick Crosby <pcrosby@gmail.com>
|
Patrick Crosby <pcrosby@gmail.com>
|
||||||
Paul Jolly <paul@myitcv.org.uk>
|
Paul Jolly <paul@myitcv.org.uk>
|
||||||
|
Shayan Pooya <shayan@arista.com>
|
||||||
Valient Gough <vgough@pobox.com>
|
Valient Gough <vgough@pobox.com>
|
||||||
Yongwoo Park <nnnlife@gmail.com>
|
Yongwoo Park <nnnlife@gmail.com>
|
||||||
|
|
|
||||||
11
vendor/github.com/hanwen/go-fuse/fuse/api.go
generated
vendored
11
vendor/github.com/hanwen/go-fuse/fuse/api.go
generated
vendored
|
|
@ -92,7 +92,18 @@ type RawFileSystem interface {
|
||||||
// If called, provide debug output through the log package.
|
// If called, provide debug output through the log package.
|
||||||
SetDebug(debug bool)
|
SetDebug(debug bool)
|
||||||
|
|
||||||
|
// Lookup is called by the kernel when the VFS wants to know
|
||||||
|
// about a file inside a directory. Many lookup calls can
|
||||||
|
// occur in parallel, but only one call happens for each (dir,
|
||||||
|
// name) pair.
|
||||||
Lookup(header *InHeader, name string, out *EntryOut) (status Status)
|
Lookup(header *InHeader, name string, out *EntryOut) (status Status)
|
||||||
|
|
||||||
|
// Forget is called when the kernel discards entries from its
|
||||||
|
// dentry cache. This happens on unmount, and when the kernel
|
||||||
|
// is short on memory. Since it is not guaranteed to occur at
|
||||||
|
// any moment, and since there is no return value, Forget
|
||||||
|
// should not do I/O, as there is no channel to report back
|
||||||
|
// I/O errors.
|
||||||
Forget(nodeid, nlookup uint64)
|
Forget(nodeid, nlookup uint64)
|
||||||
|
|
||||||
// Attributes.
|
// Attributes.
|
||||||
|
|
|
||||||
12
vendor/github.com/hanwen/go-fuse/fuse/direntry.go
generated
vendored
12
vendor/github.com/hanwen/go-fuse/fuse/direntry.go
generated
vendored
|
|
@ -24,10 +24,13 @@ type DirEntry struct {
|
||||||
|
|
||||||
// Name is the basename of the file in the directory.
|
// Name is the basename of the file in the directory.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
// Ino is the inode number.
|
||||||
|
Ino uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DirEntry) String() string {
|
func (d DirEntry) String() string {
|
||||||
return fmt.Sprintf("%o: %q", d.Mode, d.Name)
|
return fmt.Sprintf("%o: %q ino=%d", d.Mode, d.Name, d.Ino)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirEntryList holds the return value for READDIR and READDIRPLUS
|
// DirEntryList holds the return value for READDIR and READDIRPLUS
|
||||||
|
|
@ -51,12 +54,15 @@ func NewDirEntryList(data []byte, off uint64) *DirEntryList {
|
||||||
// AddDirEntry tries to add an entry, and reports whether it
|
// AddDirEntry tries to add an entry, and reports whether it
|
||||||
// succeeded.
|
// succeeded.
|
||||||
func (l *DirEntryList) AddDirEntry(e DirEntry) (bool, uint64) {
|
func (l *DirEntryList) AddDirEntry(e DirEntry) (bool, uint64) {
|
||||||
return l.Add(0, e.Name, uint64(FUSE_UNKNOWN_INO), e.Mode)
|
return l.Add(0, e.Name, e.Ino, e.Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a direntry to the DirEntryList, returning whether it
|
// Add adds a direntry to the DirEntryList, returning whether it
|
||||||
// succeeded.
|
// succeeded.
|
||||||
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (bool, uint64) {
|
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (bool, uint64) {
|
||||||
|
if inode == 0 {
|
||||||
|
inode = FUSE_UNKNOWN_INO
|
||||||
|
}
|
||||||
padding := (8 - len(name)&7) & 7
|
padding := (8 - len(name)&7) & 7
|
||||||
delta := padding + direntSize + len(name) + prefix
|
delta := padding + direntSize + len(name) + prefix
|
||||||
oldLen := len(l.buf)
|
oldLen := len(l.buf)
|
||||||
|
|
@ -90,7 +96,7 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (
|
||||||
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) (*EntryOut, uint64) {
|
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) (*EntryOut, uint64) {
|
||||||
lastStart := len(l.buf)
|
lastStart := len(l.buf)
|
||||||
ok, off := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
|
ok, off := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
|
||||||
uint64(FUSE_UNKNOWN_INO), e.Mode)
|
e.Ino, e.Mode)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, off
|
return nil, off
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
vendor/github.com/hanwen/go-fuse/fuse/mount_darwin.go
generated
vendored
19
vendor/github.com/hanwen/go-fuse/fuse/mount_darwin.go
generated
vendored
|
|
@ -20,9 +20,21 @@ func openFUSEDevice() (*os.File, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(fs) == 0 {
|
if len(fs) == 0 {
|
||||||
// TODO(hanwen): run the load_osxfuse command.
|
bin := oldLoadBin
|
||||||
return nil, fmt.Errorf("no FUSE devices found")
|
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 {
|
for _, fn := range fs {
|
||||||
f, err := os.OpenFile(fn, os.O_RDWR, 0)
|
f, err := os.OpenFile(fn, os.O_RDWR, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -34,6 +46,9 @@ func openFUSEDevice() (*os.File, error) {
|
||||||
return nil, fmt.Errorf("all FUSE devices busy")
|
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 oldMountBin = "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
|
||||||
const newMountBin = "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"
|
const newMountBin = "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"
|
||||||
|
|
||||||
|
|
|
||||||
28
vendor/github.com/hanwen/go-fuse/fuse/mount_linux.go
generated
vendored
28
vendor/github.com/hanwen/go-fuse/fuse/mount_linux.go
generated
vendored
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
@ -71,33 +70,18 @@ func mount(mountPoint string, opts *MountOptions, ready chan<- error) (fd int, e
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
close(ready)
|
||||||
return fd, err
|
return fd, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func privilegedUnmount(mountPoint string) error {
|
|
||||||
dir, _ := filepath.Split(mountPoint)
|
|
||||||
bin, err := umountBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
proc, err := os.StartProcess(bin,
|
|
||||||
[]string{bin, mountPoint},
|
|
||||||
&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w, err := proc.Wait()
|
|
||||||
if !w.Success() {
|
|
||||||
return fmt.Errorf("umount exited with code %v\n", w.Sys())
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmount(mountPoint string) (err error) {
|
func unmount(mountPoint string) (err error) {
|
||||||
if os.Geteuid() == 0 {
|
if os.Geteuid() == 0 {
|
||||||
return privilegedUnmount(mountPoint)
|
return syscall.Unmount(mountPoint, 0)
|
||||||
}
|
}
|
||||||
bin, err := fusermountBinary()
|
bin, err := fusermountBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
32
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go
generated
vendored
32
vendor/github.com/hanwen/go-fuse/fuse/nodefs/handle.go
generated
vendored
|
|
@ -35,8 +35,8 @@ type handleMap interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type handled struct {
|
type handled struct {
|
||||||
check uint32
|
|
||||||
handle uint64
|
handle uint64
|
||||||
|
generation uint64
|
||||||
count int
|
count int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,29 +76,29 @@ func newPortableHandleMap() *portableHandleMap {
|
||||||
|
|
||||||
func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
|
func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
if obj.count == 0 {
|
defer m.Unlock()
|
||||||
if obj.check != 0 {
|
// Reuse existing handle
|
||||||
panic(_ALREADY_MSG)
|
if obj.count != 0 {
|
||||||
|
obj.count++
|
||||||
|
return obj.handle, obj.generation
|
||||||
}
|
}
|
||||||
|
// Create a new handle number or recycle one on from the free list
|
||||||
if len(m.freeIds) == 0 {
|
if len(m.freeIds) == 0 {
|
||||||
handle = uint64(len(m.handles))
|
obj.handle = uint64(len(m.handles))
|
||||||
m.handles = append(m.handles, obj)
|
m.handles = append(m.handles, obj)
|
||||||
} else {
|
} else {
|
||||||
handle = m.freeIds[len(m.freeIds)-1]
|
obj.handle = m.freeIds[len(m.freeIds)-1]
|
||||||
m.freeIds = m.freeIds[:len(m.freeIds)-1]
|
m.freeIds = m.freeIds[:len(m.freeIds)-1]
|
||||||
|
m.handles[obj.handle] = obj
|
||||||
|
}
|
||||||
|
// Increment generation number to guarantee the (handle, generation) tuple
|
||||||
|
// is unique
|
||||||
m.generation++
|
m.generation++
|
||||||
m.handles[handle] = obj
|
|
||||||
}
|
|
||||||
m.used++
|
m.used++
|
||||||
obj.handle = handle
|
obj.generation = m.generation
|
||||||
} else {
|
|
||||||
handle = obj.handle
|
|
||||||
}
|
|
||||||
obj.count++
|
obj.count++
|
||||||
generation = m.generation
|
|
||||||
m.Unlock()
|
return obj.handle, obj.generation
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
|
func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
|
||||||
|
|
|
||||||
6
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go
generated
vendored
6
vendor/github.com/hanwen/go-fuse/fuse/nodefs/inode.go
generated
vendored
|
|
@ -24,10 +24,6 @@ type parentData struct {
|
||||||
type Inode struct {
|
type Inode struct {
|
||||||
handled handled
|
handled handled
|
||||||
|
|
||||||
// Generation number of the inode. Each (re)use of an inode
|
|
||||||
// should have a unique generation number.
|
|
||||||
generation uint64
|
|
||||||
|
|
||||||
// Number of open files and its protection.
|
// Number of open files and its protection.
|
||||||
openFilesMutex sync.Mutex
|
openFilesMutex sync.Mutex
|
||||||
openFiles []*openedFile
|
openFiles []*openedFile
|
||||||
|
|
@ -94,6 +90,8 @@ func (n *Inode) Parent() (parent *Inode, name string) {
|
||||||
if n.mountPoint != nil {
|
if n.mountPoint != nil {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
n.mount.treeLock.RLock()
|
||||||
|
defer n.mount.treeLock.RUnlock()
|
||||||
for k := range n.parents {
|
for k := range n.parents {
|
||||||
return k.parent, k.name
|
return k.parent, k.name
|
||||||
}
|
}
|
||||||
|
|
|
||||||
37
vendor/github.com/hanwen/go-fuse/fuse/opcode.go
generated
vendored
37
vendor/github.com/hanwen/go-fuse/fuse/opcode.go
generated
vendored
|
|
@ -90,7 +90,8 @@ func doInit(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
server.reqMu.Unlock()
|
server.reqMu.Unlock()
|
||||||
|
|
||||||
out := &InitOut{
|
out := (*InitOut)(req.outData())
|
||||||
|
*out = InitOut{
|
||||||
Major: _FUSE_KERNEL_VERSION,
|
Major: _FUSE_KERNEL_VERSION,
|
||||||
Minor: _OUR_MINOR_VERSION,
|
Minor: _OUR_MINOR_VERSION,
|
||||||
MaxReadAhead: input.MaxReadAhead,
|
MaxReadAhead: input.MaxReadAhead,
|
||||||
|
|
@ -99,6 +100,7 @@ func doInit(server *Server, req *request) {
|
||||||
CongestionThreshold: uint16(server.opts.MaxBackground * 3 / 4),
|
CongestionThreshold: uint16(server.opts.MaxBackground * 3 / 4),
|
||||||
MaxBackground: uint16(server.opts.MaxBackground),
|
MaxBackground: uint16(server.opts.MaxBackground),
|
||||||
}
|
}
|
||||||
|
|
||||||
if server.opts.MaxReadAhead != 0 && uint32(server.opts.MaxReadAhead) < out.MaxReadAhead {
|
if server.opts.MaxReadAhead != 0 && uint32(server.opts.MaxReadAhead) < out.MaxReadAhead {
|
||||||
out.MaxReadAhead = uint32(server.opts.MaxReadAhead)
|
out.MaxReadAhead = uint32(server.opts.MaxReadAhead)
|
||||||
}
|
}
|
||||||
|
|
@ -114,12 +116,11 @@ func doInit(server *Server, req *request) {
|
||||||
req.handler = &tweaked
|
req.handler = &tweaked
|
||||||
}
|
}
|
||||||
|
|
||||||
req.outData = unsafe.Pointer(out)
|
|
||||||
req.status = OK
|
req.status = OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func doOpen(server *Server, req *request) {
|
func doOpen(server *Server, req *request) {
|
||||||
out := (*OpenOut)(req.outData)
|
out := (*OpenOut)(req.outData())
|
||||||
status := server.fileSystem.Open((*OpenIn)(req.inData), out)
|
status := server.fileSystem.Open((*OpenIn)(req.inData), out)
|
||||||
req.status = status
|
req.status = status
|
||||||
if status != OK {
|
if status != OK {
|
||||||
|
|
@ -128,7 +129,7 @@ func doOpen(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCreate(server *Server, req *request) {
|
func doCreate(server *Server, req *request) {
|
||||||
out := (*CreateOut)(req.outData)
|
out := (*CreateOut)(req.outData())
|
||||||
status := server.fileSystem.Create((*CreateIn)(req.inData), req.filenames[0], out)
|
status := server.fileSystem.Create((*CreateIn)(req.inData), req.filenames[0], out)
|
||||||
req.status = status
|
req.status = status
|
||||||
}
|
}
|
||||||
|
|
@ -154,19 +155,19 @@ func doReadDirPlus(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doOpenDir(server *Server, req *request) {
|
func doOpenDir(server *Server, req *request) {
|
||||||
out := (*OpenOut)(req.outData)
|
out := (*OpenOut)(req.outData())
|
||||||
status := server.fileSystem.OpenDir((*OpenIn)(req.inData), out)
|
status := server.fileSystem.OpenDir((*OpenIn)(req.inData), out)
|
||||||
req.status = status
|
req.status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
func doSetattr(server *Server, req *request) {
|
func doSetattr(server *Server, req *request) {
|
||||||
out := (*AttrOut)(req.outData)
|
out := (*AttrOut)(req.outData())
|
||||||
req.status = server.fileSystem.SetAttr((*SetAttrIn)(req.inData), out)
|
req.status = server.fileSystem.SetAttr((*SetAttrIn)(req.inData), out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doWrite(server *Server, req *request) {
|
func doWrite(server *Server, req *request) {
|
||||||
n, status := server.fileSystem.Write((*WriteIn)(req.inData), req.arg)
|
n, status := server.fileSystem.Write((*WriteIn)(req.inData), req.arg)
|
||||||
o := (*WriteOut)(req.outData)
|
o := (*WriteOut)(req.outData())
|
||||||
o.Size = n
|
o.Size = n
|
||||||
req.status = status
|
req.status = status
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +194,7 @@ func doGetXAttr(server *Server, req *request) {
|
||||||
input := (*GetXAttrIn)(req.inData)
|
input := (*GetXAttrIn)(req.inData)
|
||||||
|
|
||||||
if input.Size == 0 {
|
if input.Size == 0 {
|
||||||
out := (*GetXAttrOut)(req.outData)
|
out := (*GetXAttrOut)(req.outData())
|
||||||
switch req.inHeader.Opcode {
|
switch req.inHeader.Opcode {
|
||||||
case _OP_GETXATTR:
|
case _OP_GETXATTR:
|
||||||
// TODO(hanwen): double check this. For getxattr, input.Size
|
// TODO(hanwen): double check this. For getxattr, input.Size
|
||||||
|
|
@ -214,8 +215,6 @@ func doGetXAttr(server *Server, req *request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req.outData = nil
|
|
||||||
var data []byte
|
var data []byte
|
||||||
switch req.inHeader.Opcode {
|
switch req.inHeader.Opcode {
|
||||||
case _OP_GETXATTR:
|
case _OP_GETXATTR:
|
||||||
|
|
@ -239,7 +238,7 @@ func doGetXAttr(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doGetAttr(server *Server, req *request) {
|
func doGetAttr(server *Server, req *request) {
|
||||||
out := (*AttrOut)(req.outData)
|
out := (*AttrOut)(req.outData())
|
||||||
s := server.fileSystem.GetAttr((*GetAttrIn)(req.inData), out)
|
s := server.fileSystem.GetAttr((*GetAttrIn)(req.inData), out)
|
||||||
req.status = s
|
req.status = s
|
||||||
}
|
}
|
||||||
|
|
@ -272,6 +271,9 @@ func doBatchForget(server *Server, req *request) {
|
||||||
if server.opts.Debug {
|
if server.opts.Debug {
|
||||||
log.Printf("doBatchForget: forgetting %d of %d: NodeId: %d, Nlookup: %d", i+1, len(forgets), f.NodeId, f.Nlookup)
|
log.Printf("doBatchForget: forgetting %d of %d: NodeId: %d, Nlookup: %d", i+1, len(forgets), f.NodeId, f.Nlookup)
|
||||||
}
|
}
|
||||||
|
if f.NodeId == pollHackInode {
|
||||||
|
continue
|
||||||
|
}
|
||||||
server.fileSystem.Forget(f.NodeId, f.Nlookup)
|
server.fileSystem.Forget(f.NodeId, f.Nlookup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,20 +283,19 @@ func doReadlink(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLookup(server *Server, req *request) {
|
func doLookup(server *Server, req *request) {
|
||||||
out := (*EntryOut)(req.outData)
|
out := (*EntryOut)(req.outData())
|
||||||
s := server.fileSystem.Lookup(req.inHeader, req.filenames[0], out)
|
s := server.fileSystem.Lookup(req.inHeader, req.filenames[0], out)
|
||||||
req.status = s
|
req.status = s
|
||||||
req.outData = unsafe.Pointer(out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func doMknod(server *Server, req *request) {
|
func doMknod(server *Server, req *request) {
|
||||||
out := (*EntryOut)(req.outData)
|
out := (*EntryOut)(req.outData())
|
||||||
|
|
||||||
req.status = server.fileSystem.Mknod((*MknodIn)(req.inData), req.filenames[0], out)
|
req.status = server.fileSystem.Mknod((*MknodIn)(req.inData), req.filenames[0], out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doMkdir(server *Server, req *request) {
|
func doMkdir(server *Server, req *request) {
|
||||||
out := (*EntryOut)(req.outData)
|
out := (*EntryOut)(req.outData())
|
||||||
req.status = server.fileSystem.Mkdir((*MkdirIn)(req.inData), req.filenames[0], out)
|
req.status = server.fileSystem.Mkdir((*MkdirIn)(req.inData), req.filenames[0], out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,7 +308,7 @@ func doRmdir(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLink(server *Server, req *request) {
|
func doLink(server *Server, req *request) {
|
||||||
out := (*EntryOut)(req.outData)
|
out := (*EntryOut)(req.outData())
|
||||||
req.status = server.fileSystem.Link((*LinkIn)(req.inData), req.filenames[0], out)
|
req.status = server.fileSystem.Link((*LinkIn)(req.inData), req.filenames[0], out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,7 +359,7 @@ func doAccess(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doSymlink(server *Server, req *request) {
|
func doSymlink(server *Server, req *request) {
|
||||||
out := (*EntryOut)(req.outData)
|
out := (*EntryOut)(req.outData())
|
||||||
req.status = server.fileSystem.Symlink(req.inHeader, req.filenames[1], req.filenames[0], out)
|
req.status = server.fileSystem.Symlink(req.inHeader, req.filenames[1], req.filenames[0], out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,7 +368,7 @@ func doRename(server *Server, req *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStatFs(server *Server, req *request) {
|
func doStatFs(server *Server, req *request) {
|
||||||
out := (*StatfsOut)(req.outData)
|
out := (*StatfsOut)(req.outData())
|
||||||
req.status = server.fileSystem.StatFs(req.inHeader, out)
|
req.status = server.fileSystem.StatFs(req.inHeader, out)
|
||||||
if req.status == ENOSYS && runtime.GOOS == "darwin" {
|
if req.status == ENOSYS && runtime.GOOS == "darwin" {
|
||||||
// OSX FUSE requires Statfs to be implemented for the
|
// OSX FUSE requires Statfs to be implemented for the
|
||||||
|
|
|
||||||
1
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go
generated
vendored
1
vendor/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go
generated
vendored
|
|
@ -99,6 +99,7 @@ func (fs *loopbackFileSystem) OpenDir(name string, context *fuse.Context) (strea
|
||||||
}
|
}
|
||||||
if s := fuse.ToStatT(infos[i]); s != nil {
|
if s := fuse.ToStatT(infos[i]); s != nil {
|
||||||
d.Mode = uint32(s.Mode)
|
d.Mode = uint32(s.Mode)
|
||||||
|
d.Ino = s.Ino
|
||||||
} else {
|
} else {
|
||||||
log.Printf("ReadDir entry %q for %q has no stat info", n, name)
|
log.Printf("ReadDir entry %q for %q has no stat info", n, name)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
vendor/github.com/hanwen/go-fuse/fuse/pathfs/pathfs.go
generated
vendored
30
vendor/github.com/hanwen/go-fuse/fuse/pathfs/pathfs.go
generated
vendored
|
|
@ -276,7 +276,6 @@ func (n *pathInode) GetPath() string {
|
||||||
// them, them, but since this is a hot path, we take some
|
// them, them, but since this is a hot path, we take some
|
||||||
// effort to avoid allocations.
|
// effort to avoid allocations.
|
||||||
|
|
||||||
n.pathFs.pathLock.RLock()
|
|
||||||
walkUp := n.Inode()
|
walkUp := n.Inode()
|
||||||
|
|
||||||
// TODO - guess depth?
|
// TODO - guess depth?
|
||||||
|
|
@ -299,7 +298,6 @@ func (n *pathInode) GetPath() string {
|
||||||
pathBytes = append(pathBytes, '/')
|
pathBytes = append(pathBytes, '/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.pathFs.pathLock.RUnlock()
|
|
||||||
|
|
||||||
path := string(pathBytes)
|
path := string(pathBytes)
|
||||||
if n.pathFs.debug {
|
if n.pathFs.debug {
|
||||||
|
|
@ -585,26 +583,34 @@ func (n *pathInode) GetAttr(out *fuse.Attr, file nodefs.File, context *fuse.Cont
|
||||||
// an open fd.
|
// an open fd.
|
||||||
file = n.Inode().AnyFile()
|
file = n.Inode().AnyFile()
|
||||||
}
|
}
|
||||||
|
// If we have found an open file, try to fstat it.
|
||||||
if file != nil {
|
if file != nil {
|
||||||
code = file.GetAttr(out)
|
code = file.GetAttr(out)
|
||||||
|
if code.Ok() {
|
||||||
|
return code
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// If we don't have an open file, or fstat on it failed due to an internal
|
||||||
|
// error, stat by path.
|
||||||
if file == nil || code == fuse.ENOSYS || code == fuse.EBADF {
|
if file == nil || code == fuse.ENOSYS || code == fuse.EBADF {
|
||||||
fi, code = n.fs.GetAttr(n.GetPath(), context)
|
fi, code = n.fs.GetAttr(n.GetPath(), context)
|
||||||
|
if !code.Ok() {
|
||||||
|
return code
|
||||||
}
|
}
|
||||||
|
// This is a bug in the filesystem implementation, but let's not
|
||||||
if fi != nil {
|
// crash.
|
||||||
|
if fi == nil {
|
||||||
|
log.Printf("Bug: fs.GetAttr returned OK with nil data")
|
||||||
|
return fuse.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set inode number (unless already set or disabled).
|
||||||
n.setClientInode(fi.Ino)
|
n.setClientInode(fi.Ino)
|
||||||
}
|
// Help filesystems that forget to set Nlink.
|
||||||
|
if !fi.IsDir() && fi.Nlink == 0 {
|
||||||
if fi != nil && !fi.IsDir() && fi.Nlink == 0 {
|
|
||||||
fi.Nlink = 1
|
fi.Nlink = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi != nil {
|
|
||||||
*out = *fi
|
*out = *fi
|
||||||
}
|
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3
vendor/github.com/hanwen/go-fuse/fuse/print.go
generated
vendored
3
vendor/github.com/hanwen/go-fuse/fuse/print.go
generated
vendored
|
|
@ -46,6 +46,9 @@ func init() {
|
||||||
CAP_ASYNC_DIO: "ASYNC_DIO",
|
CAP_ASYNC_DIO: "ASYNC_DIO",
|
||||||
CAP_WRITEBACK_CACHE: "WRITEBACK_CACHE",
|
CAP_WRITEBACK_CACHE: "WRITEBACK_CACHE",
|
||||||
CAP_NO_OPEN_SUPPORT: "NO_OPEN_SUPPORT",
|
CAP_NO_OPEN_SUPPORT: "NO_OPEN_SUPPORT",
|
||||||
|
CAP_PARALLEL_DIROPS: "CAP_PARALLEL_DIROPS",
|
||||||
|
CAP_HANDLE_KILLPRIV: "CAP_PARALLEL_DIROPS",
|
||||||
|
CAP_POSIX_ACL: "CAP_POSIX_ACL",
|
||||||
}
|
}
|
||||||
releaseFlagNames = map[int64]string{
|
releaseFlagNames = map[int64]string{
|
||||||
RELEASE_FLUSH: "FLUSH",
|
RELEASE_FLUSH: "FLUSH",
|
||||||
|
|
|
||||||
37
vendor/github.com/hanwen/go-fuse/fuse/request.go
generated
vendored
37
vendor/github.com/hanwen/go-fuse/fuse/request.go
generated
vendored
|
|
@ -26,8 +26,7 @@ type request struct {
|
||||||
|
|
||||||
filenames []string // filename arguments
|
filenames []string // filename arguments
|
||||||
|
|
||||||
// Unstructured data, a pointer to the relevant XxxxOut struct.
|
// Output data.
|
||||||
outData unsafe.Pointer
|
|
||||||
status Status
|
status Status
|
||||||
flatData []byte
|
flatData []byte
|
||||||
fdData *readResultFd
|
fdData *readResultFd
|
||||||
|
|
@ -65,7 +64,6 @@ func (r *request) clear() {
|
||||||
r.inData = nil
|
r.inData = nil
|
||||||
r.arg = nil
|
r.arg = nil
|
||||||
r.filenames = nil
|
r.filenames = nil
|
||||||
r.outData = nil
|
|
||||||
r.status = OK
|
r.status = OK
|
||||||
r.flatData = nil
|
r.flatData = nil
|
||||||
r.fdData = nil
|
r.fdData = nil
|
||||||
|
|
@ -96,8 +94,8 @@ func (r *request) InputDebug() string {
|
||||||
|
|
||||||
func (r *request) OutputDebug() string {
|
func (r *request) OutputDebug() string {
|
||||||
var dataStr string
|
var dataStr string
|
||||||
if r.handler.DecodeOut != nil && r.outData != nil {
|
if r.handler.DecodeOut != nil && r.handler.OutputSize > 0 {
|
||||||
dataStr = Print(r.handler.DecodeOut(r.outData))
|
dataStr = Print(r.handler.DecodeOut(r.outData()))
|
||||||
}
|
}
|
||||||
|
|
||||||
max := 1024
|
max := 1024
|
||||||
|
|
@ -115,7 +113,7 @@ func (r *request) OutputDebug() string {
|
||||||
if r.fdData != nil {
|
if r.fdData != nil {
|
||||||
spl = " (fd data)"
|
spl = " (fd data)"
|
||||||
}
|
}
|
||||||
flatStr = fmt.Sprintf(" %d bytes data%s\n", r.flatDataSize(), spl)
|
flatStr = fmt.Sprintf(" %d bytes data%s", r.flatDataSize(), spl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,26 +184,35 @@ func (r *request) parse() {
|
||||||
|
|
||||||
copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader],
|
copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader],
|
||||||
zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader])
|
zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader])
|
||||||
r.outData = unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *request) serializeHeader(dataSize int) (header []byte) {
|
func (r *request) outData() unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
|
||||||
|
}
|
||||||
|
|
||||||
|
// serializeHeader serializes the response header. The header points
|
||||||
|
// to an internal buffer of the receiver.
|
||||||
|
func (r *request) serializeHeader(flatDataSize int) (header []byte) {
|
||||||
dataLength := r.handler.OutputSize
|
dataLength := r.handler.OutputSize
|
||||||
if r.outData == nil || r.status > OK {
|
if r.status > OK {
|
||||||
dataLength = 0
|
dataLength = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeOfOutHeader := unsafe.Sizeof(OutHeader{})
|
// [GET|LIST]XATTR is two opcodes in one: get/list xattr size (return
|
||||||
|
// structured GetXAttrOut, no flat data) and get/list xattr data
|
||||||
|
// (return no structured data, but only flat data)
|
||||||
|
if r.inHeader.Opcode == _OP_GETXATTR || r.inHeader.Opcode == _OP_LISTXATTR {
|
||||||
|
if (*GetXAttrIn)(r.inData).Size != 0 {
|
||||||
|
dataLength = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
header = r.outBuf[:sizeOfOutHeader+dataLength]
|
header = r.outBuf[:sizeOfOutHeader+dataLength]
|
||||||
o := (*OutHeader)(unsafe.Pointer(&header[0]))
|
o := (*OutHeader)(unsafe.Pointer(&header[0]))
|
||||||
o.Unique = r.inHeader.Unique
|
o.Unique = r.inHeader.Unique
|
||||||
o.Status = int32(-r.status)
|
o.Status = int32(-r.status)
|
||||||
o.Length = uint32(
|
o.Length = uint32(
|
||||||
int(sizeOfOutHeader) + int(dataLength) + dataSize)
|
int(sizeOfOutHeader) + int(dataLength) + flatDataSize)
|
||||||
|
|
||||||
var asSlice []byte
|
|
||||||
toSlice(&asSlice, r.outData, dataLength)
|
|
||||||
copy(header[sizeOfOutHeader:], asSlice)
|
|
||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
52
vendor/github.com/hanwen/go-fuse/fuse/server.go
generated
vendored
52
vendor/github.com/hanwen/go-fuse/fuse/server.go
generated
vendored
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -161,6 +160,7 @@ func NewServer(fs RawFileSystem, mountPoint string, opts *MountOptions) (*Server
|
||||||
// FUSE device: on unmount, sometime some reads do not
|
// FUSE device: on unmount, sometime some reads do not
|
||||||
// error-out, meaning that unmount will hang.
|
// error-out, meaning that unmount will hang.
|
||||||
singleReader: runtime.GOOS == "darwin",
|
singleReader: runtime.GOOS == "darwin",
|
||||||
|
ready: make(chan error, 1),
|
||||||
}
|
}
|
||||||
ms.reqPool.New = func() interface{} { return new(request) }
|
ms.reqPool.New = func() interface{} { return new(request) }
|
||||||
ms.readPool.New = func() interface{} { return make([]byte, o.MaxWrite+pageSize) }
|
ms.readPool.New = func() interface{} { return make([]byte, o.MaxWrite+pageSize) }
|
||||||
|
|
@ -173,7 +173,6 @@ func NewServer(fs RawFileSystem, mountPoint string, opts *MountOptions) (*Server
|
||||||
}
|
}
|
||||||
mountPoint = filepath.Clean(filepath.Join(cwd, mountPoint))
|
mountPoint = filepath.Clean(filepath.Join(cwd, mountPoint))
|
||||||
}
|
}
|
||||||
ms.ready = make(chan error, 1)
|
|
||||||
fd, err := mount(mountPoint, &o, ms.ready)
|
fd, err := mount(mountPoint, &o, ms.ready)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -389,12 +388,19 @@ func (ms *Server) handleRequest(req *request) Status {
|
||||||
log.Println(req.InputDebug())
|
log.Println(req.InputDebug())
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.status.Ok() && req.handler.Func == nil {
|
if req.inHeader.NodeId == pollHackInode {
|
||||||
log.Printf("Unimplemented opcode %v", operationName(req.inHeader.Opcode))
|
// We want to avoid switching off features through our
|
||||||
|
// poll hack, so don't use ENOSYS
|
||||||
|
req.status = EIO
|
||||||
|
if req.inHeader.Opcode == _OP_POLL {
|
||||||
req.status = ENOSYS
|
req.status = ENOSYS
|
||||||
}
|
}
|
||||||
|
} else if req.inHeader.NodeId == FUSE_ROOT_ID && len(req.filenames) > 0 && req.filenames[0] == pollHackName {
|
||||||
if req.status.Ok() {
|
doPollHackLookup(ms, req)
|
||||||
|
} else if req.status.Ok() && req.handler.Func == nil {
|
||||||
|
log.Printf("Unimplemented opcode %v", operationName(req.inHeader.Opcode))
|
||||||
|
req.status = ENOSYS
|
||||||
|
} else if req.status.Ok() {
|
||||||
req.handler.Func(ms, req)
|
req.handler.Func(ms, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,11 +451,6 @@ func (ms *Server) InodeNotify(node uint64, off int64, length int64) Status {
|
||||||
return ENOSYS
|
return ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := &NotifyInvalInodeOut{
|
|
||||||
Ino: node,
|
|
||||||
Off: off,
|
|
||||||
Length: length,
|
|
||||||
}
|
|
||||||
req := request{
|
req := request{
|
||||||
inHeader: &InHeader{
|
inHeader: &InHeader{
|
||||||
Opcode: _OP_NOTIFY_INODE,
|
Opcode: _OP_NOTIFY_INODE,
|
||||||
|
|
@ -457,7 +458,11 @@ func (ms *Server) InodeNotify(node uint64, off int64, length int64) Status {
|
||||||
handler: operationHandlers[_OP_NOTIFY_INODE],
|
handler: operationHandlers[_OP_NOTIFY_INODE],
|
||||||
status: NOTIFY_INVAL_INODE,
|
status: NOTIFY_INVAL_INODE,
|
||||||
}
|
}
|
||||||
req.outData = unsafe.Pointer(entry)
|
|
||||||
|
entry := (*NotifyInvalInodeOut)(req.outData())
|
||||||
|
entry.Ino = node
|
||||||
|
entry.Off = off
|
||||||
|
entry.Length = length
|
||||||
|
|
||||||
// Protect against concurrent close.
|
// Protect against concurrent close.
|
||||||
ms.writeMu.Lock()
|
ms.writeMu.Lock()
|
||||||
|
|
@ -487,18 +492,17 @@ func (ms *Server) DeleteNotify(parent uint64, child uint64, name string) Status
|
||||||
handler: operationHandlers[_OP_NOTIFY_DELETE],
|
handler: operationHandlers[_OP_NOTIFY_DELETE],
|
||||||
status: NOTIFY_INVAL_DELETE,
|
status: NOTIFY_INVAL_DELETE,
|
||||||
}
|
}
|
||||||
entry := &NotifyInvalDeleteOut{
|
|
||||||
Parent: parent,
|
entry := (*NotifyInvalDeleteOut)(req.outData())
|
||||||
Child: child,
|
entry.Parent = parent
|
||||||
NameLen: uint32(len(name)),
|
entry.Child = child
|
||||||
}
|
entry.NameLen = uint32(len(name))
|
||||||
|
|
||||||
// Many versions of FUSE generate stacktraces if the
|
// Many versions of FUSE generate stacktraces if the
|
||||||
// terminating null byte is missing.
|
// terminating null byte is missing.
|
||||||
nameBytes := make([]byte, len(name)+1)
|
nameBytes := make([]byte, len(name)+1)
|
||||||
copy(nameBytes, name)
|
copy(nameBytes, name)
|
||||||
nameBytes[len(nameBytes)-1] = '\000'
|
nameBytes[len(nameBytes)-1] = '\000'
|
||||||
req.outData = unsafe.Pointer(entry)
|
|
||||||
req.flatData = nameBytes
|
req.flatData = nameBytes
|
||||||
|
|
||||||
// Protect against concurrent close.
|
// Protect against concurrent close.
|
||||||
|
|
@ -526,17 +530,15 @@ func (ms *Server) EntryNotify(parent uint64, name string) Status {
|
||||||
handler: operationHandlers[_OP_NOTIFY_ENTRY],
|
handler: operationHandlers[_OP_NOTIFY_ENTRY],
|
||||||
status: NOTIFY_INVAL_ENTRY,
|
status: NOTIFY_INVAL_ENTRY,
|
||||||
}
|
}
|
||||||
entry := &NotifyInvalEntryOut{
|
entry := (*NotifyInvalEntryOut)(req.outData())
|
||||||
Parent: parent,
|
entry.Parent = parent
|
||||||
NameLen: uint32(len(name)),
|
entry.NameLen = uint32(len(name))
|
||||||
}
|
|
||||||
|
|
||||||
// Many versions of FUSE generate stacktraces if the
|
// Many versions of FUSE generate stacktraces if the
|
||||||
// terminating null byte is missing.
|
// terminating null byte is missing.
|
||||||
nameBytes := make([]byte, len(name)+1)
|
nameBytes := make([]byte, len(name)+1)
|
||||||
copy(nameBytes, name)
|
copy(nameBytes, name)
|
||||||
nameBytes[len(nameBytes)-1] = '\000'
|
nameBytes[len(nameBytes)-1] = '\000'
|
||||||
req.outData = unsafe.Pointer(entry)
|
|
||||||
req.flatData = nameBytes
|
req.flatData = nameBytes
|
||||||
|
|
||||||
// Protect against concurrent close.
|
// Protect against concurrent close.
|
||||||
|
|
@ -579,8 +581,10 @@ func init() {
|
||||||
// WaitMount waits for the first request to be served. Use this to
|
// WaitMount waits for the first request to be served. Use this to
|
||||||
// avoid racing between accessing the (empty or not yet mounted)
|
// avoid racing between accessing the (empty or not yet mounted)
|
||||||
// mountpoint, and the OS trying to setup the user-space mount.
|
// mountpoint, and the OS trying to setup the user-space mount.
|
||||||
// Currently, this call only necessary on OSX.
|
|
||||||
func (ms *Server) WaitMount() error {
|
func (ms *Server) WaitMount() error {
|
||||||
err := <-ms.ready
|
err := <-ms.ready
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return pollHack(ms.mountPoint)
|
||||||
|
}
|
||||||
|
|
|
||||||
3
vendor/github.com/hanwen/go-fuse/fuse/types.go
generated
vendored
3
vendor/github.com/hanwen/go-fuse/fuse/types.go
generated
vendored
|
|
@ -194,6 +194,9 @@ const (
|
||||||
CAP_ASYNC_DIO = (1 << 15)
|
CAP_ASYNC_DIO = (1 << 15)
|
||||||
CAP_WRITEBACK_CACHE = (1 << 16)
|
CAP_WRITEBACK_CACHE = (1 << 16)
|
||||||
CAP_NO_OPEN_SUPPORT = (1 << 17)
|
CAP_NO_OPEN_SUPPORT = (1 << 17)
|
||||||
|
CAP_PARALLEL_DIROPS = (1 << 18)
|
||||||
|
CAP_HANDLE_KILLPRIV = (1 << 19)
|
||||||
|
CAP_POSIX_ACL = (1 << 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
type InitIn struct {
|
type InitIn struct {
|
||||||
|
|
|
||||||
30
vendor/github.com/hanwen/go-fuse/splice/pair.go
generated
vendored
30
vendor/github.com/hanwen/go-fuse/splice/pair.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package splice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Pair struct {
|
type Pair struct {
|
||||||
r, w *os.File
|
r, w int
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ func (p *Pair) Grow(n int) error {
|
||||||
return fmt.Errorf("splice: want %d bytes, max pipe size %d", n, maxPipeSize)
|
return fmt.Errorf("splice: want %d bytes, max pipe size %d", n, maxPipeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
newsize, errNo := fcntl(p.r.Fd(), F_SETPIPE_SZ, n)
|
newsize, errNo := fcntl(uintptr(p.r), F_SETPIPE_SZ, n)
|
||||||
if errNo != 0 {
|
if errNo != 0 {
|
||||||
return fmt.Errorf("splice: fcntl returned %v", errNo)
|
return fmt.Errorf("splice: fcntl returned %v", errNo)
|
||||||
}
|
}
|
||||||
|
|
@ -43,8 +43,8 @@ func (p *Pair) Cap() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pair) Close() error {
|
func (p *Pair) Close() error {
|
||||||
err1 := p.r.Close()
|
err1 := syscall.Close(p.r)
|
||||||
err2 := p.w.Close()
|
err2 := syscall.Close(p.w)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return err1
|
return err1
|
||||||
}
|
}
|
||||||
|
|
@ -52,17 +52,17 @@ func (p *Pair) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pair) Read(d []byte) (n int, err error) {
|
func (p *Pair) Read(d []byte) (n int, err error) {
|
||||||
return p.r.Read(d)
|
return syscall.Read(p.r, d)
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pair) ReadFd() uintptr {
|
|
||||||
return p.r.Fd()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pair) WriteFd() uintptr {
|
|
||||||
return p.w.Fd()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pair) Write(d []byte) (n int, err error) {
|
func (p *Pair) Write(d []byte) (n int, err error) {
|
||||||
return p.w.Write(d)
|
return syscall.Write(p.w, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pair) ReadFd() uintptr {
|
||||||
|
return uintptr(p.r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pair) WriteFd() uintptr {
|
||||||
|
return uintptr(p.w)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
vendor/github.com/hanwen/go-fuse/splice/pair_linux.go
generated
vendored
17
vendor/github.com/hanwen/go-fuse/splice/pair_linux.go
generated
vendored
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Pair) LoadFromAt(fd uintptr, sz int, off int64) (int, error) {
|
func (p *Pair) LoadFromAt(fd uintptr, sz int, off int64) (int, error) {
|
||||||
n, err := syscall.Splice(int(fd), &off, int(p.w.Fd()), nil, sz, 0)
|
n, err := syscall.Splice(int(fd), &off, p.w, nil, sz, 0)
|
||||||
return int(n), err
|
return int(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ func (p *Pair) LoadFrom(fd uintptr, sz int) (int, error) {
|
||||||
sz, p.size)
|
sz, p.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := syscall.Splice(int(fd), nil, int(p.w.Fd()), nil, sz, 0)
|
n, err := syscall.Splice(int(fd), nil, p.w, nil, sz, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = os.NewSyscallError("Splice load from", err)
|
err = os.NewSyscallError("Splice load from", err)
|
||||||
}
|
}
|
||||||
|
|
@ -29,9 +29,20 @@ func (p *Pair) LoadFrom(fd uintptr, sz int) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pair) WriteTo(fd uintptr, n int) (int, error) {
|
func (p *Pair) WriteTo(fd uintptr, n int) (int, error) {
|
||||||
m, err := syscall.Splice(int(p.r.Fd()), nil, int(fd), nil, int(n), 0)
|
m, err := syscall.Splice(p.r, nil, int(fd), nil, int(n), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = os.NewSyscallError("Splice write", err)
|
err = os.NewSyscallError("Splice write", err)
|
||||||
}
|
}
|
||||||
return int(m), err
|
return int(m), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _SPLICE_F_NONBLOCK = 0x2
|
||||||
|
|
||||||
|
func (p *Pair) discard() {
|
||||||
|
_, err := syscall.Splice(p.r, nil, int(devNullFD), nil, int(p.size), _SPLICE_F_NONBLOCK)
|
||||||
|
if err == syscall.EAGAIN {
|
||||||
|
// all good.
|
||||||
|
} else if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
75
vendor/github.com/hanwen/go-fuse/splice/pool.go
generated
vendored
75
vendor/github.com/hanwen/go-fuse/splice/pool.go
generated
vendored
|
|
@ -5,7 +5,6 @@
|
||||||
package splice
|
package splice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -33,7 +32,7 @@ func Used() int {
|
||||||
return splicePool.used()
|
return splicePool.used()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return pipe pair to pool
|
// Done returns the pipe pair to pool.
|
||||||
func Done(p *Pair) {
|
func Done(p *Pair) {
|
||||||
splicePool.done(p)
|
splicePool.done(p)
|
||||||
}
|
}
|
||||||
|
|
@ -47,71 +46,59 @@ func newSplicePairPool() *pairPool {
|
||||||
return &pairPool{}
|
return &pairPool{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *pairPool) clear() {
|
func (pp *pairPool) clear() {
|
||||||
me.Lock()
|
pp.Lock()
|
||||||
for _, p := range me.unused {
|
for _, p := range pp.unused {
|
||||||
p.Close()
|
p.Close()
|
||||||
}
|
}
|
||||||
me.unused = me.unused[:0]
|
pp.unused = pp.unused[:0]
|
||||||
me.Unlock()
|
pp.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *pairPool) used() (n int) {
|
func (pp *pairPool) used() (n int) {
|
||||||
me.Lock()
|
pp.Lock()
|
||||||
n = me.usedCount
|
n = pp.usedCount
|
||||||
me.Unlock()
|
pp.Unlock()
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *pairPool) total() int {
|
func (pp *pairPool) total() int {
|
||||||
me.Lock()
|
pp.Lock()
|
||||||
n := me.usedCount + len(me.unused)
|
n := pp.usedCount + len(pp.unused)
|
||||||
me.Unlock()
|
pp.Unlock()
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *pairPool) drop(p *Pair) {
|
func (pp *pairPool) drop(p *Pair) {
|
||||||
p.Close()
|
p.Close()
|
||||||
me.Lock()
|
pp.Lock()
|
||||||
me.usedCount--
|
pp.usedCount--
|
||||||
me.Unlock()
|
pp.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *pairPool) get() (p *Pair, err error) {
|
func (pp *pairPool) get() (p *Pair, err error) {
|
||||||
me.Lock()
|
pp.Lock()
|
||||||
defer me.Unlock()
|
defer pp.Unlock()
|
||||||
|
|
||||||
me.usedCount++
|
pp.usedCount++
|
||||||
l := len(me.unused)
|
l := len(pp.unused)
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
p := me.unused[l-1]
|
p := pp.unused[l-1]
|
||||||
me.unused = me.unused[:l-1]
|
pp.unused = pp.unused[:l-1]
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return newSplicePair()
|
return newSplicePair()
|
||||||
}
|
}
|
||||||
|
|
||||||
var discardBuffer [32 * 1024]byte
|
func (pp *pairPool) done(p *Pair) {
|
||||||
|
p.discard()
|
||||||
|
|
||||||
func DiscardAll(r io.Reader) {
|
pp.Lock()
|
||||||
buf := discardBuffer[:]
|
pp.usedCount--
|
||||||
for {
|
pp.unused = append(pp.unused, p)
|
||||||
n, _ := r.Read(buf)
|
pp.Unlock()
|
||||||
if n < len(buf) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (me *pairPool) done(p *Pair) {
|
|
||||||
DiscardAll(p.r)
|
|
||||||
|
|
||||||
me.Lock()
|
|
||||||
me.usedCount--
|
|
||||||
me.unused = append(me.unused, p)
|
|
||||||
me.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
35
vendor/github.com/hanwen/go-fuse/splice/splice.go
generated
vendored
35
vendor/github.com/hanwen/go-fuse/splice/splice.go
generated
vendored
|
|
@ -30,6 +30,9 @@ func MaxPipeSize() int {
|
||||||
// Since Linux 2.6.11, the pipe capacity is 65536 bytes.
|
// Since Linux 2.6.11, the pipe capacity is 65536 bytes.
|
||||||
const DefaultPipeSize = 16 * 4096
|
const DefaultPipeSize = 16 * 4096
|
||||||
|
|
||||||
|
// We empty pipes by splicing to /dev/null.
|
||||||
|
var devNullFD uintptr
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
content, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size")
|
content, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -48,6 +51,13 @@ func init() {
|
||||||
resizable = resizable && (errNo == 0)
|
resizable = resizable && (errNo == 0)
|
||||||
r.Close()
|
r.Close()
|
||||||
w.Close()
|
w.Close()
|
||||||
|
|
||||||
|
fd, err := syscall.Open("/dev/null", os.O_WRONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("splice: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
devNullFD = uintptr(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy & paste from syscall.
|
// copy & paste from syscall.
|
||||||
|
|
@ -61,30 +71,27 @@ func fcntl(fd uintptr, cmd int, arg int) (val int, errno syscall.Errno) {
|
||||||
const F_SETPIPE_SZ = 1031
|
const F_SETPIPE_SZ = 1031
|
||||||
const F_GETPIPE_SZ = 1032
|
const F_GETPIPE_SZ = 1032
|
||||||
|
|
||||||
|
func osPipe() (int, int, error) {
|
||||||
|
var fds [2]int
|
||||||
|
err := syscall.Pipe2(fds[:], syscall.O_NONBLOCK)
|
||||||
|
return fds[0], fds[1], err
|
||||||
|
}
|
||||||
|
|
||||||
func newSplicePair() (p *Pair, err error) {
|
func newSplicePair() (p *Pair, err error) {
|
||||||
p = &Pair{}
|
p = &Pair{}
|
||||||
p.r, p.w, err = os.Pipe()
|
p.r, p.w, err = osPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var errNo syscall.Errno
|
||||||
errNo := syscall.Errno(0)
|
p.size, errNo = fcntl(uintptr(p.r), F_GETPIPE_SZ, 0)
|
||||||
for _, f := range []*os.File{p.r, p.w} {
|
if err == syscall.EINVAL {
|
||||||
_, errNo = fcntl(f.Fd(), syscall.F_SETFL, syscall.O_NONBLOCK)
|
|
||||||
if errNo != 0 {
|
|
||||||
p.Close()
|
|
||||||
return nil, os.NewSyscallError("fcntl setfl", errNo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.size, errNo = fcntl(p.r.Fd(), F_GETPIPE_SZ, 0)
|
|
||||||
if errNo == syscall.EINVAL {
|
|
||||||
p.size = DefaultPipeSize
|
p.size = DefaultPipeSize
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
if errNo != 0 {
|
if errNo != 0 {
|
||||||
p.Close()
|
p.Close()
|
||||||
return nil, os.NewSyscallError("fcntl getsize", errNo)
|
return nil, fmt.Errorf("fcntl getsize: %v", errNo)
|
||||||
}
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue