github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libfuse/dir.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  	"fmt"
    12  	"math"
    13  	"os"
    14  	"strings"
    15  	"sync"
    16  	"syscall"
    17  	"time"
    18  
    19  	"bazil.org/fuse"
    20  	"bazil.org/fuse/fs"
    21  	"github.com/keybase/client/go/kbfs/data"
    22  	"github.com/keybase/client/go/kbfs/idutil"
    23  	"github.com/keybase/client/go/kbfs/libcontext"
    24  	"github.com/keybase/client/go/kbfs/libfs"
    25  	"github.com/keybase/client/go/kbfs/libkbfs"
    26  	"github.com/keybase/client/go/kbfs/sysutils"
    27  	"github.com/keybase/client/go/kbfs/tlf"
    28  	"github.com/keybase/client/go/kbfs/tlfhandle"
    29  	"github.com/keybase/client/go/libkb"
    30  	"golang.org/x/net/context"
    31  )
    32  
    33  // Folder represents the info shared among all nodes of a KBFS
    34  // top-level folder.
    35  type Folder struct {
    36  	fs   *FS
    37  	list *FolderList
    38  
    39  	handleMu       sync.RWMutex
    40  	h              *tlfhandle.Handle
    41  	hPreferredName tlf.PreferredName
    42  
    43  	folderBranchMu sync.Mutex
    44  	folderBranch   data.FolderBranch
    45  
    46  	// Protects the nodes map.
    47  	nodesMu sync.Mutex
    48  	// Map KBFS nodes to FUSE nodes, to be able to handle multiple
    49  	// lookups and incoming change notifications. A node is present
    50  	// here if the kernel holds a reference to it.
    51  	//
    52  	// If we ever support hardlinks, this would need refcounts.
    53  	//
    54  	// Children must call folder.forgetChildLocked on receiving the
    55  	// FUSE Forget request.
    56  	nodes map[libkbfs.NodeID]fs.Node
    57  
    58  	// Protects the updateChan.
    59  	updateMu sync.Mutex
    60  	// updateChan is non-nil when the user disables updates via the
    61  	// file system.  Sending a struct{}{} on this channel will unpause
    62  	// the updates.
    63  	updateChan chan<- struct{}
    64  	quarantine bool
    65  }
    66  
    67  func newFolder(ctx context.Context, fl *FolderList, h *tlfhandle.Handle,
    68  	hPreferredName tlf.PreferredName) *Folder {
    69  	f := &Folder{
    70  		fs:             fl.fs,
    71  		list:           fl,
    72  		h:              h,
    73  		hPreferredName: hPreferredName,
    74  		nodes:          map[libkbfs.NodeID]fs.Node{},
    75  		quarantine:     !libkbfs.IsOnlyWriterInNonTeamTlf(ctx, fl.fs.config.KBPKI(), h),
    76  	}
    77  	return f
    78  }
    79  
    80  func (f *Folder) name() tlf.CanonicalName {
    81  	f.handleMu.RLock()
    82  	defer f.handleMu.RUnlock()
    83  	return tlf.CanonicalName(f.hPreferredName)
    84  }
    85  
    86  func (f *Folder) processError(ctx context.Context,
    87  	mode libkbfs.ErrorModeType, err error) error {
    88  	if err == nil {
    89  		f.fs.errVlog.CLogf(ctx, libkb.VLog1, "Request complete")
    90  		return nil
    91  	}
    92  
    93  	f.fs.config.Reporter().ReportErr(ctx, f.name(), f.list.tlfType, mode, err)
    94  	// We just log the error as debug, rather than error, because it
    95  	// might just indicate an expected error such as an ENOENT.
    96  	//
    97  	// TODO: Classify errors and escalate the logging level of the
    98  	// important ones.
    99  	f.fs.errLog.CDebugf(ctx, err.Error())
   100  	return filterError(err)
   101  }
   102  
   103  func (f *Folder) setFolderBranch(folderBranch data.FolderBranch) error {
   104  	f.folderBranchMu.Lock()
   105  	defer f.folderBranchMu.Unlock()
   106  
   107  	// TODO unregister all at unmount
   108  	err := f.list.fs.config.Notifier().RegisterForChanges(
   109  		[]data.FolderBranch{folderBranch}, f)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	f.folderBranch = folderBranch
   114  	return nil
   115  }
   116  
   117  func (f *Folder) unsetFolderBranch(ctx context.Context) {
   118  	f.folderBranchMu.Lock()
   119  	defer f.folderBranchMu.Unlock()
   120  	if f.folderBranch == (data.FolderBranch{}) {
   121  		// Wasn't set.
   122  		return
   123  	}
   124  
   125  	err := f.list.fs.config.Notifier().UnregisterFromChanges([]data.FolderBranch{f.folderBranch}, f)
   126  	if err != nil {
   127  		f.fs.log.Info("cannot unregister change notifier for folder %q: %v",
   128  			f.name(), err)
   129  	}
   130  	f.folderBranch = data.FolderBranch{}
   131  }
   132  
   133  func (f *Folder) getFolderBranch() data.FolderBranch {
   134  	f.folderBranchMu.Lock()
   135  	defer f.folderBranchMu.Unlock()
   136  	return f.folderBranch
   137  }
   138  
   139  // forgetNode forgets a formerly active child with basename name.
   140  func (f *Folder) forgetNode(node libkbfs.Node) {
   141  	f.nodesMu.Lock()
   142  	defer f.nodesMu.Unlock()
   143  
   144  	delete(f.nodes, node.GetID())
   145  	if len(f.nodes) == 0 {
   146  		ctx := libcontext.BackgroundContextWithCancellationDelayer()
   147  		defer func() {
   148  			err := libcontext.CleanupCancellationDelayer(ctx)
   149  			if err != nil {
   150  				f.fs.log.CDebugf(ctx, "Coudn't cleanup ctx: %+v", err)
   151  			}
   152  		}()
   153  		f.unsetFolderBranch(ctx)
   154  		f.list.forgetFolder(string(f.name()))
   155  	}
   156  }
   157  
   158  var _ libkbfs.Observer = (*Folder)(nil)
   159  
   160  func (f *Folder) resolve(ctx context.Context) (*tlfhandle.Handle, error) {
   161  	if f.h.TlfID() == tlf.NullID {
   162  		// If the handle doesn't have a TLF ID yet, fetch it now.
   163  		handle, err := tlfhandle.ParseHandlePreferred(
   164  			ctx, f.fs.config.KBPKI(), f.fs.config.MDOps(), f.fs.config,
   165  			string(f.hPreferredName), f.h.Type())
   166  		if err != nil {
   167  			return nil, err
   168  		}
   169  		// Update the handle.
   170  		f.TlfHandleChange(ctx, handle)
   171  		return handle, nil
   172  	}
   173  
   174  	// In case there were any unresolved assertions, try them again on
   175  	// the first load.  Otherwise, since we haven't subscribed to
   176  	// updates yet for this folder, we might have missed a name
   177  	// change.
   178  	handle, err := f.h.ResolveAgain(
   179  		ctx, f.fs.config.KBPKI(), f.fs.config.MDOps(), f.fs.config)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	eq, err := f.h.Equals(f.fs.config.Codec(), *handle)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	if !eq {
   188  		// Make sure the name changes in the folder and the folder list
   189  		f.TlfHandleChange(ctx, handle)
   190  	}
   191  	return handle, nil
   192  }
   193  
   194  // invalidateNodeDataRange notifies the kernel to invalidate cached data for node.
   195  //
   196  // The arguments follow KBFS semantics:
   197  //
   198  //   - Len > 0: "bytes Off..Off+Len were mutated"
   199  //   - Len == 0: "new file Len is Off"
   200  //
   201  // For comparison, the FUSE semantics are:
   202  //
   203  //   - Len < 0: "forget data in range Off..infinity"
   204  //   - Len > 0: "forget data in range Off..Off+Len"
   205  func (f *Folder) invalidateNodeDataRange(node fs.Node, write libkbfs.WriteRange) error {
   206  	if file, ok := node.(*File); ok {
   207  		file.eiCache.destroy()
   208  	}
   209  	off := int64(write.Off)
   210  	size := int64(write.Len)
   211  	if write.Off > math.MaxInt64 || write.Len > math.MaxInt64 {
   212  		// out of bounds, just invalidate all data
   213  		off = 0
   214  		size = -1
   215  	}
   216  	if write.Len == 0 {
   217  		// truncate, invalidate all data in the now-lost tail
   218  		size = -1
   219  	}
   220  	// Off=0 Len=0 is the same as calling InvalidateNodeDataAttr; we
   221  	// can just let that go through InvalidateNodeDataRange.
   222  	return f.fs.fuse.InvalidateNodeDataRange(node, off, size)
   223  }
   224  
   225  // LocalChange is called for changes originating within in this process.
   226  func (f *Folder) LocalChange(ctx context.Context, node libkbfs.Node, write libkbfs.WriteRange) {
   227  	if !f.fs.conn.Protocol().HasInvalidate() {
   228  		// OSXFUSE 2.x does not support notifications
   229  		return
   230  	}
   231  	if origin, ok := ctx.Value(libfs.CtxAppIDKey).(*FS); ok && origin == f.fs {
   232  		return
   233  	}
   234  
   235  	// Handle in the background because we shouldn't lock during the
   236  	// notification.
   237  	f.fs.queueNotification(func() { f.localChangeInvalidate(ctx, node, write) })
   238  }
   239  
   240  func (f *Folder) localChangeInvalidate(ctx context.Context, node libkbfs.Node,
   241  	write libkbfs.WriteRange) {
   242  	f.nodesMu.Lock()
   243  	n, ok := f.nodes[node.GetID()]
   244  	f.nodesMu.Unlock()
   245  	if !ok {
   246  		return
   247  	}
   248  
   249  	if err := f.invalidateNodeDataRange(n, write); err != nil && err != fuse.ErrNotCached {
   250  		// TODO we have no mechanism to do anything about this
   251  		f.fs.log.CErrorf(ctx, "FUSE invalidate error: %v", err)
   252  	}
   253  }
   254  
   255  // BatchChanges is called for changes originating anywhere, including
   256  // other hosts.
   257  func (f *Folder) BatchChanges(
   258  	ctx context.Context, changes []libkbfs.NodeChange, _ []libkbfs.NodeID) {
   259  	if !f.fs.conn.Protocol().HasInvalidate() {
   260  		// OSXFUSE 2.x does not support notifications
   261  		return
   262  	}
   263  	if origin, ok := ctx.Value(libfs.CtxAppIDKey).(*FS); ok && origin == f.fs {
   264  		return
   265  	}
   266  	if v := ctx.Value(libkbfs.CtxBackgroundSyncKey); v != nil {
   267  		return
   268  	}
   269  
   270  	// Handle in the background because we shouldn't lock during the
   271  	// notification.
   272  	f.fs.queueNotification(func() { f.batchChangesInvalidate(ctx, changes) })
   273  }
   274  
   275  func (f *Folder) batchChangesInvalidate(ctx context.Context,
   276  	changes []libkbfs.NodeChange) {
   277  	for _, v := range changes {
   278  		f.nodesMu.Lock()
   279  		n, ok := f.nodes[v.Node.GetID()]
   280  		f.nodesMu.Unlock()
   281  		if !ok {
   282  			continue
   283  		}
   284  
   285  		switch {
   286  		case len(v.DirUpdated) > 0:
   287  			// invalidate potentially cached Readdir contents
   288  			if err := f.fs.fuse.InvalidateNodeData(n); err != nil && err != fuse.ErrNotCached {
   289  				// TODO we have no mechanism to do anything about this
   290  				f.fs.log.CErrorf(ctx, "FUSE invalidate error: %v", err)
   291  			}
   292  			for _, name := range v.DirUpdated {
   293  				// invalidate the dentry cache
   294  				if err := f.fs.fuse.InvalidateEntry(n, name.Plaintext()); err != nil && err != fuse.ErrNotCached {
   295  					// TODO we have no mechanism to do anything about this
   296  					f.fs.log.CErrorf(ctx, "FUSE invalidate error: %v", err)
   297  				}
   298  			}
   299  
   300  		case len(v.FileUpdated) > 0:
   301  			for _, write := range v.FileUpdated {
   302  				if err := f.invalidateNodeDataRange(n, write); err != nil && err != fuse.ErrNotCached {
   303  					// TODO we have no mechanism to do anything about this
   304  					f.fs.log.CErrorf(ctx, "FUSE invalidate error: %v", err)
   305  				}
   306  			}
   307  
   308  		default:
   309  			if file, ok := n.(*File); ok {
   310  				file.eiCache.destroy()
   311  			}
   312  			// just the attributes
   313  			if err := f.fs.fuse.InvalidateNodeAttr(n); err != nil && err != fuse.ErrNotCached {
   314  				// TODO we have no mechanism to do anything about this
   315  				f.fs.log.CErrorf(ctx, "FUSE invalidate error: %v", err)
   316  			}
   317  		}
   318  	}
   319  }
   320  
   321  // TlfHandleChange is called when the name of a folder changes.
   322  // Note that newHandle may be nil. Then the handle in the folder is used.
   323  // This is used on e.g. logout/login.
   324  func (f *Folder) TlfHandleChange(ctx context.Context,
   325  	newHandle *tlfhandle.Handle) {
   326  	f.fs.log.CDebugf(ctx, "TlfHandleChange called on %q",
   327  		canonicalNameIfNotNil(newHandle))
   328  	// Handle in the background because we shouldn't lock during the
   329  	// notification
   330  	f.fs.queueNotification(func() {
   331  		f.tlfHandleChangeInvalidate(context.Background(), newHandle)
   332  	})
   333  }
   334  
   335  func canonicalNameIfNotNil(h *tlfhandle.Handle) string {
   336  	if h == nil {
   337  		return "(nil)"
   338  	}
   339  	return string(h.GetCanonicalName())
   340  }
   341  
   342  func (f *Folder) tlfHandleChangeInvalidate(ctx context.Context,
   343  	newHandle *tlfhandle.Handle) {
   344  	session, err := idutil.GetCurrentSessionIfPossible(
   345  		ctx, f.fs.config.KBPKI(), f.list.tlfType == tlf.Public)
   346  	// Here we get an error, but there is little that can be done.
   347  	// session will be empty in the error case in which case we will default to the
   348  	// canonical format.
   349  	if err != nil {
   350  		f.fs.log.CDebugf(ctx,
   351  			"tlfHandleChangeInvalidate: GetCurrentUserInfoIfPossible failed: %v", err)
   352  	}
   353  	oldName, newName := func() (tlf.PreferredName, tlf.PreferredName) {
   354  		f.handleMu.Lock()
   355  		defer f.handleMu.Unlock()
   356  		oldName := f.hPreferredName
   357  		if newHandle != nil {
   358  			f.h = newHandle
   359  		}
   360  		f.hPreferredName = f.h.GetPreferredFormat(session.Name)
   361  		return oldName, f.hPreferredName
   362  	}()
   363  
   364  	if oldName != newName {
   365  		f.list.updateTlfName(ctx, string(oldName), string(newName))
   366  	}
   367  }
   368  
   369  func (f *Folder) writePermMode(ctx context.Context,
   370  	node libkbfs.Node, original os.FileMode) (os.FileMode, error) {
   371  	f.handleMu.RLock()
   372  	defer f.handleMu.RUnlock()
   373  	return libfs.WritePermMode(
   374  		ctx, node, original, f.fs.config.KBPKI(), f.fs.config, f.h)
   375  }
   376  
   377  // fillAttrWithUIDAndWritePerm sets attributes based on the entry info, and
   378  // pops in correct UID and write permissions. It only handles fields common to
   379  // all entryinfo types.
   380  func (f *Folder) fillAttrWithUIDAndWritePerm(
   381  	ctx context.Context, node libkbfs.Node, ei *data.EntryInfo,
   382  	a *fuse.Attr) (err error) {
   383  	a.Valid = 1 * time.Minute
   384  	node.FillCacheDuration(&a.Valid)
   385  
   386  	a.Size = ei.Size
   387  	a.Blocks = getNumBlocksFromSize(ei.Size)
   388  	a.Mtime = time.Unix(0, ei.Mtime)
   389  	a.Ctime = time.Unix(0, ei.Ctime)
   390  
   391  	a.Uid = uint32(os.Getuid())
   392  
   393  	if a.Mode, err = f.writePermMode(ctx, node, a.Mode); err != nil {
   394  		return err
   395  	}
   396  
   397  	return nil
   398  }
   399  
   400  func (f *Folder) isWriter(ctx context.Context) (bool, error) {
   401  	f.handleMu.RLock()
   402  	defer f.handleMu.RUnlock()
   403  	return libfs.IsWriter(ctx, f.fs.config.KBPKI(), f.fs.config, f.h)
   404  }
   405  
   406  func (f *Folder) access(ctx context.Context, r *fuse.AccessRequest) error {
   407  	if int(r.Uid) != os.Getuid() &&
   408  		// Finder likes to use UID 0 for some operations. osxfuse already allows
   409  		// ACCESS and GETXATTR requests from root to go through. This allows root
   410  		// in ACCESS handler. See KBFS-1733 for more details.
   411  		int(r.Uid) != 0 {
   412  		// short path: not accessible by anybody other than root or the user who
   413  		// executed the kbfsfuse process.
   414  		return fuse.EPERM
   415  	}
   416  
   417  	if r.Mask&02 == 0 {
   418  		// For directory, we only check for the w bit.
   419  		return nil
   420  	}
   421  
   422  	iw, err := f.isWriter(ctx)
   423  	if err != nil {
   424  		return nil
   425  	}
   426  	if !iw {
   427  		return fuse.EPERM
   428  	}
   429  
   430  	return nil
   431  }
   432  
   433  func (f *Folder) openFileCount() int64 {
   434  	f.nodesMu.Lock()
   435  	defer f.nodesMu.Unlock()
   436  	count := int64(len(f.nodes))
   437  	if count > 0 {
   438  		// The root node itself should only be counted by the folder
   439  		// list, not here.
   440  		count--
   441  	}
   442  	return count
   443  }
   444  
   445  // TODO: Expire TLF nodes periodically. See
   446  // https://keybase.atlassian.net/browse/KBFS-59 .
   447  
   448  // DirInterface gathers all the interfaces a Dir or something that
   449  // wraps a Dir should implement.
   450  type DirInterface interface {
   451  	fs.Node
   452  	fs.NodeAccesser
   453  	fs.NodeRequestLookuper
   454  	fs.NodeCreater
   455  	fs.NodeMkdirer
   456  	fs.NodeSymlinker
   457  	fs.NodeRenamer
   458  	fs.NodeRemover
   459  	fs.Handle
   460  	fs.HandleReadDirAller
   461  	fs.NodeForgetter
   462  	fs.NodeSetattrer
   463  	fs.NodeFsyncer
   464  	fs.NodeGetxattrer
   465  	fs.NodeSetxattrer
   466  }
   467  
   468  // Dir represents a subdirectory of a KBFS top-level folder (including
   469  // the TLF root directory itself).
   470  type Dir struct {
   471  	folder *Folder
   472  	node   libkbfs.Node
   473  	inode  uint64
   474  	XattrHandler
   475  }
   476  
   477  func newDirWithInode(folder *Folder, node libkbfs.Node, inode uint64) *Dir {
   478  	d := &Dir{
   479  		folder: folder,
   480  		node:   node,
   481  		inode:  inode,
   482  	}
   483  	if folder.quarantine {
   484  		d.XattrHandler = NewQuarantineXattrHandler(node, folder)
   485  	} else {
   486  		d.XattrHandler = NoXattrHandler{}
   487  	}
   488  	return d
   489  }
   490  
   491  func newDir(folder *Folder, node libkbfs.Node) *Dir {
   492  	return newDirWithInode(folder, node, folder.fs.assignInode())
   493  }
   494  
   495  var _ DirInterface = (*Dir)(nil)
   496  
   497  // Access implements the fs.NodeAccesser interface for File. See comment for
   498  // File.Access for more details.
   499  func (d *Dir) Access(ctx context.Context, r *fuse.AccessRequest) (err error) {
   500  	ctx = d.folder.fs.config.MaybeStartTrace(
   501  		ctx, "Dir.Access", d.node.GetBasename().String())
   502  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   503  
   504  	return d.folder.access(ctx, r)
   505  }
   506  
   507  // Attr implements the fs.Node interface for Dir.
   508  func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
   509  	ctx = d.folder.fs.config.MaybeStartTrace(
   510  		ctx, "Dir.Attr", d.node.GetBasename().String())
   511  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   512  
   513  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Attr")
   514  	defer func() { err = d.folder.processError(ctx, libkbfs.ReadMode, err) }()
   515  
   516  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   517  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   518  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   519  	if err != nil {
   520  		return err
   521  	}
   522  
   523  	return d.attr(ctx, a)
   524  }
   525  
   526  func (d *Dir) attr(ctx context.Context, a *fuse.Attr) (err error) {
   527  	de, err := d.folder.fs.config.KBFSOps().Stat(ctx, d.node)
   528  	if err != nil {
   529  		if isNoSuchNameError(err) {
   530  			return fuse.ESTALE
   531  		}
   532  		return err
   533  	}
   534  	if err = d.folder.fillAttrWithUIDAndWritePerm(
   535  		ctx, d.node, &de, a); err != nil {
   536  		return err
   537  	}
   538  
   539  	a.Mode |= os.ModeDir | 0500
   540  	a.Inode = d.inode
   541  	return nil
   542  }
   543  
   544  func (d *Dir) makeFile(node libkbfs.Node) (file *File) {
   545  	file = &File{
   546  		folder: d.folder,
   547  		node:   node,
   548  		inode:  d.folder.fs.assignInode(),
   549  	}
   550  	if d.folder.quarantine {
   551  		file.XattrHandler = NewQuarantineXattrHandler(node, d.folder)
   552  	} else {
   553  		file.XattrHandler = NoXattrHandler{}
   554  	}
   555  	return file
   556  }
   557  
   558  // Lookup implements the fs.NodeRequestLookuper interface for Dir.
   559  func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fs.Node, err error) {
   560  	namePPS := d.node.ChildName(req.Name)
   561  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Lookup",
   562  		fmt.Sprintf("%s %s", d.node.GetBasename(), namePPS))
   563  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   564  
   565  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Lookup %s", namePPS)
   566  	defer func() { err = d.folder.processError(ctx, libkbfs.ReadMode, err) }()
   567  
   568  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   569  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   570  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   571  	if err != nil {
   572  		return nil, err
   573  	}
   574  
   575  	specialNode := handleTLFSpecialFile(
   576  		req.Name, d.folder, &resp.EntryValid)
   577  	if specialNode != nil {
   578  		return specialNode, nil
   579  	}
   580  
   581  	// Check if this is a per-file metainformation file, if so
   582  	// return the corresponding SpecialReadFile.
   583  	if strings.HasPrefix(req.Name, libfs.FileInfoPrefix) {
   584  		name := req.Name[len(libfs.FileInfoPrefix):]
   585  		return NewFileInfoFile(d.folder.fs, d.node, name, &resp.EntryValid), nil
   586  	}
   587  
   588  	newNode, de, err := d.folder.fs.config.KBFSOps().Lookup(
   589  		ctx, d.node, namePPS)
   590  	if err != nil {
   591  		if _, ok := err.(idutil.NoSuchNameError); ok {
   592  			return nil, fuse.ENOENT
   593  		}
   594  		return nil, err
   595  	}
   596  
   597  	// No libkbfs calls after this point!
   598  	d.folder.nodesMu.Lock()
   599  	defer d.folder.nodesMu.Unlock()
   600  
   601  	// newNode can be nil even without errors when the KBFS direntry
   602  	// is of a type that doesn't get its own node (is fully contained
   603  	// in the directory); Symlink does this.
   604  	if newNode != nil {
   605  		if n, ok := d.folder.nodes[newNode.GetID()]; ok {
   606  			return n, nil
   607  		}
   608  
   609  		newNode.FillCacheDuration(&resp.EntryValid)
   610  	}
   611  
   612  	switch de.Type {
   613  	default:
   614  		return nil, fmt.Errorf("unhandled entry type: %v", de.Type)
   615  
   616  	case data.File, data.Exec:
   617  		child := d.makeFile(newNode)
   618  		d.folder.nodes[newNode.GetID()] = child
   619  		return child, nil
   620  
   621  	case data.Dir:
   622  		child := newDir(d.folder, newNode)
   623  		d.folder.nodes[newNode.GetID()] = child
   624  		return child, nil
   625  
   626  	case data.Sym:
   627  		// Give each symlink instance a unique inode.  We don't get
   628  		// enough information about remote renames of syminks to be
   629  		// able to attach a constant inode to a given symlink.
   630  		child := &Symlink{
   631  			parent: d,
   632  			name:   req.Name,
   633  			inode:  d.folder.fs.assignInode(),
   634  		}
   635  		// A Symlink is never included in Folder.nodes, as it doesn't
   636  		// have a libkbfs.Node to keep track of renames.
   637  		return child, nil
   638  	}
   639  }
   640  
   641  func getEXCLFromCreateRequest(req *fuse.CreateRequest) libkbfs.Excl {
   642  	return libkbfs.Excl(req.Flags&fuse.OpenExclusive == fuse.OpenExclusive)
   643  }
   644  
   645  // Create implements the fs.NodeCreater interface for Dir.
   646  func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fs.Node, handle fs.Handle, err error) {
   647  	namePPS := d.node.ChildName(req.Name)
   648  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Create",
   649  		fmt.Sprintf("%s %s", d.node.GetBasename(), namePPS))
   650  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   651  
   652  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Create %s", namePPS)
   653  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   654  
   655  	isExec := (req.Mode.Perm() & 0100) != 0
   656  	excl := getEXCLFromCreateRequest(req)
   657  	newNode, ei, err := d.folder.fs.config.KBFSOps().CreateFile(
   658  		ctx, d.node, namePPS, isExec, excl)
   659  	if err != nil {
   660  		return nil, nil, err
   661  	}
   662  
   663  	child := d.makeFile(newNode)
   664  
   665  	// Create is normally followed an Attr call. Fuse uses the same context for
   666  	// them. If the context is cancelled after the Create call enters the
   667  	// critical portion, and grace period has passed before Attr happens, the
   668  	// Attr can result in EINTR which application does not expect. This caches
   669  	// the EntryInfo for the created node and allows the subsequent Attr call to
   670  	// use the cached EntryInfo instead of relying on a new Stat call.
   671  	if reqID, ok := ctx.Value(CtxIDKey).(string); ok {
   672  		child.eiCache.set(reqID, ei)
   673  	}
   674  
   675  	d.folder.nodesMu.Lock()
   676  	d.folder.nodes[newNode.GetID()] = child
   677  	d.folder.nodesMu.Unlock()
   678  	return child, child, nil
   679  }
   680  
   681  // Mkdir implements the fs.NodeMkdirer interface for Dir.
   682  func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (
   683  	node fs.Node, err error) {
   684  	namePPS := d.node.ChildName(req.Name)
   685  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Mkdir",
   686  		fmt.Sprintf("%s %s", d.node.GetBasename(), namePPS))
   687  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   688  
   689  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Mkdir %s", namePPS)
   690  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   691  
   692  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   693  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   694  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   695  	if err != nil {
   696  		return nil, err
   697  	}
   698  
   699  	newNode, _, err := d.folder.fs.config.KBFSOps().CreateDir(
   700  		ctx, d.node, namePPS)
   701  	if err != nil {
   702  		return nil, err
   703  	}
   704  
   705  	child := newDir(d.folder, newNode)
   706  	d.folder.nodesMu.Lock()
   707  	d.folder.nodes[newNode.GetID()] = child
   708  	d.folder.nodesMu.Unlock()
   709  	return child, nil
   710  }
   711  
   712  // Symlink implements the fs.NodeSymlinker interface for Dir.
   713  func (d *Dir) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (
   714  	node fs.Node, err error) {
   715  	namePPS := d.node.ChildName(req.NewName)
   716  	targetPPS := d.node.ChildName(req.Target)
   717  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Symlink",
   718  		fmt.Sprintf("%s %s -> %s", d.node.GetBasename(), namePPS, targetPPS))
   719  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   720  
   721  	d.folder.fs.vlog.CLogf(
   722  		ctx, libkb.VLog1, "Dir Symlink %s -> %s", namePPS, req.Target)
   723  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   724  
   725  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   726  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   727  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   728  	if err != nil {
   729  		return nil, err
   730  	}
   731  
   732  	if _, err := d.folder.fs.config.KBFSOps().CreateLink(
   733  		ctx, d.node, namePPS, targetPPS); err != nil {
   734  		return nil, err
   735  	}
   736  
   737  	child := &Symlink{
   738  		parent: d,
   739  		name:   req.NewName,
   740  		inode:  d.folder.fs.assignInode(),
   741  	}
   742  	return child, nil
   743  }
   744  
   745  var _ fs.NodeLinker = (*Dir)(nil)
   746  
   747  // Link implements the fs.NodeLinker interface for Dir.
   748  func (d *Dir) Link(
   749  	_ context.Context, _ *fuse.LinkRequest, _ fs.Node) (fs.Node, error) {
   750  	return nil, fuse.ENOTSUP
   751  }
   752  
   753  // Rename implements the fs.NodeRenamer interface for Dir.
   754  func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest,
   755  	newDir fs.Node) (err error) {
   756  	oldNamePPS := d.node.ChildName(req.OldName)
   757  	// We need to log the new name before we have the new node, so
   758  	// just obfuscate it with the old node for now, it's the best we
   759  	// can do.
   760  	newNameLoggingPPS := d.node.ChildName(req.NewName)
   761  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Rename",
   762  		fmt.Sprintf("%s %s -> %s", d.node.GetBasename(),
   763  			oldNamePPS, newNameLoggingPPS))
   764  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   765  
   766  	d.folder.fs.vlog.CLogf(
   767  		ctx, libkb.VLog1, "Dir Rename %s -> %s", oldNamePPS, newNameLoggingPPS)
   768  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   769  
   770  	var realNewDir *Dir
   771  	switch newDir := newDir.(type) {
   772  	case *Dir:
   773  		realNewDir = newDir
   774  	case *TLF:
   775  		var err error
   776  		realNewDir, err = newDir.loadDir(ctx)
   777  		if err != nil {
   778  			return err
   779  		}
   780  	case *FolderList, *Root:
   781  		// This normally wouldn't happen since a presumably pre-check on
   782  		// destination permissions would have failed. But in case it happens, it
   783  		// should be a EACCES according to rename() man page.
   784  		return fuse.Errno(syscall.EACCES)
   785  	default:
   786  		// This shouldn't happen unless we add other nodes. EIO is not in the error
   787  		// codes listed in rename(), but there doesn't seem to be any suitable
   788  		// error code listed for this situation either.
   789  		return fuse.Errno(syscall.EIO)
   790  	}
   791  
   792  	err = d.folder.fs.config.KBFSOps().Rename(ctx,
   793  		d.node, oldNamePPS, realNewDir.node,
   794  		realNewDir.node.ChildName(req.NewName))
   795  
   796  	switch e := err.(type) {
   797  	case nil:
   798  		return nil
   799  	case libkbfs.RenameAcrossDirsError:
   800  		var execPathErr error
   801  		e.ApplicationExecPath, execPathErr = sysutils.GetExecPathFromPID(req.Pid)
   802  		if execPathErr != nil {
   803  			d.folder.fs.log.CDebugf(ctx,
   804  				"Dir Rename: getting exec path for PID %d error: %v",
   805  				req.Pid, execPathErr)
   806  		}
   807  		return e
   808  	default:
   809  		return err
   810  	}
   811  }
   812  
   813  // Remove implements the fs.NodeRemover interface for Dir.
   814  func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) (err error) {
   815  	namePPS := d.node.ChildName(req.Name)
   816  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Remove",
   817  		fmt.Sprintf("%s %s", d.node.GetBasename(), namePPS))
   818  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   819  
   820  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Remove %s", namePPS)
   821  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   822  
   823  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   824  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   825  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   826  	if err != nil {
   827  		return err
   828  	}
   829  
   830  	// node will be removed from Folder.nodes, if it is there in the
   831  	// first place, by its Forget
   832  	if req.Dir {
   833  		err = d.folder.fs.config.KBFSOps().RemoveDir(ctx, d.node, namePPS)
   834  	} else {
   835  		err = d.folder.fs.config.KBFSOps().RemoveEntry(ctx, d.node, namePPS)
   836  	}
   837  	if err != nil {
   838  		return err
   839  	}
   840  
   841  	return nil
   842  }
   843  
   844  // ReadDirAll implements the fs.NodeReadDirAller interface for Dir.
   845  func (d *Dir) ReadDirAll(ctx context.Context) (res []fuse.Dirent, err error) {
   846  	ctx = d.folder.fs.config.MaybeStartTrace(
   847  		ctx, "Dir.ReadDirAll", d.node.GetBasename().String())
   848  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   849  
   850  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir ReadDirAll")
   851  	defer func() { err = d.folder.processError(ctx, libkbfs.ReadMode, err) }()
   852  
   853  	children, err := d.folder.fs.config.KBFSOps().GetDirChildren(ctx, d.node)
   854  	if err != nil {
   855  		return nil, err
   856  	}
   857  
   858  	for name, ei := range children {
   859  		fde := fuse.Dirent{
   860  			Name: name.Plaintext(),
   861  			// Technically we should be setting the inode here, but
   862  			// since we don't have a proper node for each of these
   863  			// entries yet we can't generate one, because we don't
   864  			// have anywhere to save it.  So bazil.org/fuse will
   865  			// generate a random one for each entry, but doesn't store
   866  			// it anywhere, so it's safe.
   867  		}
   868  		switch ei.Type {
   869  		case data.File, data.Exec:
   870  			fde.Type = fuse.DT_File
   871  		case data.Dir:
   872  			fde.Type = fuse.DT_Dir
   873  		case data.Sym:
   874  			fde.Type = fuse.DT_Link
   875  		}
   876  		res = append(res, fde)
   877  	}
   878  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Returning %d entries", len(res))
   879  	return res, nil
   880  }
   881  
   882  // Forget kernel reference to this node.
   883  func (d *Dir) Forget() {
   884  	d.folder.forgetNode(d.node)
   885  }
   886  
   887  // Setattr implements the fs.NodeSetattrer interface for Dir.
   888  func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) (err error) {
   889  	valid := req.Valid
   890  	ctx = d.folder.fs.config.MaybeStartTrace(ctx, "Dir.Setattr",
   891  		fmt.Sprintf("%s %s", d.node.GetBasename(), valid))
   892  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   893  
   894  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir SetAttr %s", valid)
   895  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   896  
   897  	if valid.Mode() {
   898  		// You can't set the mode on KBFS directories, but we don't
   899  		// want to return EPERM because that unnecessarily fails some
   900  		// applications like unzip.  Instead ignore it, print a debug
   901  		// message, and advertise this behavior on the
   902  		// "understand_kbfs" doc online.
   903  		d.folder.fs.vlog.CLogf(
   904  			ctx, libkb.VLog1, "Ignoring unsupported attempt to set "+
   905  				"the mode on a directory")
   906  		valid &^= fuse.SetattrMode
   907  	}
   908  
   909  	if valid.Mtime() {
   910  		err := d.folder.fs.config.KBFSOps().SetMtime(
   911  			ctx, d.node, &req.Mtime)
   912  		if err != nil {
   913  			return err
   914  		}
   915  		valid &^= fuse.SetattrMtime | fuse.SetattrMtimeNow
   916  	}
   917  
   918  	// KBFS has no concept of persistent atime; explicitly don't handle it
   919  	valid &^= fuse.SetattrAtime | fuse.SetattrAtimeNow
   920  
   921  	// things we don't need to explicitly handle
   922  	valid &^= fuse.SetattrLockOwner | fuse.SetattrHandle
   923  
   924  	if valid.Uid() || valid.Gid() {
   925  		// You can't set the UID/GID on KBFS directories, but we don't
   926  		// want to return ENOSYS because that causes scary warnings on
   927  		// some programs like mv.  Instead ignore it, print a debug
   928  		// message, and advertise this behavior on the
   929  		// "understand_kbfs" doc online.
   930  		d.folder.fs.vlog.CLogf(
   931  			ctx, libkb.VLog1, "Ignoring unsupported attempt to set "+
   932  				"the UID/GID on a directory")
   933  		valid &^= fuse.SetattrUid | fuse.SetattrGid
   934  	}
   935  
   936  	if valid != 0 {
   937  		// don't let an unhandled operation slip by without error
   938  		d.folder.fs.log.CInfof(ctx, "Setattr did not handle %v", valid)
   939  		return fuse.ENOSYS
   940  	}
   941  
   942  	// Something in Linux kernel *requires* directories to provide
   943  	// attributes here, where it was just an optimization for files.
   944  	return d.attr(ctx, &resp.Attr)
   945  }
   946  
   947  // Fsync implements the fs.NodeFsyncer interface for Dir.
   948  func (d *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) {
   949  	ctx = d.folder.fs.config.MaybeStartTrace(
   950  		ctx, "Dir.Fsync", d.node.GetBasename().String())
   951  	defer func() { d.folder.fs.config.MaybeFinishTrace(ctx, err) }()
   952  
   953  	d.folder.fs.vlog.CLogf(ctx, libkb.VLog1, "Dir Fsync")
   954  	defer func() { err = d.folder.processError(ctx, libkbfs.WriteMode, err) }()
   955  
   956  	// This fits in situation 1 as described in libkbfs/delayed_cancellation.go
   957  	err = libcontext.EnableDelayedCancellationWithGracePeriod(
   958  		ctx, d.folder.fs.config.DelayedCancellationGracePeriod())
   959  	if err != nil {
   960  		return err
   961  	}
   962  
   963  	return d.folder.fs.config.KBFSOps().SyncAll(ctx, d.node.GetFolderBranch())
   964  }
   965  
   966  // isNoSuchNameError checks for libkbfs.NoSuchNameError.
   967  func isNoSuchNameError(err error) bool {
   968  	_, ok := err.(idutil.NoSuchNameError)
   969  	return ok
   970  }