@cryptotaxi247 / kubo / commits / e9074beb6

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.