github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libfuse/symlink.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  	"os"
    12  	"syscall"
    13  
    14  	"bazil.org/fuse"
    15  	"bazil.org/fuse/fs"
    16  	"github.com/keybase/client/go/kbfs/data"
    17  	"github.com/keybase/client/go/kbfs/idutil"
    18  	"github.com/keybase/client/go/kbfs/libkbfs"
    19  	"github.com/keybase/client/go/libkb"
    20  	"golang.org/x/net/context"
    21  )
    22  
    23  // Symlink represents KBFS symlinks.
    24  type Symlink struct {
    25  	// The directory this symlink is in. This should be safe to store
    26  	// here, without fear of Renames etc making it stale, because we
    27  	// never persist a Symlink into Folder.nodes; it has no
    28  	// libkbfs.Node, so that's impossible. This should make FUSE
    29  	// Lookup etc always get new nodes, limiting the lifetime of a
    30  	// single Symlink value.
    31  	parent *Dir
    32  	name   string
    33  	inode  uint64
    34  }
    35  
    36  var _ fs.Node = (*Symlink)(nil)
    37  
    38  // Attr implements the fs.Node interface for Symlink
    39  func (s *Symlink) Attr(ctx context.Context, a *fuse.Attr) (err error) {
    40  	s.parent.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Symlink Attr")
    41  	defer func() { err = s.parent.folder.processError(ctx, libkbfs.ReadMode, err) }()
    42  
    43  	_, de, err := s.parent.folder.fs.config.KBFSOps().Lookup(
    44  		ctx, s.parent.node, s.parent.node.ChildName(s.name))
    45  	if err != nil {
    46  		if _, ok := err.(idutil.NoSuchNameError); ok {
    47  			return fuse.ESTALE
    48  		}
    49  		return err
    50  	}
    51  
    52  	err = s.parent.folder.fillAttrWithUIDAndWritePerm(
    53  		ctx, s.parent.node, &de, a)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	a.Mode = os.ModeSymlink | a.Mode | 0500
    58  	a.Inode = s.inode
    59  	return nil
    60  }
    61  
    62  var _ fs.NodeReadlinker = (*Symlink)(nil)
    63  
    64  // Readlink implements the fs.NodeReadlinker interface for Symlink
    65  func (s *Symlink) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (link string, err error) {
    66  	s.parent.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Symlink Readlink")
    67  	defer func() { err = s.parent.folder.processError(ctx, libkbfs.ReadMode, err) }()
    68  
    69  	_, de, err := s.parent.folder.fs.config.KBFSOps().Lookup(
    70  		ctx, s.parent.node, s.parent.node.ChildName(s.name))
    71  	if err != nil {
    72  		return "", err
    73  	}
    74  
    75  	if de.Type != data.Sym {
    76  		return "", fuse.Errno(syscall.EINVAL)
    77  	}
    78  	return de.SymPath, nil
    79  }