// Lookup implements the fs.NodeRequestLookuper interface for Root. func (r *Root) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) { r.private.fs.log.CDebugf(ctx, "FS Lookup %s", req.Name) defer func() { r.private.fs.reportErr(ctx, libkbfs.ReadMode, err) }() specialNode := handleSpecialFile(req.Name, r.private.fs, resp) if specialNode != nil { return specialNode, nil } switch req.Name { case libfs.StatusFileName: return NewStatusFile(r.private.fs, nil, resp), nil case PrivateName: return r.private, nil case PublicName: return r.public, nil case libfs.HumanErrorFileName, libfs.HumanNoLoginFileName: resp.EntryValid = 0 return &SpecialReadFile{r.private.fs.remoteStatus.NewSpecialReadFunc}, nil } // Don't want to pop up errors on special OS files. if strings.HasPrefix(req.Name, ".") { return nil, fuse.ENOENT } return nil, libkbfs.NoSuchFolderListError{ Name: req.Name, PrivName: PrivateName, PubName: PublicName, } }
// NewMetricsFile returns a special read file that contains a text // representation of all metrics. func NewMetricsFile(fs *FS, resp *fuse.LookupResponse) *SpecialReadFile { resp.EntryValid = 0 return &SpecialReadFile{ read: func(_ context.Context) ([]byte, time.Time, error) { return getEncodedMetrics(fs) }, } }
// NewStatusFile returns a special read file that contains a text // representation of the status of the current TLF. func NewStatusFile(folder *Folder, resp *fuse.LookupResponse) *SpecialReadFile { resp.EntryValid = 0 return &SpecialReadFile{ read: func(ctx context.Context) ([]byte, time.Time, error) { return getEncodedStatus(ctx, folder) }, } }
// Lookup implements the fs.NodeRequestLookuper interface. func (pl ProfileList) Lookup(_ context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) { f := libfs.ProfileGet(req.Name) if f == nil { return nil, fuse.ENOENT } resp.EntryValid = 0 return &SpecialReadFile{read: f}, nil }
func (c *serveConn) saveLookup(s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) { name := path.Join(snode.name, elem) var sn *serveNode s.Node, s.Generation, sn = c.saveNode(name, n2) if s.EntryValid == 0 { s.EntryValid = 1 * time.Minute } if s.AttrValid == 0 { s.AttrValid = 1 * time.Minute } s.Attr = sn.attr() }
func (c *serveConn) saveLookup(s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) { s.Attr = nodeAttr(n2) if s.Attr.Inode == 0 { s.Attr.Inode = c.dynamicInode(snode.inode, elem) } s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2) if s.EntryValid == 0 { s.EntryValid = entryValidTime } if s.AttrValid == 0 { s.AttrValid = attrValidTime } }
func initLookupResponse(s *fuse.LookupResponse) { s.EntryValid = entryValidTime }
// Lookup implements the fs.NodeRequestLookuper interface for Dir. func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) { ctx = NewContextWithOpID(ctx, d.folder.fs.log) d.folder.fs.log.CDebugf(ctx, "Dir Lookup %s", req.Name) defer func() { d.folder.fs.reportErr(ctx, err) }() switch req.Name { case libkbfs.ErrorFile: return NewErrorFile(d.folder.fs, resp), nil case MetricsFileName: return NewMetricsFile(d.folder.fs, resp), nil case StatusFileName: return NewStatusFile(d.folder, resp), nil case UpdateHistoryFileName: return NewUpdateHistoryFile(d.folder, resp), nil case UnstageFileName: resp.EntryValid = 0 child := &UnstageFile{ folder: d.folder, } return child, nil case DisableUpdatesFileName: resp.EntryValid = 0 child := &UpdatesFile{ folder: d.folder, } return child, nil case EnableUpdatesFileName: resp.EntryValid = 0 child := &UpdatesFile{ folder: d.folder, enable: true, } return child, nil case RekeyFileName: resp.EntryValid = 0 child := &RekeyFile{ folder: d.folder, } return child, nil } newNode, de, err := d.folder.fs.config.KBFSOps().Lookup(ctx, d.node, req.Name) if err != nil { if _, ok := err.(libkbfs.NoSuchNameError); ok { return nil, fuse.ENOENT } return nil, err } // No libkbfs calls after this point! d.folder.mu.Lock() defer d.folder.mu.Unlock() // newNode can be nil even without errors when the KBFS direntry // is of a type that doesn't get its own node (is fully contained // in the directory); Symlink does this. if newNode != nil { if n, ok := d.folder.nodes[newNode.GetID()]; ok { return n, nil } } switch de.Type { default: return nil, fmt.Errorf("unhandled entry type: %v", de.Type) case libkbfs.File, libkbfs.Exec: child := &File{ folder: d.folder, node: newNode, } d.folder.nodes[newNode.GetID()] = child return child, nil case libkbfs.Dir: child := newDir(d.folder, newNode) d.folder.nodes[newNode.GetID()] = child return child, nil case libkbfs.Sym: child := &Symlink{ parent: d, name: req.Name, } // a Symlink is never included in Folder.nodes, as it doesn't // have a libkbfs.Node to keep track of renames. return child, nil } }
// Lookup implements the fs.NodeRequestLookuper interface. func (fl *FolderList) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) { ctx = NewContextWithOpID(ctx, fl.fs.log) fl.fs.log.CDebugf(ctx, "FL Lookup %s", req.Name) defer func() { fl.fs.reportErr(ctx, err) }() fl.mu.Lock() defer fl.mu.Unlock() if req.Name == libkbfs.ErrorFile { return NewErrorFile(fl.fs, resp), nil } if req.Name == MetricsFileName { return NewMetricsFile(fl.fs, resp), nil } if child, ok := fl.folders[req.Name]; ok { return child, nil } // Shortcut for dreaded extraneous OSX finder lookups if strings.HasPrefix(req.Name, "._") { return nil, fuse.ENOENT } rootNode, _, err := fl.fs.config.KBFSOps().GetOrCreateRootNode( ctx, req.Name, fl.public, libkbfs.MasterBranch) switch err := err.(type) { case nil: // No error. break case libkbfs.TlfNameNotCanonical: // Non-canonical name. n := &Alias{ canon: err.NameToTry, } return n, nil case libkbfs.NoSuchNameError: // Invalid public TLF. return nil, fuse.ENOENT case libkbfs.WriteAccessError: // No permissions to create TLF. fl.fs.log.CDebugf(ctx, "Local user doesn't have permission to create "+ " %s and it doesn't exist yet, so making an empty folder", req.Name) // Only cache this empty folder for a minute, in case a valid // writer comes along and creates it. resp.EntryValid = 60 * time.Second return &EmptyFolder{fl.fs}, nil default: // Some other error. return nil, err } folderBranch := rootNode.GetFolderBranch() folder := &Folder{ fs: fl.fs, list: fl, name: req.Name, folderBranch: folderBranch, nodes: map[libkbfs.NodeID]fs.Node{}, } // TODO unregister all at unmount if err := fl.fs.config.Notifier().RegisterForChanges([]libkbfs.FolderBranch{folderBranch}, folder); err != nil { return nil, err } child := newDir(folder, rootNode) folder.nodes[rootNode.GetID()] = child fl.folders[req.Name] = child return child, nil }
// NewErrorFile returns a special read file that contains a text // representation of the last few KBFS errors. func NewErrorFile(fs *FS, resp *fuse.LookupResponse) *SpecialReadFile { resp.EntryValid = 0 return &SpecialReadFile{read: libfs.GetEncodedErrors(fs.config)} }