diff --git a/.travis.yml b/.travis.yml
index 5f3ff9d16a16292263ed99d8c43c7dc9e1654129..4bef48a0db28f60f7b2d387d8e129c80876ca6e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,19 +5,34 @@ matrix:
   include:
     - os: linux
       dist: trusty
+      sudo: required
       go: 1.7.5
+      script:
+        - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
+        - sudo modprobe fuse
+        - sudo chmod 666 /dev/fuse
+        - sudo chown root:$USER /etc/fuse.conf
 
     # These are the latest Go versions, only run go vet and misspell on these
     - os: linux
       dist: trusty
+      sudo: required
       go: 1.8
       script:
+        - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
+        - sudo modprobe fuse
+        - sudo chmod 666 /dev/fuse
+        - sudo chown root:$USER /etc/fuse.conf
         - go run build/ci.go install
         - go run build/ci.go test -coverage -vet -misspell
 
     - os: osx
       go: 1.8
+      sudo: required
       script:
+        - brew update
+        - brew install caskroom/cask/brew-cask
+        - brew cask install osxfuse
         - go run build/ci.go install
         - go run build/ci.go test -coverage -vet -misspell
 
diff --git a/build/ci.go b/build/ci.go
index cb9c7a335b8d74e5fd0046a8d8ecc649011453f7..27589fc7f5a5ce0bc098f966d722726f577bed9d 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -173,6 +173,20 @@ func doInstall(cmdline []string) {
 	if flag.NArg() > 0 {
 		packages = flag.Args()
 	}
+
+	// Resolve ./... manually and remove vendor/bazil/fuse (fuse is not in windows)
+	out, err := goTool("list", "./...").CombinedOutput()
+	if err != nil {
+		log.Fatalf("package listing failed: %v\n%s", err, string(out))
+	}
+	packages = []string{}
+	for _, line := range strings.Split(string(out), "\n") {
+		if !strings.Contains(line, "vendor") {
+			packages = append(packages, strings.TrimSpace(line))
+		}
+	}
+
+
 	if *arch == "" || *arch == runtime.GOARCH {
 		goinstall := goTool("install", buildFlags(env)...)
 		goinstall.Args = append(goinstall.Args, "-v")
diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go
index 1716771464a99b47b6b6e5df1d79e7c6e40b2224..3c82497e5d5a30fe011d286d9303c7ae883d5b18 100644
--- a/cmd/swarm/main.go
+++ b/cmd/swarm/main.go
@@ -122,7 +122,7 @@ func init() {
 	// Override flag defaults so bzzd can run alongside geth.
 	utils.ListenPortFlag.Value = 30399
 	utils.IPCPathFlag.Value = utils.DirectoryString{Value: "bzzd.ipc"}
-	utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
+	utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, swarmfs, web3"
 
 	// Set up the cli app.
 	app.Action = bzzd
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index 23112c1f197a7bf3125fafe4aeb13a9588fa64a6..79f781781055ba14041714d0849dee3b3cb1c409 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -27,9 +27,12 @@ var Modules = map[string]string{
 	"personal":   Personal_JS,
 	"rpc":        RPC_JS,
 	"shh":        Shh_JS,
+	"swarmfs":    SWARMFS_JS,
 	"txpool":     TxPool_JS,
+
 }
 
+
 const Chequebook_JS = `
 web3._extend({
   property: 'chequebook',
@@ -486,6 +489,32 @@ web3._extend({
 	]
 });
 `
+const SWARMFS_JS = `
+web3._extend({
+  property: 'swarmfs',
+  methods:
+  [
+    new web3._extend.Method({
+      name: 'mount',
+      call: 'swarmfs_mount',
+      params: 2,
+      inputFormatter: [null,null]
+    }),
+    new web3._extend.Method({
+      name: 'unmount',
+      call: 'swarmfs_unmount',
+      params: 1,
+      inputFormatter: [null]
+    }),
+    new web3._extend.Method({
+      name: 'listmounts',
+      call: 'swarmfs_listmounts',
+      params: 0,
+      inputFormatter: []
+    })
+  ]
+});
+`
 
 const TxPool_JS = `
 web3._extend({
diff --git a/swarm/api/fuse.go b/swarm/api/fuse.go
new file mode 100644
index 0000000000000000000000000000000000000000..4b1f817f8c56610b3a05d6fad52a4e1971bfc6dd
--- /dev/null
+++ b/swarm/api/fuse.go
@@ -0,0 +1,139 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build !windows
+
+package api
+
+import (
+	"io"
+	"os"
+
+	"bazil.org/fuse"
+	"bazil.org/fuse/fs"
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/ethereum/go-ethereum/swarm/storage"
+	"golang.org/x/net/context"
+)
+
+
+
+
+// Data structures used for Fuse filesystem, serving directories and serving files to Fuse driver
+type FS struct {
+	root *Dir
+}
+
+type Dir struct {
+	inode       uint64
+	name        string
+	path        string
+	directories []*Dir
+	files       []*File
+}
+
+type File struct {
+	inode    uint64
+	name     string
+	path     string
+	key      storage.Key
+	swarmApi *Api
+	fileSize uint64
+	reader   storage.LazySectionReader
+}
+
+
+// Functions which satisfy the Fuse File System requests
+func (filesystem *FS) Root() (fs.Node, error) {
+	return filesystem.root, nil
+}
+
+func (directory *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
+	a.Inode = directory.inode
+	//TODO: need to get permission as argument
+	a.Mode = os.ModeDir | 0500
+	a.Uid = uint32(os.Getuid())
+	a.Gid = uint32(os.Getegid())
+	return nil
+}
+
+func (directory *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
+	if directory.files != nil {
+		for _, n := range directory.files {
+			if n.name == name {
+				return n, nil
+			}
+		}
+	}
+	if directory.directories != nil {
+		for _, n := range directory.directories {
+			if n.name == name {
+				return n, nil
+			}
+		}
+	}
+	return nil, fuse.ENOENT
+}
+
+func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+	var children []fuse.Dirent
+	if d.files != nil {
+		for _, file := range d.files {
+			children = append(children, fuse.Dirent{Inode: file.inode, Type: fuse.DT_File, Name: file.name})
+		}
+	}
+	if d.directories != nil {
+		for _, dir := range d.directories {
+			children = append(children, fuse.Dirent{Inode: dir.inode, Type: fuse.DT_Dir, Name: dir.name})
+		}
+	}
+	return children, nil
+}
+
+func (file *File) Attr(ctx context.Context, a *fuse.Attr) error {
+
+	a.Inode = file.inode
+	//TODO: need to get permission as argument
+	a.Mode = 0500
+	a.Uid = uint32(os.Getuid())
+	a.Gid = uint32(os.Getegid())
+
+
+	reader := file.swarmApi.Retrieve(file.key)
+	quitC := make(chan bool)
+	size, err := reader.Size(quitC)
+	if err != nil {
+		log.Warn("Couldnt file size of file %s : %v", file.path, err)
+		a.Size = uint64(0)
+	}
+	a.Size = uint64(size)
+	file.fileSize = a.Size
+	return nil
+}
+
+var _ = fs.HandleReader(&File{})
+
+func (file *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
+	buf := make([]byte, req.Size)
+	reader := file.swarmApi.Retrieve(file.key)
+	n, err := reader.ReadAt(buf, req.Offset)
+	if err == io.ErrUnexpectedEOF || err == io.EOF {
+		err = nil
+	}
+	resp.Data = buf[:n]
+	return err
+
+}
diff --git a/swarm/api/swarmfs.go b/swarm/api/swarmfs.go
new file mode 100644
index 0000000000000000000000000000000000000000..8427d3c5b138ae726db14beb438ac22353f99f9f
--- /dev/null
+++ b/swarm/api/swarmfs.go
@@ -0,0 +1,48 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package api
+
+import (
+	"time"
+	"sync"
+)
+
+const (
+	Swarmfs_Version = "0.1"
+	mountTimeout   = time.Second * 5
+	maxFuseMounts  = 5
+)
+
+
+type SwarmFS struct {
+	swarmApi     *Api
+	activeMounts map[string]*MountInfo
+	activeLock   *sync.RWMutex
+}
+
+
+
+func NewSwarmFS(api *Api) *SwarmFS {
+	swarmfs := &SwarmFS{
+		swarmApi:     api,
+		activeLock:   &sync.RWMutex{},
+		activeMounts: map[string]*MountInfo{},
+	}
+	return swarmfs
+}
+
+
diff --git a/swarm/api/swarmfs_unix.go b/swarm/api/swarmfs_unix.go
new file mode 100644
index 0000000000000000000000000000000000000000..ae0216e1d7d9e0b789edbf47f7b5cb36f46885d0
--- /dev/null
+++ b/swarm/api/swarmfs_unix.go
@@ -0,0 +1,266 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build linux darwin
+
+package api
+
+import (
+	"path/filepath"
+	"fmt"
+	"strings"
+	"time"
+	"github.com/ethereum/go-ethereum/swarm/storage"
+	"bazil.org/fuse"
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/ethereum/go-ethereum/common"
+	"bazil.org/fuse/fs"
+	"sync"
+)
+
+
+var (
+	inode  uint64  = 1
+	inodeLock   sync.RWMutex
+)
+
+// information about every active mount
+type MountInfo struct {
+	mountPoint     string
+	manifestHash   string
+	resolvedKey    storage.Key
+	rootDir        *Dir
+	fuseConnection *fuse.Conn
+}
+
+// Inode numbers need to be unique, they are used for caching inside fuse
+func NewInode() uint64 {
+	inodeLock.Lock()
+	defer  inodeLock.Unlock()
+	inode += 1
+	return inode
+}
+
+
+
+func (self *SwarmFS) Mount(mhash, mountpoint string) (string, error)  {
+
+	self.activeLock.Lock()
+	defer self.activeLock.Unlock()
+
+	noOfActiveMounts := len(self.activeMounts)
+	if noOfActiveMounts >= maxFuseMounts {
+		err := fmt.Errorf("Max mount count reached. Cannot mount %s ", mountpoint)
+		log.Warn(err.Error())
+		return err.Error(), err
+	}
+
+	cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
+	if err != nil {
+		return err.Error(), err
+	}
+
+	if _, ok := self.activeMounts[cleanedMountPoint]; ok {
+		err := fmt.Errorf("Mountpoint %s already mounted.", cleanedMountPoint)
+		log.Warn(err.Error())
+		return err.Error(), err
+	}
+
+	log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
+	key, _, path, err := self.swarmApi.parseAndResolve(mhash, true)
+	if err != nil {
+		errStr := fmt.Sprintf("Could not resolve %s : %v", mhash, err)
+		log.Warn(errStr)
+		return errStr, err
+	}
+
+	if len(path) > 0 {
+		path += "/"
+	}
+
+	quitC := make(chan bool)
+	trie, err := loadManifest(self.swarmApi.dpa, key, quitC)
+	if err != nil {
+		errStr := fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err)
+		log.Warn(errStr)
+		return errStr, err
+	}
+
+	dirTree := map[string]*Dir{}
+
+	rootDir := &Dir{
+		inode:       NewInode(),
+		name:        "root",
+		directories: nil,
+		files:       nil,
+	}
+	dirTree["root"] = rootDir
+
+	err = trie.listWithPrefix(path, quitC, func(entry *manifestTrieEntry, suffix string) {
+
+		key = common.Hex2Bytes(entry.Hash)
+		fullpath := "/" + suffix
+		basepath := filepath.Dir(fullpath)
+		filename := filepath.Base(fullpath)
+
+		parentDir := rootDir
+		dirUntilNow := ""
+		paths := strings.Split(basepath, "/")
+		for i := range paths {
+			if paths[i] != "" {
+				thisDir := paths[i]
+				dirUntilNow = dirUntilNow + "/" + thisDir
+
+				if _, ok := dirTree[dirUntilNow]; !ok {
+					dirTree[dirUntilNow] = &Dir{
+						inode:       NewInode(),
+						name:        thisDir,
+						path:        dirUntilNow,
+						directories: nil,
+						files:       nil,
+					}
+					parentDir.directories = append(parentDir.directories, dirTree[dirUntilNow])
+					parentDir = dirTree[dirUntilNow]
+
+				} else {
+					parentDir = dirTree[dirUntilNow]
+				}
+
+			}
+		}
+		thisFile := &File{
+			inode:    NewInode(),
+			name:     filename,
+			path:     fullpath,
+			key:      key,
+			swarmApi: self.swarmApi,
+		}
+		parentDir.files = append(parentDir.files, thisFile)
+	})
+
+	fconn, err := fuse.Mount(cleanedMountPoint, fuse.FSName("swarmfs"), fuse.VolumeName(mhash))
+	if err != nil {
+		fuse.Unmount(cleanedMountPoint)
+		errStr := fmt.Sprintf("Mounting %s encountered error: %v", cleanedMountPoint, err)
+		log.Warn(errStr)
+		return errStr, err
+	}
+
+	mounterr := make(chan error, 1)
+	go func() {
+		log.Info(fmt.Sprintf("Serving %s at %s", mhash, cleanedMountPoint))
+		filesys := &FS{root: rootDir}
+		if err := fs.Serve(fconn, filesys); err != nil {
+			log.Warn(fmt.Sprintf("Could not Serve FS error: %v", err))
+		}
+	}()
+
+	// Check if the mount process has an error to report.
+	select {
+
+	case <-time.After(mountTimeout):
+		err := fmt.Errorf("Mounting %s timed out.", cleanedMountPoint)
+		log.Warn(err.Error())
+		return err.Error(), err
+
+	case err := <-mounterr:
+	        errStr := fmt.Sprintf("Mounting %s encountered error: %v", cleanedMountPoint, err)
+		log.Warn(errStr)
+		return errStr, err
+
+	case <-fconn.Ready:
+		log.Debug(fmt.Sprintf("Mounting connection succeeded for : %v", cleanedMountPoint))
+	}
+
+
+
+	//Assemble and Store the mount information for future use
+	mountInformation := &MountInfo{
+		mountPoint:     cleanedMountPoint,
+		manifestHash:   mhash,
+		resolvedKey:    key,
+		rootDir:        rootDir,
+		fuseConnection: fconn,
+	}
+	self.activeMounts[cleanedMountPoint] = mountInformation
+
+	succString := fmt.Sprintf("Mounting successful for %s", cleanedMountPoint)
+	log.Info(succString)
+
+	return succString, nil
+}
+
+func (self *SwarmFS) Unmount(mountpoint string) (string, error)  {
+
+	self.activeLock.Lock()
+	defer self.activeLock.Unlock()
+
+	cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
+	if err != nil {
+		return err.Error(), err
+	}
+
+	// Get the mount information based on the mountpoint argument
+	mountInfo := self.activeMounts[cleanedMountPoint]
+
+
+	if mountInfo == nil || mountInfo.mountPoint != cleanedMountPoint {
+		err := fmt.Errorf("Could not find mount information for %s ", cleanedMountPoint)
+		log.Warn(err.Error())
+		return err.Error(), err
+	}
+
+	err = fuse.Unmount(cleanedMountPoint)
+	if err != nil {
+		//TODO: try forceful unmount if normal unmount fails
+		errStr := fmt.Sprintf("UnMount error: %v", err)
+		log.Warn(errStr)
+		return errStr, err
+	}
+
+	mountInfo.fuseConnection.Close()
+
+	//remove the mount information from the active map
+	delete(self.activeMounts, cleanedMountPoint)
+
+	succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
+	log.Info(succString)
+	return succString, nil
+}
+
+func (self *SwarmFS) Listmounts() (string, error) {
+
+	self.activeLock.RLock()
+	defer self.activeLock.RUnlock()
+
+	var rows []string
+	for mp := range self.activeMounts {
+		mountInfo := self.activeMounts[mp]
+		rows = append(rows, fmt.Sprintf("Swarm Root: %s, Mount Point: %s ", mountInfo.manifestHash, mountInfo.mountPoint))
+	}
+
+	return strings.Join(rows, "\n"), nil
+}
+
+func (self *SwarmFS) Stop() bool {
+
+	for mp := range self.activeMounts {
+		mountInfo := self.activeMounts[mp]
+		self.Unmount(mountInfo.mountPoint)
+	}
+
+	return true
+}
diff --git a/swarm/api/swarmfs_unix_test.go b/swarm/api/swarmfs_unix_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4f59dba5b67a0fd584a5ad0359d99694d7ba3311
--- /dev/null
+++ b/swarm/api/swarmfs_unix_test.go
@@ -0,0 +1,122 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build linux darwin
+
+package api
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+var testUploadDir, _ = ioutil.TempDir(os.TempDir(), "fuse-source")
+var testMountDir, _ = ioutil.TempDir(os.TempDir(), "fuse-dest")
+
+func testFuseFileSystem(t *testing.T, f func(*FileSystem)) {
+	testApi(t, func(api *Api) {
+		f(NewFileSystem(api))
+	})
+}
+
+func createTestFiles(t *testing.T, files []string) {
+
+	os.RemoveAll(testUploadDir)
+	os.RemoveAll(testMountDir)
+	defer os.MkdirAll(testMountDir, 0777)
+
+	for f := range files {
+		actualPath := filepath.Join(testUploadDir, files[f])
+		filePath := filepath.Dir(actualPath)
+
+		err := os.MkdirAll(filePath, 0777)
+		if err != nil {
+			t.Fatalf("Error creating directory '%v' : %v", filePath, err)
+		}
+
+		_, err1 := os.OpenFile(actualPath, os.O_RDONLY|os.O_CREATE, 0666)
+		if err1 != nil {
+			t.Fatalf("Error creating file %v: %v", actualPath, err1)
+		}
+	}
+
+}
+
+func compareFiles(t *testing.T, files []string) {
+
+	for f := range files {
+
+		sourceFile := filepath.Join(testUploadDir, files[f])
+		destinationFile := filepath.Join(testMountDir, files[f])
+
+		sfinfo, err := os.Stat(sourceFile)
+		if err != nil {
+			t.Fatalf("Source file %v missing in mount: %v", files[f], err)
+		}
+
+		dfinfo, err := os.Stat(destinationFile)
+		if err != nil {
+			t.Fatalf("Destination file %v missing in mount: %v", files[f], err)
+		}
+
+		if sfinfo.Size() != dfinfo.Size() {
+			t.Fatalf("Size mismatch  source (%v) vs destination(%v)", sfinfo.Size(), dfinfo.Size())
+		}
+
+		if dfinfo.Mode().Perm().String() != "-r-x------" {
+			t.Fatalf("Permission is not 0500for file: %v", err)
+		}
+
+	}
+}
+
+func doHashTest(fs *FileSystem, t *testing.T, ensName string, files ...string) {
+
+	createTestFiles(t, files)
+	bzzhash, err := fs.Upload(testUploadDir, "")
+	if err != nil {
+		t.Fatalf("Error uploading directory %v: %v", testUploadDir, err)
+	}
+
+	swarmfs := NewSwarmFS(fs.api)
+	_ ,err1 := swarmfs.Mount(bzzhash, testMountDir)
+	if err1 != nil {
+
+		t.Fatalf("Error mounting hash  %v: %v", bzzhash, err)
+	}
+	compareFiles(t, files)
+	_, err2 := swarmfs.Unmount(testMountDir)
+	if err2 != nil {
+		t.Fatalf("Error unmounting path  %v: %v", testMountDir, err)
+	}
+	swarmfs.Stop()
+
+}
+
+// mounting with manifest Hash
+func TestFuseMountingScenarios(t *testing.T) {
+	testFuseFileSystem(t, func(fs *FileSystem) {
+
+		//doHashTest(fs,t, "test","1.txt")
+		doHashTest(fs, t, "", "1.txt")
+		doHashTest(fs, t, "", "1.txt", "11.txt", "111.txt", "two/2.txt", "two/two/2.txt", "three/3.txt")
+		doHashTest(fs, t, "", "1/2/3/4/5/6/7/8/9/10/11/12/1.txt")
+		doHashTest(fs, t, "", "one/one.txt", "one.txt", "once/one.txt", "one/one/one.txt")
+
+	})
+}
diff --git a/swarm/api/swarmfs_windows.go b/swarm/api/swarmfs_windows.go
new file mode 100644
index 0000000000000000000000000000000000000000..525a25399a4e4b683cfde30c9973b3989f7a71d4
--- /dev/null
+++ b/swarm/api/swarmfs_windows.go
@@ -0,0 +1,48 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build windows
+
+package api
+
+import (
+	"github.com/ethereum/go-ethereum/log"
+)
+
+// Dummy struct and functions to satsfy windows build
+type MountInfo struct {
+}
+
+
+func (self *SwarmFS) Mount(mhash, mountpoint string) error {
+	log.Info("Platform not supported")
+	return nil
+}
+
+func (self *SwarmFS) Unmount(mountpoint string) error {
+	log.Info("Platform not supported")
+	return nil
+}
+
+func (self *SwarmFS) Listmounts() (string, error) {
+	log.Info("Platform not supported")
+	return "",nil
+}
+
+func (self *SwarmFS) Stop() error {
+	log.Info("Platform not supported")
+	return nil
+}
\ No newline at end of file
diff --git a/swarm/swarm.go b/swarm/swarm.go
index bd256edaa207433eb6025511838fa022d5427944..0ce31bcad924cc9a7e0dcd91e16742bcae858867 100644
--- a/swarm/swarm.go
+++ b/swarm/swarm.go
@@ -53,7 +53,8 @@ type Swarm struct {
 	privateKey  *ecdsa.PrivateKey
 	corsString  string
 	swapEnabled bool
-	lstore      *storage.LocalStore // local store, needs to store for releasing resources after node stopped
+	lstore      *storage.LocalStore  // local store, needs to store for releasing resources after node stopped
+	sfs          *api.SwarmFS         // need this to cleanup all the active mounts on node exit
 }
 
 type SwarmAPI struct {
@@ -142,6 +143,9 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
 	// Manifests for Smart Hosting
 	log.Debug(fmt.Sprintf("-> Web3 virtual server API"))
 
+	self.sfs = api.NewSwarmFS(self.api)
+	log.Debug("-> Initializing Fuse file system")
+
 	return self, nil
 }
 
@@ -216,7 +220,7 @@ func (self *Swarm) Stop() error {
 	if self.lstore != nil {
 		self.lstore.DbStore.Close()
 	}
-
+	self.sfs.Stop()
 	return self.config.Save()
 }
 
@@ -240,6 +244,7 @@ func (self *Swarm) APIs() []rpc.API {
 			Service:   api.NewStorage(self.api),
 			Public:    true,
 		},
+
 		{
 			Namespace: "bzz",
 			Version:   "0.1",
@@ -264,6 +269,12 @@ func (self *Swarm) APIs() []rpc.API {
 			Service:   chequebook.NewApi(self.config.Swap.Chequebook),
 			Public:    false,
 		},
+		{
+			Namespace: "swarmfs",
+			Version:   api.Swarmfs_Version,
+			Service:   self.sfs,
+			Public:    false,
+		},
 		// {Namespace, Version, api.NewAdmin(self), false},
 	}
 }
diff --git a/vendor/bazil.org/fuse/LICENSE b/vendor/bazil.org/fuse/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4ac7cd8389608f67f5c90a6bdda7d39ea321bb40
--- /dev/null
+++ b/vendor/bazil.org/fuse/LICENSE
@@ -0,0 +1,93 @@
+Copyright (c) 2013-2015 Tommi Virtanen.
+Copyright (c) 2009, 2011, 2012 The Go Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+The following included software components have additional copyright
+notices and license terms that may differ from the above.
+
+
+File fuse.go:
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+//         Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+
+File fuse_kernel.go:
+
+// Derived from FUSE's fuse_kernel.h
+/*
+   This file defines the kernel interface of FUSE
+   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+
+   This -- and only this -- header file may also be distributed under
+   the terms of the BSD Licence as follows:
+
+   Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+   SUCH DAMAGE.
+*/
diff --git a/vendor/bazil.org/fuse/README.md b/vendor/bazil.org/fuse/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c6d556ee38dbe05270ec76bbf14081fd86daa4e
--- /dev/null
+++ b/vendor/bazil.org/fuse/README.md
@@ -0,0 +1,23 @@
+bazil.org/fuse -- Filesystems in Go
+===================================
+
+`bazil.org/fuse` is a Go library for writing FUSE userspace
+filesystems.
+
+It is a from-scratch implementation of the kernel-userspace
+communication protocol, and does not use the C library from the
+project called FUSE. `bazil.org/fuse` embraces Go fully for safety and
+ease of programming.
+
+Here’s how to get going:
+
+    go get bazil.org/fuse
+
+Website: http://bazil.org/fuse/
+
+Github repository: https://github.com/bazil/fuse
+
+API docs: http://godoc.org/bazil.org/fuse
+
+Our thanks to Russ Cox for his fuse library, which this project is
+based on.
diff --git a/vendor/bazil.org/fuse/buffer.go b/vendor/bazil.org/fuse/buffer.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb1d2b77696a3520309ce7c1fa8d8e2a0d00a1c6
--- /dev/null
+++ b/vendor/bazil.org/fuse/buffer.go
@@ -0,0 +1,35 @@
+package fuse
+
+import "unsafe"
+
+// 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) buffer {
+	const hdrSize = unsafe.Sizeof(outHeader{})
+	buf := make(buffer, hdrSize, hdrSize+extra)
+	return buf
+}
diff --git a/vendor/bazil.org/fuse/debug.go b/vendor/bazil.org/fuse/debug.go
new file mode 100644
index 0000000000000000000000000000000000000000..be9f900d5e1a4df487291c015dd0346df35a01dc
--- /dev/null
+++ b/vendor/bazil.org/fuse/debug.go
@@ -0,0 +1,21 @@
+package fuse
+
+import (
+	"runtime"
+)
+
+func stack() string {
+	buf := make([]byte, 1024)
+	return string(buf[:runtime.Stack(buf, false)])
+}
+
+func nop(msg interface{}) {}
+
+// Debug is called to output debug messages, including protocol
+// traces. The default behavior is to do nothing.
+//
+// The messages have human-friendly string representations and are
+// safe to marshal to JSON.
+//
+// Implementations must not retain msg.
+var Debug func(msg interface{}) = nop
diff --git a/vendor/bazil.org/fuse/error_darwin.go b/vendor/bazil.org/fuse/error_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3fb89ca29f47afa9c4b1921eea419fb749d0b43
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_darwin.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+	"syscall"
+)
+
+const (
+	ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+	errNoXattr = ENOATTR
+)
+
+func init() {
+	errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_freebsd.go b/vendor/bazil.org/fuse/error_freebsd.go
new file mode 100644
index 0000000000000000000000000000000000000000..c6ea6d6e71ff289a4d667e12b3c47d068be3dd69
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_freebsd.go
@@ -0,0 +1,15 @@
+package fuse
+
+import "syscall"
+
+const (
+	ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+	errNoXattr = ENOATTR
+)
+
+func init() {
+	errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_linux.go b/vendor/bazil.org/fuse/error_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..6f113e71ed23ed8d6192152a65aaf5c3450c3f1a
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_linux.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+	"syscall"
+)
+
+const (
+	ENODATA = Errno(syscall.ENODATA)
+)
+
+const (
+	errNoXattr = ENODATA
+)
+
+func init() {
+	errnoNames[errNoXattr] = "ENODATA"
+}
diff --git a/vendor/bazil.org/fuse/error_std.go b/vendor/bazil.org/fuse/error_std.go
new file mode 100644
index 0000000000000000000000000000000000000000..398f43fbf69484b83297951641c64e3e7685f282
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_std.go
@@ -0,0 +1,31 @@
+package fuse
+
+// There is very little commonality in extended attribute errors
+// across platforms.
+//
+// getxattr return value for "extended attribute does not exist" is
+// ENOATTR on OS X, and ENODATA on Linux and apparently at least
+// NetBSD. There may be a #define ENOATTR on Linux too, but the value
+// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no
+// ENODATA, only ENOATTR. ENOATTR is not in any of the standards,
+// ENODATA exists but is only used for STREAMs.
+//
+// Each platform will define it a errNoXattr constant, and this file
+// will enforce that it implements the right interfaces and hide the
+// implementation.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2
+// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html
+
+// ErrNoXattr is a platform-independent error value meaning the
+// extended attribute was not found. It can be used to respond to
+// GetxattrRequest and such.
+const ErrNoXattr = errNoXattr
+
+var _ error = ErrNoXattr
+var _ Errno = ErrNoXattr
+var _ ErrorNumber = ErrNoXattr
diff --git a/vendor/bazil.org/fuse/fs/serve.go b/vendor/bazil.org/fuse/fs/serve.go
new file mode 100644
index 0000000000000000000000000000000000000000..e9fc56590fd849f1a78873ff8f6dfe67d83ead73
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/serve.go
@@ -0,0 +1,1568 @@
+// FUSE service loop, for servers that wish to use it.
+
+package fs // import "bazil.org/fuse/fs"
+
+import (
+	"encoding/binary"
+	"fmt"
+	"hash/fnv"
+	"io"
+	"log"
+	"reflect"
+	"runtime"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+import (
+	"bytes"
+
+	"bazil.org/fuse"
+	"bazil.org/fuse/fuseutil"
+)
+
+const (
+	attrValidTime  = 1 * time.Minute
+	entryValidTime = 1 * time.Minute
+)
+
+// TODO: FINISH DOCS
+
+// An FS is the interface required of a file system.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// FS* interfaces, for example FSStatfser.
+type FS interface {
+	// Root is called to obtain the Node for the file system root.
+	Root() (Node, error)
+}
+
+type FSStatfser interface {
+	// Statfs is called to obtain file system metadata.
+	// It should write that data to resp.
+	Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error
+}
+
+type FSDestroyer interface {
+	// Destroy is called when the file system is shutting down.
+	//
+	// Linux only sends this request for block device backed (fuseblk)
+	// filesystems, to allow them to flush writes to disk before the
+	// unmount completes.
+	Destroy()
+}
+
+type FSInodeGenerator interface {
+	// GenerateInode is called to pick a dynamic inode number when it
+	// would otherwise be 0.
+	//
+	// Not all filesystems bother tracking inodes, but FUSE requires
+	// the inode to be set, and fewer duplicates in general makes UNIX
+	// tools work better.
+	//
+	// Operations where the nodes may return 0 inodes include Getattr,
+	// Setattr and ReadDir.
+	//
+	// If FS does not implement FSInodeGenerator, GenerateDynamicInode
+	// is used.
+	//
+	// Implementing this is useful to e.g. constrain the range of
+	// inode values used for dynamic inodes.
+	GenerateInode(parentInode uint64, name string) uint64
+}
+
+// A Node is the interface required of a file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// A Node must be usable as a map key, that is, it cannot be a
+// function, map or slice.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Node* interfaces, for example NodeOpener.
+//
+// Methods returning Node should take care to return the same Node
+// when the result is logically the same instance. Without this, each
+// Node will get a new NodeID, causing spurious cache invalidations,
+// extra lookups and aliasing anomalies. This may not matter for a
+// simple, read-only filesystem.
+type Node interface {
+	// Attr fills attr with the standard metadata for the node.
+	//
+	// Fields with reasonable defaults are prepopulated. For example,
+	// all times are set to a fixed moment when the program started.
+	//
+	// If Inode is left as 0, a dynamic inode number is chosen.
+	//
+	// The result may be cached for the duration set in Valid.
+	Attr(ctx context.Context, attr *fuse.Attr) error
+}
+
+type NodeGetattrer interface {
+	// Getattr obtains the standard metadata for the receiver.
+	// It should store that metadata in resp.
+	//
+	// If this method is not implemented, the attributes will be
+	// generated based on Attr(), with zero values filled in.
+	Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error
+}
+
+type NodeSetattrer interface {
+	// Setattr sets the standard metadata for the receiver.
+	//
+	// Note, this is also used to communicate changes in the size of
+	// the file, outside of Writes.
+	//
+	// req.Valid is a bitmask of what fields are actually being set.
+	// For example, the method should not change the mode of the file
+	// unless req.Valid.Mode() is true.
+	Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error
+}
+
+type NodeSymlinker interface {
+	// Symlink creates a new symbolic link in the receiver, which must be a directory.
+	//
+	// TODO is the above true about directories?
+	Symlink(ctx context.Context, req *fuse.SymlinkRequest) (Node, error)
+}
+
+// This optional request will be called only for symbolic link nodes.
+type NodeReadlinker interface {
+	// Readlink reads a symbolic link.
+	Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error)
+}
+
+type NodeLinker interface {
+	// Link creates a new directory entry in the receiver based on an
+	// existing Node. Receiver must be a directory.
+	Link(ctx context.Context, req *fuse.LinkRequest, old Node) (Node, error)
+}
+
+type NodeRemover interface {
+	// Remove removes the entry with the given name from
+	// the receiver, which must be a directory.  The entry to be removed
+	// may correspond to a file (unlink) or to a directory (rmdir).
+	Remove(ctx context.Context, req *fuse.RemoveRequest) error
+}
+
+type NodeAccesser interface {
+	// Access checks whether the calling context has permission for
+	// the given operations on the receiver. If so, Access should
+	// return nil. If not, Access should return EPERM.
+	//
+	// Note that this call affects the result of the access(2) system
+	// call but not the open(2) system call. If Access is not
+	// implemented, the Node behaves as if it always returns nil
+	// (permission granted), relying on checks in Open instead.
+	Access(ctx context.Context, req *fuse.AccessRequest) error
+}
+
+type NodeStringLookuper interface {
+	// Lookup looks up a specific entry in the receiver,
+	// which must be a directory.  Lookup should return a Node
+	// corresponding to the entry.  If the name does not exist in
+	// the directory, Lookup should return ENOENT.
+	//
+	// Lookup need not to handle the names "." and "..".
+	Lookup(ctx context.Context, name string) (Node, error)
+}
+
+type NodeRequestLookuper interface {
+	// Lookup looks up a specific entry in the receiver.
+	// See NodeStringLookuper for more.
+	Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (Node, error)
+}
+
+type NodeMkdirer interface {
+	Mkdir(ctx context.Context, req *fuse.MkdirRequest) (Node, error)
+}
+
+type NodeOpener interface {
+	// Open opens the receiver. After a successful open, a client
+	// process has a file descriptor referring to this Handle.
+	//
+	// Open can also be also called on non-files. For example,
+	// directories are Opened for ReadDir or fchdir(2).
+	//
+	// If this method is not implemented, the open will always
+	// succeed, and the Node itself will be used as the Handle.
+	//
+	// XXX note about access.  XXX OpenFlags.
+	Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (Handle, error)
+}
+
+type NodeCreater interface {
+	// Create creates a new directory entry in the receiver, which
+	// must be a directory.
+	Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (Node, Handle, error)
+}
+
+type NodeForgetter interface {
+	// Forget about this node. This node will not receive further
+	// method calls.
+	//
+	// Forget is not necessarily seen on unmount, as all nodes are
+	// implicitly forgotten as part part of the unmount.
+	Forget()
+}
+
+type NodeRenamer interface {
+	Rename(ctx context.Context, req *fuse.RenameRequest, newDir Node) error
+}
+
+type NodeMknoder interface {
+	Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error)
+}
+
+// TODO this should be on Handle not Node
+type NodeFsyncer interface {
+	Fsync(ctx context.Context, req *fuse.FsyncRequest) error
+}
+
+type NodeGetxattrer interface {
+	// Getxattr gets an extended attribute by the given name from the
+	// node.
+	//
+	// If there is no xattr by that name, returns fuse.ErrNoXattr.
+	Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error
+}
+
+type NodeListxattrer interface {
+	// Listxattr lists the extended attributes recorded for the node.
+	Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error
+}
+
+type NodeSetxattrer interface {
+	// Setxattr sets an extended attribute with the given name and
+	// value for the node.
+	Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error
+}
+
+type NodeRemovexattrer interface {
+	// Removexattr removes an extended attribute for the name.
+	//
+	// If there is no xattr by that name, returns fuse.ErrNoXattr.
+	Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error
+}
+
+var startTime = time.Now()
+
+func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error {
+	attr.Valid = attrValidTime
+	attr.Nlink = 1
+	attr.Atime = startTime
+	attr.Mtime = startTime
+	attr.Ctime = startTime
+	attr.Crtime = startTime
+	if err := n.Attr(ctx, attr); err != nil {
+		return err
+	}
+	return nil
+}
+
+// A Handle is the interface required of an opened file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Handle* interfaces. The most common to implement are HandleReader,
+// HandleReadDirer, and HandleWriter.
+//
+// TODO implement methods: Getlk, Setlk, Setlkw
+type Handle interface {
+}
+
+type HandleFlusher interface {
+	// Flush is called each time the file or directory is closed.
+	// Because there can be multiple file descriptors referring to a
+	// single opened file, Flush can be called multiple times.
+	Flush(ctx context.Context, req *fuse.FlushRequest) error
+}
+
+type HandleReadAller interface {
+	ReadAll(ctx context.Context) ([]byte, error)
+}
+
+type HandleReadDirAller interface {
+	ReadDirAll(ctx context.Context) ([]fuse.Dirent, error)
+}
+
+type HandleReader interface {
+	// Read requests to read data from the handle.
+	//
+	// There is a page cache in the kernel that normally submits only
+	// page-aligned reads spanning one or more pages. However, you
+	// should not rely on this. To see individual requests as
+	// submitted by the file system clients, set OpenDirectIO.
+	//
+	// Note that reads beyond the size of the file as reported by Attr
+	// are not even attempted (except in OpenDirectIO mode).
+	Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error
+}
+
+type HandleWriter interface {
+	// Write requests to write data into the handle at the given offset.
+	// Store the amount of data written in resp.Size.
+	//
+	// There is a writeback page cache in the kernel that normally submits
+	// only page-aligned writes spanning one or more pages. However,
+	// you should not rely on this. To see individual requests as
+	// submitted by the file system clients, set OpenDirectIO.
+	//
+	// Writes that grow the file are expected to update the file size
+	// (as seen through Attr). Note that file size changes are
+	// communicated also through Setattr.
+	Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error
+}
+
+type HandleReleaser interface {
+	Release(ctx context.Context, req *fuse.ReleaseRequest) error
+}
+
+type Config struct {
+	// Function to send debug log messages to. If nil, use fuse.Debug.
+	// Note that changing this or fuse.Debug may not affect existing
+	// calls to Serve.
+	//
+	// See fuse.Debug for the rules that log functions must follow.
+	Debug func(msg interface{})
+
+	// Function to put things into context for processing the request.
+	// The returned context must have ctx as its parent.
+	//
+	// Note that changing this may not affect existing calls to Serve.
+	//
+	// Must not retain req.
+	WithContext func(ctx context.Context, req fuse.Request) context.Context
+}
+
+// New returns a new FUSE server ready to serve this kernel FUSE
+// connection.
+//
+// Config may be nil.
+func New(conn *fuse.Conn, config *Config) *Server {
+	s := &Server{
+		conn:         conn,
+		req:          map[fuse.RequestID]*serveRequest{},
+		nodeRef:      map[Node]fuse.NodeID{},
+		dynamicInode: GenerateDynamicInode,
+	}
+	if config != nil {
+		s.debug = config.Debug
+		s.context = config.WithContext
+	}
+	if s.debug == nil {
+		s.debug = fuse.Debug
+	}
+	return s
+}
+
+type Server struct {
+	// set in New
+	conn    *fuse.Conn
+	debug   func(msg interface{})
+	context func(ctx context.Context, req fuse.Request) context.Context
+
+	// set once at Serve time
+	fs           FS
+	dynamicInode func(parent uint64, name string) uint64
+
+	// state, protected by meta
+	meta       sync.Mutex
+	req        map[fuse.RequestID]*serveRequest
+	node       []*serveNode
+	nodeRef    map[Node]fuse.NodeID
+	handle     []*serveHandle
+	freeNode   []fuse.NodeID
+	freeHandle []fuse.HandleID
+	nodeGen    uint64
+
+	// Used to ensure worker goroutines finish before Serve returns
+	wg sync.WaitGroup
+}
+
+// Serve serves the FUSE connection by making calls to the methods
+// of fs and the Nodes and Handles it makes available.  It returns only
+// when the connection has been closed or an unexpected error occurs.
+func (s *Server) Serve(fs FS) error {
+	defer s.wg.Wait() // Wait for worker goroutines to complete before return
+
+	s.fs = fs
+	if dyn, ok := fs.(FSInodeGenerator); ok {
+		s.dynamicInode = dyn.GenerateInode
+	}
+
+	root, err := fs.Root()
+	if err != nil {
+		return fmt.Errorf("cannot obtain root node: %v", err)
+	}
+	// Recognize the root node if it's ever returned from Lookup,
+	// passed to Invalidate, etc.
+	s.nodeRef[root] = 1
+	s.node = append(s.node, nil, &serveNode{
+		inode:      1,
+		generation: s.nodeGen,
+		node:       root,
+		refs:       1,
+	})
+	s.handle = append(s.handle, nil)
+
+	for {
+		req, err := s.conn.ReadRequest()
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			return err
+		}
+
+		s.wg.Add(1)
+		go func() {
+			defer s.wg.Done()
+			s.serve(req)
+		}()
+	}
+	return nil
+}
+
+// Serve serves a FUSE connection with the default settings. See
+// Server.Serve.
+func Serve(c *fuse.Conn, fs FS) error {
+	server := New(c, nil)
+	return server.Serve(fs)
+}
+
+type nothing struct{}
+
+type serveRequest struct {
+	Request fuse.Request
+	cancel  func()
+}
+
+type serveNode struct {
+	inode      uint64
+	generation uint64
+	node       Node
+	refs       uint64
+
+	// Delay freeing the NodeID until waitgroup is done. This allows
+	// using the NodeID for short periods of time without holding the
+	// Server.meta lock.
+	//
+	// Rules:
+	//
+	//     - hold Server.meta while calling wg.Add, then unlock
+	//     - do NOT try to reacquire Server.meta
+	wg sync.WaitGroup
+}
+
+func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error {
+	err := nodeAttr(ctx, sn.node, attr)
+	if attr.Inode == 0 {
+		attr.Inode = sn.inode
+	}
+	return err
+}
+
+type serveHandle struct {
+	handle   Handle
+	readData []byte
+	nodeID   fuse.NodeID
+}
+
+// NodeRef is deprecated. It remains here to decrease code churn on
+// FUSE library users. You may remove it from your program now;
+// returning the same Node values are now recognized automatically,
+// without needing NodeRef.
+type NodeRef struct{}
+
+func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) {
+	c.meta.Lock()
+	defer c.meta.Unlock()
+
+	if id, ok := c.nodeRef[node]; ok {
+		sn := c.node[id]
+		sn.refs++
+		return id, sn.generation
+	}
+
+	sn := &serveNode{inode: inode, node: node, refs: 1}
+	if n := len(c.freeNode); n > 0 {
+		id = c.freeNode[n-1]
+		c.freeNode = c.freeNode[:n-1]
+		c.node[id] = sn
+		c.nodeGen++
+	} else {
+		id = fuse.NodeID(len(c.node))
+		c.node = append(c.node, sn)
+	}
+	sn.generation = c.nodeGen
+	c.nodeRef[node] = id
+	return id, sn.generation
+}
+
+func (c *Server) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) {
+	c.meta.Lock()
+	shandle := &serveHandle{handle: handle, nodeID: nodeID}
+	if n := len(c.freeHandle); n > 0 {
+		id = c.freeHandle[n-1]
+		c.freeHandle = c.freeHandle[:n-1]
+		c.handle[id] = shandle
+	} else {
+		id = fuse.HandleID(len(c.handle))
+		c.handle = append(c.handle, shandle)
+	}
+	c.meta.Unlock()
+	return
+}
+
+type nodeRefcountDropBug struct {
+	N    uint64
+	Refs uint64
+	Node fuse.NodeID
+}
+
+func (n *nodeRefcountDropBug) String() string {
+	return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node)
+}
+
+func (c *Server) dropNode(id fuse.NodeID, n uint64) (forget bool) {
+	c.meta.Lock()
+	defer c.meta.Unlock()
+	snode := c.node[id]
+
+	if snode == nil {
+		// this should only happen if refcounts kernel<->us disagree
+		// *and* two ForgetRequests for the same node race each other;
+		// this indicates a bug somewhere
+		c.debug(nodeRefcountDropBug{N: n, Node: id})
+
+		// we may end up triggering Forget twice, but that's better
+		// than not even once, and that's the best we can do
+		return true
+	}
+
+	if n > snode.refs {
+		c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id})
+		n = snode.refs
+	}
+
+	snode.refs -= n
+	if snode.refs == 0 {
+		snode.wg.Wait()
+		c.node[id] = nil
+		delete(c.nodeRef, snode.node)
+		c.freeNode = append(c.freeNode, id)
+		return true
+	}
+	return false
+}
+
+func (c *Server) dropHandle(id fuse.HandleID) {
+	c.meta.Lock()
+	c.handle[id] = nil
+	c.freeHandle = append(c.freeHandle, id)
+	c.meta.Unlock()
+}
+
+type missingHandle struct {
+	Handle    fuse.HandleID
+	MaxHandle fuse.HandleID
+}
+
+func (m missingHandle) String() string {
+	return fmt.Sprint("missing handle: ", m.Handle, m.MaxHandle)
+}
+
+// Returns nil for invalid handles.
+func (c *Server) getHandle(id fuse.HandleID) (shandle *serveHandle) {
+	c.meta.Lock()
+	defer c.meta.Unlock()
+	if id < fuse.HandleID(len(c.handle)) {
+		shandle = c.handle[uint(id)]
+	}
+	if shandle == nil {
+		c.debug(missingHandle{
+			Handle:    id,
+			MaxHandle: fuse.HandleID(len(c.handle)),
+		})
+	}
+	return
+}
+
+type request struct {
+	Op      string
+	Request *fuse.Header
+	In      interface{} `json:",omitempty"`
+}
+
+func (r request) String() string {
+	return fmt.Sprintf("<- %s", r.In)
+}
+
+type logResponseHeader struct {
+	ID fuse.RequestID
+}
+
+func (m logResponseHeader) String() string {
+	return fmt.Sprintf("ID=%v", m.ID)
+}
+
+type response struct {
+	Op      string
+	Request logResponseHeader
+	Out     interface{} `json:",omitempty"`
+	// Errno contains the errno value as a string, for example "EPERM".
+	Errno string `json:",omitempty"`
+	// Error may contain a free form error message.
+	Error string `json:",omitempty"`
+}
+
+func (r response) errstr() string {
+	s := r.Errno
+	if r.Error != "" {
+		// prefix the errno constant to the long form message
+		s = s + ": " + r.Error
+	}
+	return s
+}
+
+func (r response) String() string {
+	switch {
+	case r.Errno != "" && r.Out != nil:
+		return fmt.Sprintf("-> [%v] %v error=%s", r.Request, r.Out, r.errstr())
+	case r.Errno != "":
+		return fmt.Sprintf("-> [%v] %s error=%s", r.Request, r.Op, r.errstr())
+	case r.Out != nil:
+		// make sure (seemingly) empty values are readable
+		switch r.Out.(type) {
+		case string:
+			return fmt.Sprintf("-> [%v] %s %q", r.Request, r.Op, r.Out)
+		case []byte:
+			return fmt.Sprintf("-> [%v] %s [% x]", r.Request, r.Op, r.Out)
+		default:
+			return fmt.Sprintf("-> [%v] %v", r.Request, r.Out)
+		}
+	default:
+		return fmt.Sprintf("-> [%v] %s", r.Request, r.Op)
+	}
+}
+
+type notification struct {
+	Op   string
+	Node fuse.NodeID
+	Out  interface{} `json:",omitempty"`
+	Err  string      `json:",omitempty"`
+}
+
+func (n notification) String() string {
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "=> %s %v", n.Op, n.Node)
+	if n.Out != nil {
+		// make sure (seemingly) empty values are readable
+		switch n.Out.(type) {
+		case string:
+			fmt.Fprintf(&buf, " %q", n.Out)
+		case []byte:
+			fmt.Fprintf(&buf, " [% x]", n.Out)
+		default:
+			fmt.Fprintf(&buf, " %s", n.Out)
+		}
+	}
+	if n.Err != "" {
+		fmt.Fprintf(&buf, " Err:%v", n.Err)
+	}
+	return buf.String()
+}
+
+type logMissingNode struct {
+	MaxNode fuse.NodeID
+}
+
+func opName(req fuse.Request) string {
+	t := reflect.Indirect(reflect.ValueOf(req)).Type()
+	s := t.Name()
+	s = strings.TrimSuffix(s, "Request")
+	return s
+}
+
+type logLinkRequestOldNodeNotFound struct {
+	Request *fuse.Header
+	In      *fuse.LinkRequest
+}
+
+func (m *logLinkRequestOldNodeNotFound) String() string {
+	return fmt.Sprintf("In LinkRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.OldNode)
+}
+
+type renameNewDirNodeNotFound struct {
+	Request *fuse.Header
+	In      *fuse.RenameRequest
+}
+
+func (m *renameNewDirNodeNotFound) String() string {
+	return fmt.Sprintf("In RenameRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
+}
+
+type handlerPanickedError struct {
+	Request interface{}
+	Err     interface{}
+}
+
+var _ error = handlerPanickedError{}
+
+func (h handlerPanickedError) Error() string {
+	return fmt.Sprintf("handler panicked: %v", h.Err)
+}
+
+var _ fuse.ErrorNumber = handlerPanickedError{}
+
+func (h handlerPanickedError) Errno() fuse.Errno {
+	if err, ok := h.Err.(fuse.ErrorNumber); ok {
+		return err.Errno()
+	}
+	return fuse.DefaultErrno
+}
+
+// handlerTerminatedError happens when a handler terminates itself
+// with runtime.Goexit. This is most commonly because of incorrect use
+// of testing.TB.FailNow, typically via t.Fatal.
+type handlerTerminatedError struct {
+	Request interface{}
+}
+
+var _ error = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Error() string {
+	return fmt.Sprintf("handler terminated (called runtime.Goexit)")
+}
+
+var _ fuse.ErrorNumber = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Errno() fuse.Errno {
+	return fuse.DefaultErrno
+}
+
+type handleNotReaderError struct {
+	handle Handle
+}
+
+var _ error = handleNotReaderError{}
+
+func (e handleNotReaderError) Error() string {
+	return fmt.Sprintf("handle has no Read: %T", e.handle)
+}
+
+var _ fuse.ErrorNumber = handleNotReaderError{}
+
+func (e handleNotReaderError) Errno() fuse.Errno {
+	return fuse.ENOTSUP
+}
+
+func initLookupResponse(s *fuse.LookupResponse) {
+	s.EntryValid = entryValidTime
+}
+
+func (c *Server) serve(r fuse.Request) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	parentCtx := ctx
+	if c.context != nil {
+		ctx = c.context(ctx, r)
+	}
+
+	req := &serveRequest{Request: r, cancel: cancel}
+
+	c.debug(request{
+		Op:      opName(r),
+		Request: r.Hdr(),
+		In:      r,
+	})
+	var node Node
+	var snode *serveNode
+	c.meta.Lock()
+	hdr := r.Hdr()
+	if id := hdr.Node; id != 0 {
+		if id < fuse.NodeID(len(c.node)) {
+			snode = c.node[uint(id)]
+		}
+		if snode == nil {
+			c.meta.Unlock()
+			c.debug(response{
+				Op:      opName(r),
+				Request: logResponseHeader{ID: hdr.ID},
+				Error:   fuse.ESTALE.ErrnoName(),
+				// this is the only place that sets both Error and
+				// Out; not sure if i want to do that; might get rid
+				// of len(c.node) things altogether
+				Out: logMissingNode{
+					MaxNode: fuse.NodeID(len(c.node)),
+				},
+			})
+			r.RespondError(fuse.ESTALE)
+			return
+		}
+		node = snode.node
+	}
+	if c.req[hdr.ID] != nil {
+		// This happens with OSXFUSE.  Assume it's okay and
+		// that we'll never see an interrupt for this one.
+		// Otherwise everything wedges.  TODO: Report to OSXFUSE?
+		//
+		// TODO this might have been because of missing done() calls
+	} else {
+		c.req[hdr.ID] = req
+	}
+	c.meta.Unlock()
+
+	// Call this before responding.
+	// After responding is too late: we might get another request
+	// with the same ID and be very confused.
+	done := func(resp interface{}) {
+		msg := response{
+			Op:      opName(r),
+			Request: logResponseHeader{ID: hdr.ID},
+		}
+		if err, ok := resp.(error); ok {
+			msg.Error = err.Error()
+			if ferr, ok := err.(fuse.ErrorNumber); ok {
+				errno := ferr.Errno()
+				msg.Errno = errno.ErrnoName()
+				if errno == err {
+					// it's just a fuse.Errno with no extra detail;
+					// skip the textual message for log readability
+					msg.Error = ""
+				}
+			} else {
+				msg.Errno = fuse.DefaultErrno.ErrnoName()
+			}
+		} else {
+			msg.Out = resp
+		}
+		c.debug(msg)
+
+		c.meta.Lock()
+		delete(c.req, hdr.ID)
+		c.meta.Unlock()
+	}
+
+	var responded bool
+	defer func() {
+		if rec := recover(); rec != nil {
+			const size = 1 << 16
+			buf := make([]byte, size)
+			n := runtime.Stack(buf, false)
+			buf = buf[:n]
+			log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf)
+			err := handlerPanickedError{
+				Request: r,
+				Err:     rec,
+			}
+			done(err)
+			r.RespondError(err)
+			return
+		}
+
+		if !responded {
+			err := handlerTerminatedError{
+				Request: r,
+			}
+			done(err)
+			r.RespondError(err)
+		}
+	}()
+
+	if err := c.handleRequest(ctx, node, snode, r, done); err != nil {
+		if err == context.Canceled {
+			select {
+			case <-parentCtx.Done():
+				// We canceled the parent context because of an
+				// incoming interrupt request, so return EINTR
+				// to trigger the right behavior in the client app.
+				//
+				// Only do this when it's the parent context that was
+				// canceled, not a context controlled by the program
+				// using this library, so we don't return EINTR too
+				// eagerly -- it might cause busy loops.
+				//
+				// Decent write-up on role of EINTR:
+				// http://250bpm.com/blog:12
+				err = fuse.EINTR
+			default:
+				// nothing
+			}
+		}
+		done(err)
+		r.RespondError(err)
+	}
+
+	// disarm runtime.Goexit protection
+	responded = true
+}
+
+// handleRequest will either a) call done(s) and r.Respond(s) OR b) return an error.
+func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, r fuse.Request, done func(resp interface{})) error {
+	switch r := r.(type) {
+	default:
+		// Note: To FUSE, ENOSYS means "this server never implements this request."
+		// It would be inappropriate to return ENOSYS for other operations in this
+		// switch that might only be unavailable in some contexts, not all.
+		return fuse.ENOSYS
+
+	case *fuse.StatfsRequest:
+		s := &fuse.StatfsResponse{}
+		if fs, ok := c.fs.(FSStatfser); ok {
+			if err := fs.Statfs(ctx, r, s); err != nil {
+				return err
+			}
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	// Node operations.
+	case *fuse.GetattrRequest:
+		s := &fuse.GetattrResponse{}
+		if n, ok := node.(NodeGetattrer); ok {
+			if err := n.Getattr(ctx, r, s); err != nil {
+				return err
+			}
+		} else {
+			if err := snode.attr(ctx, &s.Attr); err != nil {
+				return err
+			}
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.SetattrRequest:
+		s := &fuse.SetattrResponse{}
+		if n, ok := node.(NodeSetattrer); ok {
+			if err := n.Setattr(ctx, r, s); err != nil {
+				return err
+			}
+		}
+
+		if err := snode.attr(ctx, &s.Attr); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.SymlinkRequest:
+		s := &fuse.SymlinkResponse{}
+		initLookupResponse(&s.LookupResponse)
+		n, ok := node.(NodeSymlinker)
+		if !ok {
+			return fuse.EIO // XXX or EPERM like Mkdir?
+		}
+		n2, err := n.Symlink(ctx, r)
+		if err != nil {
+			return err
+		}
+		if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.ReadlinkRequest:
+		n, ok := node.(NodeReadlinker)
+		if !ok {
+			return fuse.EIO /// XXX or EPERM?
+		}
+		target, err := n.Readlink(ctx, r)
+		if err != nil {
+			return err
+		}
+		done(target)
+		r.Respond(target)
+		return nil
+
+	case *fuse.LinkRequest:
+		n, ok := node.(NodeLinker)
+		if !ok {
+			return fuse.EIO /// XXX or EPERM?
+		}
+		c.meta.Lock()
+		var oldNode *serveNode
+		if int(r.OldNode) < len(c.node) {
+			oldNode = c.node[r.OldNode]
+		}
+		c.meta.Unlock()
+		if oldNode == nil {
+			c.debug(logLinkRequestOldNodeNotFound{
+				Request: r.Hdr(),
+				In:      r,
+			})
+			return fuse.EIO
+		}
+		n2, err := n.Link(ctx, r, oldNode.node)
+		if err != nil {
+			return err
+		}
+		s := &fuse.LookupResponse{}
+		initLookupResponse(s)
+		if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.RemoveRequest:
+		n, ok := node.(NodeRemover)
+		if !ok {
+			return fuse.EIO /// XXX or EPERM?
+		}
+		err := n.Remove(ctx, r)
+		if err != nil {
+			return err
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.AccessRequest:
+		if n, ok := node.(NodeAccesser); ok {
+			if err := n.Access(ctx, r); err != nil {
+				return err
+			}
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.LookupRequest:
+		var n2 Node
+		var err error
+		s := &fuse.LookupResponse{}
+		initLookupResponse(s)
+		if n, ok := node.(NodeStringLookuper); ok {
+			n2, err = n.Lookup(ctx, r.Name)
+		} else if n, ok := node.(NodeRequestLookuper); ok {
+			n2, err = n.Lookup(ctx, r, s)
+		} else {
+			return fuse.ENOENT
+		}
+		if err != nil {
+			return err
+		}
+		if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.MkdirRequest:
+		s := &fuse.MkdirResponse{}
+		initLookupResponse(&s.LookupResponse)
+		n, ok := node.(NodeMkdirer)
+		if !ok {
+			return fuse.EPERM
+		}
+		n2, err := n.Mkdir(ctx, r)
+		if err != nil {
+			return err
+		}
+		if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.OpenRequest:
+		s := &fuse.OpenResponse{}
+		var h2 Handle
+		if n, ok := node.(NodeOpener); ok {
+			hh, err := n.Open(ctx, r, s)
+			if err != nil {
+				return err
+			}
+			h2 = hh
+		} else {
+			h2 = node
+		}
+		s.Handle = c.saveHandle(h2, r.Hdr().Node)
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.CreateRequest:
+		n, ok := node.(NodeCreater)
+		if !ok {
+			// If we send back ENOSYS, FUSE will try mknod+open.
+			return fuse.EPERM
+		}
+		s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
+		initLookupResponse(&s.LookupResponse)
+		n2, h2, err := n.Create(ctx, r, s)
+		if err != nil {
+			return err
+		}
+		if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+			return err
+		}
+		s.Handle = c.saveHandle(h2, r.Hdr().Node)
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.GetxattrRequest:
+		n, ok := node.(NodeGetxattrer)
+		if !ok {
+			return fuse.ENOTSUP
+		}
+		s := &fuse.GetxattrResponse{}
+		err := n.Getxattr(ctx, r, s)
+		if err != nil {
+			return err
+		}
+		if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+			return fuse.ERANGE
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.ListxattrRequest:
+		n, ok := node.(NodeListxattrer)
+		if !ok {
+			return fuse.ENOTSUP
+		}
+		s := &fuse.ListxattrResponse{}
+		err := n.Listxattr(ctx, r, s)
+		if err != nil {
+			return err
+		}
+		if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+			return fuse.ERANGE
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.SetxattrRequest:
+		n, ok := node.(NodeSetxattrer)
+		if !ok {
+			return fuse.ENOTSUP
+		}
+		err := n.Setxattr(ctx, r)
+		if err != nil {
+			return err
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.RemovexattrRequest:
+		n, ok := node.(NodeRemovexattrer)
+		if !ok {
+			return fuse.ENOTSUP
+		}
+		err := n.Removexattr(ctx, r)
+		if err != nil {
+			return err
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.ForgetRequest:
+		forget := c.dropNode(r.Hdr().Node, r.N)
+		if forget {
+			n, ok := node.(NodeForgetter)
+			if ok {
+				n.Forget()
+			}
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	// Handle operations.
+	case *fuse.ReadRequest:
+		shandle := c.getHandle(r.Handle)
+		if shandle == nil {
+			return fuse.ESTALE
+		}
+		handle := shandle.handle
+
+		s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)}
+		if r.Dir {
+			if h, ok := handle.(HandleReadDirAller); ok {
+				// detect rewinddir(3) or similar seek and refresh
+				// contents
+				if r.Offset == 0 {
+					shandle.readData = nil
+				}
+
+				if shandle.readData == nil {
+					dirs, err := h.ReadDirAll(ctx)
+					if err != nil {
+						return err
+					}
+					var data []byte
+					for _, dir := range dirs {
+						if dir.Inode == 0 {
+							dir.Inode = c.dynamicInode(snode.inode, dir.Name)
+						}
+						data = fuse.AppendDirent(data, dir)
+					}
+					shandle.readData = data
+				}
+				fuseutil.HandleRead(r, s, shandle.readData)
+				done(s)
+				r.Respond(s)
+				return nil
+			}
+		} else {
+			if h, ok := handle.(HandleReadAller); ok {
+				if shandle.readData == nil {
+					data, err := h.ReadAll(ctx)
+					if err != nil {
+						return err
+					}
+					if data == nil {
+						data = []byte{}
+					}
+					shandle.readData = data
+				}
+				fuseutil.HandleRead(r, s, shandle.readData)
+				done(s)
+				r.Respond(s)
+				return nil
+			}
+			h, ok := handle.(HandleReader)
+			if !ok {
+				err := handleNotReaderError{handle: handle}
+				return err
+			}
+			if err := h.Read(ctx, r, s); err != nil {
+				return err
+			}
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.WriteRequest:
+		shandle := c.getHandle(r.Handle)
+		if shandle == nil {
+			return fuse.ESTALE
+		}
+
+		s := &fuse.WriteResponse{}
+		if h, ok := shandle.handle.(HandleWriter); ok {
+			if err := h.Write(ctx, r, s); err != nil {
+				return err
+			}
+			done(s)
+			r.Respond(s)
+			return nil
+		}
+		return fuse.EIO
+
+	case *fuse.FlushRequest:
+		shandle := c.getHandle(r.Handle)
+		if shandle == nil {
+			return fuse.ESTALE
+		}
+		handle := shandle.handle
+
+		if h, ok := handle.(HandleFlusher); ok {
+			if err := h.Flush(ctx, r); err != nil {
+				return err
+			}
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.ReleaseRequest:
+		shandle := c.getHandle(r.Handle)
+		if shandle == nil {
+			return fuse.ESTALE
+		}
+		handle := shandle.handle
+
+		// No matter what, release the handle.
+		c.dropHandle(r.Handle)
+
+		if h, ok := handle.(HandleReleaser); ok {
+			if err := h.Release(ctx, r); err != nil {
+				return err
+			}
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.DestroyRequest:
+		if fs, ok := c.fs.(FSDestroyer); ok {
+			fs.Destroy()
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.RenameRequest:
+		c.meta.Lock()
+		var newDirNode *serveNode
+		if int(r.NewDir) < len(c.node) {
+			newDirNode = c.node[r.NewDir]
+		}
+		c.meta.Unlock()
+		if newDirNode == nil {
+			c.debug(renameNewDirNodeNotFound{
+				Request: r.Hdr(),
+				In:      r,
+			})
+			return fuse.EIO
+		}
+		n, ok := node.(NodeRenamer)
+		if !ok {
+			return fuse.EIO // XXX or EPERM like Mkdir?
+		}
+		err := n.Rename(ctx, r, newDirNode.node)
+		if err != nil {
+			return err
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.MknodRequest:
+		n, ok := node.(NodeMknoder)
+		if !ok {
+			return fuse.EIO
+		}
+		n2, err := n.Mknod(ctx, r)
+		if err != nil {
+			return err
+		}
+		s := &fuse.LookupResponse{}
+		initLookupResponse(s)
+		if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+			return err
+		}
+		done(s)
+		r.Respond(s)
+		return nil
+
+	case *fuse.FsyncRequest:
+		n, ok := node.(NodeFsyncer)
+		if !ok {
+			return fuse.EIO
+		}
+		err := n.Fsync(ctx, r)
+		if err != nil {
+			return err
+		}
+		done(nil)
+		r.Respond()
+		return nil
+
+	case *fuse.InterruptRequest:
+		c.meta.Lock()
+		ireq := c.req[r.IntrID]
+		if ireq != nil && ireq.cancel != nil {
+			ireq.cancel()
+			ireq.cancel = nil
+		}
+		c.meta.Unlock()
+		done(nil)
+		r.Respond()
+		return nil
+
+		/*	case *FsyncdirRequest:
+				return ENOSYS
+
+			case *GetlkRequest, *SetlkRequest, *SetlkwRequest:
+				return ENOSYS
+
+			case *BmapRequest:
+				return ENOSYS
+
+			case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest:
+				return ENOSYS
+		*/
+	}
+
+	panic("not reached")
+}
+
+func (c *Server) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error {
+	if err := nodeAttr(ctx, n2, &s.Attr); err != nil {
+		return err
+	}
+	if s.Attr.Inode == 0 {
+		s.Attr.Inode = c.dynamicInode(snode.inode, elem)
+	}
+
+	s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
+	return nil
+}
+
+type invalidateNodeDetail struct {
+	Off  int64
+	Size int64
+}
+
+func (i invalidateNodeDetail) String() string {
+	return fmt.Sprintf("Off:%d Size:%d", i.Off, i.Size)
+}
+
+func errstr(err error) string {
+	if err == nil {
+		return ""
+	}
+	return err.Error()
+}
+
+func (s *Server) invalidateNode(node Node, off int64, size int64) error {
+	s.meta.Lock()
+	id, ok := s.nodeRef[node]
+	if ok {
+		snode := s.node[id]
+		snode.wg.Add(1)
+		defer snode.wg.Done()
+	}
+	s.meta.Unlock()
+	if !ok {
+		// This is what the kernel would have said, if we had been
+		// able to send this message; it's not cached.
+		return fuse.ErrNotCached
+	}
+	// Delay logging until after we can record the error too. We
+	// consider a /dev/fuse write to be instantaneous enough to not
+	// need separate before and after messages.
+	err := s.conn.InvalidateNode(id, off, size)
+	s.debug(notification{
+		Op:   "InvalidateNode",
+		Node: id,
+		Out: invalidateNodeDetail{
+			Off:  off,
+			Size: size,
+		},
+		Err: errstr(err),
+	})
+	return err
+}
+
+// InvalidateNodeAttr invalidates the kernel cache of the attributes
+// of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeAttr(node Node) error {
+	return s.invalidateNode(node, 0, 0)
+}
+
+// InvalidateNodeData invalidates the kernel cache of the attributes
+// and data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeData(node Node) error {
+	return s.invalidateNode(node, 0, -1)
+}
+
+// InvalidateNodeDataRange invalidates the kernel cache of the
+// attributes and a range of the data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeDataRange(node Node, off int64, size int64) error {
+	return s.invalidateNode(node, off, size)
+}
+
+type invalidateEntryDetail struct {
+	Name string
+}
+
+func (i invalidateEntryDetail) String() string {
+	return fmt.Sprintf("%q", i.Name)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent node and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (s *Server) InvalidateEntry(parent Node, name string) error {
+	s.meta.Lock()
+	id, ok := s.nodeRef[parent]
+	if ok {
+		snode := s.node[id]
+		snode.wg.Add(1)
+		defer snode.wg.Done()
+	}
+	s.meta.Unlock()
+	if !ok {
+		// This is what the kernel would have said, if we had been
+		// able to send this message; it's not cached.
+		return fuse.ErrNotCached
+	}
+	err := s.conn.InvalidateEntry(id, name)
+	s.debug(notification{
+		Op:   "InvalidateEntry",
+		Node: id,
+		Out: invalidateEntryDetail{
+			Name: name,
+		},
+		Err: errstr(err),
+	})
+	return err
+}
+
+// DataHandle returns a read-only Handle that satisfies reads
+// using the given data.
+func DataHandle(data []byte) Handle {
+	return &dataHandle{data}
+}
+
+type dataHandle struct {
+	data []byte
+}
+
+func (d *dataHandle) ReadAll(ctx context.Context) ([]byte, error) {
+	return d.data, nil
+}
+
+// GenerateDynamicInode returns a dynamic inode.
+//
+// The parent inode and current entry name are used as the criteria
+// for choosing a pseudorandom inode. This makes it likely the same
+// entry will get the same inode on multiple runs.
+func GenerateDynamicInode(parent uint64, name string) uint64 {
+	h := fnv.New64a()
+	var buf [8]byte
+	binary.LittleEndian.PutUint64(buf[:], parent)
+	_, _ = h.Write(buf[:])
+	_, _ = h.Write([]byte(name))
+	var inode uint64
+	for {
+		inode = h.Sum64()
+		if inode != 0 {
+			break
+		}
+		// there's a tiny probability that result is zero; change the
+		// input a little and try again
+		_, _ = h.Write([]byte{'x'})
+	}
+	return inode
+}
diff --git a/vendor/bazil.org/fuse/fs/tree.go b/vendor/bazil.org/fuse/fs/tree.go
new file mode 100644
index 0000000000000000000000000000000000000000..7e078045a5a03549eb615326c61a076e37c209ed
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/tree.go
@@ -0,0 +1,99 @@
+// FUSE directory tree, for servers that wish to use it with the service loop.
+
+package fs
+
+import (
+	"os"
+	pathpkg "path"
+	"strings"
+
+	"golang.org/x/net/context"
+)
+
+import (
+	"bazil.org/fuse"
+)
+
+// A Tree implements a basic read-only directory tree for FUSE.
+// The Nodes contained in it may still be writable.
+type Tree struct {
+	tree
+}
+
+func (t *Tree) Root() (Node, error) {
+	return &t.tree, nil
+}
+
+// Add adds the path to the tree, resolving to the given node.
+// If path or a prefix of path has already been added to the tree,
+// Add panics.
+//
+// Add is only safe to call before starting to serve requests.
+func (t *Tree) Add(path string, node Node) {
+	path = pathpkg.Clean("/" + path)[1:]
+	elems := strings.Split(path, "/")
+	dir := Node(&t.tree)
+	for i, elem := range elems {
+		dt, ok := dir.(*tree)
+		if !ok {
+			panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path)
+		}
+		n := dt.lookup(elem)
+		if n != nil {
+			if i+1 == len(elems) {
+				panic("fuse: Tree.Add for " + path + " conflicts with " + elem)
+			}
+			dir = n
+		} else {
+			if i+1 == len(elems) {
+				dt.add(elem, node)
+			} else {
+				dir = &tree{}
+				dt.add(elem, dir)
+			}
+		}
+	}
+}
+
+type treeDir struct {
+	name string
+	node Node
+}
+
+type tree struct {
+	dir []treeDir
+}
+
+func (t *tree) lookup(name string) Node {
+	for _, d := range t.dir {
+		if d.name == name {
+			return d.node
+		}
+	}
+	return nil
+}
+
+func (t *tree) add(name string, n Node) {
+	t.dir = append(t.dir, treeDir{name, n})
+}
+
+func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
+	a.Mode = os.ModeDir | 0555
+	return nil
+}
+
+func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
+	n := t.lookup(name)
+	if n != nil {
+		return n, nil
+	}
+	return nil, fuse.ENOENT
+}
+
+func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+	var out []fuse.Dirent
+	for _, d := range t.dir {
+		out = append(out, fuse.Dirent{Name: d.name})
+	}
+	return out, nil
+}
diff --git a/vendor/bazil.org/fuse/fuse.go b/vendor/bazil.org/fuse/fuse.go
new file mode 100644
index 0000000000000000000000000000000000000000..6db0ef2935f4e3ff090b7b68e186ebde5902d99c
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse.go
@@ -0,0 +1,2303 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+//         Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+// Package fuse enables writing FUSE file systems on Linux, OS X, and FreeBSD.
+//
+// On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
+//
+// There are two approaches to writing a FUSE file system.  The first is to speak
+// the low-level message protocol, reading from a Conn using ReadRequest and
+// writing using the various Respond methods.  This approach is closest to
+// the actual interaction with the kernel and can be the simplest one in contexts
+// such as protocol translators.
+//
+// Servers of synthesized file systems tend to share common
+// bookkeeping abstracted away by the second approach, which is to
+// call fs.Serve to serve the FUSE protocol using an implementation of
+// the service methods in the interfaces FS* (file system), Node* (file
+// or directory), and Handle* (opened file or directory).
+// There are a daunting number of such methods that can be written,
+// but few are required.
+// The specific methods are described in the documentation for those interfaces.
+//
+// The hellofs subdirectory contains a simple illustration of the fs.Serve approach.
+//
+// Service Methods
+//
+// The required and optional methods for the FS, Node, and Handle interfaces
+// have the general form
+//
+//	Op(ctx context.Context, req *OpRequest, resp *OpResponse) error
+//
+// where Op is the name of a FUSE operation. Op reads request
+// parameters from req and writes results to resp. An operation whose
+// only result is the error result omits the resp parameter.
+//
+// Multiple goroutines may call service methods simultaneously; the
+// methods being called are responsible for appropriate
+// synchronization.
+//
+// The operation must not hold on to the request or response,
+// including any []byte fields such as WriteRequest.Data or
+// SetxattrRequest.Xattr.
+//
+// Errors
+//
+// Operations can return errors. The FUSE interface can only
+// communicate POSIX errno error numbers to file system clients, the
+// message is not visible to file system clients. The returned error
+// can implement ErrorNumber to control the errno returned. Without
+// ErrorNumber, a generic errno (EIO) is returned.
+//
+// Error messages will be visible in the debug log as part of the
+// response.
+//
+// Interrupted Operations
+//
+// In some file systems, some operations
+// may take an undetermined amount of time.  For example, a Read waiting for
+// a network message or a matching Write might wait indefinitely.  If the request
+// is cancelled and no longer needed, the context will be cancelled.
+// Blocking operations should select on a receive from ctx.Done() and attempt to
+// abort the operation early if the receive succeeds (meaning the channel is closed).
+// To indicate that the operation failed because it was aborted, return fuse.EINTR.
+//
+// If an operation does not block for an indefinite amount of time, supporting
+// cancellation is not necessary.
+//
+// Authentication
+//
+// All requests types embed a Header, meaning that the method can
+// inspect req.Pid, req.Uid, and req.Gid as necessary to implement
+// permission checking. The kernel FUSE layer normally prevents other
+// users from accessing the FUSE file system (to change this, see
+// AllowOther, AllowRoot), but does not enforce access modes (to
+// change this, see DefaultPermissions).
+//
+// Mount Options
+//
+// Behavior and metadata of the mounted file system can be changed by
+// passing MountOption values to Mount.
+//
+package fuse // import "bazil.org/fuse"
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"sync"
+	"syscall"
+	"time"
+	"unsafe"
+)
+
+// A Conn represents a connection to a mounted FUSE file system.
+type Conn struct {
+	// Ready is closed when the mount is complete or has failed.
+	Ready <-chan struct{}
+
+	// MountError stores any error from the mount process. Only valid
+	// after Ready is closed.
+	MountError error
+
+	// File handle for kernel communication. Only safe to access if
+	// rio or wio is held.
+	dev *os.File
+	wio sync.RWMutex
+	rio sync.RWMutex
+
+	// Protocol version negotiated with InitRequest/InitResponse.
+	proto Protocol
+}
+
+// MountpointDoesNotExistError is an error returned when the
+// mountpoint does not exist.
+type MountpointDoesNotExistError struct {
+	Path string
+}
+
+var _ error = (*MountpointDoesNotExistError)(nil)
+
+func (e *MountpointDoesNotExistError) Error() string {
+	return fmt.Sprintf("mountpoint does not exist: %v", e.Path)
+}
+
+// Mount mounts a new FUSE connection on the named directory
+// and returns a connection for reading and writing FUSE messages.
+//
+// After a successful return, caller must call Close to free
+// resources.
+//
+// Even on successful return, the new mount is not guaranteed to be
+// visible until after Conn.Ready is closed. See Conn.MountError for
+// possible errors. Incoming requests on Conn must be served to make
+// progress.
+func Mount(dir string, options ...MountOption) (*Conn, error) {
+	conf := mountConfig{
+		options: make(map[string]string),
+	}
+	for _, option := range options {
+		if err := option(&conf); err != nil {
+			return nil, err
+		}
+	}
+
+	ready := make(chan struct{}, 1)
+	c := &Conn{
+		Ready: ready,
+	}
+	f, err := mount(dir, &conf, ready, &c.MountError)
+	if err != nil {
+		return nil, err
+	}
+	c.dev = f
+
+	if err := initMount(c, &conf); err != nil {
+		c.Close()
+		if err == ErrClosedWithoutInit {
+			// see if we can provide a better error
+			<-c.Ready
+			if err := c.MountError; err != nil {
+				return nil, err
+			}
+		}
+		return nil, err
+	}
+
+	return c, nil
+}
+
+type OldVersionError struct {
+	Kernel     Protocol
+	LibraryMin Protocol
+}
+
+func (e *OldVersionError) Error() string {
+	return fmt.Sprintf("kernel FUSE version is too old: %v < %v", e.Kernel, e.LibraryMin)
+}
+
+var (
+	ErrClosedWithoutInit = errors.New("fuse connection closed without init")
+)
+
+func initMount(c *Conn, conf *mountConfig) error {
+	req, err := c.ReadRequest()
+	if err != nil {
+		if err == io.EOF {
+			return ErrClosedWithoutInit
+		}
+		return err
+	}
+	r, ok := req.(*InitRequest)
+	if !ok {
+		return fmt.Errorf("missing init, got: %T", req)
+	}
+
+	min := Protocol{protoVersionMinMajor, protoVersionMinMinor}
+	if r.Kernel.LT(min) {
+		req.RespondError(Errno(syscall.EPROTO))
+		c.Close()
+		return &OldVersionError{
+			Kernel:     r.Kernel,
+			LibraryMin: min,
+		}
+	}
+
+	proto := Protocol{protoVersionMaxMajor, protoVersionMaxMinor}
+	if r.Kernel.LT(proto) {
+		// Kernel doesn't support the latest version we have.
+		proto = r.Kernel
+	}
+	c.proto = proto
+
+	s := &InitResponse{
+		Library:      proto,
+		MaxReadahead: conf.maxReadahead,
+		MaxWrite:     maxWrite,
+		Flags:        InitBigWrites | conf.initFlags,
+	}
+	r.Respond(s)
+	return nil
+}
+
+// A Request represents a single FUSE request received from the kernel.
+// Use a type switch to determine the specific kind.
+// A request of unrecognized type will have concrete type *Header.
+type Request interface {
+	// Hdr returns the Header associated with this request.
+	Hdr() *Header
+
+	// RespondError responds to the request with the given error.
+	RespondError(error)
+
+	String() string
+}
+
+// A RequestID identifies an active FUSE request.
+type RequestID uint64
+
+func (r RequestID) String() string {
+	return fmt.Sprintf("%#x", uint64(r))
+}
+
+// A NodeID is a number identifying a directory or file.
+// It must be unique among IDs returned in LookupResponses
+// that have not yet been forgotten by ForgetRequests.
+type NodeID uint64
+
+func (n NodeID) String() string {
+	return fmt.Sprintf("%#x", uint64(n))
+}
+
+// A HandleID is a number identifying an open directory or file.
+// It only needs to be unique while the directory or file is open.
+type HandleID uint64
+
+func (h HandleID) String() string {
+	return fmt.Sprintf("%#x", uint64(h))
+}
+
+// The RootID identifies the root directory of a FUSE file system.
+const RootID NodeID = rootID
+
+// A Header describes the basic information sent in every request.
+type Header struct {
+	Conn *Conn     `json:"-"` // connection this request was received on
+	ID   RequestID // unique ID for request
+	Node NodeID    // file or directory the request is about
+	Uid  uint32    // user ID of process making request
+	Gid  uint32    // group ID of process making request
+	Pid  uint32    // process ID of process making request
+
+	// for returning to reqPool
+	msg *message
+}
+
+func (h *Header) String() string {
+	return fmt.Sprintf("ID=%v Node=%v Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
+}
+
+func (h *Header) Hdr() *Header {
+	return h
+}
+
+func (h *Header) noResponse() {
+	putMessage(h.msg)
+}
+
+func (h *Header) respond(msg []byte) {
+	out := (*outHeader)(unsafe.Pointer(&msg[0]))
+	out.Unique = uint64(h.ID)
+	h.Conn.respond(msg)
+	putMessage(h.msg)
+}
+
+// An ErrorNumber is an error with a specific error number.
+//
+// Operations may return an error value that implements ErrorNumber to
+// control what specific error number (errno) to return.
+type ErrorNumber interface {
+	// Errno returns the the error number (errno) for this error.
+	Errno() Errno
+}
+
+const (
+	// ENOSYS indicates that the call is not supported.
+	ENOSYS = Errno(syscall.ENOSYS)
+
+	// ESTALE is used by Serve to respond to violations of the FUSE protocol.
+	ESTALE = Errno(syscall.ESTALE)
+
+	ENOENT = Errno(syscall.ENOENT)
+	EIO    = Errno(syscall.EIO)
+	EPERM  = Errno(syscall.EPERM)
+
+	// EINTR indicates request was interrupted by an InterruptRequest.
+	// See also fs.Intr.
+	EINTR = Errno(syscall.EINTR)
+
+	ERANGE  = Errno(syscall.ERANGE)
+	ENOTSUP = Errno(syscall.ENOTSUP)
+	EEXIST  = Errno(syscall.EEXIST)
+)
+
+// DefaultErrno is the errno used when error returned does not
+// implement ErrorNumber.
+const DefaultErrno = EIO
+
+var errnoNames = map[Errno]string{
+	ENOSYS: "ENOSYS",
+	ESTALE: "ESTALE",
+	ENOENT: "ENOENT",
+	EIO:    "EIO",
+	EPERM:  "EPERM",
+	EINTR:  "EINTR",
+	EEXIST: "EEXIST",
+}
+
+// Errno implements Error and ErrorNumber using a syscall.Errno.
+type Errno syscall.Errno
+
+var _ = ErrorNumber(Errno(0))
+var _ = error(Errno(0))
+
+func (e Errno) Errno() Errno {
+	return e
+}
+
+func (e Errno) String() string {
+	return syscall.Errno(e).Error()
+}
+
+func (e Errno) Error() string {
+	return syscall.Errno(e).Error()
+}
+
+// ErrnoName returns the short non-numeric identifier for this errno.
+// For example, "EIO".
+func (e Errno) ErrnoName() string {
+	s := errnoNames[e]
+	if s == "" {
+		s = fmt.Sprint(e.Errno())
+	}
+	return s
+}
+
+func (e Errno) MarshalText() ([]byte, error) {
+	s := e.ErrnoName()
+	return []byte(s), nil
+}
+
+func (h *Header) RespondError(err error) {
+	errno := DefaultErrno
+	if ferr, ok := err.(ErrorNumber); ok {
+		errno = ferr.Errno()
+	}
+	// FUSE uses negative errors!
+	// TODO: File bug report against OSXFUSE: positive error causes kernel panic.
+	buf := newBuffer(0)
+	hOut := (*outHeader)(unsafe.Pointer(&buf[0]))
+	hOut.Error = -int32(errno)
+	h.respond(buf)
+}
+
+// All requests read from the kernel, without data, are shorter than
+// this.
+var maxRequestSize = syscall.Getpagesize()
+var bufSize = maxRequestSize + maxWrite
+
+// reqPool is a pool of messages.
+//
+// Lifetime of a logical message is from getMessage to putMessage.
+// getMessage is called by ReadRequest. putMessage is called by
+// Conn.ReadRequest, Request.Respond, or Request.RespondError.
+//
+// Messages in the pool are guaranteed to have conn and off zeroed,
+// buf allocated and len==bufSize, and hdr set.
+var reqPool = sync.Pool{
+	New: allocMessage,
+}
+
+func allocMessage() interface{} {
+	m := &message{buf: make([]byte, bufSize)}
+	m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
+	return m
+}
+
+func getMessage(c *Conn) *message {
+	m := reqPool.Get().(*message)
+	m.conn = c
+	return m
+}
+
+func putMessage(m *message) {
+	m.buf = m.buf[:bufSize]
+	m.conn = nil
+	m.off = 0
+	reqPool.Put(m)
+}
+
+// a message represents the bytes of a single FUSE message
+type message struct {
+	conn *Conn
+	buf  []byte    // all bytes
+	hdr  *inHeader // header
+	off  int       // offset for reading additional fields
+}
+
+func (m *message) len() uintptr {
+	return uintptr(len(m.buf) - m.off)
+}
+
+func (m *message) data() unsafe.Pointer {
+	var p unsafe.Pointer
+	if m.off < len(m.buf) {
+		p = unsafe.Pointer(&m.buf[m.off])
+	}
+	return p
+}
+
+func (m *message) bytes() []byte {
+	return m.buf[m.off:]
+}
+
+func (m *message) Header() Header {
+	h := m.hdr
+	return Header{
+		Conn: m.conn,
+		ID:   RequestID(h.Unique),
+		Node: NodeID(h.Nodeid),
+		Uid:  h.Uid,
+		Gid:  h.Gid,
+		Pid:  h.Pid,
+
+		msg: m,
+	}
+}
+
+// fileMode returns a Go os.FileMode from a Unix mode.
+func fileMode(unixMode uint32) os.FileMode {
+	mode := os.FileMode(unixMode & 0777)
+	switch unixMode & syscall.S_IFMT {
+	case syscall.S_IFREG:
+		// nothing
+	case syscall.S_IFDIR:
+		mode |= os.ModeDir
+	case syscall.S_IFCHR:
+		mode |= os.ModeCharDevice | os.ModeDevice
+	case syscall.S_IFBLK:
+		mode |= os.ModeDevice
+	case syscall.S_IFIFO:
+		mode |= os.ModeNamedPipe
+	case syscall.S_IFLNK:
+		mode |= os.ModeSymlink
+	case syscall.S_IFSOCK:
+		mode |= os.ModeSocket
+	default:
+		// no idea
+		mode |= os.ModeDevice
+	}
+	if unixMode&syscall.S_ISUID != 0 {
+		mode |= os.ModeSetuid
+	}
+	if unixMode&syscall.S_ISGID != 0 {
+		mode |= os.ModeSetgid
+	}
+	return mode
+}
+
+type noOpcode struct {
+	Opcode uint32
+}
+
+func (m noOpcode) String() string {
+	return fmt.Sprintf("No opcode %v", m.Opcode)
+}
+
+type malformedMessage struct {
+}
+
+func (malformedMessage) String() string {
+	return "malformed message"
+}
+
+// Close closes the FUSE connection.
+func (c *Conn) Close() error {
+	c.wio.Lock()
+	defer c.wio.Unlock()
+	c.rio.Lock()
+	defer c.rio.Unlock()
+	return c.dev.Close()
+}
+
+// caller must hold wio or rio
+func (c *Conn) fd() int {
+	return int(c.dev.Fd())
+}
+
+func (c *Conn) Protocol() Protocol {
+	return c.proto
+}
+
+// ReadRequest returns the next FUSE request from the kernel.
+//
+// Caller must call either Request.Respond or Request.RespondError in
+// a reasonable time. Caller must not retain Request after that call.
+func (c *Conn) ReadRequest() (Request, error) {
+	m := getMessage(c)
+loop:
+	c.rio.RLock()
+	n, err := syscall.Read(c.fd(), m.buf)
+	c.rio.RUnlock()
+	if err == syscall.EINTR {
+		// OSXFUSE sends EINTR to userspace when a request interrupt
+		// completed before it got sent to userspace?
+		goto loop
+	}
+	if err != nil && err != syscall.ENODEV {
+		putMessage(m)
+		return nil, err
+	}
+	if n <= 0 {
+		putMessage(m)
+		return nil, io.EOF
+	}
+	m.buf = m.buf[:n]
+
+	if n < inHeaderSize {
+		putMessage(m)
+		return nil, errors.New("fuse: message too short")
+	}
+
+	// FreeBSD FUSE sends a short length in the header
+	// for FUSE_INIT even though the actual read length is correct.
+	if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
+		m.hdr.Len = uint32(n)
+	}
+
+	// OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
+	if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
+		m.hdr.Len = uint32(n)
+	}
+
+	if m.hdr.Len != uint32(n) {
+		// prepare error message before returning m to pool
+		err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+		putMessage(m)
+		return nil, err
+	}
+
+	m.off = inHeaderSize
+
+	// Convert to data structures.
+	// Do not trust kernel to hand us well-formed data.
+	var req Request
+	switch m.hdr.Opcode {
+	default:
+		Debug(noOpcode{Opcode: m.hdr.Opcode})
+		goto unrecognized
+
+	case opLookup:
+		buf := m.bytes()
+		n := len(buf)
+		if n == 0 || buf[n-1] != '\x00' {
+			goto corrupt
+		}
+		req = &LookupRequest{
+			Header: m.Header(),
+			Name:   string(buf[:n-1]),
+		}
+
+	case opForget:
+		in := (*forgetIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &ForgetRequest{
+			Header: m.Header(),
+			N:      in.Nlookup,
+		}
+
+	case opGetattr:
+		switch {
+		case c.proto.LT(Protocol{7, 9}):
+			req = &GetattrRequest{
+				Header: m.Header(),
+			}
+
+		default:
+			in := (*getattrIn)(m.data())
+			if m.len() < unsafe.Sizeof(*in) {
+				goto corrupt
+			}
+			req = &GetattrRequest{
+				Header: m.Header(),
+				Flags:  GetattrFlags(in.GetattrFlags),
+				Handle: HandleID(in.Fh),
+			}
+		}
+
+	case opSetattr:
+		in := (*setattrIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &SetattrRequest{
+			Header:   m.Header(),
+			Valid:    SetattrValid(in.Valid),
+			Handle:   HandleID(in.Fh),
+			Size:     in.Size,
+			Atime:    time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
+			Mtime:    time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
+			Mode:     fileMode(in.Mode),
+			Uid:      in.Uid,
+			Gid:      in.Gid,
+			Bkuptime: in.BkupTime(),
+			Chgtime:  in.Chgtime(),
+			Flags:    in.Flags(),
+		}
+
+	case opReadlink:
+		if len(m.bytes()) > 0 {
+			goto corrupt
+		}
+		req = &ReadlinkRequest{
+			Header: m.Header(),
+		}
+
+	case opSymlink:
+		// m.bytes() is "newName\0target\0"
+		names := m.bytes()
+		if len(names) == 0 || names[len(names)-1] != 0 {
+			goto corrupt
+		}
+		i := bytes.IndexByte(names, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		newName, target := names[0:i], names[i+1:len(names)-1]
+		req = &SymlinkRequest{
+			Header:  m.Header(),
+			NewName: string(newName),
+			Target:  string(target),
+		}
+
+	case opLink:
+		in := (*linkIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		newName := m.bytes()[unsafe.Sizeof(*in):]
+		if len(newName) < 2 || newName[len(newName)-1] != 0 {
+			goto corrupt
+		}
+		newName = newName[:len(newName)-1]
+		req = &LinkRequest{
+			Header:  m.Header(),
+			OldNode: NodeID(in.Oldnodeid),
+			NewName: string(newName),
+		}
+
+	case opMknod:
+		size := mknodInSize(c.proto)
+		if m.len() < size {
+			goto corrupt
+		}
+		in := (*mknodIn)(m.data())
+		name := m.bytes()[size:]
+		if len(name) < 2 || name[len(name)-1] != '\x00' {
+			goto corrupt
+		}
+		name = name[:len(name)-1]
+		r := &MknodRequest{
+			Header: m.Header(),
+			Mode:   fileMode(in.Mode),
+			Rdev:   in.Rdev,
+			Name:   string(name),
+		}
+		if c.proto.GE(Protocol{7, 12}) {
+			r.Umask = fileMode(in.Umask) & os.ModePerm
+		}
+		req = r
+
+	case opMkdir:
+		size := mkdirInSize(c.proto)
+		if m.len() < size {
+			goto corrupt
+		}
+		in := (*mkdirIn)(m.data())
+		name := m.bytes()[size:]
+		i := bytes.IndexByte(name, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		r := &MkdirRequest{
+			Header: m.Header(),
+			Name:   string(name[:i]),
+			// observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0,
+			// and this causes fileMode to go into it's "no idea"
+			// code branch; enforce type to directory
+			Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR),
+		}
+		if c.proto.GE(Protocol{7, 12}) {
+			r.Umask = fileMode(in.Umask) & os.ModePerm
+		}
+		req = r
+
+	case opUnlink, opRmdir:
+		buf := m.bytes()
+		n := len(buf)
+		if n == 0 || buf[n-1] != '\x00' {
+			goto corrupt
+		}
+		req = &RemoveRequest{
+			Header: m.Header(),
+			Name:   string(buf[:n-1]),
+			Dir:    m.hdr.Opcode == opRmdir,
+		}
+
+	case opRename:
+		in := (*renameIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		newDirNodeID := NodeID(in.Newdir)
+		oldNew := m.bytes()[unsafe.Sizeof(*in):]
+		// oldNew should be "old\x00new\x00"
+		if len(oldNew) < 4 {
+			goto corrupt
+		}
+		if oldNew[len(oldNew)-1] != '\x00' {
+			goto corrupt
+		}
+		i := bytes.IndexByte(oldNew, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+		req = &RenameRequest{
+			Header:  m.Header(),
+			NewDir:  newDirNodeID,
+			OldName: oldName,
+			NewName: newName,
+		}
+
+	case opOpendir, opOpen:
+		in := (*openIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &OpenRequest{
+			Header: m.Header(),
+			Dir:    m.hdr.Opcode == opOpendir,
+			Flags:  openFlags(in.Flags),
+		}
+
+	case opRead, opReaddir:
+		in := (*readIn)(m.data())
+		if m.len() < readInSize(c.proto) {
+			goto corrupt
+		}
+		r := &ReadRequest{
+			Header: m.Header(),
+			Dir:    m.hdr.Opcode == opReaddir,
+			Handle: HandleID(in.Fh),
+			Offset: int64(in.Offset),
+			Size:   int(in.Size),
+		}
+		if c.proto.GE(Protocol{7, 9}) {
+			r.Flags = ReadFlags(in.ReadFlags)
+			r.LockOwner = in.LockOwner
+			r.FileFlags = openFlags(in.Flags)
+		}
+		req = r
+
+	case opWrite:
+		in := (*writeIn)(m.data())
+		if m.len() < writeInSize(c.proto) {
+			goto corrupt
+		}
+		r := &WriteRequest{
+			Header: m.Header(),
+			Handle: HandleID(in.Fh),
+			Offset: int64(in.Offset),
+			Flags:  WriteFlags(in.WriteFlags),
+		}
+		if c.proto.GE(Protocol{7, 9}) {
+			r.LockOwner = in.LockOwner
+			r.FileFlags = openFlags(in.Flags)
+		}
+		buf := m.bytes()[writeInSize(c.proto):]
+		if uint32(len(buf)) < in.Size {
+			goto corrupt
+		}
+		r.Data = buf
+		req = r
+
+	case opStatfs:
+		req = &StatfsRequest{
+			Header: m.Header(),
+		}
+
+	case opRelease, opReleasedir:
+		in := (*releaseIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &ReleaseRequest{
+			Header:       m.Header(),
+			Dir:          m.hdr.Opcode == opReleasedir,
+			Handle:       HandleID(in.Fh),
+			Flags:        openFlags(in.Flags),
+			ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
+			LockOwner:    in.LockOwner,
+		}
+
+	case opFsync, opFsyncdir:
+		in := (*fsyncIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &FsyncRequest{
+			Dir:    m.hdr.Opcode == opFsyncdir,
+			Header: m.Header(),
+			Handle: HandleID(in.Fh),
+			Flags:  in.FsyncFlags,
+		}
+
+	case opSetxattr:
+		in := (*setxattrIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		m.off += int(unsafe.Sizeof(*in))
+		name := m.bytes()
+		i := bytes.IndexByte(name, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		xattr := name[i+1:]
+		if uint32(len(xattr)) < in.Size {
+			goto corrupt
+		}
+		xattr = xattr[:in.Size]
+		req = &SetxattrRequest{
+			Header:   m.Header(),
+			Flags:    in.Flags,
+			Position: in.position(),
+			Name:     string(name[:i]),
+			Xattr:    xattr,
+		}
+
+	case opGetxattr:
+		in := (*getxattrIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		name := m.bytes()[unsafe.Sizeof(*in):]
+		i := bytes.IndexByte(name, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		req = &GetxattrRequest{
+			Header:   m.Header(),
+			Name:     string(name[:i]),
+			Size:     in.Size,
+			Position: in.position(),
+		}
+
+	case opListxattr:
+		in := (*getxattrIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &ListxattrRequest{
+			Header:   m.Header(),
+			Size:     in.Size,
+			Position: in.position(),
+		}
+
+	case opRemovexattr:
+		buf := m.bytes()
+		n := len(buf)
+		if n == 0 || buf[n-1] != '\x00' {
+			goto corrupt
+		}
+		req = &RemovexattrRequest{
+			Header: m.Header(),
+			Name:   string(buf[:n-1]),
+		}
+
+	case opFlush:
+		in := (*flushIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &FlushRequest{
+			Header:    m.Header(),
+			Handle:    HandleID(in.Fh),
+			Flags:     in.FlushFlags,
+			LockOwner: in.LockOwner,
+		}
+
+	case opInit:
+		in := (*initIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &InitRequest{
+			Header:       m.Header(),
+			Kernel:       Protocol{in.Major, in.Minor},
+			MaxReadahead: in.MaxReadahead,
+			Flags:        InitFlags(in.Flags),
+		}
+
+	case opGetlk:
+		panic("opGetlk")
+	case opSetlk:
+		panic("opSetlk")
+	case opSetlkw:
+		panic("opSetlkw")
+
+	case opAccess:
+		in := (*accessIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &AccessRequest{
+			Header: m.Header(),
+			Mask:   in.Mask,
+		}
+
+	case opCreate:
+		size := createInSize(c.proto)
+		if m.len() < size {
+			goto corrupt
+		}
+		in := (*createIn)(m.data())
+		name := m.bytes()[size:]
+		i := bytes.IndexByte(name, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		r := &CreateRequest{
+			Header: m.Header(),
+			Flags:  openFlags(in.Flags),
+			Mode:   fileMode(in.Mode),
+			Name:   string(name[:i]),
+		}
+		if c.proto.GE(Protocol{7, 12}) {
+			r.Umask = fileMode(in.Umask) & os.ModePerm
+		}
+		req = r
+
+	case opInterrupt:
+		in := (*interruptIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		req = &InterruptRequest{
+			Header: m.Header(),
+			IntrID: RequestID(in.Unique),
+		}
+
+	case opBmap:
+		panic("opBmap")
+
+	case opDestroy:
+		req = &DestroyRequest{
+			Header: m.Header(),
+		}
+
+	// OS X
+	case opSetvolname:
+		panic("opSetvolname")
+	case opGetxtimes:
+		panic("opGetxtimes")
+	case opExchange:
+		in := (*exchangeIn)(m.data())
+		if m.len() < unsafe.Sizeof(*in) {
+			goto corrupt
+		}
+		oldDirNodeID := NodeID(in.Olddir)
+		newDirNodeID := NodeID(in.Newdir)
+		oldNew := m.bytes()[unsafe.Sizeof(*in):]
+		// oldNew should be "oldname\x00newname\x00"
+		if len(oldNew) < 4 {
+			goto corrupt
+		}
+		if oldNew[len(oldNew)-1] != '\x00' {
+			goto corrupt
+		}
+		i := bytes.IndexByte(oldNew, '\x00')
+		if i < 0 {
+			goto corrupt
+		}
+		oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+		req = &ExchangeDataRequest{
+			Header:  m.Header(),
+			OldDir:  oldDirNodeID,
+			NewDir:  newDirNodeID,
+			OldName: oldName,
+			NewName: newName,
+			// TODO options
+		}
+	}
+
+	return req, nil
+
+corrupt:
+	Debug(malformedMessage{})
+	putMessage(m)
+	return nil, fmt.Errorf("fuse: malformed message")
+
+unrecognized:
+	// Unrecognized message.
+	// Assume higher-level code will send a "no idea what you mean" error.
+	h := m.Header()
+	return &h, nil
+}
+
+type bugShortKernelWrite struct {
+	Written int64
+	Length  int64
+	Error   string
+	Stack   string
+}
+
+func (b bugShortKernelWrite) String() string {
+	return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack)
+}
+
+type bugKernelWriteError struct {
+	Error string
+	Stack string
+}
+
+func (b bugKernelWriteError) String() string {
+	return fmt.Sprintf("kernel write error: error=%q stack=\n%s", b.Error, b.Stack)
+}
+
+// safe to call even with nil error
+func errorString(err error) string {
+	if err == nil {
+		return ""
+	}
+	return err.Error()
+}
+
+func (c *Conn) writeToKernel(msg []byte) error {
+	out := (*outHeader)(unsafe.Pointer(&msg[0]))
+	out.Len = uint32(len(msg))
+
+	c.wio.RLock()
+	defer c.wio.RUnlock()
+	nn, err := syscall.Write(c.fd(), msg)
+	if err == nil && nn != len(msg) {
+		Debug(bugShortKernelWrite{
+			Written: int64(nn),
+			Length:  int64(len(msg)),
+			Error:   errorString(err),
+			Stack:   stack(),
+		})
+	}
+	return err
+}
+
+func (c *Conn) respond(msg []byte) {
+	if err := c.writeToKernel(msg); err != nil {
+		Debug(bugKernelWriteError{
+			Error: errorString(err),
+			Stack: stack(),
+		})
+	}
+}
+
+type notCachedError struct{}
+
+func (notCachedError) Error() string {
+	return "node not cached"
+}
+
+var _ ErrorNumber = notCachedError{}
+
+func (notCachedError) Errno() Errno {
+	// Behave just like if the original syscall.ENOENT had been passed
+	// straight through.
+	return ENOENT
+}
+
+var (
+	ErrNotCached = notCachedError{}
+)
+
+// sendInvalidate sends an invalidate notification to kernel.
+//
+// A returned ENOENT is translated to a friendlier error.
+func (c *Conn) sendInvalidate(msg []byte) error {
+	switch err := c.writeToKernel(msg); err {
+	case syscall.ENOENT:
+		return ErrNotCached
+	default:
+		return err
+	}
+}
+
+// InvalidateNode invalidates the kernel cache of the attributes and a
+// range of the data of a node.
+//
+// Giving offset 0 and size -1 means all data. To invalidate just the
+// attributes, give offset 0 and size 0.
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateNode(nodeID NodeID, off int64, size int64) error {
+	buf := newBuffer(unsafe.Sizeof(notifyInvalInodeOut{}))
+	h := (*outHeader)(unsafe.Pointer(&buf[0]))
+	// h.Unique is 0
+	h.Error = notifyCodeInvalInode
+	out := (*notifyInvalInodeOut)(buf.alloc(unsafe.Sizeof(notifyInvalInodeOut{})))
+	out.Ino = uint64(nodeID)
+	out.Off = off
+	out.Len = size
+	return c.sendInvalidate(buf)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent directory node ID and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateEntry(parent NodeID, name string) error {
+	const maxUint32 = ^uint32(0)
+	if uint64(len(name)) > uint64(maxUint32) {
+		// very unlikely, but we don't want to silently truncate
+		return syscall.ENAMETOOLONG
+	}
+	buf := newBuffer(unsafe.Sizeof(notifyInvalEntryOut{}) + uintptr(len(name)) + 1)
+	h := (*outHeader)(unsafe.Pointer(&buf[0]))
+	// h.Unique is 0
+	h.Error = notifyCodeInvalEntry
+	out := (*notifyInvalEntryOut)(buf.alloc(unsafe.Sizeof(notifyInvalEntryOut{})))
+	out.Parent = uint64(parent)
+	out.Namelen = uint32(len(name))
+	buf = append(buf, name...)
+	buf = append(buf, '\x00')
+	return c.sendInvalidate(buf)
+}
+
+// An InitRequest is the first request sent on a FUSE file system.
+type InitRequest struct {
+	Header `json:"-"`
+	Kernel Protocol
+	// Maximum readahead in bytes that the kernel plans to use.
+	MaxReadahead uint32
+	Flags        InitFlags
+}
+
+var _ = Request(&InitRequest{})
+
+func (r *InitRequest) String() string {
+	return fmt.Sprintf("Init [%v] %v ra=%d fl=%v", &r.Header, r.Kernel, r.MaxReadahead, r.Flags)
+}
+
+// An InitResponse is the response to an InitRequest.
+type InitResponse struct {
+	Library Protocol
+	// Maximum readahead in bytes that the kernel can use. Ignored if
+	// greater than InitRequest.MaxReadahead.
+	MaxReadahead uint32
+	Flags        InitFlags
+	// Maximum size of a single write operation.
+	// Linux enforces a minimum of 4 KiB.
+	MaxWrite uint32
+}
+
+func (r *InitResponse) String() string {
+	return fmt.Sprintf("Init %v ra=%d fl=%v w=%d", r.Library, r.MaxReadahead, r.Flags, r.MaxWrite)
+}
+
+// Respond replies to the request with the given response.
+func (r *InitRequest) Respond(resp *InitResponse) {
+	buf := newBuffer(unsafe.Sizeof(initOut{}))
+	out := (*initOut)(buf.alloc(unsafe.Sizeof(initOut{})))
+	out.Major = resp.Library.Major
+	out.Minor = resp.Library.Minor
+	out.MaxReadahead = resp.MaxReadahead
+	out.Flags = uint32(resp.Flags)
+	out.MaxWrite = resp.MaxWrite
+
+	// MaxWrite larger than our receive buffer would just lead to
+	// errors on large writes.
+	if out.MaxWrite > maxWrite {
+		out.MaxWrite = maxWrite
+	}
+	r.respond(buf)
+}
+
+// A StatfsRequest requests information about the mounted file system.
+type StatfsRequest struct {
+	Header `json:"-"`
+}
+
+var _ = Request(&StatfsRequest{})
+
+func (r *StatfsRequest) String() string {
+	return fmt.Sprintf("Statfs [%s]", &r.Header)
+}
+
+// Respond replies to the request with the given response.
+func (r *StatfsRequest) Respond(resp *StatfsResponse) {
+	buf := newBuffer(unsafe.Sizeof(statfsOut{}))
+	out := (*statfsOut)(buf.alloc(unsafe.Sizeof(statfsOut{})))
+	out.St = kstatfs{
+		Blocks:  resp.Blocks,
+		Bfree:   resp.Bfree,
+		Bavail:  resp.Bavail,
+		Files:   resp.Files,
+		Bsize:   resp.Bsize,
+		Namelen: resp.Namelen,
+		Frsize:  resp.Frsize,
+	}
+	r.respond(buf)
+}
+
+// A StatfsResponse is the response to a StatfsRequest.
+type StatfsResponse struct {
+	Blocks  uint64 // Total data blocks in file system.
+	Bfree   uint64 // Free blocks in file system.
+	Bavail  uint64 // Free blocks in file system if you're not root.
+	Files   uint64 // Total files in file system.
+	Ffree   uint64 // Free files in file system.
+	Bsize   uint32 // Block size
+	Namelen uint32 // Maximum file name length?
+	Frsize  uint32 // Fragment size, smallest addressable data size in the file system.
+}
+
+func (r *StatfsResponse) String() string {
+	return fmt.Sprintf("Statfs blocks=%d/%d/%d files=%d/%d bsize=%d frsize=%d namelen=%d",
+		r.Bavail, r.Bfree, r.Blocks,
+		r.Ffree, r.Files,
+		r.Bsize,
+		r.Frsize,
+		r.Namelen,
+	)
+}
+
+// An AccessRequest asks whether the file can be accessed
+// for the purpose specified by the mask.
+type AccessRequest struct {
+	Header `json:"-"`
+	Mask   uint32
+}
+
+var _ = Request(&AccessRequest{})
+
+func (r *AccessRequest) String() string {
+	return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
+}
+
+// Respond replies to the request indicating that access is allowed.
+// To deny access, use RespondError.
+func (r *AccessRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// An Attr is the metadata for a single file or directory.
+type Attr struct {
+	Valid time.Duration // how long Attr can be cached
+
+	Inode     uint64      // inode number
+	Size      uint64      // size in bytes
+	Blocks    uint64      // size in 512-byte units
+	Atime     time.Time   // time of last access
+	Mtime     time.Time   // time of last modification
+	Ctime     time.Time   // time of last inode change
+	Crtime    time.Time   // time of creation (OS X only)
+	Mode      os.FileMode // file mode
+	Nlink     uint32      // number of links (usually 1)
+	Uid       uint32      // owner uid
+	Gid       uint32      // group gid
+	Rdev      uint32      // device numbers
+	Flags     uint32      // chflags(2) flags (OS X only)
+	BlockSize uint32      // preferred blocksize for filesystem I/O
+}
+
+func (a Attr) String() string {
+	return fmt.Sprintf("valid=%v ino=%v size=%d mode=%v", a.Valid, a.Inode, a.Size, a.Mode)
+}
+
+func unix(t time.Time) (sec uint64, nsec uint32) {
+	nano := t.UnixNano()
+	sec = uint64(nano / 1e9)
+	nsec = uint32(nano % 1e9)
+	return
+}
+
+func (a *Attr) attr(out *attr, proto Protocol) {
+	out.Ino = a.Inode
+	out.Size = a.Size
+	out.Blocks = a.Blocks
+	out.Atime, out.AtimeNsec = unix(a.Atime)
+	out.Mtime, out.MtimeNsec = unix(a.Mtime)
+	out.Ctime, out.CtimeNsec = unix(a.Ctime)
+	out.SetCrtime(unix(a.Crtime))
+	out.Mode = uint32(a.Mode) & 0777
+	switch {
+	default:
+		out.Mode |= syscall.S_IFREG
+	case a.Mode&os.ModeDir != 0:
+		out.Mode |= syscall.S_IFDIR
+	case a.Mode&os.ModeDevice != 0:
+		if a.Mode&os.ModeCharDevice != 0 {
+			out.Mode |= syscall.S_IFCHR
+		} else {
+			out.Mode |= syscall.S_IFBLK
+		}
+	case a.Mode&os.ModeNamedPipe != 0:
+		out.Mode |= syscall.S_IFIFO
+	case a.Mode&os.ModeSymlink != 0:
+		out.Mode |= syscall.S_IFLNK
+	case a.Mode&os.ModeSocket != 0:
+		out.Mode |= syscall.S_IFSOCK
+	}
+	if a.Mode&os.ModeSetuid != 0 {
+		out.Mode |= syscall.S_ISUID
+	}
+	if a.Mode&os.ModeSetgid != 0 {
+		out.Mode |= syscall.S_ISGID
+	}
+	out.Nlink = a.Nlink
+	out.Uid = a.Uid
+	out.Gid = a.Gid
+	out.Rdev = a.Rdev
+	out.SetFlags(a.Flags)
+	if proto.GE(Protocol{7, 9}) {
+		out.Blksize = a.BlockSize
+	}
+
+	return
+}
+
+// A GetattrRequest asks for the metadata for the file denoted by r.Node.
+type GetattrRequest struct {
+	Header `json:"-"`
+	Flags  GetattrFlags
+	Handle HandleID
+}
+
+var _ = Request(&GetattrRequest{})
+
+func (r *GetattrRequest) String() string {
+	return fmt.Sprintf("Getattr [%s] %v fl=%v", &r.Header, r.Handle, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetattrRequest) Respond(resp *GetattrResponse) {
+	size := attrOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*attrOut)(buf.alloc(size))
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A GetattrResponse is the response to a GetattrRequest.
+type GetattrResponse struct {
+	Attr Attr // file attributes
+}
+
+func (r *GetattrResponse) String() string {
+	return fmt.Sprintf("Getattr %v", r.Attr)
+}
+
+// A GetxattrRequest asks for the extended attributes associated with r.Node.
+type GetxattrRequest struct {
+	Header `json:"-"`
+
+	// Maximum size to return.
+	Size uint32
+
+	// Name of the attribute requested.
+	Name string
+
+	// Offset within extended attributes.
+	//
+	// Only valid for OS X, and then only with the resource fork
+	// attribute.
+	Position uint32
+}
+
+var _ = Request(&GetxattrRequest{})
+
+func (r *GetxattrRequest) String() string {
+	return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
+	if r.Size == 0 {
+		buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+		out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+		out.Size = uint32(len(resp.Xattr))
+		r.respond(buf)
+	} else {
+		buf := newBuffer(uintptr(len(resp.Xattr)))
+		buf = append(buf, resp.Xattr...)
+		r.respond(buf)
+	}
+}
+
+// A GetxattrResponse is the response to a GetxattrRequest.
+type GetxattrResponse struct {
+	Xattr []byte
+}
+
+func (r *GetxattrResponse) String() string {
+	return fmt.Sprintf("Getxattr %x", r.Xattr)
+}
+
+// A ListxattrRequest asks to list the extended attributes associated with r.Node.
+type ListxattrRequest struct {
+	Header   `json:"-"`
+	Size     uint32 // maximum size to return
+	Position uint32 // offset within attribute list
+}
+
+var _ = Request(&ListxattrRequest{})
+
+func (r *ListxattrRequest) String() string {
+	return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
+	if r.Size == 0 {
+		buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+		out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+		out.Size = uint32(len(resp.Xattr))
+		r.respond(buf)
+	} else {
+		buf := newBuffer(uintptr(len(resp.Xattr)))
+		buf = append(buf, resp.Xattr...)
+		r.respond(buf)
+	}
+}
+
+// A ListxattrResponse is the response to a ListxattrRequest.
+type ListxattrResponse struct {
+	Xattr []byte
+}
+
+func (r *ListxattrResponse) String() string {
+	return fmt.Sprintf("Listxattr %x", r.Xattr)
+}
+
+// Append adds an extended attribute name to the response.
+func (r *ListxattrResponse) Append(names ...string) {
+	for _, name := range names {
+		r.Xattr = append(r.Xattr, name...)
+		r.Xattr = append(r.Xattr, '\x00')
+	}
+}
+
+// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
+type RemovexattrRequest struct {
+	Header `json:"-"`
+	Name   string // name of extended attribute
+}
+
+var _ = Request(&RemovexattrRequest{})
+
+func (r *RemovexattrRequest) String() string {
+	return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request, indicating that the attribute was removed.
+func (r *RemovexattrRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A SetxattrRequest asks to set an extended attribute associated with a file.
+type SetxattrRequest struct {
+	Header `json:"-"`
+
+	// Flags can make the request fail if attribute does/not already
+	// exist. Unfortunately, the constants are platform-specific and
+	// not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE.
+	//
+	// TODO improve this later
+	//
+	// TODO XATTR_CREATE and exist -> EEXIST
+	//
+	// TODO XATTR_REPLACE and not exist -> ENODATA
+	Flags uint32
+
+	// Offset within extended attributes.
+	//
+	// Only valid for OS X, and then only with the resource fork
+	// attribute.
+	Position uint32
+
+	Name  string
+	Xattr []byte
+}
+
+var _ = Request(&SetxattrRequest{})
+
+func trunc(b []byte, max int) ([]byte, string) {
+	if len(b) > max {
+		return b[:max], "..."
+	}
+	return b, ""
+}
+
+func (r *SetxattrRequest) String() string {
+	xattr, tail := trunc(r.Xattr, 16)
+	return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position)
+}
+
+// Respond replies to the request, indicating that the extended attribute was set.
+func (r *SetxattrRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A LookupRequest asks to look up the given name in the directory named by r.Node.
+type LookupRequest struct {
+	Header `json:"-"`
+	Name   string
+}
+
+var _ = Request(&LookupRequest{})
+
+func (r *LookupRequest) String() string {
+	return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request with the given response.
+func (r *LookupRequest) Respond(resp *LookupResponse) {
+	size := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*entryOut)(buf.alloc(size))
+	out.Nodeid = uint64(resp.Node)
+	out.Generation = resp.Generation
+	out.EntryValid = uint64(resp.EntryValid / time.Second)
+	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A LookupResponse is the response to a LookupRequest.
+type LookupResponse struct {
+	Node       NodeID
+	Generation uint64
+	EntryValid time.Duration
+	Attr       Attr
+}
+
+func (r *LookupResponse) string() string {
+	return fmt.Sprintf("%v gen=%d valid=%v attr={%v}", r.Node, r.Generation, r.EntryValid, r.Attr)
+}
+
+func (r *LookupResponse) String() string {
+	return fmt.Sprintf("Lookup %s", r.string())
+}
+
+// An OpenRequest asks to open a file or directory
+type OpenRequest struct {
+	Header `json:"-"`
+	Dir    bool // is this Opendir?
+	Flags  OpenFlags
+}
+
+var _ = Request(&OpenRequest{})
+
+func (r *OpenRequest) String() string {
+	return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *OpenRequest) Respond(resp *OpenResponse) {
+	buf := newBuffer(unsafe.Sizeof(openOut{}))
+	out := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+	out.Fh = uint64(resp.Handle)
+	out.OpenFlags = uint32(resp.Flags)
+	r.respond(buf)
+}
+
+// A OpenResponse is the response to a OpenRequest.
+type OpenResponse struct {
+	Handle HandleID
+	Flags  OpenResponseFlags
+}
+
+func (r *OpenResponse) string() string {
+	return fmt.Sprintf("%v fl=%v", r.Handle, r.Flags)
+}
+
+func (r *OpenResponse) String() string {
+	return fmt.Sprintf("Open %s", r.string())
+}
+
+// A CreateRequest asks to create and open a file (not a directory).
+type CreateRequest struct {
+	Header `json:"-"`
+	Name   string
+	Flags  OpenFlags
+	Mode   os.FileMode
+	// Umask of the request. Not supported on OS X.
+	Umask os.FileMode
+}
+
+var _ = Request(&CreateRequest{})
+
+func (r *CreateRequest) String() string {
+	return fmt.Sprintf("Create [%s] %q fl=%v mode=%v umask=%v", &r.Header, r.Name, r.Flags, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *CreateRequest) Respond(resp *CreateResponse) {
+	eSize := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(eSize + unsafe.Sizeof(openOut{}))
+
+	e := (*entryOut)(buf.alloc(eSize))
+	e.Nodeid = uint64(resp.Node)
+	e.Generation = resp.Generation
+	e.EntryValid = uint64(resp.EntryValid / time.Second)
+	e.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	e.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	e.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&e.Attr, r.Header.Conn.proto)
+
+	o := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+	o.Fh = uint64(resp.Handle)
+	o.OpenFlags = uint32(resp.Flags)
+
+	r.respond(buf)
+}
+
+// A CreateResponse is the response to a CreateRequest.
+// It describes the created node and opened handle.
+type CreateResponse struct {
+	LookupResponse
+	OpenResponse
+}
+
+func (r *CreateResponse) String() string {
+	return fmt.Sprintf("Create {%s} {%s}", r.LookupResponse.string(), r.OpenResponse.string())
+}
+
+// A MkdirRequest asks to create (but not open) a directory.
+type MkdirRequest struct {
+	Header `json:"-"`
+	Name   string
+	Mode   os.FileMode
+	// Umask of the request. Not supported on OS X.
+	Umask os.FileMode
+}
+
+var _ = Request(&MkdirRequest{})
+
+func (r *MkdirRequest) String() string {
+	return fmt.Sprintf("Mkdir [%s] %q mode=%v umask=%v", &r.Header, r.Name, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *MkdirRequest) Respond(resp *MkdirResponse) {
+	size := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*entryOut)(buf.alloc(size))
+	out.Nodeid = uint64(resp.Node)
+	out.Generation = resp.Generation
+	out.EntryValid = uint64(resp.EntryValid / time.Second)
+	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A MkdirResponse is the response to a MkdirRequest.
+type MkdirResponse struct {
+	LookupResponse
+}
+
+func (r *MkdirResponse) String() string {
+	return fmt.Sprintf("Mkdir %v", r.LookupResponse.string())
+}
+
+// A ReadRequest asks to read from an open file.
+type ReadRequest struct {
+	Header    `json:"-"`
+	Dir       bool // is this Readdir?
+	Handle    HandleID
+	Offset    int64
+	Size      int
+	Flags     ReadFlags
+	LockOwner uint64
+	FileFlags OpenFlags
+}
+
+var _ = Request(&ReadRequest{})
+
+func (r *ReadRequest) String() string {
+	return fmt.Sprintf("Read [%s] %v %d @%#x dir=%v fl=%v lock=%d ffl=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+// Respond replies to the request with the given response.
+func (r *ReadRequest) Respond(resp *ReadResponse) {
+	buf := newBuffer(uintptr(len(resp.Data)))
+	buf = append(buf, resp.Data...)
+	r.respond(buf)
+}
+
+// A ReadResponse is the response to a ReadRequest.
+type ReadResponse struct {
+	Data []byte
+}
+
+func (r *ReadResponse) String() string {
+	return fmt.Sprintf("Read %d", len(r.Data))
+}
+
+type jsonReadResponse struct {
+	Len uint64
+}
+
+func (r *ReadResponse) MarshalJSON() ([]byte, error) {
+	j := jsonReadResponse{
+		Len: uint64(len(r.Data)),
+	}
+	return json.Marshal(j)
+}
+
+// A ReleaseRequest asks to release (close) an open file handle.
+type ReleaseRequest struct {
+	Header       `json:"-"`
+	Dir          bool // is this Releasedir?
+	Handle       HandleID
+	Flags        OpenFlags // flags from OpenRequest
+	ReleaseFlags ReleaseFlags
+	LockOwner    uint32
+}
+
+var _ = Request(&ReleaseRequest{})
+
+func (r *ReleaseRequest) String() string {
+	return fmt.Sprintf("Release [%s] %v fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the handle has been released.
+func (r *ReleaseRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A DestroyRequest is sent by the kernel when unmounting the file system.
+// No more requests will be received after this one, but it should still be
+// responded to.
+type DestroyRequest struct {
+	Header `json:"-"`
+}
+
+var _ = Request(&DestroyRequest{})
+
+func (r *DestroyRequest) String() string {
+	return fmt.Sprintf("Destroy [%s]", &r.Header)
+}
+
+// Respond replies to the request.
+func (r *DestroyRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A ForgetRequest is sent by the kernel when forgetting about r.Node
+// as returned by r.N lookup requests.
+type ForgetRequest struct {
+	Header `json:"-"`
+	N      uint64
+}
+
+var _ = Request(&ForgetRequest{})
+
+func (r *ForgetRequest) String() string {
+	return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
+}
+
+// Respond replies to the request, indicating that the forgetfulness has been recorded.
+func (r *ForgetRequest) Respond() {
+	// Don't reply to forget messages.
+	r.noResponse()
+}
+
+// A Dirent represents a single directory entry.
+type Dirent struct {
+	// Inode this entry names.
+	Inode uint64
+
+	// Type of the entry, for example DT_File.
+	//
+	// Setting this is optional. The zero value (DT_Unknown) means
+	// callers will just need to do a Getattr when the type is
+	// needed. Providing a type can speed up operations
+	// significantly.
+	Type DirentType
+
+	// Name of the entry
+	Name string
+}
+
+// Type of an entry in a directory listing.
+type DirentType uint32
+
+const (
+	// These don't quite match os.FileMode; especially there's an
+	// explicit unknown, instead of zero value meaning file. They
+	// are also not quite syscall.DT_*; nothing says the FUSE
+	// protocol follows those, and even if they were, we don't
+	// want each fs to fiddle with syscall.
+
+	// The shift by 12 is hardcoded in the FUSE userspace
+	// low-level C library, so it's safe here.
+
+	DT_Unknown DirentType = 0
+	DT_Socket  DirentType = syscall.S_IFSOCK >> 12
+	DT_Link    DirentType = syscall.S_IFLNK >> 12
+	DT_File    DirentType = syscall.S_IFREG >> 12
+	DT_Block   DirentType = syscall.S_IFBLK >> 12
+	DT_Dir     DirentType = syscall.S_IFDIR >> 12
+	DT_Char    DirentType = syscall.S_IFCHR >> 12
+	DT_FIFO    DirentType = syscall.S_IFIFO >> 12
+)
+
+func (t DirentType) String() string {
+	switch t {
+	case DT_Unknown:
+		return "unknown"
+	case DT_Socket:
+		return "socket"
+	case DT_Link:
+		return "link"
+	case DT_File:
+		return "file"
+	case DT_Block:
+		return "block"
+	case DT_Dir:
+		return "dir"
+	case DT_Char:
+		return "char"
+	case DT_FIFO:
+		return "fifo"
+	}
+	return "invalid"
+}
+
+// AppendDirent appends the encoded form of a directory entry to data
+// and returns the resulting slice.
+func AppendDirent(data []byte, dir Dirent) []byte {
+	de := dirent{
+		Ino:     dir.Inode,
+		Namelen: uint32(len(dir.Name)),
+		Type:    uint32(dir.Type),
+	}
+	de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
+	data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
+	data = append(data, dir.Name...)
+	n := direntSize + uintptr(len(dir.Name))
+	if n%8 != 0 {
+		var pad [8]byte
+		data = append(data, pad[:8-n%8]...)
+	}
+	return data
+}
+
+// A WriteRequest asks to write to an open file.
+type WriteRequest struct {
+	Header
+	Handle    HandleID
+	Offset    int64
+	Data      []byte
+	Flags     WriteFlags
+	LockOwner uint64
+	FileFlags OpenFlags
+}
+
+var _ = Request(&WriteRequest{})
+
+func (r *WriteRequest) String() string {
+	return fmt.Sprintf("Write [%s] %v %d @%d fl=%v lock=%d ffl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+type jsonWriteRequest struct {
+	Handle HandleID
+	Offset int64
+	Len    uint64
+	Flags  WriteFlags
+}
+
+func (r *WriteRequest) MarshalJSON() ([]byte, error) {
+	j := jsonWriteRequest{
+		Handle: r.Handle,
+		Offset: r.Offset,
+		Len:    uint64(len(r.Data)),
+		Flags:  r.Flags,
+	}
+	return json.Marshal(j)
+}
+
+// Respond replies to the request with the given response.
+func (r *WriteRequest) Respond(resp *WriteResponse) {
+	buf := newBuffer(unsafe.Sizeof(writeOut{}))
+	out := (*writeOut)(buf.alloc(unsafe.Sizeof(writeOut{})))
+	out.Size = uint32(resp.Size)
+	r.respond(buf)
+}
+
+// A WriteResponse replies to a write indicating how many bytes were written.
+type WriteResponse struct {
+	Size int
+}
+
+func (r *WriteResponse) String() string {
+	return fmt.Sprintf("Write %d", r.Size)
+}
+
+// A SetattrRequest asks to change one or more attributes associated with a file,
+// as indicated by Valid.
+type SetattrRequest struct {
+	Header `json:"-"`
+	Valid  SetattrValid
+	Handle HandleID
+	Size   uint64
+	Atime  time.Time
+	Mtime  time.Time
+	Mode   os.FileMode
+	Uid    uint32
+	Gid    uint32
+
+	// OS X only
+	Bkuptime time.Time
+	Chgtime  time.Time
+	Crtime   time.Time
+	Flags    uint32 // see chflags(2)
+}
+
+var _ = Request(&SetattrRequest{})
+
+func (r *SetattrRequest) String() string {
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
+	if r.Valid.Mode() {
+		fmt.Fprintf(&buf, " mode=%v", r.Mode)
+	}
+	if r.Valid.Uid() {
+		fmt.Fprintf(&buf, " uid=%d", r.Uid)
+	}
+	if r.Valid.Gid() {
+		fmt.Fprintf(&buf, " gid=%d", r.Gid)
+	}
+	if r.Valid.Size() {
+		fmt.Fprintf(&buf, " size=%d", r.Size)
+	}
+	if r.Valid.Atime() {
+		fmt.Fprintf(&buf, " atime=%v", r.Atime)
+	}
+	if r.Valid.AtimeNow() {
+		fmt.Fprintf(&buf, " atime=now")
+	}
+	if r.Valid.Mtime() {
+		fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
+	}
+	if r.Valid.MtimeNow() {
+		fmt.Fprintf(&buf, " mtime=now")
+	}
+	if r.Valid.Handle() {
+		fmt.Fprintf(&buf, " handle=%v", r.Handle)
+	} else {
+		fmt.Fprintf(&buf, " handle=INVALID-%v", r.Handle)
+	}
+	if r.Valid.LockOwner() {
+		fmt.Fprintf(&buf, " lockowner")
+	}
+	if r.Valid.Crtime() {
+		fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
+	}
+	if r.Valid.Chgtime() {
+		fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
+	}
+	if r.Valid.Bkuptime() {
+		fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
+	}
+	if r.Valid.Flags() {
+		fmt.Fprintf(&buf, " flags=%v", r.Flags)
+	}
+	return buf.String()
+}
+
+// Respond replies to the request with the given response,
+// giving the updated attributes.
+func (r *SetattrRequest) Respond(resp *SetattrResponse) {
+	size := attrOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*attrOut)(buf.alloc(size))
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A SetattrResponse is the response to a SetattrRequest.
+type SetattrResponse struct {
+	Attr Attr // file attributes
+}
+
+func (r *SetattrResponse) String() string {
+	return fmt.Sprintf("Setattr %v", r.Attr)
+}
+
+// A FlushRequest asks for the current state of an open file to be flushed
+// to storage, as when a file descriptor is being closed.  A single opened Handle
+// may receive multiple FlushRequests over its lifetime.
+type FlushRequest struct {
+	Header    `json:"-"`
+	Handle    HandleID
+	Flags     uint32
+	LockOwner uint64
+}
+
+var _ = Request(&FlushRequest{})
+
+func (r *FlushRequest) String() string {
+	return fmt.Sprintf("Flush [%s] %v fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the flush succeeded.
+func (r *FlushRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A RemoveRequest asks to remove a file or directory from the
+// directory r.Node.
+type RemoveRequest struct {
+	Header `json:"-"`
+	Name   string // name of the entry to remove
+	Dir    bool   // is this rmdir?
+}
+
+var _ = Request(&RemoveRequest{})
+
+func (r *RemoveRequest) String() string {
+	return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
+}
+
+// Respond replies to the request, indicating that the file was removed.
+func (r *RemoveRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// A SymlinkRequest is a request to create a symlink making NewName point to Target.
+type SymlinkRequest struct {
+	Header          `json:"-"`
+	NewName, Target string
+}
+
+var _ = Request(&SymlinkRequest{})
+
+func (r *SymlinkRequest) String() string {
+	return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
+}
+
+// Respond replies to the request, indicating that the symlink was created.
+func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
+	size := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*entryOut)(buf.alloc(size))
+	out.Nodeid = uint64(resp.Node)
+	out.Generation = resp.Generation
+	out.EntryValid = uint64(resp.EntryValid / time.Second)
+	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A SymlinkResponse is the response to a SymlinkRequest.
+type SymlinkResponse struct {
+	LookupResponse
+}
+
+func (r *SymlinkResponse) String() string {
+	return fmt.Sprintf("Symlink %v", r.LookupResponse.string())
+}
+
+// A ReadlinkRequest is a request to read a symlink's target.
+type ReadlinkRequest struct {
+	Header `json:"-"`
+}
+
+var _ = Request(&ReadlinkRequest{})
+
+func (r *ReadlinkRequest) String() string {
+	return fmt.Sprintf("Readlink [%s]", &r.Header)
+}
+
+func (r *ReadlinkRequest) Respond(target string) {
+	buf := newBuffer(uintptr(len(target)))
+	buf = append(buf, target...)
+	r.respond(buf)
+}
+
+// A LinkRequest is a request to create a hard link.
+type LinkRequest struct {
+	Header  `json:"-"`
+	OldNode NodeID
+	NewName string
+}
+
+var _ = Request(&LinkRequest{})
+
+func (r *LinkRequest) String() string {
+	return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
+}
+
+func (r *LinkRequest) Respond(resp *LookupResponse) {
+	size := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*entryOut)(buf.alloc(size))
+	out.Nodeid = uint64(resp.Node)
+	out.Generation = resp.Generation
+	out.EntryValid = uint64(resp.EntryValid / time.Second)
+	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+// A RenameRequest is a request to rename a file.
+type RenameRequest struct {
+	Header           `json:"-"`
+	NewDir           NodeID
+	OldName, NewName string
+}
+
+var _ = Request(&RenameRequest{})
+
+func (r *RenameRequest) String() string {
+	return fmt.Sprintf("Rename [%s] from %q to dirnode %v %q", &r.Header, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *RenameRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+type MknodRequest struct {
+	Header `json:"-"`
+	Name   string
+	Mode   os.FileMode
+	Rdev   uint32
+	// Umask of the request. Not supported on OS X.
+	Umask os.FileMode
+}
+
+var _ = Request(&MknodRequest{})
+
+func (r *MknodRequest) String() string {
+	return fmt.Sprintf("Mknod [%s] Name %q mode=%v umask=%v rdev=%d", &r.Header, r.Name, r.Mode, r.Umask, r.Rdev)
+}
+
+func (r *MknodRequest) Respond(resp *LookupResponse) {
+	size := entryOutSize(r.Header.Conn.proto)
+	buf := newBuffer(size)
+	out := (*entryOut)(buf.alloc(size))
+	out.Nodeid = uint64(resp.Node)
+	out.Generation = resp.Generation
+	out.EntryValid = uint64(resp.EntryValid / time.Second)
+	out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+	out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+	out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+	resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+	r.respond(buf)
+}
+
+type FsyncRequest struct {
+	Header `json:"-"`
+	Handle HandleID
+	// TODO bit 1 is datasync, not well documented upstream
+	Flags uint32
+	Dir   bool
+}
+
+var _ = Request(&FsyncRequest{})
+
+func (r *FsyncRequest) String() string {
+	return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
+}
+
+func (r *FsyncRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
+
+// An InterruptRequest is a request to interrupt another pending request. The
+// response to that request should return an error status of EINTR.
+type InterruptRequest struct {
+	Header `json:"-"`
+	IntrID RequestID // ID of the request to be interrupt.
+}
+
+var _ = Request(&InterruptRequest{})
+
+func (r *InterruptRequest) Respond() {
+	// nothing to do here
+	r.noResponse()
+}
+
+func (r *InterruptRequest) String() string {
+	return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID)
+}
+
+// An ExchangeDataRequest is a request to exchange the contents of two
+// files, while leaving most metadata untouched.
+//
+// This request comes from OS X exchangedata(2) and represents its
+// specific semantics. Crucially, it is very different from Linux
+// renameat(2) RENAME_EXCHANGE.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
+type ExchangeDataRequest struct {
+	Header           `json:"-"`
+	OldDir, NewDir   NodeID
+	OldName, NewName string
+	// TODO options
+}
+
+var _ = Request(&ExchangeDataRequest{})
+
+func (r *ExchangeDataRequest) String() string {
+	// TODO options
+	return fmt.Sprintf("ExchangeData [%s] %v %q and %v %q", &r.Header, r.OldDir, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *ExchangeDataRequest) Respond() {
+	buf := newBuffer(0)
+	r.respond(buf)
+}
diff --git a/vendor/bazil.org/fuse/fuse.iml b/vendor/bazil.org/fuse/fuse.iml
new file mode 100644
index 0000000000000000000000000000000000000000..792ad4c30c83da1294baee046a80a37eb5c6bc82
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse.iml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="GO_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/vendor/bazil.org/fuse/fuse_darwin.go b/vendor/bazil.org/fuse/fuse_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..b58dca97d648cf28e2910fc23a877645682ca984
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_darwin.go
@@ -0,0 +1,9 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This value has to be >=16MB or OSXFUSE (3.4.0 observed) will
+// forcibly close the /dev/fuse file descriptor on a Setxattr with a
+// 16MB value. See TestSetxattr16MB and
+// https://github.com/bazil/fuse/issues/42
+const maxWrite = 16 * 1024 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_freebsd.go b/vendor/bazil.org/fuse/fuse_freebsd.go
new file mode 100644
index 0000000000000000000000000000000000000000..4aa83a0d4104987b1d8673b29e4f5020662b0157
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_freebsd.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This number is just a guess.
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_kernel.go b/vendor/bazil.org/fuse/fuse_kernel.go
new file mode 100644
index 0000000000000000000000000000000000000000..87c5ca1dc67549b156d66ab746553a7f94db5e0e
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel.go
@@ -0,0 +1,774 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Derived from FUSE's fuse_kernel.h, which carries this notice:
+/*
+   This file defines the kernel interface of FUSE
+   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+
+   This -- and only this -- header file may also be distributed under
+   the terms of the BSD Licence as follows:
+
+   Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+   SUCH DAMAGE.
+*/
+
+package fuse
+
+import (
+	"fmt"
+	"syscall"
+	"unsafe"
+)
+
+// The FUSE version implemented by the package.
+const (
+	protoVersionMinMajor = 7
+	protoVersionMinMinor = 8
+	protoVersionMaxMajor = 7
+	protoVersionMaxMinor = 12
+)
+
+const (
+	rootID = 1
+)
+
+type kstatfs struct {
+	Blocks  uint64
+	Bfree   uint64
+	Bavail  uint64
+	Files   uint64
+	Ffree   uint64
+	Bsize   uint32
+	Namelen uint32
+	Frsize  uint32
+	_       uint32
+	Spare   [6]uint32
+}
+
+type fileLock struct {
+	Start uint64
+	End   uint64
+	Type  uint32
+	Pid   uint32
+}
+
+// GetattrFlags are bit flags that can be seen in GetattrRequest.
+type GetattrFlags uint32
+
+const (
+	// Indicates the handle is valid.
+	GetattrFh GetattrFlags = 1 << 0
+)
+
+var getattrFlagsNames = []flagName{
+	{uint32(GetattrFh), "GetattrFh"},
+}
+
+func (fl GetattrFlags) String() string {
+	return flagString(uint32(fl), getattrFlagsNames)
+}
+
+// The SetattrValid are bit flags describing which fields in the SetattrRequest
+// are included in the change.
+type SetattrValid uint32
+
+const (
+	SetattrMode   SetattrValid = 1 << 0
+	SetattrUid    SetattrValid = 1 << 1
+	SetattrGid    SetattrValid = 1 << 2
+	SetattrSize   SetattrValid = 1 << 3
+	SetattrAtime  SetattrValid = 1 << 4
+	SetattrMtime  SetattrValid = 1 << 5
+	SetattrHandle SetattrValid = 1 << 6
+
+	// Linux only(?)
+	SetattrAtimeNow  SetattrValid = 1 << 7
+	SetattrMtimeNow  SetattrValid = 1 << 8
+	SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
+
+	// OS X only
+	SetattrCrtime   SetattrValid = 1 << 28
+	SetattrChgtime  SetattrValid = 1 << 29
+	SetattrBkuptime SetattrValid = 1 << 30
+	SetattrFlags    SetattrValid = 1 << 31
+)
+
+func (fl SetattrValid) Mode() bool      { return fl&SetattrMode != 0 }
+func (fl SetattrValid) Uid() bool       { return fl&SetattrUid != 0 }
+func (fl SetattrValid) Gid() bool       { return fl&SetattrGid != 0 }
+func (fl SetattrValid) Size() bool      { return fl&SetattrSize != 0 }
+func (fl SetattrValid) Atime() bool     { return fl&SetattrAtime != 0 }
+func (fl SetattrValid) Mtime() bool     { return fl&SetattrMtime != 0 }
+func (fl SetattrValid) Handle() bool    { return fl&SetattrHandle != 0 }
+func (fl SetattrValid) AtimeNow() bool  { return fl&SetattrAtimeNow != 0 }
+func (fl SetattrValid) MtimeNow() bool  { return fl&SetattrMtimeNow != 0 }
+func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 }
+func (fl SetattrValid) Crtime() bool    { return fl&SetattrCrtime != 0 }
+func (fl SetattrValid) Chgtime() bool   { return fl&SetattrChgtime != 0 }
+func (fl SetattrValid) Bkuptime() bool  { return fl&SetattrBkuptime != 0 }
+func (fl SetattrValid) Flags() bool     { return fl&SetattrFlags != 0 }
+
+func (fl SetattrValid) String() string {
+	return flagString(uint32(fl), setattrValidNames)
+}
+
+var setattrValidNames = []flagName{
+	{uint32(SetattrMode), "SetattrMode"},
+	{uint32(SetattrUid), "SetattrUid"},
+	{uint32(SetattrGid), "SetattrGid"},
+	{uint32(SetattrSize), "SetattrSize"},
+	{uint32(SetattrAtime), "SetattrAtime"},
+	{uint32(SetattrMtime), "SetattrMtime"},
+	{uint32(SetattrHandle), "SetattrHandle"},
+	{uint32(SetattrAtimeNow), "SetattrAtimeNow"},
+	{uint32(SetattrMtimeNow), "SetattrMtimeNow"},
+	{uint32(SetattrLockOwner), "SetattrLockOwner"},
+	{uint32(SetattrCrtime), "SetattrCrtime"},
+	{uint32(SetattrChgtime), "SetattrChgtime"},
+	{uint32(SetattrBkuptime), "SetattrBkuptime"},
+	{uint32(SetattrFlags), "SetattrFlags"},
+}
+
+// Flags that can be seen in OpenRequest.Flags.
+const (
+	// Access modes. These are not 1-bit flags, but alternatives where
+	// only one can be chosen. See the IsReadOnly etc convenience
+	// methods.
+	OpenReadOnly  OpenFlags = syscall.O_RDONLY
+	OpenWriteOnly OpenFlags = syscall.O_WRONLY
+	OpenReadWrite OpenFlags = syscall.O_RDWR
+
+	// File was opened in append-only mode, all writes will go to end
+	// of file. OS X does not provide this information.
+	OpenAppend    OpenFlags = syscall.O_APPEND
+	OpenCreate    OpenFlags = syscall.O_CREAT
+	OpenDirectory OpenFlags = syscall.O_DIRECTORY
+	OpenExclusive OpenFlags = syscall.O_EXCL
+	OpenNonblock  OpenFlags = syscall.O_NONBLOCK
+	OpenSync      OpenFlags = syscall.O_SYNC
+	OpenTruncate  OpenFlags = syscall.O_TRUNC
+)
+
+// OpenAccessModeMask is a bitmask that separates the access mode
+// from the other flags in OpenFlags.
+const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE
+
+// OpenFlags are the O_FOO flags passed to open/create/etc calls. For
+// example, os.O_WRONLY | os.O_APPEND.
+type OpenFlags uint32
+
+func (fl OpenFlags) String() string {
+	// O_RDONLY, O_RWONLY, O_RDWR are not flags
+	s := accModeName(fl & OpenAccessModeMask)
+	flags := uint32(fl &^ OpenAccessModeMask)
+	if flags != 0 {
+		s = s + "+" + flagString(flags, openFlagNames)
+	}
+	return s
+}
+
+// Return true if OpenReadOnly is set.
+func (fl OpenFlags) IsReadOnly() bool {
+	return fl&OpenAccessModeMask == OpenReadOnly
+}
+
+// Return true if OpenWriteOnly is set.
+func (fl OpenFlags) IsWriteOnly() bool {
+	return fl&OpenAccessModeMask == OpenWriteOnly
+}
+
+// Return true if OpenReadWrite is set.
+func (fl OpenFlags) IsReadWrite() bool {
+	return fl&OpenAccessModeMask == OpenReadWrite
+}
+
+func accModeName(flags OpenFlags) string {
+	switch flags {
+	case OpenReadOnly:
+		return "OpenReadOnly"
+	case OpenWriteOnly:
+		return "OpenWriteOnly"
+	case OpenReadWrite:
+		return "OpenReadWrite"
+	default:
+		return ""
+	}
+}
+
+var openFlagNames = []flagName{
+	{uint32(OpenAppend), "OpenAppend"},
+	{uint32(OpenCreate), "OpenCreate"},
+	{uint32(OpenDirectory), "OpenDirectory"},
+	{uint32(OpenExclusive), "OpenExclusive"},
+	{uint32(OpenNonblock), "OpenNonblock"},
+	{uint32(OpenSync), "OpenSync"},
+	{uint32(OpenTruncate), "OpenTruncate"},
+}
+
+// The OpenResponseFlags are returned in the OpenResponse.
+type OpenResponseFlags uint32
+
+const (
+	OpenDirectIO    OpenResponseFlags = 1 << 0 // bypass page cache for this open file
+	OpenKeepCache   OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
+	OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X)
+
+	OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
+	OpenPurgeUBC  OpenResponseFlags = 1 << 31 // OS X
+)
+
+func (fl OpenResponseFlags) String() string {
+	return flagString(uint32(fl), openResponseFlagNames)
+}
+
+var openResponseFlagNames = []flagName{
+	{uint32(OpenDirectIO), "OpenDirectIO"},
+	{uint32(OpenKeepCache), "OpenKeepCache"},
+	{uint32(OpenNonSeekable), "OpenNonSeekable"},
+	{uint32(OpenPurgeAttr), "OpenPurgeAttr"},
+	{uint32(OpenPurgeUBC), "OpenPurgeUBC"},
+}
+
+// The InitFlags are used in the Init exchange.
+type InitFlags uint32
+
+const (
+	InitAsyncRead     InitFlags = 1 << 0
+	InitPosixLocks    InitFlags = 1 << 1
+	InitFileOps       InitFlags = 1 << 2
+	InitAtomicTrunc   InitFlags = 1 << 3
+	InitExportSupport InitFlags = 1 << 4
+	InitBigWrites     InitFlags = 1 << 5
+	// Do not mask file access modes with umask. Not supported on OS X.
+	InitDontMask        InitFlags = 1 << 6
+	InitSpliceWrite     InitFlags = 1 << 7
+	InitSpliceMove      InitFlags = 1 << 8
+	InitSpliceRead      InitFlags = 1 << 9
+	InitFlockLocks      InitFlags = 1 << 10
+	InitHasIoctlDir     InitFlags = 1 << 11
+	InitAutoInvalData   InitFlags = 1 << 12
+	InitDoReaddirplus   InitFlags = 1 << 13
+	InitReaddirplusAuto InitFlags = 1 << 14
+	InitAsyncDIO        InitFlags = 1 << 15
+	InitWritebackCache  InitFlags = 1 << 16
+	InitNoOpenSupport   InitFlags = 1 << 17
+
+	InitCaseSensitive InitFlags = 1 << 29 // OS X only
+	InitVolRename     InitFlags = 1 << 30 // OS X only
+	InitXtimes        InitFlags = 1 << 31 // OS X only
+)
+
+type flagName struct {
+	bit  uint32
+	name string
+}
+
+var initFlagNames = []flagName{
+	{uint32(InitAsyncRead), "InitAsyncRead"},
+	{uint32(InitPosixLocks), "InitPosixLocks"},
+	{uint32(InitFileOps), "InitFileOps"},
+	{uint32(InitAtomicTrunc), "InitAtomicTrunc"},
+	{uint32(InitExportSupport), "InitExportSupport"},
+	{uint32(InitBigWrites), "InitBigWrites"},
+	{uint32(InitDontMask), "InitDontMask"},
+	{uint32(InitSpliceWrite), "InitSpliceWrite"},
+	{uint32(InitSpliceMove), "InitSpliceMove"},
+	{uint32(InitSpliceRead), "InitSpliceRead"},
+	{uint32(InitFlockLocks), "InitFlockLocks"},
+	{uint32(InitHasIoctlDir), "InitHasIoctlDir"},
+	{uint32(InitAutoInvalData), "InitAutoInvalData"},
+	{uint32(InitDoReaddirplus), "InitDoReaddirplus"},
+	{uint32(InitReaddirplusAuto), "InitReaddirplusAuto"},
+	{uint32(InitAsyncDIO), "InitAsyncDIO"},
+	{uint32(InitWritebackCache), "InitWritebackCache"},
+	{uint32(InitNoOpenSupport), "InitNoOpenSupport"},
+
+	{uint32(InitCaseSensitive), "InitCaseSensitive"},
+	{uint32(InitVolRename), "InitVolRename"},
+	{uint32(InitXtimes), "InitXtimes"},
+}
+
+func (fl InitFlags) String() string {
+	return flagString(uint32(fl), initFlagNames)
+}
+
+func flagString(f uint32, names []flagName) string {
+	var s string
+
+	if f == 0 {
+		return "0"
+	}
+
+	for _, n := range names {
+		if f&n.bit != 0 {
+			s += "+" + n.name
+			f &^= n.bit
+		}
+	}
+	if f != 0 {
+		s += fmt.Sprintf("%+#x", f)
+	}
+	return s[1:]
+}
+
+// The ReleaseFlags are used in the Release exchange.
+type ReleaseFlags uint32
+
+const (
+	ReleaseFlush ReleaseFlags = 1 << 0
+)
+
+func (fl ReleaseFlags) String() string {
+	return flagString(uint32(fl), releaseFlagNames)
+}
+
+var releaseFlagNames = []flagName{
+	{uint32(ReleaseFlush), "ReleaseFlush"},
+}
+
+// Opcodes
+const (
+	opLookup      = 1
+	opForget      = 2 // no reply
+	opGetattr     = 3
+	opSetattr     = 4
+	opReadlink    = 5
+	opSymlink     = 6
+	opMknod       = 8
+	opMkdir       = 9
+	opUnlink      = 10
+	opRmdir       = 11
+	opRename      = 12
+	opLink        = 13
+	opOpen        = 14
+	opRead        = 15
+	opWrite       = 16
+	opStatfs      = 17
+	opRelease     = 18
+	opFsync       = 20
+	opSetxattr    = 21
+	opGetxattr    = 22
+	opListxattr   = 23
+	opRemovexattr = 24
+	opFlush       = 25
+	opInit        = 26
+	opOpendir     = 27
+	opReaddir     = 28
+	opReleasedir  = 29
+	opFsyncdir    = 30
+	opGetlk       = 31
+	opSetlk       = 32
+	opSetlkw      = 33
+	opAccess      = 34
+	opCreate      = 35
+	opInterrupt   = 36
+	opBmap        = 37
+	opDestroy     = 38
+	opIoctl       = 39 // Linux?
+	opPoll        = 40 // Linux?
+
+	// OS X
+	opSetvolname = 61
+	opGetxtimes  = 62
+	opExchange   = 63
+)
+
+type entryOut struct {
+	Nodeid         uint64 // Inode ID
+	Generation     uint64 // Inode generation
+	EntryValid     uint64 // Cache timeout for the name
+	AttrValid      uint64 // Cache timeout for the attributes
+	EntryValidNsec uint32
+	AttrValidNsec  uint32
+	Attr           attr
+}
+
+func entryOutSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 9}):
+		return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize)
+	default:
+		return unsafe.Sizeof(entryOut{})
+	}
+}
+
+type forgetIn struct {
+	Nlookup uint64
+}
+
+type getattrIn struct {
+	GetattrFlags uint32
+	_            uint32
+	Fh           uint64
+}
+
+type attrOut struct {
+	AttrValid     uint64 // Cache timeout for the attributes
+	AttrValidNsec uint32
+	_             uint32
+	Attr          attr
+}
+
+func attrOutSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 9}):
+		return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize)
+	default:
+		return unsafe.Sizeof(attrOut{})
+	}
+}
+
+// OS X
+type getxtimesOut struct {
+	Bkuptime     uint64
+	Crtime       uint64
+	BkuptimeNsec uint32
+	CrtimeNsec   uint32
+}
+
+type mknodIn struct {
+	Mode  uint32
+	Rdev  uint32
+	Umask uint32
+	_     uint32
+	// "filename\x00" follows.
+}
+
+func mknodInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 12}):
+		return unsafe.Offsetof(mknodIn{}.Umask)
+	default:
+		return unsafe.Sizeof(mknodIn{})
+	}
+}
+
+type mkdirIn struct {
+	Mode  uint32
+	Umask uint32
+	// filename follows
+}
+
+func mkdirInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 12}):
+		return unsafe.Offsetof(mkdirIn{}.Umask) + 4
+	default:
+		return unsafe.Sizeof(mkdirIn{})
+	}
+}
+
+type renameIn struct {
+	Newdir uint64
+	// "oldname\x00newname\x00" follows
+}
+
+// OS X
+type exchangeIn struct {
+	Olddir  uint64
+	Newdir  uint64
+	Options uint64
+	// "oldname\x00newname\x00" follows
+}
+
+type linkIn struct {
+	Oldnodeid uint64
+}
+
+type setattrInCommon struct {
+	Valid     uint32
+	_         uint32
+	Fh        uint64
+	Size      uint64
+	LockOwner uint64 // unused on OS X?
+	Atime     uint64
+	Mtime     uint64
+	Unused2   uint64
+	AtimeNsec uint32
+	MtimeNsec uint32
+	Unused3   uint32
+	Mode      uint32
+	Unused4   uint32
+	Uid       uint32
+	Gid       uint32
+	Unused5   uint32
+}
+
+type openIn struct {
+	Flags  uint32
+	Unused uint32
+}
+
+type openOut struct {
+	Fh        uint64
+	OpenFlags uint32
+	_         uint32
+}
+
+type createIn struct {
+	Flags uint32
+	Mode  uint32
+	Umask uint32
+	_     uint32
+}
+
+func createInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 12}):
+		return unsafe.Offsetof(createIn{}.Umask)
+	default:
+		return unsafe.Sizeof(createIn{})
+	}
+}
+
+type releaseIn struct {
+	Fh           uint64
+	Flags        uint32
+	ReleaseFlags uint32
+	LockOwner    uint32
+}
+
+type flushIn struct {
+	Fh         uint64
+	FlushFlags uint32
+	_          uint32
+	LockOwner  uint64
+}
+
+type readIn struct {
+	Fh        uint64
+	Offset    uint64
+	Size      uint32
+	ReadFlags uint32
+	LockOwner uint64
+	Flags     uint32
+	_         uint32
+}
+
+func readInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 9}):
+		return unsafe.Offsetof(readIn{}.ReadFlags) + 4
+	default:
+		return unsafe.Sizeof(readIn{})
+	}
+}
+
+// The ReadFlags are passed in ReadRequest.
+type ReadFlags uint32
+
+const (
+	// LockOwner field is valid.
+	ReadLockOwner ReadFlags = 1 << 1
+)
+
+var readFlagNames = []flagName{
+	{uint32(ReadLockOwner), "ReadLockOwner"},
+}
+
+func (fl ReadFlags) String() string {
+	return flagString(uint32(fl), readFlagNames)
+}
+
+type writeIn struct {
+	Fh         uint64
+	Offset     uint64
+	Size       uint32
+	WriteFlags uint32
+	LockOwner  uint64
+	Flags      uint32
+	_          uint32
+}
+
+func writeInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 9}):
+		return unsafe.Offsetof(writeIn{}.LockOwner)
+	default:
+		return unsafe.Sizeof(writeIn{})
+	}
+}
+
+type writeOut struct {
+	Size uint32
+	_    uint32
+}
+
+// The WriteFlags are passed in WriteRequest.
+type WriteFlags uint32
+
+const (
+	WriteCache WriteFlags = 1 << 0
+	// LockOwner field is valid.
+	WriteLockOwner WriteFlags = 1 << 1
+)
+
+var writeFlagNames = []flagName{
+	{uint32(WriteCache), "WriteCache"},
+	{uint32(WriteLockOwner), "WriteLockOwner"},
+}
+
+func (fl WriteFlags) String() string {
+	return flagString(uint32(fl), writeFlagNames)
+}
+
+const compatStatfsSize = 48
+
+type statfsOut struct {
+	St kstatfs
+}
+
+type fsyncIn struct {
+	Fh         uint64
+	FsyncFlags uint32
+	_          uint32
+}
+
+type setxattrInCommon struct {
+	Size  uint32
+	Flags uint32
+}
+
+func (setxattrInCommon) position() uint32 {
+	return 0
+}
+
+type getxattrInCommon struct {
+	Size uint32
+	_    uint32
+}
+
+func (getxattrInCommon) position() uint32 {
+	return 0
+}
+
+type getxattrOut struct {
+	Size uint32
+	_    uint32
+}
+
+type lkIn struct {
+	Fh      uint64
+	Owner   uint64
+	Lk      fileLock
+	LkFlags uint32
+	_       uint32
+}
+
+func lkInSize(p Protocol) uintptr {
+	switch {
+	case p.LT(Protocol{7, 9}):
+		return unsafe.Offsetof(lkIn{}.LkFlags)
+	default:
+		return unsafe.Sizeof(lkIn{})
+	}
+}
+
+type lkOut struct {
+	Lk fileLock
+}
+
+type accessIn struct {
+	Mask uint32
+	_    uint32
+}
+
+type initIn struct {
+	Major        uint32
+	Minor        uint32
+	MaxReadahead uint32
+	Flags        uint32
+}
+
+const initInSize = int(unsafe.Sizeof(initIn{}))
+
+type initOut struct {
+	Major        uint32
+	Minor        uint32
+	MaxReadahead uint32
+	Flags        uint32
+	Unused       uint32
+	MaxWrite     uint32
+}
+
+type interruptIn struct {
+	Unique uint64
+}
+
+type bmapIn struct {
+	Block     uint64
+	BlockSize uint32
+	_         uint32
+}
+
+type bmapOut struct {
+	Block uint64
+}
+
+type inHeader struct {
+	Len    uint32
+	Opcode uint32
+	Unique uint64
+	Nodeid uint64
+	Uid    uint32
+	Gid    uint32
+	Pid    uint32
+	_      uint32
+}
+
+const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
+
+type outHeader struct {
+	Len    uint32
+	Error  int32
+	Unique uint64
+}
+
+type dirent struct {
+	Ino     uint64
+	Off     uint64
+	Namelen uint32
+	Type    uint32
+	Name    [0]byte
+}
+
+const direntSize = 8 + 8 + 4 + 4
+
+const (
+	notifyCodePoll       int32 = 1
+	notifyCodeInvalInode int32 = 2
+	notifyCodeInvalEntry int32 = 3
+)
+
+type notifyInvalInodeOut struct {
+	Ino uint64
+	Off int64
+	Len int64
+}
+
+type notifyInvalEntryOut struct {
+	Parent  uint64
+	Namelen uint32
+	_       uint32
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_darwin.go b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..b9873fdf3910c45008f4d7f0ca26d262c7c577d7
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
@@ -0,0 +1,88 @@
+package fuse
+
+import (
+	"time"
+)
+
+type attr struct {
+	Ino        uint64
+	Size       uint64
+	Blocks     uint64
+	Atime      uint64
+	Mtime      uint64
+	Ctime      uint64
+	Crtime_    uint64 // OS X only
+	AtimeNsec  uint32
+	MtimeNsec  uint32
+	CtimeNsec  uint32
+	CrtimeNsec uint32 // OS X only
+	Mode       uint32
+	Nlink      uint32
+	Uid        uint32
+	Gid        uint32
+	Rdev       uint32
+	Flags_     uint32 // OS X only; see chflags(2)
+	Blksize    uint32
+	padding    uint32
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+	a.Crtime_, a.CrtimeNsec = s, ns
+}
+
+func (a *attr) SetFlags(f uint32) {
+	a.Flags_ = f
+}
+
+type setattrIn struct {
+	setattrInCommon
+
+	// OS X only
+	Bkuptime_    uint64
+	Chgtime_     uint64
+	Crtime       uint64
+	BkuptimeNsec uint32
+	ChgtimeNsec  uint32
+	CrtimeNsec   uint32
+	Flags_       uint32 // see chflags(2)
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+	return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec))
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+	return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec))
+}
+
+func (in *setattrIn) Flags() uint32 {
+	return in.Flags_
+}
+
+func openFlags(flags uint32) OpenFlags {
+	return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+	getxattrInCommon
+
+	// OS X only
+	Position uint32
+	Padding  uint32
+}
+
+func (g *getxattrIn) position() uint32 {
+	return g.Position
+}
+
+type setxattrIn struct {
+	setxattrInCommon
+
+	// OS X only
+	Position uint32
+	Padding  uint32
+}
+
+func (s *setxattrIn) position() uint32 {
+	return s.Position
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_freebsd.go b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
new file mode 100644
index 0000000000000000000000000000000000000000..b1141e41dc9633ab51cfb27fc9aa746e2a02bbee
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
@@ -0,0 +1,62 @@
+package fuse
+
+import "time"
+
+type attr struct {
+	Ino       uint64
+	Size      uint64
+	Blocks    uint64
+	Atime     uint64
+	Mtime     uint64
+	Ctime     uint64
+	AtimeNsec uint32
+	MtimeNsec uint32
+	CtimeNsec uint32
+	Mode      uint32
+	Nlink     uint32
+	Uid       uint32
+	Gid       uint32
+	Rdev      uint32
+	Blksize   uint32
+	padding   uint32
+}
+
+func (a *attr) Crtime() time.Time {
+	return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+	// ignored on freebsd
+}
+
+func (a *attr) SetFlags(f uint32) {
+	// ignored on freebsd
+}
+
+type setattrIn struct {
+	setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+	return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+	return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+	return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+	return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+	getxattrInCommon
+}
+
+type setxattrIn struct {
+	setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_linux.go b/vendor/bazil.org/fuse/fuse_kernel_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..d3ba866178020fedffac6bf2b6f116fb9c8ed17f
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_linux.go
@@ -0,0 +1,70 @@
+package fuse
+
+import "time"
+
+type attr struct {
+	Ino       uint64
+	Size      uint64
+	Blocks    uint64
+	Atime     uint64
+	Mtime     uint64
+	Ctime     uint64
+	AtimeNsec uint32
+	MtimeNsec uint32
+	CtimeNsec uint32
+	Mode      uint32
+	Nlink     uint32
+	Uid       uint32
+	Gid       uint32
+	Rdev      uint32
+	Blksize   uint32
+	padding   uint32
+}
+
+func (a *attr) Crtime() time.Time {
+	return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+	// Ignored on Linux.
+}
+
+func (a *attr) SetFlags(f uint32) {
+	// Ignored on Linux.
+}
+
+type setattrIn struct {
+	setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+	return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+	return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+	return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+	// on amd64, the 32-bit O_LARGEFILE flag is always seen;
+	// on i386, the flag probably depends on the app
+	// requesting, but in any case should be utterly
+	// uninteresting to us here; our kernel protocol messages
+	// are not directly related to the client app's kernel
+	// API/ABI
+	flags &^= 0x8000
+
+	return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+	getxattrInCommon
+}
+
+type setxattrIn struct {
+	setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_std.go b/vendor/bazil.org/fuse/fuse_kernel_std.go
new file mode 100644
index 0000000000000000000000000000000000000000..074cfd322887daffaae6a27e3d1f8f661c8892b9
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_std.go
@@ -0,0 +1 @@
+package fuse
diff --git a/vendor/bazil.org/fuse/fuse_linux.go b/vendor/bazil.org/fuse/fuse_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..5fb96f9ae942443219523d8b8aca93f6488dd2ab
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_linux.go
@@ -0,0 +1,7 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// Linux 4.2.0 has been observed to cap this value at 128kB
+// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages).
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuseutil/fuseutil.go b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
new file mode 100644
index 0000000000000000000000000000000000000000..b3f52b73b257a367b21357c08d20e1fa3f9c09a8
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
@@ -0,0 +1,20 @@
+package fuseutil // import "bazil.org/fuse/fuseutil"
+
+import (
+	"bazil.org/fuse"
+)
+
+// HandleRead handles a read request assuming that data is the entire file content.
+// It adjusts the amount returned in resp according to req.Offset and req.Size.
+func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) {
+	if req.Offset >= int64(len(data)) {
+		data = nil
+	} else {
+		data = data[req.Offset:]
+	}
+	if len(data) > req.Size {
+		data = data[:req.Size]
+	}
+	n := copy(resp.Data[:req.Size], data)
+	resp.Data = resp.Data[:n]
+}
diff --git a/vendor/bazil.org/fuse/mount.go b/vendor/bazil.org/fuse/mount.go
new file mode 100644
index 0000000000000000000000000000000000000000..8054e9021c4e350ee1b2ebe678571085c79593f4
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount.go
@@ -0,0 +1,38 @@
+package fuse
+
+import (
+	"bufio"
+	"errors"
+	"io"
+	"log"
+	"sync"
+)
+
+var (
+	// ErrOSXFUSENotFound is returned from Mount when the OSXFUSE
+	// installation is not detected.
+	//
+	// Only happens on OS X. Make sure OSXFUSE is installed, or see
+	// OSXFUSELocations for customization.
+	ErrOSXFUSENotFound = errors.New("cannot locate OSXFUSE")
+)
+
+func neverIgnoreLine(line string) bool {
+	return false
+}
+
+func lineLogger(wg *sync.WaitGroup, prefix string, ignore func(line string) bool, r io.ReadCloser) {
+	defer wg.Done()
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if ignore(line) {
+			continue
+		}
+		log.Printf("%s: %s", prefix, line)
+	}
+	if err := scanner.Err(); err != nil {
+		log.Printf("%s, error reading: %v", prefix, err)
+	}
+}
diff --git a/vendor/bazil.org/fuse/mount_darwin.go b/vendor/bazil.org/fuse/mount_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..c1c36e62b5f3204824f437f59fcd7f2eb373ed04
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_darwin.go
@@ -0,0 +1,208 @@
+package fuse
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"path"
+	"strconv"
+	"strings"
+	"sync"
+	"syscall"
+)
+
+var (
+	errNoAvail   = errors.New("no available fuse devices")
+	errNotLoaded = errors.New("osxfuse is not loaded")
+)
+
+func loadOSXFUSE(bin string) error {
+	cmd := exec.Command(bin)
+	cmd.Dir = "/"
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	err := cmd.Run()
+	return err
+}
+
+func openOSXFUSEDev(devPrefix string) (*os.File, error) {
+	var f *os.File
+	var err error
+	for i := uint64(0); ; i++ {
+		path := devPrefix + 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 handleMountOSXFUSE(helperName string, errCh chan<- error) func(line string) (ignore bool) {
+	var noMountpointPrefix = helperName + `: `
+	const noMountpointSuffix = `: No such file or directory`
+	return func(line string) (ignore bool) {
+		if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+			// re-extract it from the error message in case some layer
+			// changed the path
+			mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+			err := &MountpointDoesNotExistError{
+				Path: mountpoint,
+			}
+			select {
+			case errCh <- err:
+				return true
+			default:
+				// not the first error; fall back to logging it
+				return false
+			}
+		}
+
+		return false
+	}
+}
+
+// isBoringMountOSXFUSEError returns whether the Wait error is
+// uninteresting; exit status 64 is.
+func isBoringMountOSXFUSEError(err error) bool {
+	if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+		if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 64 {
+			return true
+		}
+	}
+	return false
+}
+
+func callMount(bin string, daemonVar string, dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) 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 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()
+	// OSXFUSE <3.3.0
+	cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
+	// OSXFUSE >=3.3.0
+	cmd.Env = append(cmd.Env, "MOUNT_OSXFUSE_CALL_BY_LIB=")
+
+	daemon := os.Args[0]
+	if daemonVar != "" {
+		cmd.Env = append(cmd.Env, daemonVar+"="+daemon)
+	}
+
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+	}
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+	}
+
+	if err := cmd.Start(); err != nil {
+		return fmt.Errorf("mount_osxfusefs: %v", err)
+	}
+	helperErrCh := make(chan error, 1)
+	go func() {
+		var wg sync.WaitGroup
+		wg.Add(2)
+		go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+		helperName := path.Base(bin)
+		go lineLogger(&wg, "mount helper error", handleMountOSXFUSE(helperName, helperErrCh), stderr)
+		wg.Wait()
+		if err := cmd.Wait(); err != nil {
+			// see if we have a better error to report
+			select {
+			case helperErr := <-helperErrCh:
+				// log the Wait error if it's not what we expected
+				if !isBoringMountOSXFUSEError(err) {
+					log.Printf("mount helper failed: %v", err)
+				}
+				// and now return what we grabbed from stderr as the real
+				// error
+				*errp = helperErr
+				close(ready)
+				return
+			default:
+				// nope, fall back to generic message
+			}
+
+			*errp = fmt.Errorf("mount_osxfusefs: %v", err)
+			close(ready)
+			return
+		}
+
+		*errp = nil
+		close(ready)
+	}()
+	return nil
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
+	locations := conf.osxfuseLocations
+	if locations == nil {
+		locations = []OSXFUSEPaths{
+			OSXFUSELocationV3,
+			OSXFUSELocationV2,
+		}
+	}
+	for _, loc := range locations {
+		if _, err := os.Stat(loc.Mount); os.IsNotExist(err) {
+			// try the other locations
+			continue
+		}
+
+		f, err := openOSXFUSEDev(loc.DevicePrefix)
+		if err == errNotLoaded {
+			err = loadOSXFUSE(loc.Load)
+			if err != nil {
+				return nil, err
+			}
+			// try again
+			f, err = openOSXFUSEDev(loc.DevicePrefix)
+		}
+		if err != nil {
+			return nil, err
+		}
+		err = callMount(loc.Mount, loc.DaemonVar, dir, conf, f, ready, errp)
+		if err != nil {
+			f.Close()
+			return nil, err
+		}
+		return f, nil
+	}
+	return nil, ErrOSXFUSENotFound
+}
diff --git a/vendor/bazil.org/fuse/mount_freebsd.go b/vendor/bazil.org/fuse/mount_freebsd.go
new file mode 100644
index 0000000000000000000000000000000000000000..70bb41024978577fab73f193a347725228f4fe30
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_freebsd.go
@@ -0,0 +1,111 @@
+package fuse
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+	"syscall"
+)
+
+func handleMountFusefsStderr(errCh chan<- error) func(line string) (ignore bool) {
+	return func(line string) (ignore bool) {
+		const (
+			noMountpointPrefix = `mount_fusefs: `
+			noMountpointSuffix = `: No such file or directory`
+		)
+		if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+			// re-extract it from the error message in case some layer
+			// changed the path
+			mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+			err := &MountpointDoesNotExistError{
+				Path: mountpoint,
+			}
+			select {
+			case errCh <- err:
+				return true
+			default:
+				// not the first error; fall back to logging it
+				return false
+			}
+		}
+
+		return false
+	}
+}
+
+// isBoringMountFusefsError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringMountFusefsError(err error) bool {
+	if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+		if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+			return true
+		}
+	}
+	return false
+}
+
+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}
+
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+	}
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+	}
+
+	if err := cmd.Start(); err != nil {
+		return nil, fmt.Errorf("mount_fusefs: %v", err)
+	}
+	helperErrCh := make(chan error, 1)
+	var wg sync.WaitGroup
+	wg.Add(2)
+	go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+	go lineLogger(&wg, "mount helper error", handleMountFusefsStderr(helperErrCh), stderr)
+	wg.Wait()
+	if err := cmd.Wait(); err != nil {
+		// see if we have a better error to report
+		select {
+		case helperErr := <-helperErrCh:
+			// log the Wait error if it's not what we expected
+			if !isBoringMountFusefsError(err) {
+				log.Printf("mount helper failed: %v", err)
+			}
+			// and now return what we grabbed from stderr as the real
+			// error
+			return nil, helperErr
+		default:
+			// nope, fall back to generic message
+		}
+		return nil, fmt.Errorf("mount_fusefs: %v", err)
+	}
+
+	close(ready)
+	return f, nil
+}
diff --git a/vendor/bazil.org/fuse/mount_linux.go b/vendor/bazil.org/fuse/mount_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..197d1044e926daa8cd48b61992fcceeaac60e8e7
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_linux.go
@@ -0,0 +1,150 @@
+package fuse
+
+import (
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+	"syscall"
+)
+
+func handleFusermountStderr(errCh chan<- error) func(line string) (ignore bool) {
+	return func(line string) (ignore bool) {
+		if line == `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.
+			return true
+		}
+
+		const (
+			noMountpointPrefix = `fusermount: failed to access mountpoint `
+			noMountpointSuffix = `: No such file or directory`
+		)
+		if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+			// re-extract it from the error message in case some layer
+			// changed the path
+			mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+			err := &MountpointDoesNotExistError{
+				Path: mountpoint,
+			}
+			select {
+			case errCh <- err:
+				return true
+			default:
+				// not the first error; fall back to logging it
+				return false
+			}
+		}
+
+		return false
+	}
+}
+
+// isBoringFusermountError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringFusermountError(err error) bool {
+	if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+		if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+			return true
+		}
+	}
+	return false
+}
+
+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)
+	}
+	helperErrCh := make(chan error, 1)
+	wg.Add(2)
+	go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+	go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr)
+	wg.Wait()
+	if err := cmd.Wait(); err != nil {
+		// see if we have a better error to report
+		select {
+		case helperErr := <-helperErrCh:
+			// log the Wait error if it's not what we expected
+			if !isBoringFusermountError(err) {
+				log.Printf("mount helper failed: %v", err)
+			}
+			// and now return what we grabbed from stderr as the real
+			// error
+			return nil, helperErr
+		default:
+			// nope, fall back to generic message
+		}
+
+		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
+}
diff --git a/vendor/bazil.org/fuse/options.go b/vendor/bazil.org/fuse/options.go
new file mode 100644
index 0000000000000000000000000000000000000000..65ce8a5410d2729f23fd8c9b901d1e00dde69e4e
--- /dev/null
+++ b/vendor/bazil.org/fuse/options.go
@@ -0,0 +1,310 @@
+package fuse
+
+import (
+	"errors"
+	"strings"
+)
+
+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        InitFlags
+	osxfuseLocations []OSXFUSEPaths
+}
+
+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)
+}
+
+// NoAppleDouble makes OSXFUSE disallow files with names used by OS X
+// to store extended attributes on file systems that do not support
+// them natively.
+//
+// Such file names are:
+//
+//     ._*
+//     .DS_Store
+//
+// OS X only.  Others ignore this option.
+func NoAppleDouble() MountOption {
+	return noAppleDouble
+}
+
+// NoAppleXattr makes OSXFUSE disallow extended attributes with the
+// prefix "com.apple.". This disables persistent Finder state and
+// other such information.
+//
+// OS X only.  Others ignore this option.
+func NoAppleXattr() MountOption {
+	return noAppleXattr
+}
+
+// ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates,
+// i.e. create calls for which the initiator explicitly set the O_EXCL flag.
+//
+// OSXFUSE expects all create calls to return EEXIST in case the file
+// already exists, regardless of whether O_EXCL was specified or not.
+// To ensure this behavior, it normally sets OpenExclusive for all
+// Create calls, regardless of whether the original call had it set.
+// For distributed filesystems, that may force every file create to be
+// a distributed consensus action, causing undesirable delays.
+//
+// This option makes the FUSE filesystem see the original flag value,
+// and better decide when to ensure global consensus.
+//
+// Note that returning EEXIST on existing file create is still
+// expected with OSXFUSE, regardless of the presence of the
+// OpenExclusive flag.
+//
+// For more information, see
+// https://github.com/osxfuse/osxfuse/issues/209
+//
+// OS X only. Others ignore this options.
+// Requires OSXFUSE 3.4.1 or newer.
+func ExclCreate() MountOption {
+	return exclCreate
+}
+
+// DaemonTimeout sets the time in seconds between a request and a reply before
+// the FUSE mount is declared dead.
+//
+// OS X and FreeBSD only. Others ignore this option.
+func DaemonTimeout(name string) MountOption {
+	return daemonTimeout(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
+	}
+}
+
+// AllowDev enables interpreting character or block special devices on the
+// filesystem.
+func AllowDev() MountOption {
+	return func(conf *mountConfig) error {
+		conf.options["dev"] = ""
+		return nil
+	}
+}
+
+// AllowSUID allows set-user-identifier or set-group-identifier bits to take
+// effect.
+func AllowSUID() MountOption {
+	return func(conf *mountConfig) error {
+		conf.options["suid"] = ""
+		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
+	}
+}
+
+// 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 |= 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 |= InitWritebackCache
+		return nil
+	}
+}
+
+// OSXFUSEPaths describes the paths used by an installed OSXFUSE
+// version. See OSXFUSELocationV3 for typical values.
+type OSXFUSEPaths struct {
+	// Prefix for the device file. At mount time, an incrementing
+	// number is suffixed until a free FUSE device is found.
+	DevicePrefix string
+	// Path of the load helper, used to load the kernel extension if
+	// no device files are found.
+	Load string
+	// Path of the mount helper, used for the actual mount operation.
+	Mount string
+	// Environment variable used to pass the path to the executable
+	// calling the mount helper.
+	DaemonVar string
+}
+
+// Default paths for OSXFUSE. See OSXFUSELocations.
+var (
+	OSXFUSELocationV3 = OSXFUSEPaths{
+		DevicePrefix: "/dev/osxfuse",
+		Load:         "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse",
+		Mount:        "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
+		DaemonVar:    "MOUNT_OSXFUSE_DAEMON_PATH",
+	}
+	OSXFUSELocationV2 = OSXFUSEPaths{
+		DevicePrefix: "/dev/osxfuse",
+		Load:         "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs",
+		Mount:        "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
+		DaemonVar:    "MOUNT_FUSEFS_DAEMON_PATH",
+	}
+)
+
+// OSXFUSELocations sets where to look for OSXFUSE files. The
+// arguments are all the possible locations. The previous locations
+// are replaced.
+//
+// Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are
+// used.
+//
+// OS X only. Others ignore this option.
+func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption {
+	return func(conf *mountConfig) error {
+		if len(paths) == 0 {
+			return errors.New("must specify at least one location for OSXFUSELocations")
+		}
+		// replace previous values, but make a copy so there's no
+		// worries about caller mutating their slice
+		conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...)
+		return nil
+	}
+}
+
+// AllowNonEmptyMount allows the mounting over a non-empty directory.
+//
+// The files in it will be shadowed by the freshly created mount. By
+// default these mounts are rejected to prevent accidental covering up
+// of data, which could for example prevent automatic backup.
+func AllowNonEmptyMount() MountOption {
+	return func(conf *mountConfig) error {
+		conf.options["nonempty"] = ""
+		return nil
+	}
+}
diff --git a/vendor/bazil.org/fuse/options_darwin.go b/vendor/bazil.org/fuse/options_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..faa9d78e74294b0fe2eb72c620fd5ce3d95438e6
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_darwin.go
@@ -0,0 +1,35 @@
+package fuse
+
+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
+	}
+}
+
+func daemonTimeout(name string) MountOption {
+	return func(conf *mountConfig) error {
+		conf.options["daemon_timeout"] = name
+		return nil
+	}
+}
+
+func noAppleXattr(conf *mountConfig) error {
+	conf.options["noapplexattr"] = ""
+	return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+	conf.options["noappledouble"] = ""
+	return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+	conf.options["excl_create"] = ""
+	return nil
+}
diff --git a/vendor/bazil.org/fuse/options_freebsd.go b/vendor/bazil.org/fuse/options_freebsd.go
new file mode 100644
index 0000000000000000000000000000000000000000..7c164b13687d2ab8b986c6d49b10c2ffb2728452
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_freebsd.go
@@ -0,0 +1,28 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+	return nil
+}
+
+func volumeName(name string) MountOption {
+	return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+	return func(conf *mountConfig) error {
+		conf.options["timeout"] = name
+		return nil
+	}
+}
+
+func noAppleXattr(conf *mountConfig) error {
+	return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+	return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+	return nil
+}
diff --git a/vendor/bazil.org/fuse/options_linux.go b/vendor/bazil.org/fuse/options_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..13f0896d5844b7b4d4fbbf13e8a137f1b235581f
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_linux.go
@@ -0,0 +1,25 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+	return nil
+}
+
+func volumeName(name string) MountOption {
+	return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+	return dummyOption
+}
+
+func noAppleXattr(conf *mountConfig) error {
+	return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+	return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+	return nil
+}
diff --git a/vendor/bazil.org/fuse/protocol.go b/vendor/bazil.org/fuse/protocol.go
new file mode 100644
index 0000000000000000000000000000000000000000..a77bbf72f1ad28082b572c61657b31a32c2c6470
--- /dev/null
+++ b/vendor/bazil.org/fuse/protocol.go
@@ -0,0 +1,75 @@
+package fuse
+
+import (
+	"fmt"
+)
+
+// Protocol is a FUSE protocol version number.
+type Protocol struct {
+	Major uint32
+	Minor uint32
+}
+
+func (p Protocol) String() string {
+	return fmt.Sprintf("%d.%d", p.Major, p.Minor)
+}
+
+// LT returns whether a is less than b.
+func (a Protocol) LT(b Protocol) bool {
+	return a.Major < b.Major ||
+		(a.Major == b.Major && a.Minor < b.Minor)
+}
+
+// GE returns whether a is greater than or equal to b.
+func (a Protocol) GE(b Protocol) bool {
+	return a.Major > b.Major ||
+		(a.Major == b.Major && a.Minor >= b.Minor)
+}
+
+func (a Protocol) is79() bool {
+	return a.GE(Protocol{7, 9})
+}
+
+// HasAttrBlockSize returns whether Attr.BlockSize is respected by the
+// kernel.
+func (a Protocol) HasAttrBlockSize() bool {
+	return a.is79()
+}
+
+// HasReadWriteFlags returns whether ReadRequest/WriteRequest
+// fields Flags and FileFlags are valid.
+func (a Protocol) HasReadWriteFlags() bool {
+	return a.is79()
+}
+
+// HasGetattrFlags returns whether GetattrRequest field Flags is
+// valid.
+func (a Protocol) HasGetattrFlags() bool {
+	return a.is79()
+}
+
+func (a Protocol) is710() bool {
+	return a.GE(Protocol{7, 10})
+}
+
+// HasOpenNonSeekable returns whether OpenResponse field Flags flag
+// OpenNonSeekable is supported.
+func (a Protocol) HasOpenNonSeekable() bool {
+	return a.is710()
+}
+
+func (a Protocol) is712() bool {
+	return a.GE(Protocol{7, 12})
+}
+
+// HasUmask returns whether CreateRequest/MkdirRequest/MknodRequest
+// field Umask is valid.
+func (a Protocol) HasUmask() bool {
+	return a.is712()
+}
+
+// HasInvalidate returns whether InvalidateNode/InvalidateEntry are
+// supported.
+func (a Protocol) HasInvalidate() bool {
+	return a.is712()
+}
diff --git a/vendor/bazil.org/fuse/unmount.go b/vendor/bazil.org/fuse/unmount.go
new file mode 100644
index 0000000000000000000000000000000000000000..ffe3f155c4843985acad34bbd2b54689bde3ff34
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Unmount tries to unmount the filesystem mounted at dir.
+func Unmount(dir string) error {
+	return unmount(dir)
+}
diff --git a/vendor/bazil.org/fuse/unmount_linux.go b/vendor/bazil.org/fuse/unmount_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..088f0cfeeec41234b647138722d83f5296acedea
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_linux.go
@@ -0,0 +1,21 @@
+package fuse
+
+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
+}
diff --git a/vendor/bazil.org/fuse/unmount_std.go b/vendor/bazil.org/fuse/unmount_std.go
new file mode 100644
index 0000000000000000000000000000000000000000..d6efe276f6cb431d46ba58183b4d6e87f0e292c8
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_std.go
@@ -0,0 +1,17 @@
+// +build !linux
+
+package fuse
+
+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
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index eaaf0290d14b2cb3900c557781808c235932745b..c19d600c090aeb4aee24af1ad0f7e7f063e94b94 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -2,6 +2,24 @@
 	"comment": "",
 	"ignore": "test",
 	"package": [
+		{
+			"checksumSHA1": "b5bkSc2hlmUV7PlLY6JlLwiJpiE=",
+			"path": "bazil.org/fuse",
+			"revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748",
+			"revisionTime": "2016-08-11T21:22:31Z"
+		},
+		{
+			"checksumSHA1": "389JFJTJADMtZkTIfdSnsmHVOUs=",
+			"path": "bazil.org/fuse/fs",
+			"revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748",
+			"revisionTime": "2016-08-11T21:22:31Z"
+		},
+		{
+			"checksumSHA1": "NPgkh9UWMsaTtsAAs3kPrclHT9Y=",
+			"path": "bazil.org/fuse/fuseutil",
+			"revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748",
+			"revisionTime": "2016-08-11T21:22:31Z"
+		},
 		{
 			"checksumSHA1": "M30X+Wqn7AnUr1numUOkQRI7ET0=",
 			"path": "github.com/Azure/azure-sdk-for-go/storage",