func (fs *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { a := &fuse.Attr{} a.Owner = *fuse.CurrentOwner() if name == "" { // Should not write in top dir. a.Mode = fuse.S_IFDIR | 0500 return a, fuse.OK } if name == "config" { a.Mode = fuse.S_IFDIR | 0700 return a, fuse.OK } dir, base := filepath.Split(name) if dir != "" && dir != CONFIG_PREFIX { return nil, fuse.ENOENT } submode := uint32(fuse.S_IFDIR | 0700) if dir == CONFIG_PREFIX { submode = fuse.S_IFLNK | 0600 } fs.lock.RLock() defer fs.lock.RUnlock() a.Mode = submode _, hasDir := fs.zips[base] if hasDir { return a, fuse.OK } return nil, fuse.ENOENT }
// NewOptions generates FUSE options that correspond to libfuse's // defaults. func NewOptions() *Options { return &Options{ NegativeTimeout: 0, AttrTimeout: time.Second, EntryTimeout: time.Second, Owner: fuse.CurrentOwner(), } }
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 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.") 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, }, } 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, nil) 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) state.Loop() }
func makeAttr(mode uint32) types.Struct { now := time.Now() ctime := types.Number(float64(now.Unix()) + float64(now.Nanosecond())/1000000000) mtime := ctime user := fuse.CurrentOwner() gid := types.Number(float64(user.Gid)) uid := types.Number(float64(user.Uid)) return types.NewStructWithType(attrType, types.ValueSlice{ctime, gid, types.Number(mode), mtime, uid, types.NewMap()}) }
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) } }
func main() { version := flag.Bool("version", false, "print version number") debug := flag.Bool("debug", false, "debug on") threaded := flag.Bool("threaded", true, "threading on") 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 *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{ DeletionCacheTTLSecs: *delcache_ttl, BranchCacheTTLSecs: *branchcache_ttl, DeletionDirName: *deldirname, } options := unionfs.AutoUnionFsOptions{ UnionFsOptions: ufsOptions, FileSystemOptions: fuse.FileSystemOptions{ EntryTimeout: 1.0, AttrTimeout: 1.0, NegativeTimeout: 1.0, Owner: fuse.CurrentOwner(), }, UpdateOnMount: true, } gofs := unionfs.NewAutoUnionFs(flag.Arg(1), options) pathfs := fuse.NewPathNodeFs(gofs) state, conn, err := fuse.MountNodeFileSystem(flag.Arg(0), pathfs, nil) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } pathfs.Debug = *debug conn.Debug = *debug state.Debug = *debug state.Loop(*threaded) }
func (fs *autoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) { a := &fuse.Attr{ Owner: *fuse.CurrentOwner(), } if path == "" || path == _CONFIG || path == _STATUS { a.Mode = fuse.S_IFDIR | 0755 return a, fuse.OK } if path == filepath.Join(_STATUS, _VERSION) { a.Mode = fuse.S_IFREG | 0644 a.Size = uint64(len(fs.options.Version)) return a, fuse.OK } if path == filepath.Join(_STATUS, _DEBUG) { a.Mode = fuse.S_IFREG | 0644 a.Size = uint64(len(fs.DebugData())) return a, fuse.OK } if path == filepath.Join(_STATUS, _ROOT) { a.Mode = syscall.S_IFLNK | 0644 return a, fuse.OK } if path == filepath.Join(_CONFIG, _SCAN_CONFIG) { a.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.Mode = syscall.S_IFLNK | 0644 return a, fuse.OK } return nil, fuse.ENOENT }