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  }