Beispiel #1
0
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()
}
Beispiel #2
0
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
	}
}
Beispiel #3
0
// 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,
	}
}
Beispiel #4
0
// 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)
		},
	}
}
Beispiel #5
0
// 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)
		},
	}
}
Beispiel #6
0
// 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
}
Beispiel #7
0
func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fusefs.Node, error) {
	if skipDirEntry(req.Name) {
		return nil, fuse.ENOENT
	}
	path := filepath.Join(d.path, req.Name)
	isDir := false
	defer trace(NewLookupOp(req, path, isDir))
	var st syscall.Stat_t
	if err := syscall.Lstat(path, &st); err != nil {
		return nil, fuse.ENOENT
	}
	resp.Attr = statToFuseAttr(st)
	resp.Node = fuse.NodeID(resp.Attr.Inode)
	// TODO: should we overwrite resp.EntryValid?
	// resp.EntryValid = time.Duration(500) * time.Millisecond
	if isDir = resp.Attr.Mode.IsDir(); isDir {
		return NewDir(d.path, req.Name, d.fs), nil
	}
	return NewFile(d.path, req.Name, d.fs), nil
}
Beispiel #8
0
func (d Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, res *fuse.LookupResponse) (fs.Node, error) {
	log.Debug("Lookup(%s,%d,%s)", d.GetPath(), req.Node, req.Name)
	lock.Lock()
	defer lock.Unlock()

	node, err := d.lookup(ctx, req.Name)
	if err != nil {
		return nil, err
	}

	res.Node = fuse.NodeID(d.Fs.GenerateInode(uint64(req.Node), req.Name))
	return node, nil
}
Beispiel #9
0
func initLookupResponse(s *fuse.LookupResponse) {
	s.EntryValid = entryValidTime
}
Beispiel #10
0
// 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
	}
}
Beispiel #11
0
// 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
}
Beispiel #12
0
// 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)}
}