// Creates 3 directories on a temporary dir: /mnt with the overlayed // (unionfs) mount, rw with modifiable data, and ro on the bottom. func setupUfs(t *testing.T) (workdir string, cleanup func()) { // Make sure system setting does not affect test. syscall.Umask(0) wd, _ := ioutil.TempDir("", "unionfs") 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, } pathfs := pathfs.NewPathNodeFs(ufs, &pathfs.PathNodeFsOptions{ClientInodes: true}) state, conn, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } conn.SetDebug(VerboseTest()) state.SetDebug(VerboseTest()) pathfs.SetDebug(VerboseTest()) go state.Serve() return wd, func() { err := state.Unmount() if err != nil { return } setRecursiveWritable(t, wd, true) os.RemoveAll(wd) } }
func main() { debug := flag.Bool("debug", false, "debug on") hardlinks := flag.Bool("hardlinks", false, "support hardlinks") delcache_ttl := flag.Float64("deletion_cache_ttl", 5.0, "Deletion cache TTL in seconds.") branchcache_ttl := flag.Float64("branchcache_ttl", 5.0, "Branch cache TTL in seconds.") deldirname := flag.String( "deletion_dirname", "GOUNIONFS_DELETIONS", "Directory name to use for deletions.") hide_readonly_link := flag.Bool("hide_readonly_link", true, "Hides READONLY link from the top mountpoints. "+ "Enabled by default.") portableInodes := flag.Bool("portable-inodes", false, "Use sequential 32-bit inode numbers.") flag.Parse() if len(flag.Args()) < 2 { fmt.Println("Usage:\n main MOUNTPOINT BASEDIR") os.Exit(2) } ufsOptions := unionfs.UnionFsOptions{ DeletionCacheTTL: time.Duration(*delcache_ttl * float64(time.Second)), BranchCacheTTL: time.Duration(*branchcache_ttl * float64(time.Second)), DeletionDirName: *deldirname, } options := unionfs.AutoUnionFsOptions{ UnionFsOptions: ufsOptions, Options: nodefs.Options{ EntryTimeout: time.Second, AttrTimeout: time.Second, NegativeTimeout: time.Second, Owner: fuse.CurrentOwner(), }, UpdateOnMount: true, PathNodeFsOptions: pathfs.PathNodeFsOptions{ ClientInodes: *hardlinks, }, HideReadonly: *hide_readonly_link, } fsOpts := nodefs.Options{ PortableInodes: *portableInodes, } gofs := unionfs.NewAutoUnionFs(flag.Arg(1), options) pathfs := pathfs.NewPathNodeFs(gofs, nil) state, conn, err := nodefs.MountRoot(flag.Arg(0), pathfs.Root(), &fsOpts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } pathfs.SetDebug(*debug) conn.SetDebug(*debug) state.SetDebug(*debug) state.Serve() time.Sleep(1 * time.Second) }
func TestXAttrCaching(t *testing.T) { wd, _ := ioutil.TempDir("", "unionfs") 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, } pathfs := pathfs.NewPathNodeFs(ufs, &pathfs.PathNodeFsOptions{ClientInodes: true}) server, conn, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } server.SetDebug(VerboseTest()) conn.SetDebug(VerboseTest()) pathfs.SetDebug(VerboseTest()) defer server.Unmount() go server.Serve() 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 := syscall.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 / 2) n, err = syscall.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) } server.Unmount() if roFS.xattrRead != 1 { t.Errorf("got xattrRead=%d, want 1", roFS.xattrRead) } }