forked from TrueCloudLab/restic
Update bazil.org/fuse version
This commit is contained in:
parent
32a321e51e
commit
3a82612244
30 changed files with 2062 additions and 597 deletions
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
|
@ -7,7 +7,7 @@
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "bazil.org/fuse",
|
"ImportPath": "bazil.org/fuse",
|
||||||
"Rev": "6312e7c7c12b9337021a37aff2b0f655f4709688"
|
"Rev": "18419ee53958df28fcfc9490fe6123bd59e237bb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/jessevdk/go-flags",
|
"ImportPath": "github.com/jessevdk/go-flags",
|
||||||
|
|
3
Godeps/_workspace/src/bazil.org/fuse/.gitignore
generated
vendored
3
Godeps/_workspace/src/bazil.org/fuse/.gitignore
generated
vendored
|
@ -6,3 +6,6 @@
|
||||||
.*.swp
|
.*.swp
|
||||||
|
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
/clockfs
|
||||||
|
/hellofs
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/README.md
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/README.md
generated
vendored
|
@ -15,7 +15,7 @@ Here’s how to get going:
|
||||||
|
|
||||||
Website: http://bazil.org/fuse/
|
Website: http://bazil.org/fuse/
|
||||||
|
|
||||||
Github repository: https://github.com/bazillion/fuse
|
Github repository: https://github.com/bazil/fuse
|
||||||
|
|
||||||
API docs: http://godoc.org/bazil.org/fuse
|
API docs: http://godoc.org/bazil.org/fuse
|
||||||
|
|
||||||
|
|
35
Godeps/_workspace/src/bazil.org/fuse/buffer.go
generated
vendored
Normal file
35
Godeps/_workspace/src/bazil.org/fuse/buffer.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
173
Godeps/_workspace/src/bazil.org/fuse/examples/clockfs/clockfs.go
generated
vendored
Normal file
173
Godeps/_workspace/src/bazil.org/fuse/examples/clockfs/clockfs.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
// Clockfs implements a file system with the current time in a file.
|
||||||
|
// It was written to demonstrate kernel cache invalidation.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"bazil.org/fuse"
|
||||||
|
"bazil.org/fuse/fs"
|
||||||
|
_ "bazil.org/fuse/fs/fstestutil"
|
||||||
|
"bazil.org/fuse/fuseutil"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " %s MOUNTPOINT\n", os.Args[0])
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() != 1 {
|
||||||
|
usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
mountpoint := flag.Arg(0)
|
||||||
|
|
||||||
|
c, err := fuse.Mount(
|
||||||
|
mountpoint,
|
||||||
|
fuse.FSName("clock"),
|
||||||
|
fuse.Subtype("clockfsfs"),
|
||||||
|
fuse.LocalVolume(),
|
||||||
|
fuse.VolumeName("Clock filesystem"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
srv := fs.New(c, nil)
|
||||||
|
filesys := &FS{
|
||||||
|
// We pre-create the clock node so that it's always the same
|
||||||
|
// object returned from all the Lookups. You could carefully
|
||||||
|
// track its lifetime between Lookup&Forget, and have the
|
||||||
|
// ticking & invalidation happen only when active, but let's
|
||||||
|
// keep this example simple.
|
||||||
|
clockFile: &File{
|
||||||
|
fuse: srv,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
filesys.clockFile.tick()
|
||||||
|
// This goroutine never exits. That's fine for this example.
|
||||||
|
go filesys.clockFile.update()
|
||||||
|
if err := srv.Serve(filesys); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mount process has an error to report.
|
||||||
|
<-c.Ready
|
||||||
|
if err := c.MountError; err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FS struct {
|
||||||
|
clockFile *File
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.FS = (*FS)(nil)
|
||||||
|
|
||||||
|
func (f *FS) Root() (fs.Node, error) {
|
||||||
|
return &Dir{fs: f}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dir implements both Node and Handle for the root directory.
|
||||||
|
type Dir struct {
|
||||||
|
fs *FS
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.Node = (*Dir)(nil)
|
||||||
|
|
||||||
|
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
|
a.Inode = 1
|
||||||
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.NodeStringLookuper = (*Dir)(nil)
|
||||||
|
|
||||||
|
func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
|
if name == "clock" {
|
||||||
|
return d.fs.clockFile, nil
|
||||||
|
}
|
||||||
|
return nil, fuse.ENOENT
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirDirs = []fuse.Dirent{
|
||||||
|
{Inode: 2, Name: "clock", Type: fuse.DT_File},
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.HandleReadDirAller = (*Dir)(nil)
|
||||||
|
|
||||||
|
func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||||
|
return dirDirs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
fs.NodeRef
|
||||||
|
fuse *fs.Server
|
||||||
|
content atomic.Value
|
||||||
|
count uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.Node = (*File)(nil)
|
||||||
|
|
||||||
|
func (f *File) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
|
a.Inode = 2
|
||||||
|
a.Mode = 0444
|
||||||
|
t := f.content.Load().(string)
|
||||||
|
a.Size = uint64(len(t))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.NodeOpener = (*File)(nil)
|
||||||
|
|
||||||
|
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
||||||
|
if !req.Flags.IsReadOnly() {
|
||||||
|
return nil, fuse.Errno(syscall.EACCES)
|
||||||
|
}
|
||||||
|
resp.Flags |= fuse.OpenKeepCache
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fs.Handle = (*File)(nil)
|
||||||
|
|
||||||
|
var _ fs.HandleReader = (*File)(nil)
|
||||||
|
|
||||||
|
func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
||||||
|
t := f.content.Load().(string)
|
||||||
|
fuseutil.HandleRead(req, resp, []byte(t))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) tick() {
|
||||||
|
// Intentionally a variable-length format, to demonstrate size changes.
|
||||||
|
f.count++
|
||||||
|
s := fmt.Sprintf("%d\t%s\n", f.count, time.Now())
|
||||||
|
f.content.Store(s)
|
||||||
|
|
||||||
|
// For simplicity, this example tries to send invalidate
|
||||||
|
// notifications even when the kernel does not hold a reference to
|
||||||
|
// the node, so be extra sure to ignore ErrNotCached.
|
||||||
|
if err := f.fuse.InvalidateNodeData(f); err != nil && err != fuse.ErrNotCached {
|
||||||
|
log.Printf("invalidate error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) update() {
|
||||||
|
tick := time.NewTicker(1 * time.Second)
|
||||||
|
defer tick.Stop()
|
||||||
|
for range tick.C {
|
||||||
|
f.tick()
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,9 +63,10 @@ func (FS) Root() (fs.Node, error) {
|
||||||
// Dir implements both Node and Handle for the root directory.
|
// Dir implements both Node and Handle for the root directory.
|
||||||
type Dir struct{}
|
type Dir struct{}
|
||||||
|
|
||||||
func (Dir) Attr(a *fuse.Attr) {
|
func (Dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = 1
|
a.Inode = 1
|
||||||
a.Mode = os.ModeDir | 0555
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
|
@ -88,10 +89,11 @@ type File struct{}
|
||||||
|
|
||||||
const greeting = "hello, world\n"
|
const greeting = "hello, world\n"
|
||||||
|
|
||||||
func (File) Attr(a *fuse.Attr) {
|
func (File) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = 2
|
a.Inode = 2
|
||||||
a.Mode = 0444
|
a.Mode = 0444
|
||||||
a.Size = uint64(len(greeting))
|
a.Size = uint64(len(greeting))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (File) ReadAll(ctx context.Context) ([]byte, error) {
|
func (File) ReadAll(ctx context.Context) ([]byte, error) {
|
25
Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go
generated
vendored
25
Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go
generated
vendored
|
@ -22,13 +22,6 @@ type benchFS struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = fs.FS(benchFS{})
|
var _ = fs.FS(benchFS{})
|
||||||
var _ = fs.FSIniter(benchFS{})
|
|
||||||
|
|
||||||
func (benchFS) Init(ctx context.Context, req *fuse.InitRequest, resp *fuse.InitResponse) error {
|
|
||||||
resp.MaxReadahead = 64 * 1024 * 1024
|
|
||||||
resp.Flags |= fuse.InitAsyncRead
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f benchFS) Root() (fs.Node, error) {
|
func (f benchFS) Root() (fs.Node, error) {
|
||||||
return benchDir{conf: f.conf}, nil
|
return benchDir{conf: f.conf}, nil
|
||||||
|
@ -43,9 +36,10 @@ var _ = fs.NodeStringLookuper(benchDir{})
|
||||||
var _ = fs.Handle(benchDir{})
|
var _ = fs.Handle(benchDir{})
|
||||||
var _ = fs.HandleReadDirAller(benchDir{})
|
var _ = fs.HandleReadDirAller(benchDir{})
|
||||||
|
|
||||||
func (benchDir) Attr(a *fuse.Attr) {
|
func (benchDir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = 1
|
a.Inode = 1
|
||||||
a.Mode = os.ModeDir | 0555
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d benchDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
func (d benchDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
|
@ -73,10 +67,11 @@ var _ = fs.Handle(benchFile{})
|
||||||
var _ = fs.HandleReader(benchFile{})
|
var _ = fs.HandleReader(benchFile{})
|
||||||
var _ = fs.HandleWriter(benchFile{})
|
var _ = fs.HandleWriter(benchFile{})
|
||||||
|
|
||||||
func (benchFile) Attr(a *fuse.Attr) {
|
func (benchFile) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = 2
|
a.Inode = 2
|
||||||
a.Mode = 0644
|
a.Mode = 0644
|
||||||
a.Size = 9999999999999999
|
a.Size = 9999999999999999
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f benchFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
func (f benchFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
||||||
|
@ -103,12 +98,14 @@ func (benchFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmark(b *testing.B, fn func(b *testing.B, mnt string), conf *benchConfig) {
|
func benchmark(b *testing.B, fn func(b *testing.B, mnt string), conf *benchConfig) {
|
||||||
srv := &fs.Server{
|
filesys := benchFS{
|
||||||
FS: benchFS{
|
conf: conf,
|
||||||
conf: conf,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
mnt, err := fstestutil.Mounted(srv)
|
mnt, err := fstestutil.Mounted(filesys, nil,
|
||||||
|
fuse.MaxReadahead(64*1024*1024),
|
||||||
|
fuse.AsyncRead(),
|
||||||
|
fuse.WritebackCache(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
34
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
generated
vendored
34
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
generated
vendored
|
@ -17,7 +17,8 @@ type Mount struct {
|
||||||
// Dir is the temporary directory where the filesystem is mounted.
|
// Dir is the temporary directory where the filesystem is mounted.
|
||||||
Dir string
|
Dir string
|
||||||
|
|
||||||
Conn *fuse.Conn
|
Conn *fuse.Conn
|
||||||
|
Server *fs.Server
|
||||||
|
|
||||||
// Error will receive the return value of Serve.
|
// Error will receive the return value of Serve.
|
||||||
Error <-chan error
|
Error <-chan error
|
||||||
|
@ -55,7 +56,7 @@ func (mnt *Mount) Close() {
|
||||||
// workaround).
|
// workaround).
|
||||||
//
|
//
|
||||||
// After successful return, caller must clean up by calling Close.
|
// After successful return, caller must clean up by calling Close.
|
||||||
func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) {
|
func Mounted(filesys fs.FS, conf *fs.Config, options ...fuse.MountOption) (*Mount, error) {
|
||||||
dir, err := ioutil.TempDir("", "fusetest")
|
dir, err := ioutil.TempDir("", "fusetest")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -64,26 +65,27 @@ func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
server := fs.New(c, conf)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
serveErr := make(chan error, 1)
|
serveErr := make(chan error, 1)
|
||||||
mnt := &Mount{
|
mnt := &Mount{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
Conn: c,
|
Conn: c,
|
||||||
Error: serveErr,
|
Server: server,
|
||||||
done: done,
|
Error: serveErr,
|
||||||
|
done: done,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
serveErr <- srv.Serve(c)
|
serveErr <- server.Serve(filesys)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-mnt.Conn.Ready:
|
case <-mnt.Conn.Ready:
|
||||||
if mnt.Conn.MountError != nil {
|
if err := mnt.Conn.MountError; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return mnt, err
|
return mnt, nil
|
||||||
case err = <-mnt.Error:
|
case err = <-mnt.Error:
|
||||||
// Serve quit early
|
// Serve quit early
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,14 +102,14 @@ func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) {
|
||||||
//
|
//
|
||||||
// The debug log is not enabled by default. Use `-fuse.debug` or call
|
// The debug log is not enabled by default. Use `-fuse.debug` or call
|
||||||
// DebugByDefault to enable.
|
// DebugByDefault to enable.
|
||||||
func MountedT(t testing.TB, filesys fs.FS, options ...fuse.MountOption) (*Mount, error) {
|
func MountedT(t testing.TB, filesys fs.FS, conf *fs.Config, options ...fuse.MountOption) (*Mount, error) {
|
||||||
srv := &fs.Server{
|
if conf == nil {
|
||||||
FS: filesys,
|
conf = &fs.Config{}
|
||||||
}
|
}
|
||||||
if debug {
|
if debug && conf.Debug == nil {
|
||||||
srv.Debug = func(msg interface{}) {
|
conf.Debug = func(msg interface{}) {
|
||||||
t.Logf("FUSE: %s", msg)
|
t.Logf("FUSE: %s", msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Mounted(srv, options...)
|
return Mounted(filesys, conf, options...)
|
||||||
}
|
}
|
||||||
|
|
5
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go
generated
vendored
5
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go
generated
vendored
|
@ -35,7 +35,7 @@ type Counter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Counter) Inc() {
|
func (r *Counter) Inc() {
|
||||||
atomic.StoreUint32(&r.count, 1)
|
atomic.AddUint32(&r.count, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Counter) Count() uint32 {
|
func (r *Counter) Count() uint32 {
|
||||||
|
@ -341,6 +341,9 @@ var _ = fs.NodeSetxattrer(&Setxattrs{})
|
||||||
// wrap this call in a function that returns a more useful result.
|
// wrap this call in a function that returns a more useful result.
|
||||||
func (r *Setxattrs) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error {
|
func (r *Setxattrs) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error {
|
||||||
tmp := *req
|
tmp := *req
|
||||||
|
// The byte slice points to memory that will be reused, so make a
|
||||||
|
// deep copy.
|
||||||
|
tmp.Xattr = append([]byte(nil), req.Xattr...)
|
||||||
r.rec.RecordRequest(&tmp)
|
r.rec.RecordRequest(&tmp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
17
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
generated
vendored
17
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
generated
vendored
|
@ -22,29 +22,32 @@ func (f SimpleFS) Root() (fs.Node, error) {
|
||||||
// File can be embedded in a struct to make it look like a file.
|
// File can be embedded in a struct to make it look like a file.
|
||||||
type File struct{}
|
type File struct{}
|
||||||
|
|
||||||
func (f File) Attr(a *fuse.Attr) {
|
func (f File) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Mode = 0666
|
a.Mode = 0666
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dir can be embedded in a struct to make it look like a directory.
|
// Dir can be embedded in a struct to make it look like a directory.
|
||||||
type Dir struct{}
|
type Dir struct{}
|
||||||
|
|
||||||
func (f Dir) Attr(a *fuse.Attr) {
|
func (f Dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Mode = os.ModeDir | 0777
|
a.Mode = os.ModeDir | 0777
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChildMap is a directory with child nodes looked up from a map.
|
// ChildMap is a directory with child nodes looked up from a map.
|
||||||
type ChildMap map[string]fs.Node
|
type ChildMap map[string]fs.Node
|
||||||
|
|
||||||
var _ = fs.Node(ChildMap{})
|
var _ = fs.Node(&ChildMap{})
|
||||||
var _ = fs.NodeStringLookuper(ChildMap{})
|
var _ = fs.NodeStringLookuper(&ChildMap{})
|
||||||
|
|
||||||
func (f ChildMap) Attr(a *fuse.Attr) {
|
func (f *ChildMap) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Mode = os.ModeDir | 0777
|
a.Mode = os.ModeDir | 0777
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f ChildMap) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
func (f *ChildMap) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
child, ok := f[name]
|
child, ok := (*f)[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fuse.ENOENT
|
return nil, fuse.ENOENT
|
||||||
}
|
}
|
||||||
|
|
505
Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
generated
vendored
505
Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
generated
vendored
|
@ -7,7 +7,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -30,19 +32,12 @@ const (
|
||||||
// An FS is the interface required of a file system.
|
// An FS is the interface required of a file system.
|
||||||
//
|
//
|
||||||
// Other FUSE requests can be handled by implementing methods from the
|
// Other FUSE requests can be handled by implementing methods from the
|
||||||
// FS* interfaces, for example FSIniter.
|
// FS* interfaces, for example FSStatfser.
|
||||||
type FS interface {
|
type FS interface {
|
||||||
// Root is called to obtain the Node for the file system root.
|
// Root is called to obtain the Node for the file system root.
|
||||||
Root() (Node, error)
|
Root() (Node, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FSIniter interface {
|
|
||||||
// Init is called to initialize the FUSE connection.
|
|
||||||
// It can inspect the request and adjust the response as desired.
|
|
||||||
// Init must return promptly.
|
|
||||||
Init(ctx context.Context, req *fuse.InitRequest, resp *fuse.InitResponse) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type FSStatfser interface {
|
type FSStatfser interface {
|
||||||
// Statfs is called to obtain file system metadata.
|
// Statfs is called to obtain file system metadata.
|
||||||
// It should write that data to resp.
|
// It should write that data to resp.
|
||||||
|
@ -81,10 +76,20 @@ type FSInodeGenerator interface {
|
||||||
// See the documentation for type FS for general information
|
// See the documentation for type FS for general information
|
||||||
// pertaining to all methods.
|
// 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
|
// Other FUSE requests can be handled by implementing methods from the
|
||||||
// Node* interfaces, for example NodeOpener.
|
// 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 {
|
type Node interface {
|
||||||
Attr(*fuse.Attr)
|
// Attr fills attr with the standard metadata for the node.
|
||||||
|
Attr(ctx context.Context, attr *fuse.Attr) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeGetattrer interface {
|
type NodeGetattrer interface {
|
||||||
|
@ -152,7 +157,7 @@ type NodeStringLookuper interface {
|
||||||
// Lookup looks up a specific entry in the receiver,
|
// Lookup looks up a specific entry in the receiver,
|
||||||
// which must be a directory. Lookup should return a Node
|
// which must be a directory. Lookup should return a Node
|
||||||
// corresponding to the entry. If the name does not exist in
|
// corresponding to the entry. If the name does not exist in
|
||||||
// the directory, Lookup should return nil, err.
|
// the directory, Lookup should return ENOENT.
|
||||||
//
|
//
|
||||||
// Lookup need not to handle the names "." and "..".
|
// Lookup need not to handle the names "." and "..".
|
||||||
Lookup(ctx context.Context, name string) (Node, error)
|
Lookup(ctx context.Context, name string) (Node, error)
|
||||||
|
@ -238,14 +243,17 @@ type NodeRemovexattrer interface {
|
||||||
|
|
||||||
var startTime = time.Now()
|
var startTime = time.Now()
|
||||||
|
|
||||||
func nodeAttr(n Node) (attr fuse.Attr) {
|
func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error {
|
||||||
|
attr.Valid = attrValidTime
|
||||||
attr.Nlink = 1
|
attr.Nlink = 1
|
||||||
attr.Atime = startTime
|
attr.Atime = startTime
|
||||||
attr.Mtime = startTime
|
attr.Mtime = startTime
|
||||||
attr.Ctime = startTime
|
attr.Ctime = startTime
|
||||||
attr.Crtime = startTime
|
attr.Crtime = startTime
|
||||||
n.Attr(&attr)
|
if err := n.Attr(ctx, attr); err != nil {
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Handle is the interface required of an opened file or directory.
|
// A Handle is the interface required of an opened file or directory.
|
||||||
|
@ -306,43 +314,97 @@ type HandleReleaser interface {
|
||||||
Release(ctx context.Context, req *fuse.ReleaseRequest) error
|
Release(ctx context.Context, req *fuse.ReleaseRequest) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Config struct {
|
||||||
FS FS
|
|
||||||
|
|
||||||
// Function to send debug log messages to. If nil, use fuse.Debug.
|
// Function to send debug log messages to. If nil, use fuse.Debug.
|
||||||
// Note that changing this or fuse.Debug may not affect existing
|
// Note that changing this or fuse.Debug may not affect existing
|
||||||
// calls to Serve.
|
// calls to Serve.
|
||||||
//
|
//
|
||||||
// See fuse.Debug for the rules that log functions must follow.
|
// See fuse.Debug for the rules that log functions must follow.
|
||||||
Debug func(msg interface{})
|
Debug func(msg interface{})
|
||||||
|
|
||||||
|
// Function to create new contexts. If nil, use
|
||||||
|
// context.Background.
|
||||||
|
//
|
||||||
|
// Note that changing this may not affect existing calls to Serve.
|
||||||
|
GetContext func() 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.GetContext
|
||||||
|
}
|
||||||
|
if s.debug == nil {
|
||||||
|
s.debug = fuse.Debug
|
||||||
|
}
|
||||||
|
if s.context == nil {
|
||||||
|
s.context = context.Background
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
// set in New
|
||||||
|
conn *fuse.Conn
|
||||||
|
debug func(msg interface{})
|
||||||
|
context func() 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
|
// Serve serves the FUSE connection by making calls to the methods
|
||||||
// of fs and the Nodes and Handles it makes available. It returns only
|
// of fs and the Nodes and Handles it makes available. It returns only
|
||||||
// when the connection has been closed or an unexpected error occurs.
|
// when the connection has been closed or an unexpected error occurs.
|
||||||
func (s *Server) Serve(c *fuse.Conn) error {
|
func (s *Server) Serve(fs FS) error {
|
||||||
sc := serveConn{
|
defer s.wg.Wait() // Wait for worker goroutines to complete before return
|
||||||
fs: s.FS,
|
|
||||||
debug: s.Debug,
|
s.fs = fs
|
||||||
req: map[fuse.RequestID]*serveRequest{},
|
if dyn, ok := fs.(FSInodeGenerator); ok {
|
||||||
dynamicInode: GenerateDynamicInode,
|
s.dynamicInode = dyn.GenerateInode
|
||||||
}
|
|
||||||
if sc.debug == nil {
|
|
||||||
sc.debug = fuse.Debug
|
|
||||||
}
|
|
||||||
if dyn, ok := sc.fs.(FSInodeGenerator); ok {
|
|
||||||
sc.dynamicInode = dyn.GenerateInode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root, err := sc.fs.Root()
|
root, err := fs.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot obtain root node: %v", err)
|
return fmt.Errorf("cannot obtain root node: %v", err)
|
||||||
}
|
}
|
||||||
sc.node = append(sc.node, nil, &serveNode{inode: 1, node: root, refs: 1})
|
// Recognize the root node if it's ever returned from Lookup,
|
||||||
sc.handle = append(sc.handle, nil)
|
// 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 {
|
for {
|
||||||
req, err := c.ReadRequest()
|
req, err := s.conn.ReadRequest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
|
@ -350,7 +412,11 @@ func (s *Server) Serve(c *fuse.Conn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go sc.serve(req)
|
s.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer s.wg.Done()
|
||||||
|
s.serve(req)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -358,44 +424,40 @@ func (s *Server) Serve(c *fuse.Conn) error {
|
||||||
// Serve serves a FUSE connection with the default settings. See
|
// Serve serves a FUSE connection with the default settings. See
|
||||||
// Server.Serve.
|
// Server.Serve.
|
||||||
func Serve(c *fuse.Conn, fs FS) error {
|
func Serve(c *fuse.Conn, fs FS) error {
|
||||||
server := Server{
|
server := New(c, nil)
|
||||||
FS: fs,
|
return server.Serve(fs)
|
||||||
}
|
|
||||||
return server.Serve(c)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type nothing struct{}
|
type nothing struct{}
|
||||||
|
|
||||||
type serveConn struct {
|
|
||||||
meta sync.Mutex
|
|
||||||
fs FS
|
|
||||||
req map[fuse.RequestID]*serveRequest
|
|
||||||
node []*serveNode
|
|
||||||
handle []*serveHandle
|
|
||||||
freeNode []fuse.NodeID
|
|
||||||
freeHandle []fuse.HandleID
|
|
||||||
nodeGen uint64
|
|
||||||
debug func(msg interface{})
|
|
||||||
dynamicInode func(parent uint64, name string) uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type serveRequest struct {
|
type serveRequest struct {
|
||||||
Request fuse.Request
|
Request fuse.Request
|
||||||
cancel func()
|
cancel func()
|
||||||
}
|
}
|
||||||
|
|
||||||
type serveNode struct {
|
type serveNode struct {
|
||||||
inode uint64
|
inode uint64
|
||||||
node Node
|
generation uint64
|
||||||
refs 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() (attr fuse.Attr) {
|
func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error {
|
||||||
attr = nodeAttr(sn.node)
|
err := nodeAttr(ctx, sn.node, attr)
|
||||||
if attr.Inode == 0 {
|
if attr.Inode == 0 {
|
||||||
attr.Inode = sn.inode
|
attr.Inode = sn.inode
|
||||||
}
|
}
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type serveHandle struct {
|
type serveHandle struct {
|
||||||
|
@ -404,42 +466,20 @@ type serveHandle struct {
|
||||||
nodeID fuse.NodeID
|
nodeID fuse.NodeID
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeRef can be embedded in a Node to recognize the same Node being
|
// NodeRef is deprecated. It remains here to decrease code churn on
|
||||||
// returned from multiple Lookup, Create etc calls.
|
// FUSE library users. You may remove it from your program now;
|
||||||
//
|
// returning the same Node values are now recognized automatically,
|
||||||
// Without this, each Node will get a new NodeID, causing spurious
|
// without needing NodeRef.
|
||||||
// cache invalidations, extra lookups and aliasing anomalies. This may
|
type NodeRef struct{}
|
||||||
// not matter for a simple, read-only filesystem.
|
|
||||||
type NodeRef struct {
|
|
||||||
id fuse.NodeID
|
|
||||||
generation uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// nodeRef is only ever accessed while holding serveConn.meta
|
func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) {
|
||||||
func (n *NodeRef) nodeRef() *NodeRef {
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
type nodeRef interface {
|
|
||||||
nodeRef() *NodeRef
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *serveConn) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) {
|
|
||||||
c.meta.Lock()
|
c.meta.Lock()
|
||||||
defer c.meta.Unlock()
|
defer c.meta.Unlock()
|
||||||
|
|
||||||
var ref *NodeRef
|
if id, ok := c.nodeRef[node]; ok {
|
||||||
if nodeRef, ok := node.(nodeRef); ok {
|
sn := c.node[id]
|
||||||
ref = nodeRef.nodeRef()
|
sn.refs++
|
||||||
|
return id, sn.generation
|
||||||
if ref.id != 0 {
|
|
||||||
// dropNode guarantees that NodeRef is zeroed at the same
|
|
||||||
// time as the NodeID is removed from serveConn.node, as
|
|
||||||
// guarded by c.meta; this means sn cannot be nil here
|
|
||||||
sn := c.node[ref.id]
|
|
||||||
sn.refs++
|
|
||||||
return ref.id, ref.generation
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sn := &serveNode{inode: inode, node: node, refs: 1}
|
sn := &serveNode{inode: inode, node: node, refs: 1}
|
||||||
|
@ -452,15 +492,12 @@ func (c *serveConn) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint6
|
||||||
id = fuse.NodeID(len(c.node))
|
id = fuse.NodeID(len(c.node))
|
||||||
c.node = append(c.node, sn)
|
c.node = append(c.node, sn)
|
||||||
}
|
}
|
||||||
gen = c.nodeGen
|
sn.generation = c.nodeGen
|
||||||
if ref != nil {
|
c.nodeRef[node] = id
|
||||||
ref.id = id
|
|
||||||
ref.generation = gen
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serveConn) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) {
|
func (c *Server) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) {
|
||||||
c.meta.Lock()
|
c.meta.Lock()
|
||||||
shandle := &serveHandle{handle: handle, nodeID: nodeID}
|
shandle := &serveHandle{handle: handle, nodeID: nodeID}
|
||||||
if n := len(c.freeHandle); n > 0 {
|
if n := len(c.freeHandle); n > 0 {
|
||||||
|
@ -485,7 +522,7 @@ func (n *nodeRefcountDropBug) String() string {
|
||||||
return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node)
|
return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serveConn) dropNode(id fuse.NodeID, n uint64) (forget bool) {
|
func (c *Server) dropNode(id fuse.NodeID, n uint64) (forget bool) {
|
||||||
c.meta.Lock()
|
c.meta.Lock()
|
||||||
defer c.meta.Unlock()
|
defer c.meta.Unlock()
|
||||||
snode := c.node[id]
|
snode := c.node[id]
|
||||||
|
@ -508,18 +545,16 @@ func (c *serveConn) dropNode(id fuse.NodeID, n uint64) (forget bool) {
|
||||||
|
|
||||||
snode.refs -= n
|
snode.refs -= n
|
||||||
if snode.refs == 0 {
|
if snode.refs == 0 {
|
||||||
|
snode.wg.Wait()
|
||||||
c.node[id] = nil
|
c.node[id] = nil
|
||||||
if nodeRef, ok := snode.node.(nodeRef); ok {
|
delete(c.nodeRef, snode.node)
|
||||||
ref := nodeRef.nodeRef()
|
|
||||||
*ref = NodeRef{}
|
|
||||||
}
|
|
||||||
c.freeNode = append(c.freeNode, id)
|
c.freeNode = append(c.freeNode, id)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serveConn) dropHandle(id fuse.HandleID) {
|
func (c *Server) dropHandle(id fuse.HandleID) {
|
||||||
c.meta.Lock()
|
c.meta.Lock()
|
||||||
c.handle[id] = nil
|
c.handle[id] = nil
|
||||||
c.freeHandle = append(c.freeHandle, id)
|
c.freeHandle = append(c.freeHandle, id)
|
||||||
|
@ -532,11 +567,11 @@ type missingHandle struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m missingHandle) String() string {
|
func (m missingHandle) String() string {
|
||||||
return fmt.Sprint("missing handle", m.Handle, m.MaxHandle)
|
return fmt.Sprint("missing handle: ", m.Handle, m.MaxHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns nil for invalid handles.
|
// Returns nil for invalid handles.
|
||||||
func (c *serveConn) getHandle(id fuse.HandleID) (shandle *serveHandle) {
|
func (c *Server) getHandle(id fuse.HandleID) (shandle *serveHandle) {
|
||||||
c.meta.Lock()
|
c.meta.Lock()
|
||||||
defer c.meta.Unlock()
|
defer c.meta.Unlock()
|
||||||
if id < fuse.HandleID(len(c.handle)) {
|
if id < fuse.HandleID(len(c.handle)) {
|
||||||
|
@ -609,6 +644,30 @@ func (r response) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type notification struct {
|
||||||
|
Op string
|
||||||
|
Node fuse.NodeID
|
||||||
|
Out interface{} `json:",omitempty"`
|
||||||
|
Err string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n notification) String() string {
|
||||||
|
switch {
|
||||||
|
case n.Out != nil:
|
||||||
|
// make sure (seemingly) empty values are readable
|
||||||
|
switch n.Out.(type) {
|
||||||
|
case string:
|
||||||
|
return fmt.Sprintf("=> %s %d %q Err:%v", n.Op, n.Node, n.Out, n.Err)
|
||||||
|
case []byte:
|
||||||
|
return fmt.Sprintf("=> %s %d [% x] Err:%v", n.Op, n.Node, n.Out, n.Err)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("=> %s %d %s Err:%v", n.Op, n.Node, n.Out, n.Err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("=> %s %d Err:%v", n.Op, n.Node, n.Err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type logMissingNode struct {
|
type logMissingNode struct {
|
||||||
MaxNode fuse.NodeID
|
MaxNode fuse.NodeID
|
||||||
}
|
}
|
||||||
|
@ -638,8 +697,32 @@ func (m *renameNewDirNodeNotFound) String() string {
|
||||||
return fmt.Sprintf("In RenameRequest (request %#x), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
|
return fmt.Sprintf("In RenameRequest (request %#x), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serveConn) serve(r fuse.Request) {
|
type handlerPanickedError struct {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLookupResponse(s *fuse.LookupResponse) {
|
||||||
|
s.EntryValid = entryValidTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Server) serve(r fuse.Request) {
|
||||||
|
ctx, cancel := context.WithCancel(c.context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &serveRequest{Request: r, cancel: cancel}
|
req := &serveRequest{Request: r, cancel: cancel}
|
||||||
|
@ -717,6 +800,22 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
c.meta.Unlock()
|
c.meta.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
switch r := r.(type) {
|
switch r := r.(type) {
|
||||||
default:
|
default:
|
||||||
// Note: To FUSE, ENOSYS means "this server never implements this request."
|
// Note: To FUSE, ENOSYS means "this server never implements this request."
|
||||||
|
@ -725,22 +824,6 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
done(fuse.ENOSYS)
|
done(fuse.ENOSYS)
|
||||||
r.RespondError(fuse.ENOSYS)
|
r.RespondError(fuse.ENOSYS)
|
||||||
|
|
||||||
// FS operations.
|
|
||||||
case *fuse.InitRequest:
|
|
||||||
s := &fuse.InitResponse{
|
|
||||||
MaxWrite: 128 * 1024,
|
|
||||||
Flags: fuse.InitBigWrites,
|
|
||||||
}
|
|
||||||
if fs, ok := c.fs.(FSIniter); ok {
|
|
||||||
if err := fs.Init(ctx, r, s); err != nil {
|
|
||||||
done(err)
|
|
||||||
r.RespondError(err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done(s)
|
|
||||||
r.Respond(s)
|
|
||||||
|
|
||||||
case *fuse.StatfsRequest:
|
case *fuse.StatfsRequest:
|
||||||
s := &fuse.StatfsResponse{}
|
s := &fuse.StatfsResponse{}
|
||||||
if fs, ok := c.fs.(FSStatfser); ok {
|
if fs, ok := c.fs.(FSStatfser); ok {
|
||||||
|
@ -763,8 +846,11 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.AttrValid = attrValidTime
|
if err := snode.attr(ctx, &s.Attr); err != nil {
|
||||||
s.Attr = snode.attr()
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
@ -782,15 +868,17 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.AttrValid == 0 {
|
if err := snode.attr(ctx, &s.Attr); err != nil {
|
||||||
s.AttrValid = attrValidTime
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
s.Attr = snode.attr()
|
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
case *fuse.SymlinkRequest:
|
case *fuse.SymlinkRequest:
|
||||||
s := &fuse.SymlinkResponse{}
|
s := &fuse.SymlinkResponse{}
|
||||||
|
initLookupResponse(&s.LookupResponse)
|
||||||
n, ok := node.(NodeSymlinker)
|
n, ok := node.(NodeSymlinker)
|
||||||
if !ok {
|
if !ok {
|
||||||
done(fuse.EIO) // XXX or EPERM like Mkdir?
|
done(fuse.EIO) // XXX or EPERM like Mkdir?
|
||||||
|
@ -803,7 +891,11 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
r.RespondError(err)
|
r.RespondError(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
c.saveLookup(&s.LookupResponse, snode, r.NewName, n2)
|
if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
|
@ -852,7 +944,12 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s := &fuse.LookupResponse{}
|
s := &fuse.LookupResponse{}
|
||||||
c.saveLookup(s, snode, r.NewName, n2)
|
initLookupResponse(s)
|
||||||
|
if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
|
@ -887,6 +984,7 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
var n2 Node
|
var n2 Node
|
||||||
var err error
|
var err error
|
||||||
s := &fuse.LookupResponse{}
|
s := &fuse.LookupResponse{}
|
||||||
|
initLookupResponse(s)
|
||||||
if n, ok := node.(NodeStringLookuper); ok {
|
if n, ok := node.(NodeStringLookuper); ok {
|
||||||
n2, err = n.Lookup(ctx, r.Name)
|
n2, err = n.Lookup(ctx, r.Name)
|
||||||
} else if n, ok := node.(NodeRequestLookuper); ok {
|
} else if n, ok := node.(NodeRequestLookuper); ok {
|
||||||
|
@ -901,12 +999,17 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
r.RespondError(err)
|
r.RespondError(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
c.saveLookup(s, snode, r.Name, n2)
|
if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
case *fuse.MkdirRequest:
|
case *fuse.MkdirRequest:
|
||||||
s := &fuse.MkdirResponse{}
|
s := &fuse.MkdirResponse{}
|
||||||
|
initLookupResponse(&s.LookupResponse)
|
||||||
n, ok := node.(NodeMkdirer)
|
n, ok := node.(NodeMkdirer)
|
||||||
if !ok {
|
if !ok {
|
||||||
done(fuse.EPERM)
|
done(fuse.EPERM)
|
||||||
|
@ -919,7 +1022,11 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
r.RespondError(err)
|
r.RespondError(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
|
if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
|
@ -950,13 +1057,18 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
|
s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
|
||||||
|
initLookupResponse(&s.LookupResponse)
|
||||||
n2, h2, err := n.Create(ctx, r, s)
|
n2, h2, err := n.Create(ctx, r, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
done(err)
|
done(err)
|
||||||
r.RespondError(err)
|
r.RespondError(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
|
if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
s.Handle = c.saveHandle(h2, hdr.Node)
|
s.Handle = c.saveHandle(h2, hdr.Node)
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
@ -1232,7 +1344,12 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s := &fuse.LookupResponse{}
|
s := &fuse.LookupResponse{}
|
||||||
c.saveLookup(s, snode, r.Name, n2)
|
initLookupResponse(s)
|
||||||
|
if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
|
||||||
|
done(err)
|
||||||
|
r.RespondError(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
done(s)
|
done(s)
|
||||||
r.Respond(s)
|
r.Respond(s)
|
||||||
|
|
||||||
|
@ -1282,19 +1399,133 @@ func (c *serveConn) serve(r fuse.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serveConn) saveLookup(s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) {
|
func (c *Server) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error {
|
||||||
s.Attr = nodeAttr(n2)
|
if err := nodeAttr(ctx, n2, &s.Attr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if s.Attr.Inode == 0 {
|
if s.Attr.Inode == 0 {
|
||||||
s.Attr.Inode = c.dynamicInode(snode.inode, elem)
|
s.Attr.Inode = c.dynamicInode(snode.inode, elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
|
s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
|
||||||
if s.EntryValid == 0 {
|
return nil
|
||||||
s.EntryValid = entryValidTime
|
}
|
||||||
|
|
||||||
|
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 ""
|
||||||
}
|
}
|
||||||
if s.AttrValid == 0 {
|
return err.Error()
|
||||||
s.AttrValid = attrValidTime
|
}
|
||||||
|
|
||||||
|
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
|
// DataHandle returns a read-only Handle that satisfies reads
|
||||||
|
|
666
Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
generated
vendored
666
Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
3
Godeps/_workspace/src/bazil.org/fuse/fs/tree.go
generated
vendored
3
Godeps/_workspace/src/bazil.org/fuse/fs/tree.go
generated
vendored
|
@ -77,8 +77,9 @@ func (t *tree) add(name string, n Node) {
|
||||||
t.dir = append(t.dir, treeDir{name, n})
|
t.dir = append(t.dir, treeDir{name, n})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tree) Attr(a *fuse.Attr) {
|
func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Mode = os.ModeDir | 0555
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
|
func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
|
||||||
|
|
706
Godeps/_workspace/src/bazil.org/fuse/fuse.go
generated
vendored
706
Godeps/_workspace/src/bazil.org/fuse/fuse.go
generated
vendored
File diff suppressed because it is too large
Load diff
217
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
generated
vendored
217
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
generated
vendored
|
@ -41,13 +41,16 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version is the FUSE version implemented by the package.
|
// The FUSE version implemented by the package.
|
||||||
const Version = "7.8"
|
const (
|
||||||
|
protoVersionMinMajor = 7
|
||||||
|
protoVersionMinMinor = 8
|
||||||
|
protoVersionMaxMajor = 7
|
||||||
|
protoVersionMaxMinor = 12
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
kernelVersion = 7
|
rootID = 1
|
||||||
kernelMinorVersion = 8
|
|
||||||
rootID = 1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type kstatfs struct {
|
type kstatfs struct {
|
||||||
|
@ -70,6 +73,22 @@ type fileLock struct {
|
||||||
Pid 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
|
// The SetattrValid are bit flags describing which fields in the SetattrRequest
|
||||||
// are included in the change.
|
// are included in the change.
|
||||||
type SetattrValid uint32
|
type SetattrValid uint32
|
||||||
|
@ -207,7 +226,7 @@ type OpenResponseFlags uint32
|
||||||
const (
|
const (
|
||||||
OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file
|
OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file
|
||||||
OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
|
OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
|
||||||
OpenNonSeekable OpenResponseFlags = 1 << 2 // (Linux?)
|
OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X)
|
||||||
|
|
||||||
OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
|
OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
|
||||||
OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X
|
OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X
|
||||||
|
@ -220,6 +239,7 @@ func (fl OpenResponseFlags) String() string {
|
||||||
var openResponseFlagNames = []flagName{
|
var openResponseFlagNames = []flagName{
|
||||||
{uint32(OpenDirectIO), "OpenDirectIO"},
|
{uint32(OpenDirectIO), "OpenDirectIO"},
|
||||||
{uint32(OpenKeepCache), "OpenKeepCache"},
|
{uint32(OpenKeepCache), "OpenKeepCache"},
|
||||||
|
{uint32(OpenNonSeekable), "OpenNonSeekable"},
|
||||||
{uint32(OpenPurgeAttr), "OpenPurgeAttr"},
|
{uint32(OpenPurgeAttr), "OpenPurgeAttr"},
|
||||||
{uint32(OpenPurgeUBC), "OpenPurgeUBC"},
|
{uint32(OpenPurgeUBC), "OpenPurgeUBC"},
|
||||||
}
|
}
|
||||||
|
@ -368,7 +388,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type entryOut struct {
|
type entryOut struct {
|
||||||
outHeader
|
|
||||||
Nodeid uint64 // Inode ID
|
Nodeid uint64 // Inode ID
|
||||||
Generation uint64 // Inode generation
|
Generation uint64 // Inode generation
|
||||||
EntryValid uint64 // Cache timeout for the name
|
EntryValid uint64 // Cache timeout for the name
|
||||||
|
@ -378,21 +397,43 @@ type entryOut struct {
|
||||||
Attr attr
|
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 {
|
type forgetIn struct {
|
||||||
Nlookup uint64
|
Nlookup uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type getattrIn struct {
|
||||||
|
GetattrFlags uint32
|
||||||
|
dummy uint32
|
||||||
|
Fh uint64
|
||||||
|
}
|
||||||
|
|
||||||
type attrOut struct {
|
type attrOut struct {
|
||||||
outHeader
|
|
||||||
AttrValid uint64 // Cache timeout for the attributes
|
AttrValid uint64 // Cache timeout for the attributes
|
||||||
AttrValidNsec uint32
|
AttrValidNsec uint32
|
||||||
Dummy uint32
|
Dummy uint32
|
||||||
Attr attr
|
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
|
// OS X
|
||||||
type getxtimesOut struct {
|
type getxtimesOut struct {
|
||||||
outHeader
|
|
||||||
Bkuptime uint64
|
Bkuptime uint64
|
||||||
Crtime uint64
|
Crtime uint64
|
||||||
BkuptimeNsec uint32
|
BkuptimeNsec uint32
|
||||||
|
@ -400,17 +441,37 @@ type getxtimesOut struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type mknodIn struct {
|
type mknodIn struct {
|
||||||
Mode uint32
|
Mode uint32
|
||||||
Rdev uint32
|
Rdev uint32
|
||||||
|
Umask uint32
|
||||||
|
padding uint32
|
||||||
// "filename\x00" follows.
|
// "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 {
|
type mkdirIn struct {
|
||||||
Mode uint32
|
Mode uint32
|
||||||
Padding uint32
|
Umask uint32
|
||||||
// filename follows
|
// 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 {
|
type renameIn struct {
|
||||||
Newdir uint64
|
Newdir uint64
|
||||||
// "oldname\x00newname\x00" follows
|
// "oldname\x00newname\x00" follows
|
||||||
|
@ -452,31 +513,25 @@ type openIn struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type openOut struct {
|
type openOut struct {
|
||||||
outHeader
|
|
||||||
Fh uint64
|
Fh uint64
|
||||||
OpenFlags uint32
|
OpenFlags uint32
|
||||||
Padding uint32
|
Padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type createIn struct {
|
type createIn struct {
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Mode uint32
|
Mode uint32
|
||||||
|
Umask uint32
|
||||||
|
padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type createOut struct {
|
func createInSize(p Protocol) uintptr {
|
||||||
outHeader
|
switch {
|
||||||
|
case p.LT(Protocol{7, 12}):
|
||||||
Nodeid uint64 // Inode ID
|
return unsafe.Offsetof(createIn{}.Umask)
|
||||||
Generation uint64 // Inode generation
|
default:
|
||||||
EntryValid uint64 // Cache timeout for the name
|
return unsafe.Sizeof(createIn{})
|
||||||
AttrValid uint64 // Cache timeout for the attributes
|
}
|
||||||
EntryValidNsec uint32
|
|
||||||
AttrValidNsec uint32
|
|
||||||
Attr attr
|
|
||||||
|
|
||||||
Fh uint64
|
|
||||||
OpenFlags uint32
|
|
||||||
Padding uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type releaseIn struct {
|
type releaseIn struct {
|
||||||
|
@ -494,10 +549,38 @@ type flushIn struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type readIn struct {
|
type readIn struct {
|
||||||
Fh uint64
|
Fh uint64
|
||||||
Offset uint64
|
Offset uint64
|
||||||
Size uint32
|
Size uint32
|
||||||
Padding uint32
|
ReadFlags uint32
|
||||||
|
LockOwner uint64
|
||||||
|
Flags uint32
|
||||||
|
padding 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 {
|
type writeIn struct {
|
||||||
|
@ -505,10 +588,21 @@ type writeIn struct {
|
||||||
Offset uint64
|
Offset uint64
|
||||||
Size uint32
|
Size uint32
|
||||||
WriteFlags uint32
|
WriteFlags uint32
|
||||||
|
LockOwner uint64
|
||||||
|
Flags uint32
|
||||||
|
padding 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 {
|
type writeOut struct {
|
||||||
outHeader
|
|
||||||
Size uint32
|
Size uint32
|
||||||
Padding uint32
|
Padding uint32
|
||||||
}
|
}
|
||||||
|
@ -516,16 +610,24 @@ type writeOut struct {
|
||||||
// The WriteFlags are passed in WriteRequest.
|
// The WriteFlags are passed in WriteRequest.
|
||||||
type WriteFlags uint32
|
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 {
|
func (fl WriteFlags) String() string {
|
||||||
return flagString(uint32(fl), writeFlagNames)
|
return flagString(uint32(fl), writeFlagNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeFlagNames = []flagName{}
|
|
||||||
|
|
||||||
const compatStatfsSize = 48
|
const compatStatfsSize = 48
|
||||||
|
|
||||||
type statfsOut struct {
|
type statfsOut struct {
|
||||||
outHeader
|
|
||||||
St kstatfs
|
St kstatfs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,19 +656,28 @@ func (getxattrInCommon) position() uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
type getxattrOut struct {
|
type getxattrOut struct {
|
||||||
outHeader
|
|
||||||
Size uint32
|
Size uint32
|
||||||
Padding uint32
|
Padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type lkIn struct {
|
type lkIn struct {
|
||||||
Fh uint64
|
Fh uint64
|
||||||
Owner uint64
|
Owner uint64
|
||||||
Lk fileLock
|
Lk fileLock
|
||||||
|
LkFlags uint32
|
||||||
|
padding 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 {
|
type lkOut struct {
|
||||||
outHeader
|
|
||||||
Lk fileLock
|
Lk fileLock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +696,6 @@ type initIn struct {
|
||||||
const initInSize = int(unsafe.Sizeof(initIn{}))
|
const initInSize = int(unsafe.Sizeof(initIn{}))
|
||||||
|
|
||||||
type initOut struct {
|
type initOut struct {
|
||||||
outHeader
|
|
||||||
Major uint32
|
Major uint32
|
||||||
Minor uint32
|
Minor uint32
|
||||||
MaxReadahead uint32
|
MaxReadahead uint32
|
||||||
|
@ -605,7 +715,6 @@ type bmapIn struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type bmapOut struct {
|
type bmapOut struct {
|
||||||
outHeader
|
|
||||||
Block uint64
|
Block uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,3 +746,21 @@ type dirent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const direntSize = 8 + 8 + 4 + 4
|
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
|
||||||
|
padding uint32
|
||||||
|
}
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_darwin.go
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_darwin.go
generated
vendored
|
@ -22,6 +22,8 @@ type attr struct {
|
||||||
Gid uint32
|
Gid uint32
|
||||||
Rdev uint32
|
Rdev uint32
|
||||||
Flags_ uint32 // OS X only; see chflags(2)
|
Flags_ uint32 // OS X only; see chflags(2)
|
||||||
|
Blksize uint32
|
||||||
|
padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *attr) SetCrtime(s uint64, ns uint32) {
|
func (a *attr) SetCrtime(s uint64, ns uint32) {
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_freebsd.go
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_freebsd.go
generated
vendored
|
@ -17,6 +17,8 @@ type attr struct {
|
||||||
Uid uint32
|
Uid uint32
|
||||||
Gid uint32
|
Gid uint32
|
||||||
Rdev uint32
|
Rdev uint32
|
||||||
|
Blksize uint32
|
||||||
|
padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *attr) Crtime() time.Time {
|
func (a *attr) Crtime() time.Time {
|
||||||
|
|
4
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_linux.go
generated
vendored
4
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel_linux.go
generated
vendored
|
@ -17,8 +17,8 @@ type attr struct {
|
||||||
Uid uint32
|
Uid uint32
|
||||||
Gid uint32
|
Gid uint32
|
||||||
Rdev uint32
|
Rdev uint32
|
||||||
// Blksize uint32 // Only in protocol 7.9
|
Blksize uint32
|
||||||
// padding_ uint32 // Only in protocol 7.9
|
padding uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *attr) Crtime() time.Time {
|
func (a *attr) Crtime() time.Time {
|
||||||
|
|
4
Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
generated
vendored
4
Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
generated
vendored
|
@ -52,7 +52,7 @@ func openOSXFUSEDev() (*os.File, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func callMount(dir string, conf *MountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
|
func callMount(dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
|
||||||
bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
|
bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
|
||||||
|
|
||||||
for k, v := range conf.options {
|
for k, v := range conf.options {
|
||||||
|
@ -104,7 +104,7 @@ func callMount(dir string, conf *MountConfig, f *os.File, ready chan<- struct{},
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
||||||
f, err := openOSXFUSEDev()
|
f, err := openOSXFUSEDev()
|
||||||
if err == errNotLoaded {
|
if err == errNotLoaded {
|
||||||
err = loadOSXFUSE()
|
err = loadOSXFUSE()
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/mount_freebsd.go
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/mount_freebsd.go
generated
vendored
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
||||||
for k, v := range conf.options {
|
for k, v := range conf.options {
|
||||||
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
||||||
// Silly limitation but the mount helper does not
|
// Silly limitation but the mount helper does not
|
||||||
|
|
60
Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
generated
vendored
60
Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
generated
vendored
|
@ -1,14 +1,38 @@
|
||||||
package fuse
|
package fuse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
|
func lineLogger(wg *sync.WaitGroup, prefix string, r io.ReadCloser) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
switch line := scanner.Text(); line {
|
||||||
|
case `fusermount: failed to open /etc/fuse.conf: Permission denied`:
|
||||||
|
// Silence this particular message, it occurs way too
|
||||||
|
// commonly and isn't very relevant to whether the mount
|
||||||
|
// succeeds or not.
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
log.Printf("%s: %s", prefix, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Printf("%s, error reading: %v", prefix, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
|
||||||
// linux mount is never delayed
|
// linux mount is never delayed
|
||||||
close(ready)
|
close(ready)
|
||||||
|
|
||||||
|
@ -16,8 +40,12 @@ func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (f
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("socketpair error: %v", err)
|
return nil, fmt.Errorf("socketpair error: %v", err)
|
||||||
}
|
}
|
||||||
defer syscall.Close(fds[0])
|
|
||||||
defer syscall.Close(fds[1])
|
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(
|
cmd := exec.Command(
|
||||||
"fusermount",
|
"fusermount",
|
||||||
|
@ -27,17 +55,29 @@ func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (f
|
||||||
)
|
)
|
||||||
cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
|
cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
|
||||||
|
|
||||||
writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
|
|
||||||
defer writeFile.Close()
|
|
||||||
cmd.ExtraFiles = []*os.File{writeFile}
|
cmd.ExtraFiles = []*os.File{writeFile}
|
||||||
|
|
||||||
out, err := cmd.CombinedOutput()
|
var wg sync.WaitGroup
|
||||||
if len(out) > 0 || err != nil {
|
stdout, err := cmd.StdoutPipe()
|
||||||
return nil, fmt.Errorf("fusermount: %q, %v", out, err)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
||||||
|
}
|
||||||
|
stderr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, fmt.Errorf("fusermount: %v", err)
|
||||||
|
}
|
||||||
|
wg.Add(2)
|
||||||
|
go lineLogger(&wg, "mount helper output", stdout)
|
||||||
|
go lineLogger(&wg, "mount helper error", stderr)
|
||||||
|
wg.Wait()
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, fmt.Errorf("fusermount: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
|
|
||||||
defer readFile.Close()
|
|
||||||
c, err := net.FileConn(readFile)
|
c, err := net.FileConn(readFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
|
return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
|
||||||
|
|
62
Godeps/_workspace/src/bazil.org/fuse/options.go
generated
vendored
62
Godeps/_workspace/src/bazil.org/fuse/options.go
generated
vendored
|
@ -5,14 +5,16 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func dummyOption(conf *MountConfig) error {
|
func dummyOption(conf *mountConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MountConfig holds the configuration for a mount operation.
|
// mountConfig holds the configuration for a mount operation.
|
||||||
// Use it by passing MountOption values to Mount.
|
// Use it by passing MountOption values to Mount.
|
||||||
type MountConfig struct {
|
type mountConfig struct {
|
||||||
options map[string]string
|
options map[string]string
|
||||||
|
maxReadahead uint32
|
||||||
|
initFlags InitFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
func escapeComma(s string) string {
|
func escapeComma(s string) string {
|
||||||
|
@ -24,7 +26,7 @@ func escapeComma(s string) string {
|
||||||
// getOptions makes a string of options suitable for passing to FUSE
|
// getOptions makes a string of options suitable for passing to FUSE
|
||||||
// mount flag `-o`. Returns an empty string if no options were set.
|
// mount flag `-o`. Returns an empty string if no options were set.
|
||||||
// Any platform specific adjustments should happen before the call.
|
// Any platform specific adjustments should happen before the call.
|
||||||
func (m *MountConfig) getOptions() string {
|
func (m *mountConfig) getOptions() string {
|
||||||
var opts []string
|
var opts []string
|
||||||
for k, v := range m.options {
|
for k, v := range m.options {
|
||||||
k = escapeComma(k)
|
k = escapeComma(k)
|
||||||
|
@ -36,15 +38,17 @@ func (m *MountConfig) getOptions() string {
|
||||||
return strings.Join(opts, ",")
|
return strings.Join(opts, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mountOption func(*mountConfig) error
|
||||||
|
|
||||||
// MountOption is passed to Mount to change the behavior of the mount.
|
// MountOption is passed to Mount to change the behavior of the mount.
|
||||||
type MountOption func(*MountConfig) error
|
type MountOption mountOption
|
||||||
|
|
||||||
// FSName sets the file system name (also called source) that is
|
// FSName sets the file system name (also called source) that is
|
||||||
// visible in the list of mounted file systems.
|
// visible in the list of mounted file systems.
|
||||||
//
|
//
|
||||||
// FreeBSD ignores this option.
|
// FreeBSD ignores this option.
|
||||||
func FSName(name string) MountOption {
|
func FSName(name string) MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
conf.options["fsname"] = name
|
conf.options["fsname"] = name
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -57,7 +61,7 @@ func FSName(name string) MountOption {
|
||||||
// OS X ignores this option.
|
// OS X ignores this option.
|
||||||
// FreeBSD ignores this option.
|
// FreeBSD ignores this option.
|
||||||
func Subtype(fstype string) MountOption {
|
func Subtype(fstype string) MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
conf.options["subtype"] = fstype
|
conf.options["subtype"] = fstype
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -84,7 +88,7 @@ var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOth
|
||||||
//
|
//
|
||||||
// Only one of AllowOther or AllowRoot can be used.
|
// Only one of AllowOther or AllowRoot can be used.
|
||||||
func AllowOther() MountOption {
|
func AllowOther() MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
if _, ok := conf.options["allow_root"]; ok {
|
if _, ok := conf.options["allow_root"]; ok {
|
||||||
return ErrCannotCombineAllowOtherAndAllowRoot
|
return ErrCannotCombineAllowOtherAndAllowRoot
|
||||||
}
|
}
|
||||||
|
@ -99,7 +103,7 @@ func AllowOther() MountOption {
|
||||||
//
|
//
|
||||||
// FreeBSD ignores this option.
|
// FreeBSD ignores this option.
|
||||||
func AllowRoot() MountOption {
|
func AllowRoot() MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
if _, ok := conf.options["allow_other"]; ok {
|
if _, ok := conf.options["allow_other"]; ok {
|
||||||
return ErrCannotCombineAllowOtherAndAllowRoot
|
return ErrCannotCombineAllowOtherAndAllowRoot
|
||||||
}
|
}
|
||||||
|
@ -117,7 +121,7 @@ func AllowRoot() MountOption {
|
||||||
//
|
//
|
||||||
// FreeBSD ignores this option.
|
// FreeBSD ignores this option.
|
||||||
func DefaultPermissions() MountOption {
|
func DefaultPermissions() MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
conf.options["default_permissions"] = ""
|
conf.options["default_permissions"] = ""
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -125,8 +129,42 @@ func DefaultPermissions() MountOption {
|
||||||
|
|
||||||
// ReadOnly makes the mount read-only.
|
// ReadOnly makes the mount read-only.
|
||||||
func ReadOnly() MountOption {
|
func ReadOnly() MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
conf.options["ro"] = ""
|
conf.options["ro"] = ""
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
4
Godeps/_workspace/src/bazil.org/fuse/options_darwin.go
generated
vendored
4
Godeps/_workspace/src/bazil.org/fuse/options_darwin.go
generated
vendored
|
@ -1,12 +1,12 @@
|
||||||
package fuse
|
package fuse
|
||||||
|
|
||||||
func localVolume(conf *MountConfig) error {
|
func localVolume(conf *mountConfig) error {
|
||||||
conf.options["local"] = ""
|
conf.options["local"] = ""
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func volumeName(name string) MountOption {
|
func volumeName(name string) MountOption {
|
||||||
return func(conf *MountConfig) error {
|
return func(conf *mountConfig) error {
|
||||||
conf.options["volname"] = name
|
conf.options["volname"] = name
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/options_freebsd.go
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/options_freebsd.go
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
package fuse
|
package fuse
|
||||||
|
|
||||||
func localVolume(conf *MountConfig) error {
|
func localVolume(conf *mountConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
Godeps/_workspace/src/bazil.org/fuse/options_helper_test.go
generated
vendored
8
Godeps/_workspace/src/bazil.org/fuse/options_helper_test.go
generated
vendored
|
@ -1,6 +1,10 @@
|
||||||
package fuse
|
package fuse
|
||||||
|
|
||||||
// for TestMountOptionCommaError
|
// for TestMountOptionCommaError
|
||||||
func ForTestSetMountOption(conf *MountConfig, k, v string) {
|
func ForTestSetMountOption(k, v string) MountOption {
|
||||||
conf.options[k] = v
|
fn := func(conf *mountConfig) error {
|
||||||
|
conf.options[k] = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fn
|
||||||
}
|
}
|
||||||
|
|
2
Godeps/_workspace/src/bazil.org/fuse/options_linux.go
generated
vendored
2
Godeps/_workspace/src/bazil.org/fuse/options_linux.go
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
package fuse
|
package fuse
|
||||||
|
|
||||||
func localVolume(conf *MountConfig) error {
|
func localVolume(conf *mountConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
Godeps/_workspace/src/bazil.org/fuse/options_nocomma_test.go
generated
vendored
7
Godeps/_workspace/src/bazil.org/fuse/options_nocomma_test.go
generated
vendored
|
@ -18,11 +18,8 @@ func TestMountOptionCommaError(t *testing.T) {
|
||||||
// this test is not tied to any specific option, it just needs
|
// this test is not tied to any specific option, it just needs
|
||||||
// some string content
|
// some string content
|
||||||
var evil = "FuseTest,Marker"
|
var evil = "FuseTest,Marker"
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
func(conf *fuse.MountConfig) error {
|
fuse.ForTestSetMountOption("fusetest", evil),
|
||||||
fuse.ForTestSetMountOption(conf, "fusetest", evil)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
mnt.Close()
|
mnt.Close()
|
||||||
|
|
17
Godeps/_workspace/src/bazil.org/fuse/options_test.go
generated
vendored
17
Godeps/_workspace/src/bazil.org/fuse/options_test.go
generated
vendored
|
@ -22,7 +22,7 @@ func TestMountOptionFSName(t *testing.T) {
|
||||||
}
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
const name = "FuseTestMarker"
|
const name = "FuseTestMarker"
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
fuse.FSName(name),
|
fuse.FSName(name),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -45,7 +45,7 @@ func testMountOptionFSNameEvil(t *testing.T, evil string) {
|
||||||
}
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
var name = "FuseTest" + evil + "Marker"
|
var name = "FuseTest" + evil + "Marker"
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
fuse.FSName(name),
|
fuse.FSName(name),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,7 +102,7 @@ func TestMountOptionSubtype(t *testing.T) {
|
||||||
}
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
const name = "FuseTestMarker"
|
const name = "FuseTestMarker"
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
fuse.Subtype(name),
|
fuse.Subtype(name),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -125,7 +125,7 @@ func TestMountOptionSubtype(t *testing.T) {
|
||||||
|
|
||||||
func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
|
func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
fuse.AllowOther(),
|
fuse.AllowOther(),
|
||||||
fuse.AllowRoot(),
|
fuse.AllowRoot(),
|
||||||
)
|
)
|
||||||
|
@ -141,7 +141,7 @@ func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
|
||||||
|
|
||||||
func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
|
func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
|
mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, nil,
|
||||||
fuse.AllowRoot(),
|
fuse.AllowRoot(),
|
||||||
fuse.AllowOther(),
|
fuse.AllowOther(),
|
||||||
)
|
)
|
||||||
|
@ -155,8 +155,9 @@ func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
|
||||||
|
|
||||||
type unwritableFile struct{}
|
type unwritableFile struct{}
|
||||||
|
|
||||||
func (f unwritableFile) Attr(a *fuse.Attr) {
|
func (f unwritableFile) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Mode = 0000
|
a.Mode = 0000
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMountOptionDefaultPermissions(t *testing.T) {
|
func TestMountOptionDefaultPermissions(t *testing.T) {
|
||||||
|
@ -166,8 +167,9 @@ func TestMountOptionDefaultPermissions(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
mnt, err := fstestutil.MountedT(t,
|
mnt, err := fstestutil.MountedT(t,
|
||||||
fstestutil.SimpleFS{
|
fstestutil.SimpleFS{
|
||||||
fstestutil.ChildMap{"child": unwritableFile{}},
|
&fstestutil.ChildMap{"child": unwritableFile{}},
|
||||||
},
|
},
|
||||||
|
nil,
|
||||||
fuse.DefaultPermissions(),
|
fuse.DefaultPermissions(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -203,6 +205,7 @@ func TestMountOptionReadOnly(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
mnt, err := fstestutil.MountedT(t,
|
mnt, err := fstestutil.MountedT(t,
|
||||||
fstestutil.SimpleFS{createrDir{}},
|
fstestutil.SimpleFS{createrDir{}},
|
||||||
|
nil,
|
||||||
fuse.ReadOnly(),
|
fuse.ReadOnly(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
75
Godeps/_workspace/src/bazil.org/fuse/protocol.go
generated
vendored
Normal file
75
Godeps/_workspace/src/bazil.org/fuse/protocol.go
generated
vendored
Normal file
|
@ -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()
|
||||||
|
}
|
|
@ -91,9 +91,10 @@ type snapshots struct {
|
||||||
repo *repository.Repository
|
repo *repository.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sn *snapshots) Attr(a *fuse.Attr) {
|
func (sn *snapshots) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = 0
|
a.Inode = 0
|
||||||
a.Mode = os.ModeDir | 0555
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sn *snapshots) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
func (sn *snapshots) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||||
|
@ -144,9 +145,10 @@ type dir struct {
|
||||||
inode uint64
|
inode uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dir) Attr(a *fuse.Attr) {
|
func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = d.inode
|
a.Inode = d.inode
|
||||||
a.Mode = os.ModeDir | 0555
|
a.Mode = os.ModeDir | 0555
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||||
|
@ -224,10 +226,11 @@ func makeFile(repo *repository.Repository, node *restic.Node) (*file, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Attr(a *fuse.Attr) {
|
func (f *file) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Inode = f.node.Inode
|
a.Inode = f.node.Inode
|
||||||
a.Mode = f.node.Mode
|
a.Mode = f.node.Mode
|
||||||
a.Size = f.node.Size
|
a.Size = f.node.Size
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
func (f *file) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
||||||
|
|
Loading…
Reference in a new issue