@cryptotaxi247 / kubo / commits / 56867c8b7

updated bazil.org/fuse

Juan Batiz-Benet committed Jan 2, 2015 at 04:48 UTC 56867c8b7035c7c76b5328481065a9dfbeefd8fb
21 files changed +736 -137
Godeps/Godeps.json
+1 -1
@@ -7,7 +7,7 @@
7 "Deps": [
8 {
9 "ImportPath": "bazil.org/fuse",
10 - "Rev": "a04507d54fc3610d38ee951402d8c4acab56c7b1"
10 + "Rev": "d62a1291477b51b24becf4def173bd843138c4b6"
11 },
12 {
13 "ImportPath": "bitbucket.org/kardianos/osext",
Godeps/_workspace/src/bazil.org/fuse/debug.go
+7
@@ -11,4 +11,11 @@ func stack() string {
11
12 func nop(msg interface{}) {}
13
14 +// Debug is called to output debug messages, including protocol
15 +// traces. The default behavior is to do nothing.
16 +//
17 +// The messages have human-friendly string representations and are
18 +// safe to marshal to JSON.
19 +//
20 +// Implementations must not retain msg.
21 var Debug func(msg interface{}) = nop
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go new
+1
@@ -0,0 +1 @@
1 +package fstestutil
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
+4 -4
@@ -55,12 +55,12 @@ func (mnt *Mount) Close() {
55 // workaround).
56 //
57 // After successful return, caller must clean up by calling Close.
58 -func Mounted(srv *fs.Server) (*Mount, error) {
58 +func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) {
59 dir, err := ioutil.TempDir("", "fusetest")
60 if err != nil {
61 return nil, err
62 }
63 - c, err := fuse.Mount(dir)
63 + c, err := fuse.Mount(dir, options...)
64 if err != nil {
65 return nil, err
66 }
@@ -100,7 +100,7 @@ func Mounted(srv *fs.Server) (*Mount, error) {
100 //
101 // The debug log is not enabled by default. Use `-fuse.debug` or call
102 // DebugByDefault to enable.
103 -func MountedT(t testing.TB, filesys fs.FS) (*Mount, error) {
103 +func MountedT(t testing.TB, filesys fs.FS, options ...fuse.MountOption) (*Mount, error) {
104 srv := &fs.Server{
105 FS: filesys,
106 }
@@ -109,5 +109,5 @@ func MountedT(t testing.TB, filesys fs.FS) (*Mount, error) {
109 t.Logf("FUSE: %s", msg)
110 }
111 }
112 - return Mounted(srv)
112 + return Mounted(srv, options...)
113 }
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go new
+14
@@ -0,0 +1,14 @@
1 +package fstestutil
2 +
3 +// MountInfo describes a mounted file system.
4 +type MountInfo struct {
5 + FSName string
6 + Type string
7 +}
8 +
9 +// GetMountInfo finds information about the mount at mnt. It is
10 +// intended for use by tests only, and only fetches information
11 +// relevant to the current tests.
12 +func GetMountInfo(mnt string) (*MountInfo, error) {
13 + return getMountInfo(mnt)
14 +}
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go new
+41
@@ -0,0 +1,41 @@
1 +package fstestutil
2 +
3 +import (
4 + "regexp"
5 + "syscall"
6 +)
7 +
8 +// cstr converts a nil-terminated C string into a Go string
9 +func cstr(ca []int8) string {
10 + s := make([]byte, 0, len(ca))
11 + for _, c := range ca {
12 + if c == 0x00 {
13 + break
14 + }
15 + s = append(s, byte(c))
16 + }
17 + return string(s)
18 +}
19 +
20 +var re = regexp.MustCompile(`\\(.)`)
21 +
22 +// unescape removes backslash-escaping. The escaped characters are not
23 +// mapped in any way; that is, unescape(`\n` ) == `n`.
24 +func unescape(s string) string {
25 + return re.ReplaceAllString(s, `$1`)
26 +}
27 +
28 +func getMountInfo(mnt string) (*MountInfo, error) {
29 + var st syscall.Statfs_t
30 + err := syscall.Statfs(mnt, &st)
31 + if err != nil {
32 + return nil, err
33 + }
34 + i := &MountInfo{
35 + // osx getmntent(3) fails to un-escape the data, so we do it..
36 + // this might lead to double-unescaping in the future. fun.
37 + // TestMountOptionFSNameEvilBackslashDouble checks for that.
38 + FSName: unescape(cstr(st.Mntfromname[:])),
39 + }
40 + return i, nil
41 +}
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go new
+51
@@ -0,0 +1,51 @@
1 +package fstestutil
2 +
3 +import (
4 + "errors"
5 + "io/ioutil"
6 + "strings"
7 +)
8 +
9 +// Linux /proc/mounts shows current mounts.
10 +// Same format as /etc/fstab. Quoting getmntent(3):
11 +//
12 +// Since fields in the mtab and fstab files are separated by whitespace,
13 +// octal escapes are used to represent the four characters space (\040),
14 +// tab (\011), newline (\012) and backslash (\134) in those files when
15 +// they occur in one of the four strings in a mntent structure.
16 +//
17 +// http://linux.die.net/man/3/getmntent
18 +
19 +var fstabUnescape = strings.NewReplacer(
20 + `\040`, "\040",
21 + `\011`, "\011",
22 + `\012`, "\012",
23 + `\134`, "\134",
24 +)
25 +
26 +var errNotFound = errors.New("mount not found")
27 +
28 +func getMountInfo(mnt string) (*MountInfo, error) {
29 + data, err := ioutil.ReadFile("/proc/mounts")
30 + if err != nil {
31 + return nil, err
32 + }
33 + for _, line := range strings.Split(string(data), "\n") {
34 + fields := strings.Fields(line)
35 + if len(fields) < 3 {
36 + continue
37 + }
38 + // Fields are: fsname dir type opts freq passno
39 + fsname := fstabUnescape.Replace(fields[0])
40 + dir := fstabUnescape.Replace(fields[1])
41 + fstype := fstabUnescape.Replace(fields[2])
42 + if mnt == dir {
43 + info := &MountInfo{
44 + FSName: fsname,
45 + Type: fstype,
46 + }
47 + return info, nil
48 + }
49 + }
50 + return nil, errNotFound
51 +}
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go new
+29
@@ -0,0 +1,29 @@
1 +package fstestutil
2 +
3 +import (
4 + "os"
5 +
6 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
8 +)
9 +
10 +// SimpleFS is a trivial FS that just implements the Root method.
11 +type SimpleFS struct {
12 + Node fs.Node
13 +}
14 +
15 +var _ = fs.FS(SimpleFS{})
16 +
17 +func (f SimpleFS) Root() (fs.Node, fuse.Error) {
18 + return f.Node, nil
19 +}
20 +
21 +// File can be embedded in a struct to make it look like a file.
22 +type File struct{}
23 +
24 +func (f File) Attr() fuse.Attr { return fuse.Attr{Mode: 0666} }
25 +
26 +// Dir can be embedded in a struct to make it look like a directory.
27 +type Dir struct{}
28 +
29 +func (f Dir) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeDir | 0777} }
Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
+3 -2
@@ -10,7 +10,6 @@ import (
10 "reflect"
11 "strings"
12 "sync"
13 - "syscall"
13 "time"
14 )
15
@@ -295,6 +294,8 @@ type Server struct {
294 // Function to send debug log messages to. If nil, use fuse.Debug.
295 // Note that changing this or fuse.Debug may not affect existing
296 // calls to Serve.
297 + //
298 + // See fuse.Debug for the rules that log functions must follow.
299 Debug func(msg interface{})
300 }
301
@@ -317,7 +318,7 @@ func (s *Server) Serve(c *fuse.Conn) error {
318
319 root, err := sc.fs.Root()
320 if err != nil {
320 - return fmt.Errorf("cannot obtain root node: %v", syscall.Errno(err.(fuse.Errno)).Error())
321 + return fmt.Errorf("cannot obtain root node: %v", err)
322 }
323 sc.node = append(sc.node, nil, &serveNode{inode: 1, node: root, refs: 1})
324 sc.handle = append(sc.handle, nil)
Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
+77 -73
@@ -87,27 +87,6 @@ func (f childMapFS) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
87 return child, nil
88 }
89
90 -// simpleFS is a trivial FS that just implements the Root method.
91 -type simpleFS struct {
92 - node fs.Node
93 -}
94 -
95 -var _ = fs.FS(simpleFS{})
96 -
97 -func (f simpleFS) Root() (fs.Node, fuse.Error) {
98 - return f.node, nil
99 -}
100 -
101 -// file can be embedded in a struct to make it look like a file.
102 -type file struct{}
103 -
104 -func (f file) Attr() fuse.Attr { return fuse.Attr{Mode: 0666} }
105 -
106 -// dir can be embedded in a struct to make it look like a directory.
107 -type dir struct{}
108 -
109 -func (f dir) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeDir | 0777} }
110 -
90 // symlink can be embedded in a struct to make it look like a symlink.
91 type symlink struct {
92 target string
@@ -261,7 +240,9 @@ func TestStatRoot(t *testing.T) {
240
241 // Test Read calling ReadAll.
242
264 -type readAll struct{ file }
243 +type readAll struct {
244 + fstestutil.File
245 +}
246
247 const hi = "hello, world"
248
@@ -299,7 +280,9 @@ func TestReadAll(t *testing.T) {
280
281 // Test Read.
282
302 -type readWithHandleRead struct{ file }
283 +type readWithHandleRead struct {
284 + fstestutil.File
285 +}
286
287 func (readWithHandleRead) Attr() fuse.Attr {
288 return fuse.Attr{
@@ -327,7 +310,7 @@ func TestReadAllWithHandleRead(t *testing.T) {
310 // Test Release.
311
312 type release struct {
330 - file
313 + fstestutil.File
314 record.ReleaseWaiter
315 }
316
@@ -353,7 +336,7 @@ func TestRelease(t *testing.T) {
336 // Test Write calling basic Write, with an fsync thrown in too.
337
338 type write struct {
356 - file
339 + fstestutil.File
340 record.Writes
341 record.Fsyncs
342 }
@@ -401,7 +384,7 @@ func TestWrite(t *testing.T) {
384 // Test Write of a larger buffer.
385
386 type writeLarge struct {
404 - file
387 + fstestutil.File
388 record.Writes
389 }
390
@@ -446,7 +429,7 @@ func TestWriteLarge(t *testing.T) {
429 // Test Write calling Setattr+Write+Flush.
430
431 type writeTruncateFlush struct {
449 - file
432 + fstestutil.File
433 record.Writes
434 record.Setattrs
435 record.Flushes
@@ -479,7 +462,7 @@ func TestWriteTruncateFlush(t *testing.T) {
462 // Test Mkdir.
463
464 type mkdir1 struct {
482 - dir
465 + fstestutil.Dir
466 record.Mkdirs
467 }
468
@@ -491,7 +474,7 @@ func (f *mkdir1) Mkdir(req *fuse.MkdirRequest, intr fs.Intr) (fs.Node, fuse.Erro
474 func TestMkdir(t *testing.T) {
475 t.Parallel()
476 f := &mkdir1{}
494 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
477 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
478 if err != nil {
479 t.Fatal(err)
480 }
@@ -513,12 +496,12 @@ func TestMkdir(t *testing.T) {
496 // Test Create (and fsync)
497
498 type create1file struct {
516 - file
499 + fstestutil.File
500 record.Fsyncs
501 }
502
503 type create1 struct {
521 - dir
504 + fstestutil.Dir
505 f create1file
506 }
507
@@ -553,7 +536,7 @@ func (f *create1) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, int
536 func TestCreate(t *testing.T) {
537 t.Parallel()
538 f := &create1{}
556 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
539 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
540 if err != nil {
541 t.Fatal(err)
542 }
@@ -583,12 +566,12 @@ func TestCreate(t *testing.T) {
566 // Test Create + Write + Remove
567
568 type create3file struct {
586 - file
569 + fstestutil.File
570 record.Writes
571 }
572
573 type create3 struct {
591 - dir
574 + fstestutil.Dir
575 f create3file
576 fooCreated record.MarkRecorder
577 fooRemoved record.MarkRecorder
@@ -622,7 +605,7 @@ func (f *create3) Remove(r *fuse.RemoveRequest, intr fs.Intr) fuse.Error {
605 func TestCreateWriteRemove(t *testing.T) {
606 t.Parallel()
607 f := &create3{}
625 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
608 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
609 if err != nil {
610 t.Fatal(err)
611 }
@@ -659,7 +642,7 @@ func (f symlink1link) Readlink(*fuse.ReadlinkRequest, fs.Intr) (string, fuse.Err
642 }
643
644 type symlink1 struct {
662 - dir
645 + fstestutil.Dir
646 record.Symlinks
647 }
648
@@ -671,7 +654,7 @@ func (f *symlink1) Symlink(req *fuse.SymlinkRequest, intr fs.Intr) (fs.Node, fus
654 func TestSymlink(t *testing.T) {
655 t.Parallel()
656 f := &symlink1{}
674 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
657 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
658 if err != nil {
659 t.Fatal(err)
660 }
@@ -701,26 +684,26 @@ func TestSymlink(t *testing.T) {
684 // Test link
685
686 type link1 struct {
704 - dir
687 + fstestutil.Dir
688 record.Links
689 }
690
691 func (f *link1) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
692 if name == "old" {
710 - return file{}, nil
693 + return fstestutil.File{}, nil
694 }
695 return nil, fuse.ENOENT
696 }
697
698 func (f *link1) Link(r *fuse.LinkRequest, old fs.Node, intr fs.Intr) (fs.Node, fuse.Error) {
699 f.Links.Link(r, old, intr)
717 - return file{}, nil
700 + return fstestutil.File{}, nil
701 }
702
703 func TestLink(t *testing.T) {
704 t.Parallel()
705 f := &link1{}
723 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
706 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
707 if err != nil {
708 t.Fatal(err)
709 }
@@ -745,13 +728,13 @@ func TestLink(t *testing.T) {
728 // Test Rename
729
730 type rename1 struct {
748 - dir
731 + fstestutil.Dir
732 renamed record.Counter
733 }
734
735 func (f *rename1) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
736 if name == "old" {
754 - return file{}, nil
737 + return fstestutil.File{}, nil
738 }
739 return nil, fuse.ENOENT
740 }
@@ -767,7 +750,7 @@ func (f *rename1) Rename(r *fuse.RenameRequest, newDir fs.Node, intr fs.Intr) fu
750 func TestRename(t *testing.T) {
751 t.Parallel()
752 f := &rename1{}
770 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
753 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
754 if err != nil {
755 t.Fatal(err)
756 }
@@ -789,7 +772,7 @@ func TestRename(t *testing.T) {
772 // Test mknod
773
774 type mknod1 struct {
792 - dir
775 + fstestutil.Dir
776 record.Mknods
777 }
778
@@ -805,7 +788,7 @@ func TestMknod(t *testing.T) {
788 }
789
790 f := &mknod1{}
808 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
791 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
792 if err != nil {
793 t.Fatal(err)
794 }
@@ -836,7 +819,7 @@ func TestMknod(t *testing.T) {
819 // Test Read served with DataHandle.
820
821 type dataHandleTest struct {
839 - file
822 + fstestutil.File
823 }
824
825 func (dataHandleTest) Attr() fuse.Attr {
@@ -872,7 +855,7 @@ func TestDataHandle(t *testing.T) {
855 // Test interrupt
856
857 type interrupt struct {
875 - file
858 + fstestutil.File
859
860 // strobes to signal we have a read hanging
861 hanging chan struct{}
@@ -955,7 +938,7 @@ func TestInterrupt(t *testing.T) {
938 // Test truncate
939
940 type truncate struct {
958 - file
941 + fstestutil.File
942 record.Setattrs
943 }
944
@@ -996,7 +979,7 @@ func TestTruncate0(t *testing.T) {
979 // Test ftruncate
980
981 type ftruncate struct {
999 - file
982 + fstestutil.File
983 record.Setattrs
984 }
985
@@ -1046,7 +1029,7 @@ func TestFtruncate0(t *testing.T) {
1029 // Test opening existing file truncates
1030
1031 type truncateWithOpen struct {
1049 - file
1032 + fstestutil.File
1033 record.Setattrs
1034 }
1035
@@ -1083,7 +1066,7 @@ func TestTruncateWithOpen(t *testing.T) {
1066 // Test readdir
1067
1068 type readdir struct {
1086 - dir
1069 + fstestutil.Dir
1070 }
1071
1072 func (d *readdir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
@@ -1097,7 +1080,7 @@ func (d *readdir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
1080 func TestReadDir(t *testing.T) {
1081 t.Parallel()
1082 f := &readdir{}
1100 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
1083 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
1084 if err != nil {
1085 t.Fatal(err)
1086 }
@@ -1133,7 +1116,7 @@ func TestReadDir(t *testing.T) {
1116 // Test Chmod.
1117
1118 type chmod struct {
1136 - file
1119 + fstestutil.File
1120 record.Setattrs
1121 }
1122
@@ -1169,7 +1152,7 @@ func TestChmod(t *testing.T) {
1152 // Test open
1153
1154 type open struct {
1172 - file
1155 + fstestutil.File
1156 record.Opens
1157 }
1158
@@ -1233,14 +1216,14 @@ func TestOpen(t *testing.T) {
1216 // Test Fsync on a dir
1217
1218 type fsyncDir struct {
1236 - dir
1219 + fstestutil.Dir
1220 record.Fsyncs
1221 }
1222
1223 func TestFsyncDir(t *testing.T) {
1224 t.Parallel()
1225 f := &fsyncDir{}
1243 - mnt, err := fstestutil.MountedT(t, simpleFS{f})
1226 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
1227 if err != nil {
1228 t.Fatal(err)
1229 }
@@ -1278,7 +1261,7 @@ func TestFsyncDir(t *testing.T) {
1261 // Test Getxattr
1262
1263 type getxattr struct {
1281 - file
1264 + fstestutil.File
1265 record.Getxattrs
1266 }
1267
@@ -1316,7 +1299,7 @@ func TestGetxattr(t *testing.T) {
1299 // Test Getxattr that has no space to return value
1300
1301 type getxattrTooSmall struct {
1319 - file
1302 + fstestutil.File
1303 }
1304
1305 func (f *getxattrTooSmall) Getxattr(req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
@@ -1347,7 +1330,7 @@ func TestGetxattrTooSmall(t *testing.T) {
1330 // Test Getxattr used to probe result size
1331
1332 type getxattrSize struct {
1350 - file
1333 + fstestutil.File
1334 }
1335
1336 func (f *getxattrSize) Getxattr(req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
@@ -1377,7 +1360,7 @@ func TestGetxattrSize(t *testing.T) {
1360 // Test Listxattr
1361
1362 type listxattr struct {
1380 - file
1363 + fstestutil.File
1364 record.Listxattrs
1365 }
1366
@@ -1418,7 +1401,7 @@ func TestListxattr(t *testing.T) {
1401 // Test Listxattr that has no space to return value
1402
1403 type listxattrTooSmall struct {
1421 - file
1404 + fstestutil.File
1405 }
1406
1407 func (f *listxattrTooSmall) Listxattr(req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
@@ -1449,7 +1432,7 @@ func TestListxattrTooSmall(t *testing.T) {
1432 // Test Listxattr used to probe result size
1433
1434 type listxattrSize struct {
1452 - file
1435 + fstestutil.File
1436 }
1437
1438 func (f *listxattrSize) Listxattr(req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
@@ -1479,11 +1462,16 @@ func TestListxattrSize(t *testing.T) {
1462 // Test Setxattr
1463
1464 type setxattr struct {
1482 - file
1465 + fstestutil.File
1466 record.Setxattrs
1467 }
1468
1486 -func TestSetxattr(t *testing.T) {
1469 +func testSetxattr(t *testing.T, size int) {
1470 + const linux_XATTR_NAME_MAX = 64 * 1024
1471 + if size > linux_XATTR_NAME_MAX && runtime.GOOS == "linux" {
1472 + t.Skip("large xattrs are not supported by linux")
1473 + }
1474 +
1475 t.Parallel()
1476 f := &setxattr{}
1477 mnt, err := fstestutil.MountedT(t, childMapFS{"child": f})
@@ -1492,7 +1480,9 @@ func TestSetxattr(t *testing.T) {
1480 }
1481 defer mnt.Close()
1482
1495 - err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte("hello, world"), 0)
1483 + const g = "hello, world"
1484 + greeting := strings.Repeat(g, size/len(g)+1)[:size]
1485 + err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte(greeting), 0)
1486 if err != nil {
1487 t.Errorf("unexpected error: %v", err)
1488 return
@@ -1510,15 +1500,27 @@ func TestSetxattr(t *testing.T) {
1500 t.Errorf("Setxattr incorrect flags: %d != %d", g, e)
1501 }
1502
1513 - if g, e := string(got.Xattr), "hello, world"; g != e {
1503 + if g, e := string(got.Xattr), greeting; g != e {
1504 t.Errorf("Setxattr incorrect data: %q != %q", g, e)
1505 }
1506 }
1507
1508 +func TestSetxattr(t *testing.T) {
1509 + testSetxattr(t, 20)
1510 +}
1511 +
1512 +func TestSetxattr64kB(t *testing.T) {
1513 + testSetxattr(t, 64*1024)
1514 +}
1515 +
1516 +func TestSetxattr16MB(t *testing.T) {
1517 + testSetxattr(t, 16*1024*1024)
1518 +}
1519 +
1520 // Test Removexattr
1521
1522 type removexattr struct {
1521 - file
1523 + fstestutil.File
1524 record.Removexattrs
1525 }
1526
@@ -1546,7 +1548,7 @@ func TestRemovexattr(t *testing.T) {
1548 // Test default error.
1549
1550 type defaultErrno struct {
1549 - dir
1551 + fstestutil.Dir
1552 }
1553
1554 func (f defaultErrno) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
@@ -1555,7 +1557,7 @@ func (f defaultErrno) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
1557
1558 func TestDefaultErrno(t *testing.T) {
1559 t.Parallel()
1558 - mnt, err := fstestutil.MountedT(t, simpleFS{defaultErrno{}})
1560 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{defaultErrno{}})
1561 if err != nil {
1562 t.Fatal(err)
1563 }
@@ -1580,7 +1582,7 @@ func TestDefaultErrno(t *testing.T) {
1582 // Test custom error.
1583
1584 type customErrNode struct {
1583 - dir
1585 + fstestutil.Dir
1586 }
1587
1588 type myCustomError struct {
@@ -1601,7 +1603,7 @@ func (f customErrNode) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
1603
1604 func TestCustomErrno(t *testing.T) {
1605 t.Parallel()
1604 - mnt, err := fstestutil.MountedT(t, simpleFS{customErrNode{}})
1606 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{customErrNode{}})
1607 if err != nil {
1608 t.Fatal(err)
1609 }
@@ -1736,7 +1738,9 @@ func TestMmap(t *testing.T) {
1738
1739 // Test direct Read.
1740
1739 -type directRead struct{ file }
1741 +type directRead struct {
1742 + fstestutil.File
1743 +}
1744
1745 // explicitly not defining Attr and setting Size
1746
Godeps/_workspace/src/bazil.org/fuse/fuse.go
+185 -48
@@ -74,7 +74,8 @@
74 //
75 // Mount Options
76 //
77 -// XXX
77 +// Behavior and metadata of the mounted file system can be changed by
78 +// passing MountOption values to Mount.
79 //
80 package fuse
81
@@ -120,13 +121,21 @@ type Conn struct {
121 // visible until after Conn.Ready is closed. See Conn.MountError for
122 // possible errors. Incoming requests on Conn must be served to make
123 // progress.
123 -func Mount(dir string) (*Conn, error) {
124 - // TODO(rsc): mount options (...string?)
124 +func Mount(dir string, options ...MountOption) (*Conn, error) {
125 + conf := MountConfig{
126 + options: make(map[string]string),
127 + }
128 + for _, option := range options {
129 + if err := option(&conf); err != nil {
130 + return nil, err
131 + }
132 + }
133 +
134 ready := make(chan struct{}, 1)
135 c := &Conn{
136 Ready: ready,
137 }
129 - f, err := mount(dir, ready, &c.MountError)
138 + f, err := mount(dir, &conf, ready, &c.MountError)
139 if err != nil {
140 return nil, err
141 }
@@ -170,6 +179,9 @@ type Header struct {
179 Uid uint32 // user ID of process making request
180 Gid uint32 // group ID of process making request
181 Pid uint32 // process ID of process making request
182 +
183 + // for returning to reqPool
184 + msg *message
185 }
186
187 func (h *Header) String() string {
@@ -180,6 +192,20 @@ func (h *Header) Hdr() *Header {
192 return h
193 }
194
195 +func (h *Header) noResponse() {
196 + putMessage(h.msg)
197 +}
198 +
199 +func (h *Header) respond(out *outHeader, n uintptr) {
200 + h.Conn.respond(out, n)
201 + putMessage(h.msg)
202 +}
203 +
204 +func (h *Header) respondData(out *outHeader, n uintptr, data []byte) {
205 + h.Conn.respondData(out, n, data)
206 + putMessage(h.msg)
207 +}
208 +
209 // An Error is a FUSE error.
210 //
211 // Errors messages will be visible in the debug log as part of the
@@ -279,17 +305,48 @@ func (h *Header) RespondError(err Error) {
305 // FUSE uses negative errors!
306 // TODO: File bug report against OSXFUSE: positive error causes kernel panic.
307 out := &outHeader{Error: -int32(errno), Unique: uint64(h.ID)}
282 - h.Conn.respond(out, unsafe.Sizeof(*out))
308 + h.respond(out, unsafe.Sizeof(*out))
309 }
310
311 // Maximum file write size we are prepared to receive from the kernel.
286 -const maxWrite = 128 * 1024
312 +const maxWrite = 16 * 1024 * 1024
313
314 // All requests read from the kernel, without data, are shorter than
315 // this.
316 var maxRequestSize = syscall.Getpagesize()
317 var bufSize = maxRequestSize + maxWrite
318
319 +// reqPool is a pool of messages.
320 +//
321 +// Lifetime of a logical message is from getMessage to putMessage.
322 +// getMessage is called by ReadRequest. putMessage is called by
323 +// Conn.ReadRequest, Request.Respond, or Request.RespondError.
324 +//
325 +// Messages in the pool are guaranteed to have conn and off zeroed,
326 +// buf allocated and len==bufSize, and hdr set.
327 +var reqPool = sync.Pool{
328 + New: allocMessage,
329 +}
330 +
331 +func allocMessage() interface{} {
332 + m := &message{buf: make([]byte, bufSize)}
333 + m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
334 + return m
335 +}
336 +
337 +func getMessage(c *Conn) *message {
338 + m := reqPool.Get().(*message)
339 + m.conn = c
340 + return m
341 +}
342 +
343 +func putMessage(m *message) {
344 + m.buf = m.buf[:bufSize]
345 + m.conn = nil
346 + m.off = 0
347 + reqPool.Put(m)
348 +}
349 +
350 // a message represents the bytes of a single FUSE message
351 type message struct {
352 conn *Conn
@@ -298,12 +355,6 @@ type message struct {
355 off int // offset for reading additional fields
356 }
357
301 -func newMessage(c *Conn) *message {
302 - m := &message{conn: c, buf: make([]byte, bufSize)}
303 - m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
304 - return m
305 -}
306 -
358 func (m *message) len() uintptr {
359 return uintptr(len(m.buf) - m.off)
360 }
@@ -322,7 +373,16 @@ func (m *message) bytes() []byte {
373
374 func (m *message) Header() Header {
375 h := m.hdr
325 - return Header{Conn: m.conn, ID: RequestID(h.Unique), Node: NodeID(h.Nodeid), Uid: h.Uid, Gid: h.Gid, Pid: h.Pid}
376 + return Header{
377 + Conn: m.conn,
378 + ID: RequestID(h.Unique),
379 + Node: NodeID(h.Nodeid),
380 + Uid: h.Uid,
381 + Gid: h.Gid,
382 + Pid: h.Pid,
383 +
384 + msg: m,
385 + }
386 }
387
388 // fileMode returns a Go os.FileMode from a Unix mode.
@@ -385,9 +445,12 @@ func (c *Conn) fd() int {
445 return int(c.dev.Fd())
446 }
447
448 +// ReadRequest returns the next FUSE request from the kernel.
449 +//
450 +// Caller must call either Request.Respond or Request.RespondError in
451 +// a reasonable time. Caller must not retain Request after that call.
452 func (c *Conn) ReadRequest() (Request, error) {
389 - // TODO: Some kind of buffer reuse.
390 - m := newMessage(c)
453 + m := getMessage(c)
454 loop:
455 c.rio.RLock()
456 n, err := syscall.Read(c.fd(), m.buf)
@@ -398,14 +461,17 @@ loop:
461 goto loop
462 }
463 if err != nil && err != syscall.ENODEV {
464 + putMessage(m)
465 return nil, err
466 }
467 if n <= 0 {
468 + putMessage(m)
469 return nil, io.EOF
470 }
471 m.buf = m.buf[:n]
472
473 if n < inHeaderSize {
474 + putMessage(m)
475 return nil, errors.New("fuse: message too short")
476 }
477
@@ -421,7 +487,10 @@ loop:
487 }
488
489 if m.hdr.Len != uint32(n) {
424 - return nil, fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
490 + // prepare error message before returning m to pool
491 + err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
492 + putMessage(m)
493 + return nil, err
494 }
495
496 m.off = inHeaderSize
@@ -821,6 +890,7 @@ loop:
890
891 corrupt:
892 Debug(malformedMessage{})
893 + putMessage(m)
894 return nil, fmt.Errorf("fuse: malformed message")
895
896 unrecognized:
@@ -886,6 +956,8 @@ type InitRequest struct {
956 Flags InitFlags
957 }
958
959 +var _ = Request(&InitRequest{})
960 +
961 func (r *InitRequest) String() string {
962 return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags)
963 }
@@ -920,7 +992,7 @@ func (r *InitRequest) Respond(resp *InitResponse) {
992 if out.MaxWrite > maxWrite {
993 out.MaxWrite = maxWrite
994 }
923 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
995 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
996 }
997
998 // A StatfsRequest requests information about the mounted file system.
@@ -928,8 +1000,10 @@ type StatfsRequest struct {
1000 Header `json:"-"`
1001 }
1002
1003 +var _ = Request(&StatfsRequest{})
1004 +
1005 func (r *StatfsRequest) String() string {
932 - return fmt.Sprintf("Statfs [%s]\n", &r.Header)
1006 + return fmt.Sprintf("Statfs [%s]", &r.Header)
1007 }
1008
1009 // Respond replies to the request with the given response.
@@ -946,7 +1020,7 @@ func (r *StatfsRequest) Respond(resp *StatfsResponse) {
1020 Frsize: resp.Frsize,
1021 },
1022 }
949 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1023 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1024 }
1025
1026 // A StatfsResponse is the response to a StatfsRequest.
@@ -972,6 +1046,8 @@ type AccessRequest struct {
1046 Mask uint32
1047 }
1048
1049 +var _ = Request(&AccessRequest{})
1050 +
1051 func (r *AccessRequest) String() string {
1052 return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
1053 }
@@ -980,7 +1056,7 @@ func (r *AccessRequest) String() string {
1056 // To deny access, use RespondError.
1057 func (r *AccessRequest) Respond() {
1058 out := &outHeader{Unique: uint64(r.ID)}
983 - r.Conn.respond(out, unsafe.Sizeof(*out))
1059 + r.respond(out, unsafe.Sizeof(*out))
1060 }
1061
1062 // An Attr is the metadata for a single file or directory.
@@ -1057,6 +1133,8 @@ type GetattrRequest struct {
1133 Header `json:"-"`
1134 }
1135
1136 +var _ = Request(&GetattrRequest{})
1137 +
1138 func (r *GetattrRequest) String() string {
1139 return fmt.Sprintf("Getattr [%s]", &r.Header)
1140 }
@@ -1069,7 +1147,7 @@ func (r *GetattrRequest) Respond(resp *GetattrResponse) {
1147 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1148 Attr: resp.Attr.attr(),
1149 }
1072 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1150 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1151 }
1152
1153 // A GetattrResponse is the response to a GetattrRequest.
@@ -1099,6 +1177,8 @@ type GetxattrRequest struct {
1177 Position uint32
1178 }
1179
1180 +var _ = Request(&GetxattrRequest{})
1181 +
1182 func (r *GetxattrRequest) String() string {
1183 return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position)
1184 }
@@ -1110,10 +1190,10 @@ func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
1190 outHeader: outHeader{Unique: uint64(r.ID)},
1191 Size: uint32(len(resp.Xattr)),
1192 }
1113 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1193 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1194 } else {
1195 out := &outHeader{Unique: uint64(r.ID)}
1116 - r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
1196 + r.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
1197 }
1198 }
1199
@@ -1138,6 +1218,8 @@ type ListxattrRequest struct {
1218 Position uint32 // offset within attribute list
1219 }
1220
1221 +var _ = Request(&ListxattrRequest{})
1222 +
1223 func (r *ListxattrRequest) String() string {
1224 return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
1225 }
@@ -1149,10 +1231,10 @@ func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
1231 outHeader: outHeader{Unique: uint64(r.ID)},
1232 Size: uint32(len(resp.Xattr)),
1233 }
1152 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1234 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1235 } else {
1236 out := &outHeader{Unique: uint64(r.ID)}
1155 - r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
1237 + r.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
1238 }
1239 }
1240
@@ -1179,6 +1261,8 @@ type RemovexattrRequest struct {
1261 Name string // name of extended attribute
1262 }
1263
1264 +var _ = Request(&RemovexattrRequest{})
1265 +
1266 func (r *RemovexattrRequest) String() string {
1267 return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
1268 }
@@ -1186,7 +1270,7 @@ func (r *RemovexattrRequest) String() string {
1270 // Respond replies to the request, indicating that the attribute was removed.
1271 func (r *RemovexattrRequest) Respond() {
1272 out := &outHeader{Unique: uint64(r.ID)}
1189 - r.Conn.respond(out, unsafe.Sizeof(*out))
1273 + r.respond(out, unsafe.Sizeof(*out))
1274 }
1275
1276 func (r *RemovexattrRequest) RespondError(err Error) {
@@ -1219,14 +1303,24 @@ type SetxattrRequest struct {
1303 Xattr []byte
1304 }
1305
1306 +var _ = Request(&SetxattrRequest{})
1307 +
1308 +func trunc(b []byte, max int) ([]byte, string) {
1309 + if len(b) > max {
1310 + return b[:max], "..."
1311 + }
1312 + return b, ""
1313 +}
1314 +
1315 func (r *SetxattrRequest) String() string {
1223 - return fmt.Sprintf("Setxattr [%s] %q %x fl=%v @%#x", &r.Header, r.Name, r.Xattr, r.Flags, r.Position)
1316 + xattr, tail := trunc(r.Xattr, 16)
1317 + return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position)
1318 }
1319
1320 // Respond replies to the request, indicating that the extended attribute was set.
1321 func (r *SetxattrRequest) Respond() {
1322 out := &outHeader{Unique: uint64(r.ID)}
1229 - r.Conn.respond(out, unsafe.Sizeof(*out))
1323 + r.respond(out, unsafe.Sizeof(*out))
1324 }
1325
1326 func (r *SetxattrRequest) RespondError(err Error) {
@@ -1240,6 +1334,8 @@ type LookupRequest struct {
1334 Name string
1335 }
1336
1337 +var _ = Request(&LookupRequest{})
1338 +
1339 func (r *LookupRequest) String() string {
1340 return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
1341 }
@@ -1256,7 +1352,7 @@ func (r *LookupRequest) Respond(resp *LookupResponse) {
1352 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1353 Attr: resp.Attr.attr(),
1354 }
1259 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1355 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1356 }
1357
1358 // A LookupResponse is the response to a LookupRequest.
@@ -1279,6 +1375,8 @@ type OpenRequest struct {
1375 Flags OpenFlags
1376 }
1377
1378 +var _ = Request(&OpenRequest{})
1379 +
1380 func (r *OpenRequest) String() string {
1381 return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
1382 }
@@ -1290,7 +1388,7 @@ func (r *OpenRequest) Respond(resp *OpenResponse) {
1388 Fh: uint64(resp.Handle),
1389 OpenFlags: uint32(resp.Flags),
1390 }
1293 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1391 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1392 }
1393
1394 // A OpenResponse is the response to a OpenRequest.
@@ -1311,6 +1409,8 @@ type CreateRequest struct {
1409 Mode os.FileMode
1410 }
1411
1412 +var _ = Request(&CreateRequest{})
1413 +
1414 func (r *CreateRequest) String() string {
1415 return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode)
1416 }
@@ -1331,7 +1431,7 @@ func (r *CreateRequest) Respond(resp *CreateResponse) {
1431 Fh: uint64(resp.Handle),
1432 OpenFlags: uint32(resp.Flags),
1433 }
1334 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1434 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1435 }
1436
1437 // A CreateResponse is the response to a CreateRequest.
@@ -1352,6 +1452,8 @@ type MkdirRequest struct {
1452 Mode os.FileMode
1453 }
1454
1455 +var _ = Request(&MkdirRequest{})
1456 +
1457 func (r *MkdirRequest) String() string {
1458 return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode)
1459 }
@@ -1368,7 +1470,7 @@ func (r *MkdirRequest) Respond(resp *MkdirResponse) {
1470 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1471 Attr: resp.Attr.attr(),
1472 }
1371 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1473 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1474 }
1475
1476 // A MkdirResponse is the response to a MkdirRequest.
@@ -1389,6 +1491,8 @@ type ReadRequest struct {
1491 Size int
1492 }
1493
1494 +var _ = Request(&ReadRequest{})
1495 +
1496 func (r *ReadRequest) String() string {
1497 return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir)
1498 }
@@ -1396,7 +1500,7 @@ func (r *ReadRequest) String() string {
1500 // Respond replies to the request with the given response.
1501 func (r *ReadRequest) Respond(resp *ReadResponse) {
1502 out := &outHeader{Unique: uint64(r.ID)}
1399 - r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Data)
1503 + r.respondData(out, unsafe.Sizeof(*out), resp.Data)
1504 }
1505
1506 // A ReadResponse is the response to a ReadRequest.
@@ -1429,6 +1533,8 @@ type ReleaseRequest struct {
1533 LockOwner uint32
1534 }
1535
1536 +var _ = Request(&ReleaseRequest{})
1537 +
1538 func (r *ReleaseRequest) String() string {
1539 return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
1540 }
@@ -1436,7 +1542,7 @@ func (r *ReleaseRequest) String() string {
1542 // Respond replies to the request, indicating that the handle has been released.
1543 func (r *ReleaseRequest) Respond() {
1544 out := &outHeader{Unique: uint64(r.ID)}
1439 - r.Conn.respond(out, unsafe.Sizeof(*out))
1545 + r.respond(out, unsafe.Sizeof(*out))
1546 }
1547
1548 // A DestroyRequest is sent by the kernel when unmounting the file system.
@@ -1446,6 +1552,8 @@ type DestroyRequest struct {
1552 Header `json:"-"`
1553 }
1554
1555 +var _ = Request(&DestroyRequest{})
1556 +
1557 func (r *DestroyRequest) String() string {
1558 return fmt.Sprintf("Destroy [%s]", &r.Header)
1559 }
@@ -1453,7 +1561,7 @@ func (r *DestroyRequest) String() string {
1561 // Respond replies to the request.
1562 func (r *DestroyRequest) Respond() {
1563 out := &outHeader{Unique: uint64(r.ID)}
1456 - r.Conn.respond(out, unsafe.Sizeof(*out))
1564 + r.respond(out, unsafe.Sizeof(*out))
1565 }
1566
1567 // A ForgetRequest is sent by the kernel when forgetting about r.Node
@@ -1463,6 +1571,8 @@ type ForgetRequest struct {
1571 N uint64
1572 }
1573
1574 +var _ = Request(&ForgetRequest{})
1575 +
1576 func (r *ForgetRequest) String() string {
1577 return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
1578 }
@@ -1470,6 +1580,7 @@ func (r *ForgetRequest) String() string {
1580 // Respond replies to the request, indicating that the forgetfulness has been recorded.
1581 func (r *ForgetRequest) Respond() {
1582 // Don't reply to forget messages.
1583 + r.noResponse()
1584 }
1585
1586 // A Dirent represents a single directory entry.
@@ -1562,6 +1673,8 @@ type WriteRequest struct {
1673 Flags WriteFlags
1674 }
1675
1676 +var _ = Request(&WriteRequest{})
1677 +
1678 func (r *WriteRequest) String() string {
1679 return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags)
1680 }
@@ -1589,7 +1702,7 @@ func (r *WriteRequest) Respond(resp *WriteResponse) {
1702 outHeader: outHeader{Unique: uint64(r.ID)},
1703 Size: uint32(resp.Size),
1704 }
1592 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1705 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1706 }
1707
1708 // A WriteResponse replies to a write indicating how many bytes were written.
@@ -1621,6 +1734,8 @@ type SetattrRequest struct {
1734 Flags uint32 // see chflags(2)
1735 }
1736
1737 +var _ = Request(&SetattrRequest{})
1738 +
1739 func (r *SetattrRequest) String() string {
1740 var buf bytes.Buffer
1741 fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
@@ -1680,7 +1795,7 @@ func (r *SetattrRequest) Respond(resp *SetattrResponse) {
1795 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1796 Attr: resp.Attr.attr(),
1797 }
1683 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1798 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1799 }
1800
1801 // A SetattrResponse is the response to a SetattrRequest.
@@ -1703,6 +1818,8 @@ type FlushRequest struct {
1818 LockOwner uint64
1819 }
1820
1821 +var _ = Request(&FlushRequest{})
1822 +
1823 func (r *FlushRequest) String() string {
1824 return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
1825 }
@@ -1710,16 +1827,19 @@ func (r *FlushRequest) String() string {
1827 // Respond replies to the request, indicating that the flush succeeded.
1828 func (r *FlushRequest) Respond() {
1829 out := &outHeader{Unique: uint64(r.ID)}
1713 - r.Conn.respond(out, unsafe.Sizeof(*out))
1830 + r.respond(out, unsafe.Sizeof(*out))
1831 }
1832
1716 -// A RemoveRequest asks to remove a file or directory.
1833 +// A RemoveRequest asks to remove a file or directory from the
1834 +// directory r.Node.
1835 type RemoveRequest struct {
1836 Header `json:"-"`
1719 - Name string // name of extended attribute
1837 + Name string // name of the entry to remove
1838 Dir bool // is this rmdir?
1839 }
1840
1841 +var _ = Request(&RemoveRequest{})
1842 +
1843 func (r *RemoveRequest) String() string {
1844 return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
1845 }
@@ -1727,7 +1847,7 @@ func (r *RemoveRequest) String() string {
1847 // Respond replies to the request, indicating that the file was removed.
1848 func (r *RemoveRequest) Respond() {
1849 out := &outHeader{Unique: uint64(r.ID)}
1730 - r.Conn.respond(out, unsafe.Sizeof(*out))
1850 + r.respond(out, unsafe.Sizeof(*out))
1851 }
1852
1853 // A SymlinkRequest is a request to create a symlink making NewName point to Target.
@@ -1736,6 +1856,8 @@ type SymlinkRequest struct {
1856 NewName, Target string
1857 }
1858
1859 +var _ = Request(&SymlinkRequest{})
1860 +
1861 func (r *SymlinkRequest) String() string {
1862 return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
1863 }
@@ -1752,7 +1874,7 @@ func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
1874 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1875 Attr: resp.Attr.attr(),
1876 }
1755 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1877 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1878 }
1879
1880 // A SymlinkResponse is the response to a SymlinkRequest.
@@ -1765,13 +1887,15 @@ type ReadlinkRequest struct {
1887 Header `json:"-"`
1888 }
1889
1890 +var _ = Request(&ReadlinkRequest{})
1891 +
1892 func (r *ReadlinkRequest) String() string {
1893 return fmt.Sprintf("Readlink [%s]", &r.Header)
1894 }
1895
1896 func (r *ReadlinkRequest) Respond(target string) {
1897 out := &outHeader{Unique: uint64(r.ID)}
1774 - r.Conn.respondData(out, unsafe.Sizeof(*out), []byte(target))
1898 + r.respondData(out, unsafe.Sizeof(*out), []byte(target))
1899 }
1900
1901 // A LinkRequest is a request to create a hard link.
@@ -1781,6 +1905,8 @@ type LinkRequest struct {
1905 NewName string
1906 }
1907
1908 +var _ = Request(&LinkRequest{})
1909 +
1910 func (r *LinkRequest) String() string {
1911 return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
1912 }
@@ -1796,7 +1922,7 @@ func (r *LinkRequest) Respond(resp *LookupResponse) {
1922 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1923 Attr: resp.Attr.attr(),
1924 }
1799 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1925 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1926 }
1927
1928 // A RenameRequest is a request to rename a file.
@@ -1806,13 +1932,15 @@ type RenameRequest struct {
1932 OldName, NewName string
1933 }
1934
1935 +var _ = Request(&RenameRequest{})
1936 +
1937 func (r *RenameRequest) String() string {
1938 return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName)
1939 }
1940
1941 func (r *RenameRequest) Respond() {
1942 out := &outHeader{Unique: uint64(r.ID)}
1815 - r.Conn.respond(out, unsafe.Sizeof(*out))
1943 + r.respond(out, unsafe.Sizeof(*out))
1944 }
1945
1946 type MknodRequest struct {
@@ -1822,6 +1950,8 @@ type MknodRequest struct {
1950 Rdev uint32
1951 }
1952
1953 +var _ = Request(&MknodRequest{})
1954 +
1955 func (r *MknodRequest) String() string {
1956 return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev)
1957 }
@@ -1837,7 +1967,7 @@ func (r *MknodRequest) Respond(resp *LookupResponse) {
1967 AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
1968 Attr: resp.Attr.attr(),
1969 }
1840 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
1970 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
1971 }
1972
1973 type FsyncRequest struct {
@@ -1848,13 +1978,15 @@ type FsyncRequest struct {
1978 Dir bool
1979 }
1980
1981 +var _ = Request(&FsyncRequest{})
1982 +
1983 func (r *FsyncRequest) String() string {
1984 return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
1985 }
1986
1987 func (r *FsyncRequest) Respond() {
1988 out := &outHeader{Unique: uint64(r.ID)}
1857 - r.Conn.respond(out, unsafe.Sizeof(*out))
1989 + r.respond(out, unsafe.Sizeof(*out))
1990 }
1991
1992 // An InterruptRequest is a request to interrupt another pending request. The
@@ -1864,8 +1996,11 @@ type InterruptRequest struct {
1996 IntrID RequestID // ID of the request to be interrupt.
1997 }
1998
1999 +var _ = Request(&InterruptRequest{})
2000 +
2001 func (r *InterruptRequest) Respond() {
2002 // nothing to do here
2003 + r.noResponse()
2004 }
2005
2006 func (r *InterruptRequest) String() string {
@@ -1880,6 +2015,8 @@ type XXXRequest struct {
2015 xxx
2016 }
2017
2018 +var _ = Request(&XXXRequest{})
2019 +
2020 func (r *XXXRequest) String() string {
2021 return fmt.Sprintf("XXX [%s] xxx", &r.Header)
2022 }
@@ -1890,7 +2027,7 @@ func (r *XXXRequest) Respond(resp *XXXResponse) {
2027 outHeader: outHeader{Unique: uint64(r.ID)},
2028 xxx,
2029 }
1893 - r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
2030 + r.respond(&out.outHeader, unsafe.Sizeof(*out))
2031 }
2032
2033 // A XXXResponse is the response to a XXXRequest.
Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
+1 -1
@@ -513,7 +513,7 @@ type writeOut struct {
513 Padding uint32
514 }
515
516 -// The WriteFlags are returned in the WriteResponse.
516 +// The WriteFlags are passed in WriteRequest.
517 type WriteFlags uint32
518
519 func (fl WriteFlags) String() string {
Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
+7 -1
@@ -28,7 +28,13 @@ func main() {
28 }
29 mountpoint := flag.Arg(0)
30
31 - c, err := fuse.Mount(mountpoint)
31 + c, err := fuse.Mount(
32 + mountpoint,
33 + fuse.FSName("helloworld"),
34 + fuse.Subtype("hellofs"),
35 + fuse.LocalVolume(),
36 + fuse.VolumeName("Hello world!"),
37 + )
38 if err != nil {
39 log.Fatal(err)
40 }
Godeps/_workspace/src/bazil.org/fuse/hellofs/hellofs
Binary files /dev/null and b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hellofs differ
Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
+14 -5
@@ -3,9 +3,11 @@ package fuse
3 import (
4 "bytes"
5 "errors"
6 + "fmt"
7 "os"
8 "os/exec"
9 "strconv"
10 + "strings"
11 "syscall"
12 )
13
@@ -50,15 +52,22 @@ func openOSXFUSEDev() (*os.File, error) {
52 }
53 }
54
53 -func callMount(dir string, f *os.File, ready chan<- struct{}, errp *error) error {
55 +func callMount(dir string, conf *MountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
56 bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
57 +
58 + for k, v := range conf.options {
59 + if strings.Contains(k, ",") || strings.Contains(v, ",") {
60 + // Silly limitation but the mount helper does not
61 + // understand any escaping. See TestMountOptionCommaError.
62 + return fmt.Errorf("mount options cannot contain commas on OS X: %q=%q", k, v)
63 + }
64 + }
65 cmd := exec.Command(
66 bin,
67 + "-o", conf.getOptions(),
68 // Tell osxfuse-kext how large our buffer is. It must split
69 // writes larger than this into multiple writes.
70 //
60 - // TODO add buffer reuse, bump this up significantly
61 - //
71 // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
72 // this instead.
73 "-o", "iosize="+strconv.FormatUint(maxWrite, 10),
@@ -95,7 +104,7 @@ func callMount(dir string, f *os.File, ready chan<- struct{}, errp *error) error
104 return err
105 }
106
98 -func mount(dir string, ready chan<- struct{}, errp *error) (*os.File, error) {
107 +func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
108 f, err := openOSXFUSEDev()
109 if err == errNotLoaded {
110 err = loadOSXFUSE()
@@ -108,7 +117,7 @@ func mount(dir string, ready chan<- struct{}, errp *error) (*os.File, error) {
117 if err != nil {
118 return nil, err
119 }
111 - err = callMount(dir, f, ready, errp)
120 + err = callMount(dir, conf, f, ready, errp)
121 if err != nil {
122 f.Close()
123 return nil, err
Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
+7 -2
@@ -8,7 +8,7 @@ import (
8 "syscall"
9 )
10
11 -func mount(dir string, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
11 +func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
12 // linux mount is never delayed
13 close(ready)
14
@@ -19,7 +19,12 @@ func mount(dir string, ready chan<- struct{}, errp *error) (fusefd *os.File, err
19 defer syscall.Close(fds[0])
20 defer syscall.Close(fds[1])
21
22 - cmd := exec.Command("fusermount", "--", dir)
22 + cmd := exec.Command(
23 + "fusermount",
24 + "-o", conf.getOptions(),
25 + "--",
26 + dir,
27 + )
28 cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
29
30 writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
Godeps/_workspace/src/bazil.org/fuse/options.go new
+100
@@ -0,0 +1,100 @@
1 +package fuse
2 +
3 +import (
4 + "errors"
5 + "strings"
6 +)
7 +
8 +// MountConfig holds the configuration for a mount operation.
9 +// Use it by passing MountOption values to Mount.
10 +type MountConfig struct {
11 + options map[string]string
12 +}
13 +
14 +func escapeComma(s string) string {
15 + s = strings.Replace(s, `\`, `\\`, -1)
16 + s = strings.Replace(s, `,`, `\,`, -1)
17 + return s
18 +}
19 +
20 +// getOptions makes a string of options suitable for passing to FUSE
21 +// mount flag `-o`. Returns an empty string if no options were set.
22 +// Any platform specific adjustments should happen before the call.
23 +func (m *MountConfig) getOptions() string {
24 + var opts []string
25 + for k, v := range m.options {
26 + k = escapeComma(k)
27 + if v != "" {
28 + k += "=" + escapeComma(v)
29 + }
30 + opts = append(opts, k)
31 + }
32 + return strings.Join(opts, ",")
33 +}
34 +
35 +// MountOption is passed to Mount to change the behavior of the mount.
36 +type MountOption func(*MountConfig) error
37 +
38 +// FSName sets the file system name (also called source) that is
39 +// visible in the list of mounted file systems.
40 +func FSName(name string) MountOption {
41 + return func(conf *MountConfig) error {
42 + conf.options["fsname"] = name
43 + return nil
44 + }
45 +}
46 +
47 +// Subtype sets the subtype of the mount. The main type is always
48 +// `fuse`. The type in a list of mounted file systems will look like
49 +// `fuse.foo`.
50 +//
51 +// OS X ignores this option.
52 +func Subtype(fstype string) MountOption {
53 + return func(conf *MountConfig) error {
54 + conf.options["subtype"] = fstype
55 + return nil
56 + }
57 +}
58 +
59 +// LocalVolume sets the volume to be local (instead of network),
60 +// changing the behavior of Finder, Spotlight, and such.
61 +//
62 +// OS X only. Others ignore this option.
63 +func LocalVolume() MountOption {
64 + return localVolume
65 +}
66 +
67 +// VolumeName sets the volume name shown in Finder.
68 +//
69 +// OS X only. Others ignore this option.
70 +func VolumeName(name string) MountOption {
71 + return volumeName(name)
72 +}
73 +
74 +var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
75 +
76 +// AllowOther allows other users to access the file system.
77 +//
78 +// Only one of AllowOther or AllowRoot can be used.
79 +func AllowOther() MountOption {
80 + return func(conf *MountConfig) error {
81 + if _, ok := conf.options["allow_root"]; ok {
82 + return ErrCannotCombineAllowOtherAndAllowRoot
83 + }
84 + conf.options["allow_other"] = ""
85 + return nil
86 + }
87 +}
88 +
89 +// AllowRoot allows other users to access the file system.
90 +//
91 +// Only one of AllowOther or AllowRoot can be used.
92 +func AllowRoot() MountOption {
93 + return func(conf *MountConfig) error {
94 + if _, ok := conf.options["allow_other"]; ok {
95 + return ErrCannotCombineAllowOtherAndAllowRoot
96 + }
97 + conf.options["allow_root"] = ""
98 + return nil
99 + }
100 +}
Godeps/_workspace/src/bazil.org/fuse/options_darwin.go new
+13
@@ -0,0 +1,13 @@
1 +package fuse
2 +
3 +func localVolume(conf *MountConfig) error {
4 + conf.options["local"] = ""
5 + return nil
6 +}
7 +
8 +func volumeName(name string) MountOption {
9 + return func(conf *MountConfig) error {
10 + conf.options["volname"] = name
11 + return nil
12 + }
13 +}
Godeps/_workspace/src/bazil.org/fuse/options_darwin_test.go new
+27
@@ -0,0 +1,27 @@
1 +package fuse_test
2 +
3 +import (
4 + "testing"
5 +
6 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
8 +)
9 +
10 +func TestMountOptionCommaError(t *testing.T) {
11 + t.Parallel()
12 + // this test is not tied to FSName, but needs just some option
13 + // with string content
14 + var name = "FuseTest,Marker"
15 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
16 + fuse.FSName(name),
17 + )
18 + switch {
19 + case err == nil:
20 + mnt.Close()
21 + t.Fatal("expected an error about commas")
22 + case err.Error() == `mount options cannot contain commas on OS X: "fsname"="FuseTest,Marker"`:
23 + // all good
24 + default:
25 + t.Fatalf("expected an error about commas, got: %v", err)
26 + }
27 +}
Godeps/_workspace/src/bazil.org/fuse/options_linux.go new
+13
@@ -0,0 +1,13 @@
1 +package fuse
2 +
3 +func dummyOption(conf *MountConfig) error {
4 + return nil
5 +}
6 +
7 +func localVolume(conf *MountConfig) error {
8 + return nil
9 +}
10 +
11 +func volumeName(name string) MountOption {
12 + return dummyOption
13 +}
Godeps/_workspace/src/bazil.org/fuse/options_test.go new
+141
@@ -0,0 +1,141 @@
1 +package fuse_test
2 +
3 +import (
4 + "runtime"
5 + "testing"
6 +
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
8 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
9 +)
10 +
11 +func init() {
12 + fstestutil.DebugByDefault()
13 +}
14 +
15 +func TestMountOptionFSName(t *testing.T) {
16 + t.Parallel()
17 + const name = "FuseTestMarker"
18 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
19 + fuse.FSName(name),
20 + )
21 + if err != nil {
22 + t.Fatal(err)
23 + }
24 + defer mnt.Close()
25 +
26 + info, err := fstestutil.GetMountInfo(mnt.Dir)
27 + if err != nil {
28 + t.Fatal(err)
29 + }
30 + if g, e := info.FSName, name; g != e {
31 + t.Errorf("wrong FSName: %q != %q", g, e)
32 + }
33 +}
34 +
35 +func testMountOptionFSNameEvil(t *testing.T, evil string) {
36 + t.Parallel()
37 + var name = "FuseTest" + evil + "Marker"
38 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
39 + fuse.FSName(name),
40 + )
41 + if err != nil {
42 + t.Fatal(err)
43 + }
44 + defer mnt.Close()
45 +
46 + info, err := fstestutil.GetMountInfo(mnt.Dir)
47 + if err != nil {
48 + t.Fatal(err)
49 + }
50 + if g, e := info.FSName, name; g != e {
51 + t.Errorf("wrong FSName: %q != %q", g, e)
52 + }
53 +}
54 +
55 +func TestMountOptionFSNameEvilComma(t *testing.T) {
56 + if runtime.GOOS == "darwin" {
57 + // see TestMountOptionCommaError for a test that enforces we
58 + // at least give a nice error, instead of corrupting the mount
59 + // options
60 + t.Skip("TODO: OS X gets this wrong, commas in mount options cannot be escaped at all")
61 + }
62 + testMountOptionFSNameEvil(t, ",")
63 +}
64 +
65 +func TestMountOptionFSNameEvilSpace(t *testing.T) {
66 + testMountOptionFSNameEvil(t, " ")
67 +}
68 +
69 +func TestMountOptionFSNameEvilTab(t *testing.T) {
70 + testMountOptionFSNameEvil(t, "\t")
71 +}
72 +
73 +func TestMountOptionFSNameEvilNewline(t *testing.T) {
74 + testMountOptionFSNameEvil(t, "\n")
75 +}
76 +
77 +func TestMountOptionFSNameEvilBackslash(t *testing.T) {
78 + testMountOptionFSNameEvil(t, `\`)
79 +}
80 +
81 +func TestMountOptionFSNameEvilBackslashDouble(t *testing.T) {
82 + // catch double-unescaping, if it were to happen
83 + testMountOptionFSNameEvil(t, `\\`)
84 +}
85 +
86 +func TestMountOptionSubtype(t *testing.T) {
87 + if runtime.GOOS == "darwin" {
88 + t.Skip("OS X does not support Subtype")
89 + }
90 + t.Parallel()
91 + const name = "FuseTestMarker"
92 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
93 + fuse.Subtype(name),
94 + )
95 + if err != nil {
96 + t.Fatal(err)
97 + }
98 + defer mnt.Close()
99 +
100 + info, err := fstestutil.GetMountInfo(mnt.Dir)
101 + if err != nil {
102 + t.Fatal(err)
103 + }
104 + if g, e := info.Type, "fuse."+name; g != e {
105 + t.Errorf("wrong Subtype: %q != %q", g, e)
106 + }
107 +}
108 +
109 +// TODO test LocalVolume
110 +
111 +// TODO test AllowOther; hard because needs system-level authorization
112 +
113 +func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
114 + t.Parallel()
115 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
116 + fuse.AllowOther(),
117 + fuse.AllowRoot(),
118 + )
119 + if err == nil {
120 + mnt.Close()
121 + }
122 + if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
123 + t.Fatalf("wrong error: %v != %v", g, e)
124 + }
125 +}
126 +
127 +// TODO test AllowRoot; hard because needs system-level authorization
128 +
129 +func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
130 + t.Parallel()
131 + mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
132 + fuse.AllowRoot(),
133 + fuse.AllowOther(),
134 + )
135 + if err == nil {
136 + mnt.Close()
137 + }
138 + if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
139 + t.Fatalf("wrong error: %v != %v", g, e)
140 + }
141 +}