github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libfuse/profilelist.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 // 5 //go:build !windows 6 // +build !windows 7 8 package libfuse 9 10 import ( 11 "io" 12 "os" 13 "strings" 14 "time" 15 16 "bazil.org/fuse" 17 "bazil.org/fuse/fs" 18 "github.com/keybase/client/go/kbfs/libfs" 19 "github.com/keybase/client/go/kbfs/libkbfs" 20 21 "golang.org/x/net/context" 22 ) 23 24 // timedProfileFile represents a file whose contents are determined by 25 // taking a profile for some duration. 26 type timedProfileFile struct { 27 pfs libfs.ProfileFS 28 name string 29 } 30 31 var _ fs.Node = timedProfileFile{} 32 33 func (tpf timedProfileFile) Attr(ctx context.Context, a *fuse.Attr) error { 34 // Have a low non-zero value for Valid to avoid being swamped 35 // with requests. 36 a.Valid = 1 * time.Second 37 now := time.Now() 38 a.Size = 0 39 a.Mtime = now 40 a.Ctime = now 41 a.Mode = 0444 42 return nil 43 } 44 45 var _ fs.NodeOpener = timedProfileFile{} 46 47 func (tpf timedProfileFile) Open(ctx context.Context, 48 req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { 49 f, err := tpf.pfs.OpenWithContext(ctx, tpf.name) 50 if err != nil { 51 return nil, err 52 } 53 54 buf, err := io.ReadAll(f) 55 if err != nil { 56 return nil, err 57 } 58 59 resp.Flags |= fuse.OpenDirectIO 60 return fs.DataHandle(buf), nil 61 } 62 63 // ProfileList is a node that can list all of the available profiles. 64 type ProfileList struct { 65 config libkbfs.Config 66 } 67 68 var _ fs.Node = ProfileList{} 69 70 // Attr implements the fs.Node interface. 71 func (ProfileList) Attr(_ context.Context, a *fuse.Attr) error { 72 a.Mode = os.ModeDir | 0755 73 return nil 74 } 75 76 var _ fs.NodeRequestLookuper = ProfileList{} 77 78 // Lookup implements the fs.NodeRequestLookuper interface. 79 func (pl ProfileList) Lookup(_ context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) { 80 pfs := libfs.NewProfileFS(pl.config) 81 82 // Handle timed profiles first. 83 if strings.HasPrefix(req.Name, libfs.CPUProfilePrefix) || 84 strings.HasPrefix(req.Name, libfs.TraceProfilePrefix) { 85 return timedProfileFile{pfs, req.Name}, nil 86 } 87 88 f := libfs.ProfileGet(req.Name) 89 if f == nil { 90 return nil, fuse.ENOENT 91 } 92 resp.EntryValid = 0 93 return &SpecialReadFile{read: f}, nil 94 } 95 96 var _ fs.Handle = ProfileList{} 97 98 var _ fs.HandleReadDirAller = ProfileList{} 99 100 // ReadDirAll implements the ReadDirAll interface. 101 func (pl ProfileList) ReadDirAll(_ context.Context) (res []fuse.Dirent, err error) { 102 profiles := libfs.ListProfileNames() 103 res = make([]fuse.Dirent, 0, len(profiles)) 104 for _, p := range profiles { 105 res = append(res, fuse.Dirent{ 106 Type: fuse.DT_File, 107 Name: p, 108 }) 109 } 110 return res, nil 111 } 112 113 var _ fs.NodeRemover = (*FolderList)(nil) 114 115 // Remove implements the fs.NodeRemover interface for ProfileList. 116 func (ProfileList) Remove(_ context.Context, req *fuse.RemoveRequest) (err error) { 117 return fuse.EPERM 118 }