func setupCacheTest(t *testing.T) (string, *pathfs.PathNodeFs, func()) { dir, err := ioutil.TempDir("", "go-fuse-cachetest") if err != nil { t.Fatalf("TempDir failed: %v", err) } os.Mkdir(dir+"/mnt", 0755) os.Mkdir(dir+"/orig", 0755) fs := &cacheFs{ pathfs.NewLoopbackFileSystem(dir + "/orig"), } pfs := pathfs.NewPathNodeFs(fs, nil) state, conn, err := nodefs.MountFileSystem(dir+"/mnt", pfs, nil) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } state.SetDebug(VerboseTest()) conn.SetDebug(VerboseTest()) pfs.SetDebug(VerboseTest()) go state.Serve() return dir, pfs, func() { err := state.Unmount() if err == nil { os.RemoveAll(dir) } } }
func setupFAttrTest(t *testing.T, fs pathfs.FileSystem) (dir string, clean func()) { dir, err := ioutil.TempDir("", "go-fuse-fsetattr_test") if err != nil { t.Fatalf("TempDir failed: %v", err) } nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(dir, nfs, nil) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } state.SetDebug(VerboseTest()) go state.Serve() // Trigger INIT. os.Lstat(dir) if state.KernelSettings().Flags&fuse.CAP_FILE_OPS == 0 { t.Log("Mount does not support file operations") } return dir, func() { if state.Unmount() == nil { os.RemoveAll(dir) } } }
func setup(t *testing.T) (workdir string, cleanup func()) { wd, _ := ioutil.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.MountFileSystem(wd+"/mnt", nfs, &testAOpts.Options) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } fs.SetDebug(VerboseTest()) go state.Serve() return wd, func() { state.Unmount() os.RemoveAll(wd) } }
func setupFs(fs pathfs.FileSystem) (string, func()) { opts := &nodefs.Options{ EntryTimeout: 0.0, AttrTimeout: 0.0, NegativeTimeout: 0.0, } mountPoint, _ := ioutil.TempDir("", "stat_test") nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(mountPoint, nfs, opts) if err != nil { panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods. } lmap := NewLatencyMap() state.RecordLatencies(lmap) // state.SetDebug(true) go state.Serve() return mountPoint, func() { lc, lns := lmap.Get("LOOKUP") gc, gns := lmap.Get("GETATTR") fmt.Printf("GETATTR %v/call n=%d, LOOKUP %v/call n=%d\n", gns/time.Duration(gc), gc, lns/time.Duration(lc), lc) err := state.Unmount() if err != nil { log.Println("error during unmount", err) } else { os.RemoveAll(mountPoint) } } }
func NewNotifyTest(t *testing.T) *NotifyTest { me := &NotifyTest{} me.fs = newNotifyFs() var err error me.dir, err = ioutil.TempDir("", "go-fuse-notify_test") if err != nil { t.Fatalf("TempDir failed: %v", err) } entryTtl := 100 * time.Millisecond opts := &nodefs.Options{ EntryTimeout: entryTtl, AttrTimeout: entryTtl, NegativeTimeout: entryTtl, } me.pathfs = pathfs.NewPathNodeFs(me.fs, nil) me.state, me.connector, err = nodefs.MountFileSystem(me.dir, me.pathfs, opts) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } me.state.SetDebug(VerboseTest()) go me.state.Serve() return me }
func TestNonseekable(t *testing.T) { fs := &nonseekFs{FileSystem: pathfs.NewDefaultFileSystem()} fs.Length = 200 * 1024 dir, err := ioutil.TempDir("", "go-fuse-cache_test") if err != nil { t.Fatalf("failed: %v", err) } defer os.RemoveAll(dir) nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(dir, nfs, nil) if err != nil { t.Fatalf("failed: %v", err) } state.SetDebug(VerboseTest()) defer state.Unmount() go state.Serve() 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") } }
// 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.MountFileSystem(wd+"/mnt", pathfs, 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.MountFileSystem(flag.Arg(0), pathfs, &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 main() { flag.Parse() if len(flag.Args()) < 1 { log.Fatal("Usage:\n hello MOUNTPOINT") } nfs := pathfs.NewPathNodeFs(&HelloFs{FileSystem: pathfs.NewDefaultFileSystem()}, nil) server, _, err := nodefs.MountFileSystem(flag.Arg(0), nfs, nil) if err != nil { log.Fatal("Mount fail: %v\n", err) } server.Serve() }
func main() { flag.Parse() fs, err := cloudfs.New(*data, *raddr) if err != nil { log.Fatal("Cloudfs initialization error: ", err) } nfs := pathfs.NewPathNodeFs(fs, nil) server, _, err := nodefs.MountFileSystem(*mnt, nfs, nil) if err != nil { log.Fatal("Mount fail: ", err) } server.Serve() }
func setupOwnerTest(t *testing.T, opts *nodefs.Options) (workdir string, cleanup func()) { wd, err := ioutil.TempDir("", "go-fuse-owner_test") fs := &ownerFs{NewDefaultFileSystem()} nfs := NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(wd, nfs, opts) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } go state.Serve() return wd, func() { state.Unmount() os.RemoveAll(wd) } }
func TestGetAttrRace(t *testing.T) { dir, err := ioutil.TempDir("", "go-fuse-cache_test") if err != nil { t.Fatalf("failed: %v", err) } defer os.RemoveAll(dir) os.Mkdir(dir+"/mnt", 0755) os.Mkdir(dir+"/orig", 0755) fs := pathfs.NewLoopbackFileSystem(dir + "/orig") pfs := pathfs.NewPathNodeFs(fs, nil) state, conn, err := nodefs.MountFileSystem(dir+"/mnt", pfs, &nodefs.Options{}) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } state.SetDebug(VerboseTest()) conn.SetDebug(VerboseTest()) pfs.SetDebug(VerboseTest()) go state.Serve() 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) } }
func setupZipfs(t *testing.T) (mountPoint string, cleanup func()) { zfs, err := NewArchiveFileSystem(testZipFile()) if err != nil { t.Fatalf("NewArchiveFileSystem failed: %v", err) } mountPoint, _ = ioutil.TempDir("", "") state, _, err := nodefs.MountFileSystem(mountPoint, zfs, nil) state.SetDebug(VerboseTest()) go state.Serve() return mountPoint, func() { state.Unmount() os.RemoveAll(mountPoint) } }
func main() { var commandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) var kafkaAddrs = commandLine.String("kafkaAddrs", "localhost:9092", "Kafka server addresses host1:port1[;host2:port2...]") var metadataRetries = commandLine.Int("metadataRetries", 10, "Max times to attempt metadata refresh from Kafka before failing") var waitForElectionMs = commandLine.Int("waitForElectionMs", 250, "Max milliseconds to wait for Kafka leader election before failing") var maxMsgBytes = commandLine.Int("maxMsgBytes", 1024*1024*10, "Max bytes to pull for a single message") commandLine.Parse(os.Args[1:]) commandLine.Usage = func() { fmt.Fprintf(os.Stderr, "usage: kafkafs [options] mountpoint\n") commandLine.PrintDefaults() os.Exit(2) } if commandLine.NArg() != 1 { commandLine.Usage() } mountpoint := commandLine.Arg(0) addrs := strings.Split(*kafkaAddrs, ";") client, err := sarama.NewClient("kafkafs", addrs, &sarama.ClientConfig{MetadataRetries: *metadataRetries, WaitForElection: time.Duration(*waitForElectionMs) * time.Millisecond}) if err != nil { log.Fatalf("Error from client %s", err) } kClient := kafkafs.NewKafkaClient(client, int32(*maxMsgBytes)) nfs := pathfs.NewPathNodeFs(kafkafs.NewKafkaRoFs(kClient), nil) server, _, err := nodefs.MountFileSystem(mountpoint, nfs, nil) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go unmountOnInt(c, server, client) server.Serve() }
func main() { debug := flag.Bool("debug", false, "debug on") portable := flag.Bool("portable", false, "use 32 bit inodes") entry_ttl := flag.Float64("entry_ttl", 1.0, "fuse entry cache TTL.") negative_ttl := flag.Float64("negative_ttl", 1.0, "fuse negative entry cache TTL.") 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.") flag.Parse() if len(flag.Args()) < 2 { fmt.Println("Usage:\n unionfs MOUNTPOINT RW-DIRECTORY RO-DIRECTORY ...") os.Exit(2) } ufsOptions := unionfs.UnionFsOptions{ DeletionCacheTTL: time.Duration(*delcache_ttl * float64(time.Second)), BranchCacheTTL: time.Duration(*branchcache_ttl * float64(time.Second)), DeletionDirName: *deldirname, } ufs, err := unionfs.NewUnionFsFromRoots(flag.Args()[1:], &ufsOptions, true) if err != nil { log.Fatal("Cannot create UnionFs", err) os.Exit(1) } nodeFs := pathfs.NewPathNodeFs(ufs, &pathfs.PathNodeFsOptions{ClientInodes: true}) mOpts := nodefs.Options{ EntryTimeout: time.Duration(*entry_ttl * float64(time.Second)), AttrTimeout: time.Duration(*entry_ttl * float64(time.Second)), NegativeTimeout: time.Duration(*negative_ttl * float64(time.Second)), PortableInodes: *portable, } mountState, _, err := nodefs.MountFileSystem(flag.Arg(0), nodeFs, &mOpts) if err != nil { log.Fatal("Mount fail:", err) } mountState.SetDebug(*debug) mountState.Serve() }
func setupMzfs(t *testing.T) (mountPoint string, cleanup func()) { fs := NewMultiZipFs() mountPoint, _ = ioutil.TempDir("", "") nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(mountPoint, nfs, &nodefs.Options{ EntryTimeout: testTtl, AttrTimeout: testTtl, NegativeTimeout: 0.0, }) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } state.SetDebug(VerboseTest()) go state.Serve() return mountPoint, func() { state.Unmount() os.RemoveAll(mountPoint) } }
func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "debug on") flag.Parse() if flag.NArg() < 1 { _, prog := filepath.Split(os.Args[0]) fmt.Printf("usage: %s MOUNTPOINT\n", prog) os.Exit(2) } fs := zipfs.NewMultiZipFs() nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(flag.Arg(0), nfs, nil) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } state.SetDebug(*debug) state.Serve() }
func xattrTestCase(t *testing.T, nm string) (mountPoint string, cleanup func()) { xfs := NewXAttrFs(nm, xattrGolden) xfs.tester = t mountPoint, err := ioutil.TempDir("", "go-fuse-xattr_test") if err != nil { t.Fatalf("TempDir failed: %v", err) } nfs := NewPathNodeFs(xfs, nil) state, _, err := nodefs.MountFileSystem(mountPoint, nfs, nil) if err != nil { t.Fatalf("TempDir failed: %v", err) } state.SetDebug(VerboseTest()) go state.Serve() return mountPoint, func() { state.Unmount() os.RemoveAll(mountPoint) } }
func defaultReadTest(t *testing.T) (root string, cleanup func()) { fs := &DefaultReadFS{ FileSystem: pathfs.NewDefaultFileSystem(), } var err error dir, err := ioutil.TempDir("", "go-fuse") if err != nil { t.Fatalf("TempDir failed: %v", err) } pathfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(dir, pathfs, nil) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } state.SetDebug(VerboseTest()) go state.Serve() return dir, func() { state.Unmount() os.Remove(dir) } }
func TestOriginalIsSymlink(t *testing.T) { tmpDir, err := ioutil.TempDir("", "go-fuse-loopback_test") if err != nil { t.Fatalf("TempDir failed: %v", err) } 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" err = os.Mkdir(mnt, 0755) if err != nil { t.Fatalf("Mkdir failed: %v", err) } err = os.Symlink("orig", link) if err != nil { t.Fatalf("Symlink failed: %v", err) } fs := pathfs.NewLoopbackFileSystem(link) nfs := pathfs.NewPathNodeFs(fs, nil) state, _, err := nodefs.MountFileSystem(mnt, nfs, nil) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } defer state.Unmount() go state.Serve() _, err = os.Lstat(mnt) if err != nil { t.Fatalf("Lstat failed: %v", err) } }
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.MountFileSystem(wd+"/mnt", pathfs, 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) } }
func TestUnionFsDisappearing(t *testing.T) { // This init is like setupUfs, but we want access to the // writable Fs. wd, _ := ioutil.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, } nfs := pathfs.NewPathNodeFs(ufs, nil) state, _, err := nodefs.MountFileSystem(wd+"/mnt", nfs, opts) if err != nil { t.Fatalf("MountNodeFileSystem failed: %v", err) } defer state.Unmount() state.SetDebug(VerboseTest()) go state.Serve() log.Println("TestUnionFsDisappearing2") 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") } log.Println("expected readdir failure:", err) err = ioutil.WriteFile(wd+"/mnt/file2", []byte("blabla"), 0644) if err == nil { t.Fatal("write should have failed") } log.Println("expected write failure:", err) // Restore, and wait for caches to catch up. wrFs.visibleChan <- true time.Sleep((3 * entryTtl) / 2) _, 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 main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") profile := flag.String("profile", "", "record cpu profile.") mem_profile := flag.String("mem-profile", "", "record memory profile.") command := flag.String("run", "", "run this command after mounting.") ttl := flag.Float64("ttl", 1.0, "attribute/entry cache TTL.") flag.Parse() if flag.NArg() < 2 { fmt.Fprintf(os.Stderr, "usage: %s MOUNTPOINT ZIP-FILE\n", os.Args[0]) os.Exit(2) } var profFile, memProfFile io.Writer var err error if *profile != "" { profFile, err = os.Create(*profile) if err != nil { log.Fatalf("os.Create: %v", err) } } if *mem_profile != "" { memProfFile, err = os.Create(*mem_profile) if err != nil { log.Fatalf("os.Create: %v", err) } } var fs nodefs.FileSystem fs, err = zipfs.NewArchiveFileSystem(flag.Arg(1)) if err != nil { fmt.Fprintf(os.Stderr, "NewArchiveFileSystem failed: %v\n", err) os.Exit(1) } opts := &nodefs.Options{ AttrTimeout: time.Duration(*ttl * float64(time.Second)), EntryTimeout: time.Duration(*ttl * float64(time.Second)), } state, _, err := nodefs.MountFileSystem(flag.Arg(0), fs, opts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } state.SetDebug(*debug) runtime.GC() if profFile != nil { pprof.StartCPUProfile(profFile) defer pprof.StopCPUProfile() } if *command != "" { args := strings.Split(*command, " ") cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout cmd.Start() } state.Serve() if memProfFile != nil { pprof.WriteHeapProfile(memProfFile) } }