func setupFAttrTest(t *testing.T, fs pathfs.FileSystem) (dir string, clean func()) {
	dir = testutil.TempDir()
	nfs := pathfs.NewPathNodeFs(fs, nil)
	opts := nodefs.NewOptions()
	opts.Debug = testutil.VerboseTest()

	state, _, err := nodefs.MountRoot(dir, nfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}

	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	clean = func() {
		if err := state.Unmount(); err != nil {
			t.Errorf("cleanup: Unmount: %v", err)
		} else {
			os.RemoveAll(dir)
		}
	}

	if state.KernelSettings().Flags&fuse.CAP_FILE_OPS == 0 {
		clean()
		t.Skip("Mount does not support file operations")
	}

	return dir, clean
}
func NewNotifyTest(t *testing.T) *NotifyTest {
	me := &NotifyTest{}
	me.fs = newNotifyFs()
	me.dir = testutil.TempDir()
	entryTtl := 100 * time.Millisecond
	opts := &nodefs.Options{
		EntryTimeout:    entryTtl,
		AttrTimeout:     entryTtl,
		NegativeTimeout: entryTtl,
		Debug:           testutil.VerboseTest(),
	}

	me.pathfs = pathfs.NewPathNodeFs(me.fs, nil)
	var err error
	me.state, me.connector, err = nodefs.MountRoot(me.dir, me.pathfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go me.state.Serve()
	if err := me.state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	return me
}
Beispiel #3
0
func TestOriginalIsSymlink(t *testing.T) {
	tmpDir := testutil.TempDir()
	defer os.RemoveAll(tmpDir)
	orig := tmpDir + "/orig"
	err := os.Mkdir(orig, 0755)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}
	link := tmpDir + "/link"
	mnt := tmpDir + "/mnt"
	if err := os.Mkdir(mnt, 0755); err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}
	if err := os.Symlink("orig", link); err != nil {
		t.Fatalf("Symlink failed: %v", err)
	}

	fs := pathfs.NewLoopbackFileSystem(link)
	nfs := pathfs.NewPathNodeFs(fs, nil)
	state, _, err := nodefs.MountRoot(mnt, nfs.Root(), nil)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	defer state.Unmount()

	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	if _, err := os.Lstat(mnt); err != nil {
		t.Fatalf("Lstat failed: %v", err)
	}
}
Beispiel #4
0
func setupCacheTest(t *testing.T) (string, *pathfs.PathNodeFs, func()) {
	dir := testutil.TempDir()
	os.Mkdir(dir+"/mnt", 0755)
	os.Mkdir(dir+"/orig", 0755)

	fs := &cacheFs{
		pathfs.NewLoopbackFileSystem(dir + "/orig"),
	}
	pfs := pathfs.NewPathNodeFs(fs, &pathfs.PathNodeFsOptions{Debug: testutil.VerboseTest()})

	opts := nodefs.NewOptions()
	opts.Debug = testutil.VerboseTest()
	state, _, err := nodefs.MountRoot(dir+"/mnt", pfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	return dir, pfs, func() {
		err := state.Unmount()
		if err == nil {
			os.RemoveAll(dir)
		}
	}
}
Beispiel #5
0
func TestDefaultXAttr(t *testing.T) {
	dir := testutil.TempDir()
	defer os.RemoveAll(dir)

	root := &xattrNode{
		Node: nodefs.NewDefaultNode(),
	}

	opts := nodefs.NewOptions()
	opts.Debug = testutil.VerboseTest()
	s, _, err := nodefs.MountRoot(dir, root, opts)
	if err != nil {
		t.Fatalf("MountRoot: %v", err)
	}
	go s.Serve()
	if err := s.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	defer s.Unmount()

	var data [1024]byte
	sz, err := syscall.Getxattr(filepath.Join(dir, "child"), "attr", data[:])
	if err != nil {
		t.Fatalf("Getxattr: %v", err)
	} else if val := string(data[:sz]); val != "value" {
		t.Fatalf("got %v, want 'value'", val)
	}
}
Beispiel #6
0
func TestLiveness(t *testing.T) {
	dir := testutil.TempDir()
	defer os.RemoveAll(dir)
	root := nodefs.NewDefaultNode()
	s, _, err := nodefs.MountRoot(dir, root, nil)
	if err != nil {
		t.Fatalf("MountRoot: %v", err)
	}
	go s.Serve()
	if err := s.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	defer s.Unmount()

	if _, err := ioutil.ReadDir(dir); err != nil {
		t.Fatalf("ReadDir: %v", err)
	}

	// We previously encountered a sitation where a finalizer would close our fd out from under us. Try to force both finalizers to run and object destruction to complete.
	runtime.GC()
	runtime.GC()

	if _, err := ioutil.ReadDir(dir); err != nil {
		t.Fatalf("ReadDir: %v", err)
	}
}
Beispiel #7
0
func TestNonseekable(t *testing.T) {
	fs := &nonseekFs{FileSystem: pathfs.NewDefaultFileSystem()}
	fs.Length = 200 * 1024

	dir := testutil.TempDir()
	defer os.RemoveAll(dir)
	nfs := pathfs.NewPathNodeFs(fs, nil)
	opts := nodefs.NewOptions()
	opts.Debug = testutil.VerboseTest()
	state, _, err := nodefs.MountRoot(dir, nfs.Root(), opts)
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
	defer state.Unmount()

	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	f, err := os.Open(dir + "/file")
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
	defer f.Close()

	b := make([]byte, 200)
	n, err := f.ReadAt(b, 20)
	if err == nil || n > 0 {
		t.Errorf("file was opened nonseekable, but seek successful")
	}
}
Beispiel #8
0
func TestDefaultNodeMount(t *testing.T) {
	dir := testutil.TempDir()
	defer os.RemoveAll(dir)
	root := nodefs.NewDefaultNode()
	s, conn, err := nodefs.MountRoot(dir, root, nil)
	if err != nil {
		t.Fatalf("MountRoot: %v", err)
	}
	go s.Serve()
	if err := s.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	defer s.Unmount()

	if err := conn.Mount(root.Inode(), "sub", nodefs.NewDefaultNode(), nil); !err.Ok() {
		t.Fatalf("Mount: %v", err)
	}

	if entries, err := ioutil.ReadDir(dir); err != nil {
		t.Fatalf("ReadDir: %v", err)
	} else if len(entries) != 1 {
		t.Fatalf("got %d entries", len(entries))
	} else if entries[0].Name() != "sub" {
		t.Fatalf("got %q, want %q", entries[0].Name(), "sub")
	}
}
Beispiel #9
0
func setup(t *testing.T) (workdir string, server *fuse.Server, cleanup func()) {
	wd := testutil.TempDir()
	err := os.Mkdir(wd+"/mnt", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	err = os.Mkdir(wd+"/store", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	os.Mkdir(wd+"/ro", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}
	WriteFile(t, wd+"/ro/file1", "file1")
	WriteFile(t, wd+"/ro/file2", "file2")

	fs := NewAutoUnionFs(wd+"/store", testAOpts)

	nfs := pathfs.NewPathNodeFs(fs, nil)
	state, _, err := nodefs.MountRoot(wd+"/mnt", nfs.Root(), &testAOpts.Options)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	state.WaitMount()

	return wd, state, func() {
		state.Unmount()
		os.RemoveAll(wd)
	}
}
func defaultReadTest(t *testing.T) (root string, cleanup func()) {
	fs := &DefaultReadFS{
		FileSystem: pathfs.NewDefaultFileSystem(),
		size:       22,
	}

	var err error
	dir := testutil.TempDir()
	pathfs := pathfs.NewPathNodeFs(fs, nil)
	opts := nodefs.NewOptions()
	opts.Debug = testutil.VerboseTest()

	state, _, err := nodefs.MountRoot(dir, pathfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	return dir, func() {
		state.Unmount()
		os.Remove(dir)
	}
}
Beispiel #11
0
func BenchmarkCFuseThreadedStat(b *testing.B) {
	b.StopTimer()

	wd, _ := os.Getwd()
	fileList := wd + "/testpaths.txt"
	lines := ReadLines(fileList)
	unique := map[string]int{}
	for _, l := range lines {
		unique[l] = 1
		dir, _ := filepath.Split(l)
		for dir != "/" && dir != "" {
			unique[dir] = 1
			dir = filepath.Clean(dir)
			dir, _ = filepath.Split(dir)
		}
	}

	out := []string{}
	for k := range unique {
		out = append(out, k)
	}

	f, err := ioutil.TempFile("", "")
	if err != nil {
		b.Fatalf("failed: %v", err)
	}
	sort.Strings(out)
	for _, k := range out {
		f.Write([]byte(fmt.Sprintf("/%s\n", k)))
	}
	f.Close()

	mountPoint := testutil.TempDir()
	cmd := exec.Command(wd+"/cstatfs",
		"-o",
		"entry_timeout=0.0,attr_timeout=0.0,ac_attr_timeout=0.0,negative_timeout=0.0",
		mountPoint)
	cmd.Env = append(os.Environ(),
		fmt.Sprintf("STATFS_INPUT=%s", f.Name()))
	cmd.Start()

	bin, err := exec.LookPath("fusermount")
	if err != nil {
		b.Fatalf("failed: %v", err)
	}
	stop := exec.Command(bin, "-u", mountPoint)
	if err != nil {
		b.Fatalf("failed: %v", err)
	}
	defer stop.Run()

	time.Sleep(100 * time.Millisecond)
	os.Lstat(mountPoint)
	threads := runtime.GOMAXPROCS(0)
	if err := TestingBOnePass(b, threads, fileList, mountPoint); err != nil {
		log.Fatalf("TestingBOnePass %v", err)
	}
}
Beispiel #12
0
// Creates a temporary dir "wd" with 3 directories:
// mnt ... overlayed (unionfs) mount
// rw .... modifiable data
// ro .... read-only data
func setupUfs(t *testing.T) (wd string, cleanup func()) {
	// Make sure system setting does not affect test.
	syscall.Umask(0)

	wd = testutil.TempDir()
	err := os.Mkdir(wd+"/mnt", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	err = os.Mkdir(wd+"/rw", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	os.Mkdir(wd+"/ro", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	var fses []pathfs.FileSystem
	fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/rw"))
	fses = append(fses,
		NewCachingFileSystem(pathfs.NewLoopbackFileSystem(wd+"/ro"), 0))
	ufs, err := NewUnionFs(fses, testOpts)
	if err != nil {
		t.Fatalf("NewUnionFs: %v", err)
	}
	// We configure timeouts are smaller, so we can check for
	// UnionFs's cache consistency.
	opts := &nodefs.Options{
		EntryTimeout:    entryTtl / 2,
		AttrTimeout:     entryTtl / 2,
		NegativeTimeout: entryTtl / 2,
		PortableInodes:  true,
		Debug:           testutil.VerboseTest(),
	}

	pathfs := pathfs.NewPathNodeFs(ufs,
		&pathfs.PathNodeFsOptions{ClientInodes: true,
			Debug: opts.Debug,
		})
	state, _, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	state.WaitMount()

	return wd, func() {
		err := state.Unmount()
		if err != nil {
			return
		}
		setRecursiveWritable(t, wd, true)
		os.RemoveAll(wd)
	}
}
Beispiel #13
0
func TestCopyFile(t *testing.T) {
	d1 := testutil.TempDir()
	defer os.RemoveAll(d1)
	d2 := testutil.TempDir()
	defer os.RemoveAll(d2)

	fs1 := NewLoopbackFileSystem(d1)
	fs2 := NewLoopbackFileSystem(d2)

	content1 := "blabla"

	err := ioutil.WriteFile(d1+"/file", []byte(content1), 0644)
	if err != nil {
		t.Fatalf("WriteFile failed: %v", err)
	}

	code := CopyFile(fs1, fs2, "file", "file", nil)
	if !code.Ok() {
		t.Fatal("Unexpected ret code", code)
	}

	data, err := ioutil.ReadFile(d2 + "/file")
	if content1 != string(data) {
		t.Fatal("Unexpected content", string(data))
	}

	content2 := "foobar"

	err = ioutil.WriteFile(d2+"/file", []byte(content2), 0644)
	if err != nil {
		t.Fatalf("WriteFile failed: %v", err)
	}

	// Copy back: should overwrite.
	code = CopyFile(fs2, fs1, "file", "file", nil)
	if !code.Ok() {
		t.Fatal("Unexpected ret code", code)
	}

	data, err = ioutil.ReadFile(d1 + "/file")
	if content2 != string(data) {
		t.Fatal("Unexpected content", string(data))
	}

}
Beispiel #14
0
func TestDefaultNodeGetAttr(t *testing.T) {
	dir := testutil.TempDir()
	defer os.RemoveAll(dir)

	opts := &nodefs.Options{
		// Note: defaultNode.GetAttr() calling file.GetAttr() is only useful if
		// AttrTimeout is zero.
		// See https://github.com/JonathonReinhart/gitlab-fuse/issues/2
		Owner: fuse.CurrentOwner(),
	}

	root := nodefs.NewDefaultNode()
	s, _, err := nodefs.MountRoot(dir, root, opts)
	if err != nil {
		t.Fatalf("MountRoot: %v", err)
	}
	go s.Serve()
	if err := s.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	defer s.Unmount()

	// Attach another custom node type
	root.Inode().NewChild("foo", false, &myNode{
		Node:    nodefs.NewDefaultNode(),
		content: []byte("success"),
	})

	filepath := path.Join(dir, "foo")

	// NewDefaultNode() should provide for stat that indicates 0-byte regular file
	fi, err := os.Stat(filepath)
	if err != nil {
		t.Fatalf("Stat: %v", err)
	}
	if mode := (fi.Mode() & os.ModeType); mode != 0 {
		// Mode() & ModeType should be zero for regular files
		t.Fatalf("Unexpected mode: %#o", mode)
	}
	if size := fi.Size(); size != 0 {
		t.Fatalf("Unexpected size: %d", size)
	}

	// But when we open the file, we should get the content
	content, err := ioutil.ReadFile(filepath)
	if err != nil {
		t.Fatalf("ReadFile: %v", err)
	}
	if string(content) != "success" {
		t.Fatalf("Unexpected content: %v", content)
	}
}
Beispiel #15
0
// 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 = testutil.TempDir()
	tc.orig = tc.tmpDir + "/orig"
	tc.mnt = tc.tmpDir + "/mnt"

	tc.Mkdir(tc.orig, 0700)
	tc.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,
			Debug:           testutil.VerboseTest(),
		})
	tc.state, err = fuse.NewServer(
		fuse.NewRawFileSystem(tc.connector.RawFS()), tc.mnt, &fuse.MountOptions{
			SingleThreaded: true,
			Debug:          testutil.VerboseTest(),
		})
	if err != nil {
		t.Fatal("NewServer:", err)
	}

	go tc.state.Serve()
	if err := tc.state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	return tc
}
Beispiel #16
0
func xattrTestCase(t *testing.T, nm string, m map[string][]byte) (mountPoint string, cleanup func()) {
	xfs := NewXAttrFs(nm, m)
	mountPoint = testutil.TempDir()

	nfs := NewPathNodeFs(xfs, nil)
	state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(),
		&nodefs.Options{Debug: VerboseTest()})
	if err != nil {
		t.Fatalf("MountRoot failed: %v", err)
	}

	go state.Serve()
	return mountPoint, func() {
		state.Unmount()
		os.RemoveAll(mountPoint)
	}
}
Beispiel #17
0
func TestGetAttrRace(t *testing.T) {
	dir := testutil.TempDir()
	defer os.RemoveAll(dir)
	os.Mkdir(dir+"/mnt", 0755)
	os.Mkdir(dir+"/orig", 0755)

	fs := pathfs.NewLoopbackFileSystem(dir + "/orig")
	pfs := pathfs.NewPathNodeFs(fs, &pathfs.PathNodeFsOptions{Debug: testutil.VerboseTest()})
	state, _, err := nodefs.MountRoot(dir+"/mnt", pfs.Root(),
		&nodefs.Options{Debug: testutil.VerboseTest()})
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	defer state.Unmount()

	var wg sync.WaitGroup

	n := 100
	wg.Add(n)
	var statErr error
	for i := 0; i < n; i++ {
		go func() {
			defer wg.Done()
			fn := dir + "/mnt/file"
			err := ioutil.WriteFile(fn, []byte{42}, 0644)
			if err != nil {
				statErr = err
				return
			}
			_, err = os.Lstat(fn)
			if err != nil {
				statErr = err
			}
		}()
	}
	wg.Wait()
	if statErr != nil {
		t.Error(statErr)
	}
}
Beispiel #18
0
func setupOwnerTest(t *testing.T, opts *nodefs.Options) (workdir string, cleanup func()) {
	wd := testutil.TempDir()

	fs := &ownerFs{NewDefaultFileSystem()}
	nfs := NewPathNodeFs(fs, nil)
	state, _, err := nodefs.MountRoot(wd, nfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}
	return wd, func() {
		state.Unmount()
		os.RemoveAll(wd)
	}
}
Beispiel #19
0
func setupZipfs(t *testing.T) (mountPoint string, cleanup func()) {
	root, err := NewArchiveFileSystem(testZipFile())
	if err != nil {
		t.Fatalf("NewArchiveFileSystem failed: %v", err)
	}

	mountPoint = testutil.TempDir()
	state, _, err := nodefs.MountRoot(mountPoint, root, &nodefs.Options{
		Debug: testutil.VerboseTest(),
	})

	go state.Serve()
	state.WaitMount()

	return mountPoint, func() {
		state.Unmount()
		os.RemoveAll(mountPoint)
	}
}
Beispiel #20
0
func TestCachingFs(t *testing.T) {
	wd := testutil.TempDir()
	defer os.RemoveAll(wd)

	fs := pathfs.NewLoopbackFileSystem(wd)
	cfs := NewCachingFileSystem(fs, 0)

	os.Mkdir(wd+"/orig", 0755)
	fi, code := cfs.GetAttr("orig", nil)
	if !code.Ok() {
		t.Fatal("GetAttr failure", code)
	}
	if !fi.IsDir() {
		t.Error("unexpected attr", fi)
	}

	os.Symlink("orig", wd+"/symlink")

	val, code := cfs.Readlink("symlink", nil)
	if val != "orig" {
		t.Error("unexpected readlink", val)
	}
	if !code.Ok() {
		t.Error("code !ok ", code)
	}

	stream, code := cfs.OpenDir("", nil)
	if !code.Ok() {
		t.Fatal("Readdir fail", code)
	}

	results := make(map[string]uint32)
	for _, v := range stream {
		results[v.Name] = v.Mode &^ 07777
	}
	expected := map[string]uint32{
		"symlink": syscall.S_IFLNK,
		"orig":    fuse.S_IFDIR,
	}
	if !modeMapEq(results, expected) {
		t.Error("Unexpected readdir result", results, expected)
	}
}
Beispiel #21
0
func setupFs(fs pathfs.FileSystem, N int) (string, func()) {
	opts := &nodefs.Options{
		EntryTimeout:    0.0,
		AttrTimeout:     0.0,
		NegativeTimeout: 0.0,
	}
	mountPoint := testutil.TempDir()
	nfs := pathfs.NewPathNodeFs(fs, nil)
	state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), opts)
	if err != nil {
		panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods.
	}
	lmap := NewLatencyMap()
	if testutil.VerboseTest() {
		state.RecordLatencies(lmap)
	}
	go state.Serve()

	return mountPoint, func() {
		if testutil.VerboseTest() {
			var total time.Duration
			for _, n := range []string{"LOOKUP", "GETATTR", "OPENDIR", "READDIR",
				"READDIRPLUS", "RELEASEDIR", "FLUSH",
			} {
				if count, dt := lmap.Get(n); count > 0 {
					total += dt
					log.Printf("%s %v/call n=%d", n,
						dt/time.Duration(count), count)
				}
			}

			log.Printf("total %v, %v/bench op", total, total/time.Duration(N))
		}

		err := state.Unmount()
		if err != nil {
			log.Println("error during unmount", err)
		} else {
			os.RemoveAll(mountPoint)
		}
	}
}
Beispiel #22
0
func setupMzfs(t *testing.T) (mountPoint string, state *fuse.Server, cleanup func()) {
	fs := NewMultiZipFs()
	mountPoint = testutil.TempDir()
	nfs := pathfs.NewPathNodeFs(fs, nil)
	state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), &nodefs.Options{
		EntryTimeout:    testTtl,
		AttrTimeout:     testTtl,
		NegativeTimeout: 0.0,
		Debug:           testutil.VerboseTest(),
	})
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	go state.Serve()
	state.WaitMount()

	return mountPoint, state, func() {
		state.Unmount()
		os.RemoveAll(mountPoint)
	}
}
Beispiel #23
0
func TestXAttrCaching(t *testing.T) {
	wd := testutil.TempDir()
	defer os.RemoveAll(wd)
	os.Mkdir(wd+"/mnt", 0700)
	err := os.Mkdir(wd+"/rw", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	rwFS := pathfs.NewLoopbackFileSystem(wd + "/rw")
	roFS := &TestFS{
		FileSystem: pathfs.NewDefaultFileSystem(),
	}

	ufs, err := NewUnionFs([]pathfs.FileSystem{rwFS,
		NewCachingFileSystem(roFS, entryTtl)}, testOpts)
	if err != nil {
		t.Fatalf("NewUnionFs: %v", err)
	}

	opts := &nodefs.Options{
		EntryTimeout:    entryTtl / 2,
		AttrTimeout:     entryTtl / 2,
		NegativeTimeout: entryTtl / 2,
		Debug:           testutil.VerboseTest(),
	}

	pathfs := pathfs.NewPathNodeFs(ufs,
		&pathfs.PathNodeFsOptions{ClientInodes: true,
			Debug: testutil.VerboseTest()})

	server, _, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	defer server.Unmount()
	go server.Serve()
	server.WaitMount()

	if fi, err := os.Lstat(wd + "/mnt"); err != nil || !fi.IsDir() {
		t.Fatalf("root not readable: %v, %v", err, fi)
	}

	buf := make([]byte, 1024)
	n, err := Getxattr(wd+"/mnt/file", "user.attr", buf)
	if err != nil {
		t.Fatalf("Getxattr: %v", err)
	}
	want := "\x2a"
	got := string(buf[:n])
	if got != want {
		t.Fatalf("Got %q want %q", got, err)
	}

	time.Sleep(entryTtl / 3)

	n, err = Getxattr(wd+"/mnt/file", "user.attr", buf)
	if err != nil {
		t.Fatalf("Getxattr: %v", err)
	}
	got = string(buf[:n])
	if got != want {
		t.Fatalf("Got %q want %q", got, err)
	}

	time.Sleep(entryTtl / 3)

	// Make sure that an interceding Getxattr() to a filesystem that doesn't implement GetXAttr() doesn't affect future calls.
	Getxattr(wd, "whatever", buf)

	n, err = Getxattr(wd+"/mnt/file", "user.attr", buf)
	if err != nil {
		t.Fatalf("Getxattr: %v", err)
	}
	got = string(buf[:n])
	if got != want {
		t.Fatalf("Got %q want %q", got, err)
	}

	if roFS.xattrRead != 1 {
		t.Errorf("got xattrRead=%d, want 1", roFS.xattrRead)
	}
}
Beispiel #24
0
func TestUnionFsDisappearing(t *testing.T) {
	// This init is like setupUfs, but we want access to the
	// writable Fs.
	wd := testutil.TempDir()
	defer os.RemoveAll(wd)
	err := os.Mkdir(wd+"/mnt", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	err = os.Mkdir(wd+"/rw", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	os.Mkdir(wd+"/ro", 0700)
	if err != nil {
		t.Fatalf("Mkdir failed: %v", err)
	}

	wrFs := newDisappearingFS(pathfs.NewLoopbackFileSystem(wd+"/rw"),
		pathfs.NewLoopbackFileSystem("/dev/null"))
	var fses []pathfs.FileSystem
	fses = append(fses, pathfs.NewLockingFileSystem(wrFs))
	fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/ro"))
	ufs, err := NewUnionFs(fses, testOpts)
	if err != nil {
		t.Fatalf("NewUnionFs: %v", err)
	}

	opts := &nodefs.Options{
		EntryTimeout:    entryTtl,
		AttrTimeout:     entryTtl,
		NegativeTimeout: entryTtl,
		Debug:           testutil.VerboseTest(),
	}

	nfs := pathfs.NewPathNodeFs(ufs, nil)
	state, _, err := nodefs.MountRoot(wd+"/mnt", nfs.Root(), opts)
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
	defer state.Unmount()
	go state.Serve()
	state.WaitMount()

	err = ioutil.WriteFile(wd+"/ro/file", []byte("blabla"), 0644)
	if err != nil {
		t.Fatalf("WriteFile failed: %v", err)
	}
	setRecursiveWritable(t, wd+"/ro", false)

	err = os.Remove(wd + "/mnt/file")
	if err != nil {
		t.Fatalf("Remove failed: %v", err)
	}

	wrFs.visibleChan <- false
	time.Sleep((3 * entryTtl) / 2)

	_, err = ioutil.ReadDir(wd + "/mnt")
	if err == nil {
		t.Fatal("Readdir should have failed")
	}

	err = ioutil.WriteFile(wd+"/mnt/file2", []byte("blabla"), 0644)
	if err == nil {
		t.Fatal("write should have failed")
	}

	// Wait for the caches to purge, and then restore.
	time.Sleep((3 * entryTtl) / 2)
	wrFs.visibleChan <- true

	_, err = ioutil.ReadDir(wd + "/mnt")
	if err != nil {
		t.Fatal("Readdir should succeed", err)
	}
	err = ioutil.WriteFile(wd+"/mnt/file2", []byte("blabla"), 0644)
	if err != nil {
		t.Fatal("write should succeed", err)
	}
}
func TestDeleteNotify(t *testing.T) {
	dir := testutil.TempDir()
	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, &fuse.MountOptions{
		Debug: testutil.VerboseTest(),
	})
	if err != nil {
		t.Fatal(err)
	}
	go state.Serve()
	defer state.Unmount()
	if err := state.WaitMount(); err != nil {
		t.Fatal("WaitMount", err)
	}

	_, 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)
	}
}