github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }