func (fs *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) { if path == "" || path == _CONFIG || path == _STATUS { a := &fuse.Attr{ Mode: fuse.S_IFDIR | 0755, } return a, fuse.OK } if path == filepath.Join(_STATUS, _DEBUG_SETTING) && fs.hasDebug() { return &fuse.Attr{ Mode: fuse.S_IFLNK | 0644, }, fuse.OK } if path == filepath.Join(_STATUS, _VERSION) { a := &fuse.Attr{ Mode: fuse.S_IFREG | 0644, Size: uint64(len(fuse.Version())), } return a, fuse.OK } if path == filepath.Join(_STATUS, _DEBUG) { a := &fuse.Attr{ Mode: fuse.S_IFREG | 0644, Size: uint64(len(fs.DebugData())), } return a, fuse.OK } if path == filepath.Join(_STATUS, _ROOT) { a := &fuse.Attr{ Mode: syscall.S_IFLNK | 0644, } return a, fuse.OK } if path == filepath.Join(_CONFIG, _SCAN_CONFIG) { a := &fuse.Attr{ Mode: fuse.S_IFREG | 0644, } return a, fuse.OK } comps := strings.Split(path, string(filepath.Separator)) if len(comps) > 1 && comps[0] == _CONFIG { fs := fs.getUnionFs(comps[1]) if fs == nil { return nil, fuse.ENOENT } a := &fuse.Attr{ Mode: syscall.S_IFLNK | 0644, } return a, fuse.OK } return nil, fuse.ENOENT }
func (fs *AutoUnionFs) DebugData() string { if fs.mountState == nil { return "AutoUnionFs.mountState not set" } setting := fs.mountState.KernelSettings() msg := fmt.Sprintf( "Version: %v\n"+ "Bufferpool: %v\n"+ "Kernel: %v\n", fuse.Version(), fs.mountState.BufferPoolStats(), &setting) if fs.connector != nil { msg += fmt.Sprintf("Live inodes: %d\n", fs.connector.InodeHandleCount()) } return msg }
func (fs *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (fuse.File, fuse.Status) { if path == filepath.Join(_STATUS, _DEBUG) { if flags&fuse.O_ANYWRITE != 0 { return nil, fuse.EPERM } return fuse.NewDataFile([]byte(fs.DebugData())), fuse.OK } if path == filepath.Join(_STATUS, _VERSION) { if flags&fuse.O_ANYWRITE != 0 { return nil, fuse.EPERM } return fuse.NewDataFile([]byte(fuse.Version())), fuse.OK } if path == filepath.Join(_CONFIG, _SCAN_CONFIG) { if flags&fuse.O_ANYWRITE != 0 { fs.updateKnownFses() } return fuse.NewDevNullFile(), fuse.OK } return nil, fuse.ENOENT }
func main() { version := flag.Bool("version", false, "print version number") 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 *version { fmt.Println(fuse.Version()) os.Exit(0) } 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, FileSystemOptions: fuse.FileSystemOptions{ EntryTimeout: time.Second, AttrTimeout: time.Second, NegativeTimeout: time.Second, Owner: fuse.CurrentOwner(), }, UpdateOnMount: true, PathNodeFsOptions: fuse.PathNodeFsOptions{ ClientInodes: *hardlinks, }, HideReadonly: *hide_readonly_link, } fsOpts := fuse.FileSystemOptions{ PortableInodes: *portableInodes, } fmt.Printf("AutoUnionFs - Go-FUSE Version %v.\n", fuse.Version()) gofs := unionfs.NewAutoUnionFs(flag.Arg(1), options) pathfs := fuse.NewPathNodeFs(gofs, nil) state, conn, err := fuse.MountNodeFileSystem(flag.Arg(0), pathfs, &fsOpts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } pathfs.Debug = *debug conn.Debug = *debug state.Debug = *debug gofs.SetMountState(state) gofs.SetFileSystemConnector(conn) state.Loop() time.Sleep(1 * time.Second) }