godeps: update bazil.org/fuse
fuse: Attr() now has a Context parameter and error return value ~GOPATH/src/bazil.org/fuse:master$ git shortlog 48c34fb7780b88aca1696bf865508f6703aa47f1..e4fcc9a2c7567d1c42861deebeb483315d222262 Tommi Virtanen (8): Remove dead code Make saveLookup take Context, return error Make serveNode.attr take Context, return error Make nodeAttr take Context, return error API change: Move attribute validity time inside Attr Set attribute validity default time in one place API change: Attr method takes Context, returns error Set LookupResponse validity times up front, instead of after the handler
Henry committed
May 28, 2015 at 22:09 UTC
e9074beb6da592a203ddcea3e4a22dd9c0af13fb
16 files changed
+407
-139
Godeps/Godeps.json
+1
-1
@@ -7,7 +7,7 @@
7
"Deps": [
8
{
9
"ImportPath": "bazil.org/fuse",
10
- "Rev": "79d103f5608724e3ccee0a10daccc5e4aff03591"
10
+ "Rev": "e4fcc9a2c7567d1c42861deebeb483315d222262"
11
},
12
{
13
"ImportPath": "code.google.com/p/go-uuid/uuid",
Godeps/_workspace/src/bazil.org/fuse/LICENSE
+1
-1
@@ -1,4 +1,4 @@
1
-Copyright (c) 2013, 2014 Tommi Virtanen.
1
+Copyright (c) 2013-2015 Tommi Virtanen.
2
Copyright (c) 2009, 2011, 2012 The Go Authors.
3
All rights reserved.
4
Godeps/_workspace/src/bazil.org/fuse/README.md
+1
-1
@@ -15,7 +15,7 @@ Here’s how to get going:
15
16
Website: http://bazil.org/fuse/
17
18
-Github repository: https://github.com/bazillion/fuse
18
+Github repository: https://github.com/bazil/fuse
19
20
API docs: http://godoc.org/bazil.org/fuse
21
Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go
+9
-4
@@ -43,8 +43,10 @@ var _ = fs.NodeStringLookuper(benchDir{})
43
var _ = fs.Handle(benchDir{})
44
var _ = fs.HandleReadDirAller(benchDir{})
45
46
-func (benchDir) Attr() fuse.Attr {
47
- return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555}
46
+func (benchDir) Attr(ctx context.Context, a *fuse.Attr) error {
47
+ a.Inode = 1
48
+ a.Mode = os.ModeDir | 0555
49
+ return nil
50
}
51
52
func (d benchDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
@@ -72,8 +74,11 @@ var _ = fs.Handle(benchFile{})
74
var _ = fs.HandleReader(benchFile{})
75
var _ = fs.HandleWriter(benchFile{})
76
75
-func (benchFile) Attr() fuse.Attr {
76
- return fuse.Attr{Inode: 2, Mode: 0644, Size: 9999999999999999}
77
+func (benchFile) Attr(ctx context.Context, a *fuse.Attr) error {
78
+ a.Inode = 2
79
+ a.Mode = 0644
80
+ a.Size = 9999999999999999
81
+ return nil
82
}
83
84
func (f benchFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
+11
-4
@@ -22,12 +22,18 @@ func (f SimpleFS) Root() (fs.Node, error) {
22
// File can be embedded in a struct to make it look like a file.
23
type File struct{}
24
25
-func (f File) Attr() fuse.Attr { return fuse.Attr{Mode: 0666} }
25
+func (f File) Attr(ctx context.Context, a *fuse.Attr) error {
26
+ a.Mode = 0666
27
+ return nil
28
+}
29
30
// Dir can be embedded in a struct to make it look like a directory.
31
type Dir struct{}
32
30
-func (f Dir) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeDir | 0777} }
33
+func (f Dir) Attr(ctx context.Context, a *fuse.Attr) error {
34
+ a.Mode = os.ModeDir | 0777
35
+ return nil
36
+}
37
38
// ChildMap is a directory with child nodes looked up from a map.
39
type ChildMap map[string]fs.Node
@@ -35,8 +41,9 @@ type ChildMap map[string]fs.Node
41
var _ = fs.Node(ChildMap{})
42
var _ = fs.NodeStringLookuper(ChildMap{})
43
38
-func (f ChildMap) Attr() fuse.Attr {
39
- return fuse.Attr{Mode: os.ModeDir | 0777}
44
+func (f ChildMap) Attr(ctx context.Context, a *fuse.Attr) error {
45
+ a.Mode = os.ModeDir | 0777
46
+ return nil
47
}
48
49
func (f ChildMap) Lookup(ctx context.Context, name string) (fs.Node, error) {
Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
+122
-44
@@ -7,7 +7,9 @@ import (
7
"fmt"
8
"hash/fnv"
9
"io"
10
+ "log"
11
"reflect"
12
+ "runtime"
13
"strings"
14
"sync"
15
"time"
@@ -55,9 +57,6 @@ type FSDestroyer interface {
57
// Linux only sends this request for block device backed (fuseblk)
58
// filesystems, to allow them to flush writes to disk before the
59
// unmount completes.
58
- //
59
- // On normal FUSE filesystems, use Forget of the root Node to
60
- // do actions at unmount time.
60
Destroy()
61
}
62
@@ -87,7 +86,8 @@ type FSInodeGenerator interface {
86
// Other FUSE requests can be handled by implementing methods from the
87
// Node* interfaces, for example NodeOpener.
88
type Node interface {
90
- Attr() fuse.Attr
89
+ // Attr fills attr with the standard metadata for the node.
90
+ Attr(ctx context.Context, attr *fuse.Attr) error
91
}
92
93
type NodeGetattrer interface {
@@ -192,6 +192,11 @@ type NodeCreater interface {
192
}
193
194
type NodeForgetter interface {
195
+ // Forget about this node. This node will not receive further
196
+ // method calls.
197
+ //
198
+ // Forget is not necessarily seen on unmount, as all nodes are
199
+ // implicitly forgotten as part part of the unmount.
200
Forget()
201
}
202
@@ -236,24 +241,17 @@ type NodeRemovexattrer interface {
241
242
var startTime = time.Now()
243
239
-func nodeAttr(n Node) (attr fuse.Attr) {
240
- attr = n.Attr()
241
- if attr.Nlink == 0 {
242
- attr.Nlink = 1
243
- }
244
- if attr.Atime.IsZero() {
245
- attr.Atime = startTime
246
- }
247
- if attr.Mtime.IsZero() {
248
- attr.Mtime = startTime
244
+func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error {
245
+ attr.Valid = attrValidTime
246
+ attr.Nlink = 1
247
+ attr.Atime = startTime
248
+ attr.Mtime = startTime
249
+ attr.Ctime = startTime
250
+ attr.Crtime = startTime
251
+ if err := n.Attr(ctx, attr); err != nil {
252
+ return err
253
}
250
- if attr.Ctime.IsZero() {
251
- attr.Ctime = startTime
252
- }
253
- if attr.Crtime.IsZero() {
254
- attr.Crtime = startTime
255
- }
256
- return
254
+ return nil
255
}
256
257
// A Handle is the interface required of an opened file or directory.
@@ -323,12 +321,17 @@ type Server struct {
321
//
322
// See fuse.Debug for the rules that log functions must follow.
323
Debug func(msg interface{})
324
+
325
+ // Used to ensure worker goroutines finish before Serve returns
326
+ wg sync.WaitGroup
327
}
328
329
// Serve serves the FUSE connection by making calls to the methods
330
// of fs and the Nodes and Handles it makes available. It returns only
331
// when the connection has been closed or an unexpected error occurs.
332
func (s *Server) Serve(c *fuse.Conn) error {
333
+ defer s.wg.Wait() // Wait for worker goroutines to complete before return
334
+
335
sc := serveConn{
336
fs: s.FS,
337
debug: s.Debug,
@@ -358,7 +361,11 @@ func (s *Server) Serve(c *fuse.Conn) error {
361
return err
362
}
363
361
- go sc.serve(req)
364
+ s.wg.Add(1)
365
+ go func() {
366
+ defer s.wg.Done()
367
+ sc.serve(req)
368
+ }()
369
}
370
return nil
371
}
@@ -398,12 +405,12 @@ type serveNode struct {
405
refs uint64
406
}
407
401
-func (sn *serveNode) attr() (attr fuse.Attr) {
402
- attr = nodeAttr(sn.node)
408
+func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error {
409
+ err := nodeAttr(ctx, sn.node, attr)
410
if attr.Inode == 0 {
411
attr.Inode = sn.inode
412
}
406
- return
413
+ return err
414
}
415
416
type serveHandle struct {
@@ -646,6 +653,30 @@ func (m *renameNewDirNodeNotFound) String() string {
653
return fmt.Sprintf("In RenameRequest (request %#x), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
654
}
655
656
+type handlerPanickedError struct {
657
+ Request interface{}
658
+ Err interface{}
659
+}
660
+
661
+var _ error = handlerPanickedError{}
662
+
663
+func (h handlerPanickedError) Error() string {
664
+ return fmt.Sprintf("handler panicked: %v", h.Err)
665
+}
666
+
667
+var _ fuse.ErrorNumber = handlerPanickedError{}
668
+
669
+func (h handlerPanickedError) Errno() fuse.Errno {
670
+ if err, ok := h.Err.(fuse.ErrorNumber); ok {
671
+ return err.Errno()
672
+ }
673
+ return fuse.DefaultErrno
674
+}
675
+
676
+func initLookupResponse(s *fuse.LookupResponse) {
677
+ s.EntryValid = entryValidTime
678
+}
679
+
680
func (c *serveConn) serve(r fuse.Request) {
681
ctx, cancel := context.WithCancel(context.Background())
682
defer cancel()
@@ -725,6 +756,22 @@ func (c *serveConn) serve(r fuse.Request) {
756
c.meta.Unlock()
757
}
758
759
+ defer func() {
760
+ if rec := recover(); rec != nil {
761
+ const size = 1 << 16
762
+ buf := make([]byte, size)
763
+ n := runtime.Stack(buf, false)
764
+ buf = buf[:n]
765
+ log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf)
766
+ err := handlerPanickedError{
767
+ Request: r,
768
+ Err: rec,
769
+ }
770
+ done(err)
771
+ r.RespondError(err)
772
+ }
773
+ }()
774
+
775
switch r := r.(type) {
776
default:
777
// Note: To FUSE, ENOSYS means "this server never implements this request."
@@ -771,8 +818,11 @@ func (c *serveConn) serve(r fuse.Request) {
818
break
819
}
820
} else {
774
- s.AttrValid = attrValidTime
775
- s.Attr = snode.attr()
821
+ if err := snode.attr(ctx, &s.Attr); err != nil {
822
+ done(err)
823
+ r.RespondError(err)
824
+ break
825
+ }
826
}
827
done(s)
828
r.Respond(s)
@@ -790,15 +840,17 @@ func (c *serveConn) serve(r fuse.Request) {
840
break
841
}
842
793
- if s.AttrValid == 0 {
794
- s.AttrValid = attrValidTime
843
+ if err := snode.attr(ctx, &s.Attr); err != nil {
844
+ done(err)
845
+ r.RespondError(err)
846
+ break
847
}
796
- s.Attr = snode.attr()
848
done(s)
849
r.Respond(s)
850
851
case *fuse.SymlinkRequest:
852
s := &fuse.SymlinkResponse{}
853
+ initLookupResponse(&s.LookupResponse)
854
n, ok := node.(NodeSymlinker)
855
if !ok {
856
done(fuse.EIO) // XXX or EPERM like Mkdir?
@@ -811,7 +863,11 @@ func (c *serveConn) serve(r fuse.Request) {
863
r.RespondError(err)
864
break
865
}
814
- c.saveLookup(&s.LookupResponse, snode, r.NewName, n2)
866
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil {
867
+ done(err)
868
+ r.RespondError(err)
869
+ break
870
+ }
871
done(s)
872
r.Respond(s)
873
@@ -860,7 +916,12 @@ func (c *serveConn) serve(r fuse.Request) {
916
break
917
}
918
s := &fuse.LookupResponse{}
863
- c.saveLookup(s, snode, r.NewName, n2)
919
+ initLookupResponse(s)
920
+ if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil {
921
+ done(err)
922
+ r.RespondError(err)
923
+ break
924
+ }
925
done(s)
926
r.Respond(s)
927
@@ -895,6 +956,7 @@ func (c *serveConn) serve(r fuse.Request) {
956
var n2 Node
957
var err error
958
s := &fuse.LookupResponse{}
959
+ initLookupResponse(s)
960
if n, ok := node.(NodeStringLookuper); ok {
961
n2, err = n.Lookup(ctx, r.Name)
962
} else if n, ok := node.(NodeRequestLookuper); ok {
@@ -909,12 +971,17 @@ func (c *serveConn) serve(r fuse.Request) {
971
r.RespondError(err)
972
break
973
}
912
- c.saveLookup(s, snode, r.Name, n2)
974
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
975
+ done(err)
976
+ r.RespondError(err)
977
+ break
978
+ }
979
done(s)
980
r.Respond(s)
981
982
case *fuse.MkdirRequest:
983
s := &fuse.MkdirResponse{}
984
+ initLookupResponse(&s.LookupResponse)
985
n, ok := node.(NodeMkdirer)
986
if !ok {
987
done(fuse.EPERM)
@@ -927,7 +994,11 @@ func (c *serveConn) serve(r fuse.Request) {
994
r.RespondError(err)
995
break
996
}
930
- c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
997
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
998
+ done(err)
999
+ r.RespondError(err)
1000
+ break
1001
+ }
1002
done(s)
1003
r.Respond(s)
1004
@@ -958,13 +1029,18 @@ func (c *serveConn) serve(r fuse.Request) {
1029
break
1030
}
1031
s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
1032
+ initLookupResponse(&s.LookupResponse)
1033
n2, h2, err := n.Create(ctx, r, s)
1034
if err != nil {
1035
done(err)
1036
r.RespondError(err)
1037
break
1038
}
967
- c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
1039
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
1040
+ done(err)
1041
+ r.RespondError(err)
1042
+ break
1043
+ }
1044
s.Handle = c.saveHandle(h2, hdr.Node)
1045
done(s)
1046
r.Respond(s)
@@ -1240,7 +1316,12 @@ func (c *serveConn) serve(r fuse.Request) {
1316
break
1317
}
1318
s := &fuse.LookupResponse{}
1243
- c.saveLookup(s, snode, r.Name, n2)
1319
+ initLookupResponse(s)
1320
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
1321
+ done(err)
1322
+ r.RespondError(err)
1323
+ break
1324
+ }
1325
done(s)
1326
r.Respond(s)
1327
@@ -1290,19 +1371,16 @@ func (c *serveConn) serve(r fuse.Request) {
1371
}
1372
}
1373
1293
-func (c *serveConn) saveLookup(s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) {
1294
- s.Attr = nodeAttr(n2)
1374
+func (c *serveConn) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error {
1375
+ if err := nodeAttr(ctx, n2, &s.Attr); err != nil {
1376
+ return err
1377
+ }
1378
if s.Attr.Inode == 0 {
1379
s.Attr.Inode = c.dynamicInode(snode.inode, elem)
1380
}
1381
1382
s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
1300
- if s.EntryValid == 0 {
1301
- s.EntryValid = entryValidTime
1302
- }
1303
- if s.AttrValid == 0 {
1304
- s.AttrValid = attrValidTime
1305
- }
1383
+ return nil
1384
}
1385
1386
// DataHandle returns a read-only Handle that satisfies reads
Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
+152
-32
@@ -10,6 +10,7 @@ import (
10
"os/exec"
11
"runtime"
12
"strings"
13
+ "sync"
14
"syscall"
15
"testing"
16
"time"
@@ -42,12 +43,18 @@ type symlink struct {
43
target string
44
}
45
45
-func (f symlink) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeSymlink | 0666} }
46
+func (f symlink) Attr(ctx context.Context, a *fuse.Attr) error {
47
+ a.Mode = os.ModeSymlink | 0666
48
+ return nil
49
+}
50
51
// fifo can be embedded in a struct to make it look like a named pipe.
52
type fifo struct{}
53
50
-func (f fifo) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeNamedPipe | 0666} }
54
+func (f fifo) Attr(ctx context.Context, a *fuse.Attr) error {
55
+ a.Mode = os.ModeNamedPipe | 0666
56
+ return nil
57
+}
58
59
type badRootFS struct{}
60
@@ -79,14 +86,59 @@ func TestRootErr(t *testing.T) {
86
}
87
}
88
89
+type testPanic struct{}
90
+
91
+type panicSentinel struct{}
92
+
93
+var _ error = panicSentinel{}
94
+
95
+func (panicSentinel) Error() string { return "just a test" }
96
+
97
+var _ fuse.ErrorNumber = panicSentinel{}
98
+
99
+func (panicSentinel) Errno() fuse.Errno {
100
+ return fuse.Errno(syscall.ENAMETOOLONG)
101
+}
102
+
103
+func (f testPanic) Root() (fs.Node, error) {
104
+ return f, nil
105
+}
106
+
107
+func (f testPanic) Attr(ctx context.Context, a *fuse.Attr) error {
108
+ a.Inode = 1
109
+ a.Mode = os.ModeDir | 0777
110
+ return nil
111
+}
112
+
113
+func (f testPanic) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {
114
+ panic(panicSentinel{})
115
+}
116
+
117
+func TestPanic(t *testing.T) {
118
+ t.Parallel()
119
+ mnt, err := fstestutil.MountedT(t, testPanic{})
120
+ if err != nil {
121
+ t.Fatal(err)
122
+ }
123
+ defer mnt.Close()
124
+
125
+ var st syscall.Statfs_t
126
+ err = syscall.Statfs(mnt.Dir, &st)
127
+ if g, e := err, syscall.ENAMETOOLONG; g != e {
128
+ t.Fatalf("wrong error from panicking handler: %v != %v", g, e)
129
+ }
130
+}
131
+
132
type testStatFS struct{}
133
134
func (f testStatFS) Root() (fs.Node, error) {
135
return f, nil
136
}
137
88
-func (f testStatFS) Attr() fuse.Attr {
89
- return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0777}
138
+func (f testStatFS) Attr(ctx context.Context, a *fuse.Attr) error {
139
+ a.Inode = 1
140
+ a.Mode = os.ModeDir | 0777
141
+ return nil
142
}
143
144
func (f testStatFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {
@@ -148,8 +200,10 @@ func (f root) Root() (fs.Node, error) {
200
return f, nil
201
}
202
151
-func (root) Attr() fuse.Attr {
152
- return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555}
203
+func (root) Attr(ctx context.Context, a *fuse.Attr) error {
204
+ a.Inode = 1
205
+ a.Mode = os.ModeDir | 0555
206
+ return nil
207
}
208
209
func TestStatRoot(t *testing.T) {
@@ -196,11 +250,10 @@ type readAll struct {
250
251
const hi = "hello, world"
252
199
-func (readAll) Attr() fuse.Attr {
200
- return fuse.Attr{
201
- Mode: 0666,
202
- Size: uint64(len(hi)),
203
- }
253
+func (readAll) Attr(ctx context.Context, a *fuse.Attr) error {
254
+ a.Mode = 0666
255
+ a.Size = uint64(len(hi))
256
+ return nil
257
}
258
259
func (readAll) ReadAll(ctx context.Context) ([]byte, error) {
@@ -234,11 +287,10 @@ type readWithHandleRead struct {
287
fstestutil.File
288
}
289
237
-func (readWithHandleRead) Attr() fuse.Attr {
238
- return fuse.Attr{
239
- Mode: 0666,
240
- Size: uint64(len(hi)),
241
- }
290
+func (readWithHandleRead) Attr(ctx context.Context, a *fuse.Attr) error {
291
+ a.Mode = 0666
292
+ a.Size = uint64(len(hi))
293
+ return nil
294
}
295
296
func (readWithHandleRead) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
@@ -772,11 +824,10 @@ type dataHandleTest struct {
824
fstestutil.File
825
}
826
775
-func (dataHandleTest) Attr() fuse.Attr {
776
- return fuse.Attr{
777
- Mode: 0666,
778
- Size: uint64(len(hi)),
779
- }
827
+func (dataHandleTest) Attr(ctx context.Context, a *fuse.Attr) error {
828
+ a.Mode = 0666
829
+ a.Size = uint64(len(hi))
830
+ return nil
831
}
832
833
func (dataHandleTest) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
@@ -811,11 +862,10 @@ type interrupt struct {
862
hanging chan struct{}
863
}
864
814
-func (interrupt) Attr() fuse.Attr {
815
- return fuse.Attr{
816
- Mode: 0666,
817
- Size: 1,
818
- }
865
+func (interrupt) Attr(ctx context.Context, a *fuse.Attr) error {
866
+ a.Mode = 0666
867
+ a.Size = 1
868
+ return nil
869
}
870
871
func (it *interrupt) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
@@ -1609,22 +1659,38 @@ func TestCustomErrno(t *testing.T) {
1659
// Test Mmap writing
1660
1661
type inMemoryFile struct {
1662
+ mu sync.Mutex
1663
data []byte
1664
}
1665
1615
-func (f *inMemoryFile) Attr() fuse.Attr {
1616
- return fuse.Attr{
1617
- Mode: 0666,
1618
- Size: uint64(len(f.data)),
1619
- }
1666
+func (f *inMemoryFile) bytes() []byte {
1667
+ f.mu.Lock()
1668
+ defer f.mu.Unlock()
1669
+
1670
+ return f.data
1671
+}
1672
+
1673
+func (f *inMemoryFile) Attr(ctx context.Context, a *fuse.Attr) error {
1674
+ f.mu.Lock()
1675
+ defer f.mu.Unlock()
1676
+
1677
+ a.Mode = 0666
1678
+ a.Size = uint64(len(f.data))
1679
+ return nil
1680
}
1681
1682
func (f *inMemoryFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
1683
+ f.mu.Lock()
1684
+ defer f.mu.Unlock()
1685
+
1686
fuseutil.HandleRead(req, resp, f.data)
1687
return nil
1688
}
1689
1690
func (f *inMemoryFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
1691
+ f.mu.Lock()
1692
+ defer f.mu.Unlock()
1693
+
1694
resp.Size = copy(f.data[req.Offset:], req.Data)
1695
return nil
1696
}
@@ -1709,7 +1775,7 @@ func TestMmap(t *testing.T) {
1775
t.Fatal(err)
1776
}
1777
1712
- got := w.data
1778
+ got := w.bytes()
1779
if g, e := len(got), mmapSize; g != e {
1780
t.Fatalf("bad write length: %d != %d", g, e)
1781
}
@@ -1797,3 +1863,57 @@ func TestDirectWrite(t *testing.T) {
1863
t.Errorf("write = %q, want %q", got, hi)
1864
}
1865
}
1866
+
1867
+// Test Attr
1868
+
1869
+// attrUnlinked is a file that is unlinked (Nlink==0).
1870
+type attrUnlinked struct {
1871
+ fstestutil.File
1872
+}
1873
+
1874
+var _ fs.Node = attrUnlinked{}
1875
+
1876
+func (f attrUnlinked) Attr(ctx context.Context, a *fuse.Attr) error {
1877
+ if err := f.File.Attr(ctx, a); err != nil {
1878
+ return err
1879
+ }
1880
+ a.Nlink = 0
1881
+ return nil
1882
+}
1883
+
1884
+func TestAttrUnlinked(t *testing.T) {
1885
+ t.Parallel()
1886
+ mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": attrUnlinked{}}})
1887
+
1888
+ fi, err := os.Stat(mnt.Dir + "/child")
1889
+ if err != nil {
1890
+ t.Fatalf("Stat failed with %v", err)
1891
+ }
1892
+ switch stat := fi.Sys().(type) {
1893
+ case *syscall.Stat_t:
1894
+ if stat.Nlink != 0 {
1895
+ t.Errorf("wrong link count: %v", stat.Nlink)
1896
+ }
1897
+ }
1898
+}
1899
+
1900
+// Test behavior when Attr method fails
1901
+
1902
+type attrBad struct {
1903
+}
1904
+
1905
+var _ fs.Node = attrBad{}
1906
+
1907
+func (attrBad) Attr(ctx context.Context, attr *fuse.Attr) error {
1908
+ return fuse.Errno(syscall.ENAMETOOLONG)
1909
+}
1910
+
1911
+func TestAttrBad(t *testing.T) {
1912
+ t.Parallel()
1913
+ mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.ChildMap{"child": attrBad{}}})
1914
+
1915
+ _, err = os.Stat(mnt.Dir + "/child")
1916
+ if nerr, ok := err.(*os.PathError); !ok || nerr.Err != syscall.ENAMETOOLONG {
1917
+ t.Fatalf("wrong error: %v", err)
1918
+ }
1919
+}
Godeps/_workspace/src/bazil.org/fuse/fs/tree.go
+3
-2
@@ -77,8 +77,9 @@ func (t *tree) add(name string, n Node) {
77
t.dir = append(t.dir, treeDir{name, n})
78
}
79
80
-func (t *tree) Attr() fuse.Attr {
81
- return fuse.Attr{Mode: os.ModeDir | 0555}
80
+func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
81
+ a.Mode = os.ModeDir | 0555
82
+ return nil
83
}
84
85
func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
Godeps/_workspace/src/bazil.org/fuse/fuse.go
+23
-23
@@ -1,4 +1,5 @@
1
// See the file LICENSE for copyright and licensing information.
2
+
3
// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
4
// which carries this notice:
5
//
@@ -45,7 +46,7 @@
46
// The required and optional methods for the FS, Node, and Handle interfaces
47
// have the general form
48
//
48
-// Op(ctx context.Context, req *OpRequest, resp *OpResponse) Error
49
+// Op(ctx context.Context, req *OpRequest, resp *OpResponse) error
50
//
51
// where Op is the name of a FUSE operation. Op reads request
52
// parameters from req and writes results to resp. An operation whose
@@ -67,7 +68,7 @@
68
// can implement ErrorNumber to control the errno returned. Without
69
// ErrorNumber, a generic errno (EIO) is returned.
70
//
70
-// Errors messages will be visible in the debug log as part of the
71
+// Error messages will be visible in the debug log as part of the
72
// response.
73
//
74
// Interrupted Operations
@@ -1064,6 +1065,8 @@ func (r *AccessRequest) Respond() {
1065
1066
// An Attr is the metadata for a single file or directory.
1067
type Attr struct {
1068
+ Valid time.Duration // how long Attr can be cached
1069
+
1070
Inode uint64 // inode number
1071
Size uint64 // size in bytes
1072
Blocks uint64 // size in blocks
@@ -1143,8 +1146,8 @@ func (r *GetattrRequest) String() string {
1146
func (r *GetattrRequest) Respond(resp *GetattrResponse) {
1147
out := &attrOut{
1148
outHeader: outHeader{Unique: uint64(r.ID)},
1146
- AttrValid: uint64(resp.AttrValid / time.Second),
1147
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1149
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1150
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1151
Attr: resp.Attr.attr(),
1152
}
1153
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1152,8 +1155,7 @@ func (r *GetattrRequest) Respond(resp *GetattrResponse) {
1155
1156
// A GetattrResponse is the response to a GetattrRequest.
1157
type GetattrResponse struct {
1155
- AttrValid time.Duration // how long Attr can be cached
1156
- Attr Attr // file attributes
1158
+ Attr Attr // file attributes
1159
}
1160
1161
func (r *GetattrResponse) String() string {
@@ -1333,8 +1335,8 @@ func (r *LookupRequest) Respond(resp *LookupResponse) {
1335
Generation: resp.Generation,
1336
EntryValid: uint64(resp.EntryValid / time.Second),
1337
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1336
- AttrValid: uint64(resp.AttrValid / time.Second),
1337
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1338
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1339
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1340
Attr: resp.Attr.attr(),
1341
}
1342
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1345,7 +1347,6 @@ type LookupResponse struct {
1347
Node NodeID
1348
Generation uint64
1349
EntryValid time.Duration
1348
- AttrValid time.Duration
1350
Attr Attr
1351
}
1352
@@ -1409,8 +1410,8 @@ func (r *CreateRequest) Respond(resp *CreateResponse) {
1410
Generation: resp.Generation,
1411
EntryValid: uint64(resp.EntryValid / time.Second),
1412
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1412
- AttrValid: uint64(resp.AttrValid / time.Second),
1413
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1413
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1414
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1415
Attr: resp.Attr.attr(),
1416
1417
Fh: uint64(resp.Handle),
@@ -1451,8 +1452,8 @@ func (r *MkdirRequest) Respond(resp *MkdirResponse) {
1452
Generation: resp.Generation,
1453
EntryValid: uint64(resp.EntryValid / time.Second),
1454
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1454
- AttrValid: uint64(resp.AttrValid / time.Second),
1455
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1455
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1456
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1457
Attr: resp.Attr.attr(),
1458
}
1459
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1776,8 +1777,8 @@ func (r *SetattrRequest) String() string {
1777
func (r *SetattrRequest) Respond(resp *SetattrResponse) {
1778
out := &attrOut{
1779
outHeader: outHeader{Unique: uint64(r.ID)},
1779
- AttrValid: uint64(resp.AttrValid / time.Second),
1780
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1780
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1781
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1782
Attr: resp.Attr.attr(),
1783
}
1784
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1785,8 +1786,7 @@ func (r *SetattrRequest) Respond(resp *SetattrResponse) {
1786
1787
// A SetattrResponse is the response to a SetattrRequest.
1788
type SetattrResponse struct {
1788
- AttrValid time.Duration // how long Attr can be cached
1789
- Attr Attr // file attributes
1789
+ Attr Attr // file attributes
1790
}
1791
1792
func (r *SetattrResponse) String() string {
@@ -1855,8 +1855,8 @@ func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
1855
Generation: resp.Generation,
1856
EntryValid: uint64(resp.EntryValid / time.Second),
1857
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1858
- AttrValid: uint64(resp.AttrValid / time.Second),
1859
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1858
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1859
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1860
Attr: resp.Attr.attr(),
1861
}
1862
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1903,8 +1903,8 @@ func (r *LinkRequest) Respond(resp *LookupResponse) {
1903
Generation: resp.Generation,
1904
EntryValid: uint64(resp.EntryValid / time.Second),
1905
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1906
- AttrValid: uint64(resp.AttrValid / time.Second),
1907
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1906
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1907
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1908
Attr: resp.Attr.attr(),
1909
}
1910
r.respond(&out.outHeader, unsafe.Sizeof(*out))
@@ -1948,8 +1948,8 @@ func (r *MknodRequest) Respond(resp *LookupResponse) {
1948
Generation: resp.Generation,
1949
EntryValid: uint64(resp.EntryValid / time.Second),
1950
EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
1951
- AttrValid: uint64(resp.AttrValid / time.Second),
1952
- AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1951
+ AttrValid: uint64(resp.Attr.Valid / time.Second),
1952
+ AttrValidNsec: uint32(resp.Attr.Valid % time.Second / time.Nanosecond),
1953
Attr: resp.Attr.attr(),
1954
}
1955
r.respond(&out.outHeader, unsafe.Sizeof(*out))
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
+1
-1
@@ -1,6 +1,6 @@
1
// See the file LICENSE for copyright and licensing information.
2
3
-// Derived from FUSE's fuse_kernel.h
3
+// Derived from FUSE's fuse_kernel.h, which carries this notice:
4
/*
5
This file defines the kernel interface of FUSE
6
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
+9
-4
@@ -63,8 +63,10 @@ func (FS) Root() (fs.Node, error) {
63
// Dir implements both Node and Handle for the root directory.
64
type Dir struct{}
65
66
-func (Dir) Attr() fuse.Attr {
67
- return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555}
66
+func (Dir) Attr(ctx context.Context, a *fuse.Attr) error {
67
+ a.Inode = 1
68
+ a.Mode = os.ModeDir | 0555
69
+ return nil
70
}
71
72
func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
@@ -87,8 +89,11 @@ type File struct{}
89
90
const greeting = "hello, world\n"
91
90
-func (File) Attr() fuse.Attr {
91
- return fuse.Attr{Inode: 2, Mode: 0444, Size: uint64(len(greeting))}
92
+func (File) Attr(ctx context.Context, a *fuse.Attr) error {
93
+ a.Inode = 2
94
+ a.Mode = 0444
95
+ a.Size = uint64(len(greeting))
96
+ return nil
97
}
98
99
func (File) ReadAll(ctx context.Context) ([]byte, error) {
Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
+43
-3
@@ -1,13 +1,37 @@
1
package fuse
2
3
import (
4
+ "bufio"
5
"fmt"
6
+ "io"
7
+ "log"
8
"net"
9
"os"
10
"os/exec"
11
+ "sync"
12
"syscall"
13
)
14
15
+func lineLogger(wg *sync.WaitGroup, prefix string, r io.ReadCloser) {
16
+ defer wg.Done()
17
+
18
+ scanner := bufio.NewScanner(r)
19
+ for scanner.Scan() {
20
+ switch line := scanner.Text(); line {
21
+ case `fusermount: failed to open /etc/fuse.conf: Permission denied`:
22
+ // Silence this particular message, it occurs way too
23
+ // commonly and isn't very relevant to whether the mount
24
+ // succeeds or not.
25
+ continue
26
+ default:
27
+ log.Printf("%s: %s", prefix, line)
28
+ }
29
+ }
30
+ if err := scanner.Err(); err != nil {
31
+ log.Printf("%s, error reading: %v", prefix, err)
32
+ }
33
+}
34
+
35
func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
36
// linux mount is never delayed
37
close(ready)
@@ -31,9 +55,25 @@ func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (f
55
defer writeFile.Close()
56
cmd.ExtraFiles = []*os.File{writeFile}
57
34
- out, err := cmd.CombinedOutput()
35
- if len(out) > 0 || err != nil {
36
- return nil, fmt.Errorf("fusermount: %q, %v", out, err)
58
+ var wg sync.WaitGroup
59
+ stdout, err := cmd.StdoutPipe()
60
+ if err != nil {
61
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
62
+ }
63
+ stderr, err := cmd.StderrPipe()
64
+ if err != nil {
65
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
66
+ }
67
+
68
+ if err := cmd.Start(); err != nil {
69
+ return nil, fmt.Errorf("fusermount: %v", err)
70
+ }
71
+ wg.Add(2)
72
+ go lineLogger(&wg, "mount helper output", stdout)
73
+ go lineLogger(&wg, "mount helper error", stderr)
74
+ wg.Wait()
75
+ if err := cmd.Wait(); err != nil {
76
+ return nil, fmt.Errorf("fusermount: %v", err)
77
}
78
79
readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
Godeps/_workspace/src/bazil.org/fuse/options_test.go
+4
-1
@@ -155,7 +155,10 @@ func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
155
156
type unwritableFile struct{}
157
158
-func (f unwritableFile) Attr() fuse.Attr { return fuse.Attr{Mode: 0000} }
158
+func (f unwritableFile) Attr(ctx context.Context, a *fuse.Attr) error {
159
+ a.Mode = 0000
160
+ return nil
161
+}
162
163
func TestMountOptionDefaultPermissions(t *testing.T) {
164
if runtime.GOOS == "freebsd" {
fuse/ipns/ipns_unix.go
+11
-7
@@ -6,6 +6,7 @@ package ipns
6
7
import (
8
"errors"
9
+ "fmt"
10
"os"
11
"strings"
12
@@ -106,9 +107,10 @@ func CreateRoot(ipfs *core.IpfsNode, keys []ci.PrivKey, ipfspath, ipnspath strin
107
}
108
109
// Attr returns file attributes.
109
-func (*Root) Attr() fuse.Attr {
110
+func (*Root) Attr(ctx context.Context, a *fuse.Attr) error {
111
log.Debug("Root Attr")
111
- return fuse.Attr{Mode: os.ModeDir | 0111} // -rw+x
112
+ *a = fuse.Attr{Mode: os.ModeDir | 0111} // -rw+x
113
+ return nil
114
}
115
116
// Lookup performs a lookup under this node.
@@ -215,29 +217,31 @@ type File struct {
217
}
218
219
// Attr returns the attributes of a given node.
218
-func (d *Directory) Attr() fuse.Attr {
220
+func (d *Directory) Attr(ctx context.Context, a *fuse.Attr) error {
221
log.Debug("Directory Attr")
220
- return fuse.Attr{
222
+ *a = fuse.Attr{
223
Mode: os.ModeDir | 0555,
224
Uid: uint32(os.Getuid()),
225
Gid: uint32(os.Getgid()),
226
}
227
+ return nil
228
}
229
230
// Attr returns the attributes of a given node.
228
-func (fi *File) Attr() fuse.Attr {
231
+func (fi *File) Attr(ctx context.Context, a *fuse.Attr) error {
232
log.Debug("File Attr")
233
size, err := fi.fi.Size()
234
if err != nil {
235
// In this case, the dag node in question may not be unixfs
233
- log.Critical("Failed to get file size: %s", err)
236
+ return fmt.Errorf("fuse/ipns: failed to get file.Size(): %s", err)
237
}
235
- return fuse.Attr{
238
+ *a = fuse.Attr{
239
Mode: os.FileMode(0666),
240
Size: uint64(size),
241
Uid: uint32(os.Getuid()),
242
Gid: uint32(os.Getgid()),
243
}
244
+ return nil
245
}
246
247
// Lookup performs a lookup under this node.
fuse/ipns/link_unix.go
+3
-2
@@ -14,11 +14,12 @@ type Link struct {
14
Target string
15
}
16
17
-func (l *Link) Attr() fuse.Attr {
17
+func (l *Link) Attr(ctx context.Context, a *fuse.Attr) error {
18
log.Debug("Link attr.")
19
- return fuse.Attr{
19
+ *a = fuse.Attr{
20
Mode: os.ModeSymlink | 0555,
21
}
22
+ return nil
23
}
24
25
func (l *Link) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) {
fuse/readonly/readonly_unix.go
+13
-9
@@ -4,6 +4,7 @@
4
package readonly
5
6
import (
7
+ "fmt"
8
"io"
9
"os"
10
@@ -43,8 +44,9 @@ type Root struct {
44
}
45
46
// Attr returns file attributes.
46
-func (*Root) Attr() fuse.Attr {
47
- return fuse.Attr{Mode: os.ModeDir | 0111} // -rw+x
47
+func (*Root) Attr(ctx context.Context, a *fuse.Attr) error {
48
+ *a = fuse.Attr{Mode: os.ModeDir | 0111} // -rw+x
49
+ return nil
50
}
51
52
// Lookup performs a lookup under this node.
@@ -85,21 +87,23 @@ func (s *Node) loadData() error {
87
}
88
89
// Attr returns the attributes of a given node.
88
-func (s *Node) Attr() fuse.Attr {
90
+func (s *Node) Attr(ctx context.Context, a *fuse.Attr) error {
91
log.Debug("Node attr.")
92
if s.cached == nil {
91
- s.loadData()
93
+ if err := s.loadData(); err != nil {
94
+ return fmt.Errorf("readonly: loadData() failed: %s", err)
95
+ }
96
}
97
switch s.cached.GetType() {
98
case ftpb.Data_Directory:
95
- return fuse.Attr{
99
+ *a = fuse.Attr{
100
Mode: os.ModeDir | 0555,
101
Uid: uint32(os.Getuid()),
102
Gid: uint32(os.Getgid()),
103
}
104
case ftpb.Data_File:
105
size := s.cached.GetFilesize()
102
- return fuse.Attr{
106
+ *a = fuse.Attr{
107
Mode: 0444,
108
Size: uint64(size),
109
Blocks: uint64(len(s.Nd.Links)),
@@ -107,7 +111,7 @@ func (s *Node) Attr() fuse.Attr {
111
Gid: uint32(os.Getgid()),
112
}
113
case ftpb.Data_Raw:
110
- return fuse.Attr{
114
+ *a = fuse.Attr{
115
Mode: 0444,
116
Size: uint64(len(s.cached.GetData())),
117
Blocks: uint64(len(s.Nd.Links)),
@@ -116,9 +120,9 @@ func (s *Node) Attr() fuse.Attr {
120
}
121
122
default:
119
- log.Debug("Invalid data type.")
120
- return fuse.Attr{}
123
+ return fmt.Errorf("Invalid data type - %s", s.cached.GetType())
124
}
125
+ return nil
126
}
127
128
// Lookup performs a lookup under this node.