func setupMemNodeTest(t *testing.T) (wd string, root Node, clean func()) { tmp, err := ioutil.TempDir("", "go-fuse-memnode_test") if err != nil { t.Fatalf("TempDir failed: %v", err) } back := tmp + "/backing" os.Mkdir(back, 0700) root = NewMemNodeFSRoot(back) mnt := tmp + "/mnt" os.Mkdir(mnt, 0700) connector := NewFileSystemConnector(root, &Options{ EntryTimeout: testTtl, AttrTimeout: testTtl, NegativeTimeout: 0.0, }) connector.SetDebug(VerboseTest()) state, err := fuse.NewServer(connector.RawFS(), mnt, nil) if err != nil { t.Fatal("NewServer", err) } //me.state.SetDebug(false) state.SetDebug(VerboseTest()) // Unthreaded, but in background. go state.Serve() return mnt, root, func() { state.Unmount() os.RemoveAll(tmp) } }
// Mounts a filesystem with the given root node on the given directory func MountRoot(mountpoint string, root Node, opts *Options) (*fuse.Server, *FileSystemConnector, error) { conn := NewFileSystemConnector(root, opts) s, err := fuse.NewServer(conn.RawFS(), mountpoint, nil) if err != nil { return nil, nil, err } return s, conn, nil }
// Create and mount filesystem. func NewTestCase(t *testing.T) *testCase { tc := &testCase{} tc.tester = t // Make sure system setting does not affect test. syscall.Umask(0) const name string = "hello.txt" const subdir string = "subdir" var err error tc.tmpDir, err = ioutil.TempDir("", "go-fuse") if err != nil { t.Fatalf("TempDir failed: %v", err) } tc.orig = tc.tmpDir + "/orig" tc.mnt = tc.tmpDir + "/mnt" os.Mkdir(tc.orig, 0700) os.Mkdir(tc.mnt, 0700) tc.mountFile = filepath.Join(tc.mnt, name) tc.mountSubdir = filepath.Join(tc.mnt, subdir) tc.origFile = filepath.Join(tc.orig, name) tc.origSubdir = filepath.Join(tc.orig, subdir) var pfs pathfs.FileSystem pfs = pathfs.NewLoopbackFileSystem(tc.orig) pfs = pathfs.NewLockingFileSystem(pfs) tc.pathFs = pathfs.NewPathNodeFs(pfs, &pathfs.PathNodeFsOptions{ ClientInodes: true}) tc.connector = nodefs.NewFileSystemConnector(tc.pathFs.Root(), &nodefs.Options{ EntryTimeout: testTtl, AttrTimeout: testTtl, NegativeTimeout: 0.0, }) tc.connector.SetDebug(VerboseTest()) tc.state, err = fuse.NewServer( fuse.NewRawFileSystem(tc.connector.RawFS()), tc.mnt, &fuse.MountOptions{SingleThreaded: true}) if err != nil { t.Fatal("NewServer:", err) } tc.state.SetDebug(VerboseTest()) // Unthreaded, but in background. go tc.state.Serve() tc.state.WaitMount() return tc }
func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") other := flag.Bool("allow-other", false, "mount with -o allowother.") flag.Parse() if flag.NArg() < 2 { // TODO - where to get program name? fmt.Println("usage: main MOUNTPOINT ORIGINAL") os.Exit(2) } var finalFs pathfs.FileSystem orig := flag.Arg(1) loopbackfs := pathfs.NewLoopbackFileSystem(orig) finalFs = loopbackfs opts := &nodefs.Options{ // These options are to be compatible with libfuse defaults, // making benchmarking easier. NegativeTimeout: time.Second, AttrTimeout: time.Second, EntryTimeout: time.Second, } pathFs := pathfs.NewPathNodeFs(finalFs, nil) conn := nodefs.NewFileSystemConnector(pathFs.Root(), opts) mountPoint := flag.Arg(0) origAbs, _ := filepath.Abs(orig) mOpts := &fuse.MountOptions{ AllowOther: *other, Name: "loopbackfs", FsName: origAbs, } state, err := fuse.NewServer(conn.RawFS(), mountPoint, mOpts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } state.SetDebug(*debug) fmt.Println("Mounted!") state.Serve() }
func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") flag.Parse() if flag.NArg() < 2 { // TODO - where to get program name? fmt.Println("usage: main MOUNTPOINT BACKING-PREFIX") os.Exit(2) } mountPoint := flag.Arg(0) prefix := flag.Arg(1) root := nodefs.NewMemNodeFSRoot(prefix) conn := nodefs.NewFileSystemConnector(root, nil) server, err := fuse.NewServer(conn.RawFS(), mountPoint, nil) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } server.SetDebug(*debug) fmt.Println("Mounted!") server.Serve() }
func TestDeleteNotify(t *testing.T) { dir, err := ioutil.TempDir("", "go-fuse-delete_test") if err != nil { t.Fatalf("TempDir failed %v", err) } defer os.RemoveAll(dir) root := nodefs.NewMemNodeFSRoot(dir + "/backing") conn := nodefs.NewFileSystemConnector(root, &nodefs.Options{PortableInodes: true}) mnt := dir + "/mnt" err = os.Mkdir(mnt, 0755) if err != nil { t.Fatal(err) } state, err := fuse.NewServer(conn.RawFS(), mnt, nil) if err != nil { t.Fatal(err) } state.SetDebug(VerboseTest()) go state.Serve() defer state.Unmount() _, code := root.Mkdir("testdir", 0755, nil) if !code.Ok() { t.Fatal(code) } ch := root.Inode().RmChild("testdir") ch.Node().SetInode(nil) flip := flipNode{ Node: ch.Node(), ok: make(chan int), } root.Inode().NewChild("testdir", true, &flip) err = ioutil.WriteFile(mnt+"/testdir/testfile", []byte{42}, 0644) if err != nil { t.Fatal(err) } // Do the test here, so we surely have state.KernelSettings() if state.KernelSettings().Minor < 18 { t.Log("Kernel does not support deletion notify; aborting test.") return } buf := bytes.Buffer{} cmd := exec.Command("/usr/bin/tail", "-f", "testfile") cmd.Dir = mnt + "/testdir" cmd.Stdin = &buf cmd.Stdout = &bytes.Buffer{} cmd.Stderr = os.Stderr err = cmd.Start() if err != nil { t.Fatal(err) } defer func() { cmd.Process.Kill() time.Sleep(100 * time.Millisecond) }() // Wait until tail opened the file. time.Sleep(100 * time.Millisecond) err = os.Remove(mnt + "/testdir/testfile") if err != nil { t.Fatal(err) } // Simulate deletion+mkdir coming from the network close(flip.ok) oldCh := root.Inode().RmChild("testdir") _, code = root.Inode().Node().Mkdir("testdir", 0755, nil) if !code.Ok() { t.Fatal("mkdir status", code) } conn.DeleteNotify(root.Inode(), oldCh, "testdir") _, err = os.Lstat(mnt + "/testdir") if err != nil { t.Fatalf("lstat after del + mkdir failed: %v", err) } }