github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/vfs/dir.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path" 8 "sort" 9 "strings" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/rclone/rclone/fs" 15 "github.com/rclone/rclone/fs/dirtree" 16 "github.com/rclone/rclone/fs/list" 17 "github.com/rclone/rclone/fs/log" 18 "github.com/rclone/rclone/fs/operations" 19 "github.com/rclone/rclone/fs/walk" 20 "github.com/rclone/rclone/vfs/vfscommon" 21 "golang.org/x/text/unicode/norm" 22 ) 23 24 // Dir represents a directory entry 25 type Dir struct { 26 vfs *VFS // read only 27 inode uint64 // read only: inode number 28 f fs.Fs // read only 29 cleanupTimer *time.Timer // read only: timer to call cacheCleanup 30 31 mu sync.RWMutex // protects the following 32 parent *Dir // parent, nil for root 33 path string 34 entry fs.Directory 35 read time.Time // time directory entry last read 36 items map[string]Node // directory entries - can be empty but not nil 37 virtual map[string]vState // virtual directory entries - may be nil 38 sys atomic.Value // user defined info to be attached here 39 40 modTimeMu sync.Mutex // protects the following 41 modTime time.Time 42 43 _hasVirtual atomic.Bool // shows if the directory has virtual entries 44 } 45 46 //go:generate stringer -type=vState 47 48 // vState describes the state of the virtual directory entries 49 type vState byte 50 51 const ( 52 vOK vState = iota // Not virtual 53 vAddFile // added file 54 vAddDir // added directory 55 vDel // removed file or directory 56 ) 57 58 func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir { 59 d := &Dir{ 60 vfs: vfs, 61 f: f, 62 parent: parent, 63 entry: fsDir, 64 path: fsDir.Remote(), 65 modTime: fsDir.ModTime(context.TODO()), 66 inode: newInode(), 67 items: make(map[string]Node), 68 } 69 d.cleanupTimer = time.AfterFunc(vfs.Opt.DirCacheTime*2, d.cacheCleanup) 70 d.setHasVirtual(false) 71 return d 72 } 73 74 func (d *Dir) cacheCleanup() { 75 defer func() { 76 // We should never panic here 77 _ = recover() 78 }() 79 80 when := time.Now() 81 82 d.mu.Lock() 83 _, stale := d._age(when) 84 d.mu.Unlock() 85 86 if stale { 87 d.ForgetAll() 88 } 89 } 90 91 // String converts it to printable 92 func (d *Dir) String() string { 93 if d == nil { 94 return "<nil *Dir>" 95 } 96 d.mu.RLock() 97 defer d.mu.RUnlock() 98 return d.path + "/" 99 } 100 101 // Dumps the directory tree to the string builder with the given indent 102 // 103 //lint:ignore U1000 false positive when running staticcheck, 104 //nolint:unused // Don't include unused when running golangci-lint 105 func (d *Dir) dumpIndent(out *strings.Builder, indent string) { 106 if d == nil { 107 fmt.Fprintf(out, "%s<nil *Dir>\n", indent) 108 return 109 } 110 d.mu.RLock() 111 defer d.mu.RUnlock() 112 fmt.Fprintf(out, "%sPath: %s\n", indent, d.path) 113 fmt.Fprintf(out, "%sEntry: %v\n", indent, d.entry) 114 fmt.Fprintf(out, "%sRead: %v\n", indent, d.read) 115 fmt.Fprintf(out, "%s- items %d\n", indent, len(d.items)) 116 // Sort? 117 for leaf, node := range d.items { 118 switch x := node.(type) { 119 case *Dir: 120 fmt.Fprintf(out, "%s %s/ - %v\n", indent, leaf, x) 121 // check the parent is correct 122 if x.parent != d { 123 fmt.Fprintf(out, "%s PARENT POINTER WRONG\n", indent) 124 } 125 x.dumpIndent(out, indent+"\t") 126 case *File: 127 fmt.Fprintf(out, "%s %s - %v\n", indent, leaf, x) 128 default: 129 panic("bad dir entry") 130 } 131 } 132 fmt.Fprintf(out, "%s- virtual %d\n", indent, len(d.virtual)) 133 for leaf, state := range d.virtual { 134 fmt.Fprintf(out, "%s %s - %v\n", indent, leaf, state) 135 } 136 } 137 138 // Dumps a nicely formatted directory tree to a string 139 // 140 //lint:ignore U1000 false positive when running staticcheck, 141 //nolint:unused // Don't include unused when running golangci-lint 142 func (d *Dir) dump() string { 143 var out strings.Builder 144 d.dumpIndent(&out, "") 145 return out.String() 146 } 147 148 // IsFile returns false for Dir - satisfies Node interface 149 func (d *Dir) IsFile() bool { 150 return false 151 } 152 153 // IsDir returns true for Dir - satisfies Node interface 154 func (d *Dir) IsDir() bool { 155 return true 156 } 157 158 // Mode bits of the directory - satisfies Node interface 159 func (d *Dir) Mode() (mode os.FileMode) { 160 return d.vfs.Opt.DirPerms 161 } 162 163 // Name (base) of the directory - satisfies Node interface 164 func (d *Dir) Name() (name string) { 165 d.mu.RLock() 166 name = path.Base(d.path) 167 d.mu.RUnlock() 168 if name == "." { 169 name = "/" 170 } 171 return name 172 } 173 174 // Path of the directory - satisfies Node interface 175 func (d *Dir) Path() (name string) { 176 d.mu.RLock() 177 defer d.mu.RUnlock() 178 return d.path 179 } 180 181 // Sys returns underlying data source (can be nil) - satisfies Node interface 182 func (d *Dir) Sys() interface{} { 183 return d.sys.Load() 184 } 185 186 // SetSys sets the underlying data source (can be nil) - satisfies Node interface 187 func (d *Dir) SetSys(x interface{}) { 188 d.sys.Store(x) 189 } 190 191 // Inode returns the inode number - satisfies Node interface 192 func (d *Dir) Inode() uint64 { 193 return d.inode 194 } 195 196 // Node returns the Node associated with this - satisfies Noder interface 197 func (d *Dir) Node() Node { 198 return d 199 } 200 201 // hasVirtual returns whether the directory has virtual entries 202 func (d *Dir) hasVirtual() bool { 203 return d._hasVirtual.Load() 204 } 205 206 // setHasVirtual sets the hasVirtual flag for the directory 207 func (d *Dir) setHasVirtual(hasVirtual bool) { 208 d._hasVirtual.Store(hasVirtual) 209 } 210 211 // ForgetAll forgets directory entries for this directory and any children. 212 // 213 // It does not invalidate or clear the cache of the parent directory. 214 // 215 // It returns true if the directory or any of its children had virtual entries 216 // so could not be forgotten. Children which didn't have virtual entries and 217 // children with virtual entries will be forgotten even if true is returned. 218 func (d *Dir) ForgetAll() (hasVirtual bool) { 219 d.mu.RLock() 220 221 fs.Debugf(d.path, "forgetting directory cache") 222 for _, node := range d.items { 223 if dir, ok := node.(*Dir); ok { 224 if dir.ForgetAll() { 225 d.setHasVirtual(true) 226 } 227 } 228 } 229 230 d.mu.RUnlock() 231 232 d.mu.Lock() 233 defer d.mu.Unlock() 234 235 // Purge any unnecessary virtual entries 236 d._purgeVirtual() 237 238 d.read = time.Time{} 239 240 // Check if this dir has virtual entries 241 if len(d.virtual) != 0 { 242 d.setHasVirtual(true) 243 } 244 245 // Don't clear directory entries if there are virtual entries in this 246 // directory or any children 247 if !d.hasVirtual() { 248 d.items = make(map[string]Node) 249 d.cleanupTimer.Stop() 250 } 251 252 return d.hasVirtual() 253 } 254 255 // forgetDirPath clears the cache for itself and all subdirectories if 256 // they match the given path. The path is specified relative from the 257 // directory it is called from. 258 // 259 // It does not invalidate or clear the cache of the parent directory. 260 func (d *Dir) forgetDirPath(relativePath string) { 261 dir := d.cachedDir(relativePath) 262 if dir == nil { 263 return 264 } 265 dir.ForgetAll() 266 } 267 268 // invalidateDir invalidates the directory cache for absPath relative to the root 269 func (d *Dir) invalidateDir(absPath string) { 270 node := d.vfs.root.cachedNode(absPath) 271 if dir, ok := node.(*Dir); ok { 272 dir.mu.Lock() 273 if !dir.read.IsZero() { 274 fs.Debugf(dir.path, "invalidating directory cache") 275 dir.read = time.Time{} 276 } 277 dir.mu.Unlock() 278 } 279 } 280 281 // changeNotify invalidates the directory cache for the relativePath 282 // passed in. 283 // 284 // if entryType is a directory it invalidates the parent of the directory too. 285 func (d *Dir) changeNotify(relativePath string, entryType fs.EntryType) { 286 defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("") 287 d.mu.RLock() 288 absPath := path.Join(d.path, relativePath) 289 d.mu.RUnlock() 290 d.invalidateDir(vfscommon.FindParent(absPath)) 291 if entryType == fs.EntryDirectory { 292 d.invalidateDir(absPath) 293 } 294 } 295 296 // ForgetPath clears the cache for itself and all subdirectories if 297 // they match the given path. The path is specified relative from the 298 // directory it is called from. The cache of the parent directory is 299 // marked as stale, but not cleared otherwise. 300 // It is not possible to traverse the directory tree upwards, i.e. 301 // you cannot clear the cache for the Dir's ancestors or siblings. 302 func (d *Dir) ForgetPath(relativePath string, entryType fs.EntryType) { 303 defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("") 304 d.mu.RLock() 305 absPath := path.Join(d.path, relativePath) 306 d.mu.RUnlock() 307 if absPath != "" { 308 d.invalidateDir(vfscommon.FindParent(absPath)) 309 } 310 if entryType == fs.EntryDirectory { 311 d.forgetDirPath(relativePath) 312 } 313 } 314 315 // walk runs a function on all cached directories. It will be called 316 // on a directory's children first. 317 // 318 // The mutex will be held for the directory when fun is called 319 func (d *Dir) walk(fun func(*Dir)) { 320 d.mu.Lock() 321 defer d.mu.Unlock() 322 for _, node := range d.items { 323 if dir, ok := node.(*Dir); ok { 324 dir.walk(fun) 325 } 326 } 327 328 fun(d) 329 } 330 331 // countActiveWriters returns the number of writers active in this 332 // directory and any subdirectories. 333 func (d *Dir) countActiveWriters() (writers int) { 334 d.walk(func(d *Dir) { 335 // NB d.mu is held by walk() here 336 fs.Debugf(d.path, "Looking for writers") 337 for leaf, item := range d.items { 338 fs.Debugf(leaf, "reading active writers") 339 if file, ok := item.(*File); ok { 340 n := file.activeWriters() 341 if n != 0 { 342 fs.Debugf(file, "active writers %d", n) 343 } 344 writers += n 345 } 346 } 347 }) 348 return writers 349 } 350 351 // age returns the duration since the last time the directory contents 352 // was read and the content is considered stale. age will be 0 and 353 // stale true if the last read time is empty. 354 // age must be called with d.mu held. 355 func (d *Dir) _age(when time.Time) (age time.Duration, stale bool) { 356 if d.read.IsZero() { 357 return age, true 358 } 359 age = when.Sub(d.read) 360 stale = age > d.vfs.Opt.DirCacheTime 361 return 362 } 363 364 // renameTree renames the directories under this directory 365 // 366 // path should be the desired path 367 func (d *Dir) renameTree(dirPath string) { 368 d.mu.Lock() 369 defer d.mu.Unlock() 370 371 // Make sure the path is correct for each node 372 if d.path != dirPath { 373 fs.Debugf(d.path, "Renaming to %q", dirPath) 374 d.path = dirPath 375 d.entry = fs.NewDirCopy(context.TODO(), d.entry).SetRemote(dirPath) 376 } 377 378 // Do the same to any child directories and files 379 for leaf, node := range d.items { 380 switch x := node.(type) { 381 case *Dir: 382 x.renameTree(path.Join(dirPath, leaf)) 383 case *File: 384 x.renameDir(dirPath) 385 default: 386 panic("bad dir entry") 387 } 388 } 389 } 390 391 // rename should be called after the directory is renamed 392 // 393 // Reset the directory to new state, discarding all the objects and 394 // reading everything again 395 func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) { 396 d.ForgetAll() 397 398 d.modTimeMu.Lock() 399 d.modTime = fsDir.ModTime(context.TODO()) 400 d.modTimeMu.Unlock() 401 d.mu.Lock() 402 oldPath := d.path 403 d.parent = newParent 404 d.entry = fsDir 405 d.path = fsDir.Remote() 406 newPath := d.path 407 d.read = time.Time{} 408 d.mu.Unlock() 409 410 // Rename any remaining items in the tree that we couldn't forget 411 d.renameTree(d.path) 412 413 // Rename in the cache 414 if d.vfs.cache != nil && d.vfs.cache.DirExists(oldPath) { 415 if err := d.vfs.cache.DirRename(oldPath, newPath); err != nil { 416 fs.Infof(d, "Dir.Rename failed in Cache: %v", err) 417 } 418 } 419 } 420 421 // addObject adds a new object or directory to the directory 422 // 423 // The name passed in is marked as virtual as it hasn't been read from a remote 424 // directory listing. 425 // 426 // note that we add new objects rather than updating old ones 427 func (d *Dir) addObject(node Node) { 428 d.mu.Lock() 429 leaf := node.Name() 430 d.items[leaf] = node 431 if d.virtual == nil { 432 d.virtual = make(map[string]vState) 433 } 434 vAdd := vAddFile 435 if node.IsDir() { 436 vAdd = vAddDir 437 } 438 d.virtual[leaf] = vAdd 439 d.setHasVirtual(true) 440 fs.Debugf(d.path, "Added virtual directory entry %v: %q", vAdd, leaf) 441 d.mu.Unlock() 442 } 443 444 // AddVirtual adds a virtual object of name and size to the directory 445 // 446 // This will be replaced with a real object when it is read back from the 447 // remote. 448 // 449 // This is used to add directory entries while things are uploading 450 func (d *Dir) AddVirtual(leaf string, size int64, isDir bool) { 451 var node Node 452 d.mu.RLock() 453 dPath := d.path 454 _, found := d.items[leaf] 455 d.mu.RUnlock() 456 if found { 457 // Don't overwrite existing objects 458 return 459 } 460 if isDir { 461 remote := path.Join(dPath, leaf) 462 entry := fs.NewDir(remote, time.Now()) 463 node = newDir(d.vfs, d.f, d, entry) 464 } else { 465 f := newFile(d, dPath, nil, leaf) 466 f.setSize(size) 467 node = f 468 } 469 d.addObject(node) 470 } 471 472 // delObject removes an object from the directory 473 // 474 // The name passed in is marked as virtual as the delete it hasn't been read 475 // from a remote directory listing. 476 func (d *Dir) delObject(leaf string) { 477 d.mu.Lock() 478 delete(d.items, leaf) 479 if d.virtual == nil { 480 d.virtual = make(map[string]vState) 481 } 482 d.virtual[leaf] = vDel 483 d.setHasVirtual(true) 484 fs.Debugf(d.path, "Added virtual directory entry %v: %q", vDel, leaf) 485 d.mu.Unlock() 486 } 487 488 // DelVirtual removes an object from the directory listing 489 // 490 // It marks it as removed until it has confirmed the object is missing when the 491 // directory entries are re-read in. 492 // 493 // This is used to remove directory entries after things have been deleted or 494 // renamed but before we've had confirmation from the backend. 495 func (d *Dir) DelVirtual(leaf string) { 496 d.delObject(leaf) 497 } 498 499 // read the directory and sets d.items - must be called with the lock held 500 func (d *Dir) _readDir() error { 501 when := time.Now() 502 if age, stale := d._age(when); stale { 503 if age != 0 { 504 fs.Debugf(d.path, "Re-reading directory (%v old)", age) 505 } 506 } else { 507 return nil 508 } 509 entries, err := list.DirSorted(context.TODO(), d.f, false, d.path) 510 if err == fs.ErrorDirNotFound { 511 // We treat directory not found as empty because we 512 // create directories on the fly 513 } else if err != nil { 514 return err 515 } 516 517 if d.vfs.Opt.BlockNormDupes { // do this only if requested, as it will have a performance hit 518 ci := fs.GetConfig(context.TODO()) 519 520 // sort entries such that NFD comes before NFC of same name 521 sort.Slice(entries, func(i, j int) bool { 522 if entries[i] != entries[j] && fs.DirEntryType(entries[i]) == fs.DirEntryType(entries[j]) && norm.NFC.String(entries[i].Remote()) == norm.NFC.String(entries[j].Remote()) { 523 if norm.NFD.IsNormalString(entries[i].Remote()) && !norm.NFD.IsNormalString(entries[j].Remote()) { 524 return true 525 } 526 } 527 return entries.Less(i, j) 528 }) 529 530 // detect dupes, remove them from the list and log an error 531 normalizedNames := make(map[string]struct{}, entries.Len()) 532 filteredEntries := make(fs.DirEntries, 0) 533 for _, e := range entries { 534 normName := fmt.Sprintf("%s-%T", operations.ToNormal(e.Remote(), !ci.NoUnicodeNormalization, (ci.IgnoreCaseSync || d.vfs.Opt.CaseInsensitive)), e) // include type to track objects and dirs separately 535 _, found := normalizedNames[normName] 536 if found { 537 fs.Errorf(e.Remote(), "duplicate normalized names detected - skipping") 538 continue 539 } 540 normalizedNames[normName] = struct{}{} 541 filteredEntries = append(filteredEntries, e) 542 } 543 entries = filteredEntries 544 } 545 546 err = d._readDirFromEntries(entries, nil, time.Time{}) 547 if err != nil { 548 return err 549 } 550 551 d.read = when 552 d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2) 553 554 return nil 555 } 556 557 // update d.items for each dir in the DirTree below this one and 558 // set the last read time - must be called with the lock held 559 func (d *Dir) _readDirFromDirTree(dirTree dirtree.DirTree, when time.Time) error { 560 return d._readDirFromEntries(dirTree[d.path], dirTree, when) 561 } 562 563 // Remove the virtual directory entry leaf 564 func (d *Dir) _deleteVirtual(name string) { 565 virtualState, ok := d.virtual[name] 566 if !ok { 567 return 568 } 569 delete(d.virtual, name) 570 if len(d.virtual) == 0 { 571 d.virtual = nil 572 d.setHasVirtual(false) 573 } 574 fs.Debugf(d.path, "Removed virtual directory entry %v: %q", virtualState, name) 575 } 576 577 // Purge virtual entries assuming the directory has just been re-read 578 // 579 // Remove all the entries except: 580 // 581 // 1) vDirAdd on remotes which can't have empty directories. These will remain 582 // virtual as long as the directory is empty. When the directory becomes real 583 // (ie files are added) the virtual directory will be removed. This means that 584 // directories will disappear when the last file is deleted which is probably 585 // OK. 586 // 587 // 2) vFileAdd that are being written or uploaded 588 func (d *Dir) _purgeVirtual() { 589 canHaveEmptyDirectories := d.f.Features().CanHaveEmptyDirectories 590 for name, virtualState := range d.virtual { 591 switch virtualState { 592 case vAddDir: 593 if canHaveEmptyDirectories { 594 // if remote can have empty directories then a 595 // new dir will be read in the listing 596 d._deleteVirtual(name) 597 //} else { 598 // leave the empty directory marker 599 } 600 case vAddFile: 601 // Delete all virtual file adds that have finished uploading 602 node, ok := d.items[name] 603 if !ok { 604 // if the object has disappeared somehow then remove the virtual 605 d._deleteVirtual(name) 606 continue 607 } 608 f, ok := node.(*File) 609 if !ok { 610 // if the object isn't a file then remove the virtual as it is wrong 611 d._deleteVirtual(name) 612 continue 613 } 614 if f.writingInProgress() { 615 // if writing in progress then leave virtual 616 continue 617 } 618 if d.vfs.Opt.CacheMode >= vfscommon.CacheModeMinimal && d.vfs.cache.InUse(f.Path()) { 619 // if object in use or dirty then leave virtual 620 continue 621 } 622 d._deleteVirtual(name) 623 default: 624 d._deleteVirtual(name) 625 } 626 } 627 } 628 629 // Manage the virtuals in a listing 630 // 631 // This keeps a record of the names listed in this directory so far 632 type manageVirtuals map[string]struct{} 633 634 // Create a new manageVirtuals and purge the d.virtuals of any entries which can 635 // be removed. 636 // 637 // must be called with the Dir lock held 638 func (d *Dir) _newManageVirtuals() manageVirtuals { 639 tv := make(manageVirtuals) 640 d._purgeVirtual() 641 return tv 642 } 643 644 // This should be called for every entry added to the directory 645 // 646 // It returns true if this entry should be skipped. 647 // 648 // must be called with the Dir lock held 649 func (mv manageVirtuals) add(d *Dir, name string) bool { 650 // Keep a record of all names listed 651 mv[name] = struct{}{} 652 // Remove virtuals if possible 653 switch d.virtual[name] { 654 case vAddFile, vAddDir: 655 // item was added to the dir but since it is found in a 656 // listing is no longer virtual 657 d._deleteVirtual(name) 658 case vDel: 659 // item is deleted from the dir so skip it 660 return true 661 case vOK: 662 } 663 return false 664 } 665 666 // This should be called after the directory entry is read to update d.items 667 // with virtual entries 668 // 669 // must be called with the Dir lock held 670 func (mv manageVirtuals) end(d *Dir) { 671 // delete unused d.items 672 for name := range d.items { 673 if _, ok := mv[name]; !ok { 674 // name was previously in the directory but wasn't found 675 // in the current listing 676 switch d.virtual[name] { 677 case vAddFile, vAddDir: 678 // virtually added so leave virtual item 679 default: 680 // otherwise delete it 681 delete(d.items, name) 682 } 683 } 684 } 685 // delete unused d.virtual~s 686 for name, virtualState := range d.virtual { 687 if _, ok := mv[name]; !ok { 688 // name exists as a virtual but isn't in the current 689 // listing so if it is a virtual delete we can remove it 690 // as it is no longer needed. 691 if virtualState == vDel { 692 d._deleteVirtual(name) 693 } 694 } 695 } 696 } 697 698 // update d.items and if dirTree is not nil update each dir in the DirTree below this one and 699 // set the last read time - must be called with the lock held 700 func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree, when time.Time) error { 701 var err error 702 mv := d._newManageVirtuals() 703 for _, entry := range entries { 704 name := path.Base(entry.Remote()) 705 if name == "." || name == ".." { 706 continue 707 } 708 node := d.items[name] 709 if mv.add(d, name) { 710 continue 711 } 712 switch item := entry.(type) { 713 case fs.Object: 714 obj := item 715 // Reuse old file value if it exists 716 if file, ok := node.(*File); node != nil && ok { 717 file.setObjectNoUpdate(obj) 718 } else { 719 node = newFile(d, d.path, obj, name) 720 } 721 case fs.Directory: 722 // Reuse old dir value if it exists 723 if node == nil || !node.IsDir() { 724 node = newDir(d.vfs, d.f, d, item) 725 } 726 dir := node.(*Dir) 727 dir.mu.Lock() 728 dir.modTime = item.ModTime(context.TODO()) 729 if dirTree != nil { 730 err = dir._readDirFromDirTree(dirTree, when) 731 if err != nil { 732 dir.read = time.Time{} 733 } else { 734 dir.read = when 735 dir.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2) 736 } 737 } 738 dir.mu.Unlock() 739 if err != nil { 740 return err 741 } 742 default: 743 err = fmt.Errorf("unknown type %T", item) 744 fs.Errorf(d, "readDir error: %v", err) 745 return err 746 } 747 d.items[name] = node 748 } 749 mv.end(d) 750 return nil 751 } 752 753 // readDirTree forces a refresh of the complete directory tree 754 func (d *Dir) readDirTree() error { 755 d.mu.RLock() 756 f, path := d.f, d.path 757 d.mu.RUnlock() 758 when := time.Now() 759 fs.Debugf(path, "Reading directory tree") 760 dt, err := walk.NewDirTree(context.TODO(), f, path, false, -1) 761 if err != nil { 762 return err 763 } 764 d.mu.Lock() 765 defer d.mu.Unlock() 766 d.read = time.Time{} 767 err = d._readDirFromDirTree(dt, when) 768 if err != nil { 769 return err 770 } 771 fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when)) 772 d.read = when 773 d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2) 774 return nil 775 } 776 777 // readDir forces a refresh of the directory 778 func (d *Dir) readDir() error { 779 d.mu.Lock() 780 defer d.mu.Unlock() 781 d.read = time.Time{} 782 return d._readDir() 783 } 784 785 // stat a single item in the directory 786 // 787 // returns ENOENT if not found. 788 // returns a custom error if directory on a case-insensitive file system 789 // contains files with names that differ only by case. 790 func (d *Dir) stat(leaf string) (Node, error) { 791 d.mu.Lock() 792 defer d.mu.Unlock() 793 err := d._readDir() 794 if err != nil { 795 return nil, err 796 } 797 item, ok := d.items[leaf] 798 799 ci := fs.GetConfig(context.TODO()) 800 normUnicode := !ci.NoUnicodeNormalization 801 normCase := ci.IgnoreCaseSync || d.vfs.Opt.CaseInsensitive 802 if !ok && (normUnicode || normCase) { 803 leafNormalized := operations.ToNormal(leaf, normUnicode, normCase) // this handles both case and unicode normalization 804 for name, node := range d.items { 805 if operations.ToNormal(name, normUnicode, normCase) == leafNormalized { 806 if ok { 807 // duplicate normalized match is an error 808 return nil, fmt.Errorf("duplicate filename %q detected with case/unicode normalization settings", leaf) 809 } 810 // found a normalized match 811 ok = true 812 item = node 813 } 814 } 815 } 816 817 if !ok { 818 return nil, ENOENT 819 } 820 return item, nil 821 } 822 823 // Check to see if a directory is empty 824 func (d *Dir) isEmpty() (bool, error) { 825 d.mu.Lock() 826 defer d.mu.Unlock() 827 err := d._readDir() 828 if err != nil { 829 return false, err 830 } 831 return len(d.items) == 0, nil 832 } 833 834 // ModTime returns the modification time of the directory 835 func (d *Dir) ModTime() time.Time { 836 d.modTimeMu.Lock() 837 defer d.modTimeMu.Unlock() 838 // fs.Debugf(d.path, "Dir.ModTime %v", d.modTime) 839 return d.modTime 840 } 841 842 // Size of the directory 843 func (d *Dir) Size() int64 { 844 return 0 845 } 846 847 // SetModTime sets the modTime for this dir 848 func (d *Dir) SetModTime(modTime time.Time) error { 849 if d.vfs.Opt.ReadOnly { 850 return EROFS 851 } 852 d.modTimeMu.Lock() 853 d.modTime = modTime 854 d.modTimeMu.Unlock() 855 return nil 856 } 857 858 func (d *Dir) cachedDir(relativePath string) (dir *Dir) { 859 dir, _ = d.cachedNode(relativePath).(*Dir) 860 return 861 } 862 863 func (d *Dir) cachedNode(relativePath string) Node { 864 segments := strings.Split(strings.Trim(relativePath, "/"), "/") 865 var node Node = d 866 for _, s := range segments { 867 if s == "" { 868 continue 869 } 870 if dir, ok := node.(*Dir); ok { 871 dir.mu.Lock() 872 node = dir.items[s] 873 dir.mu.Unlock() 874 875 if node != nil { 876 continue 877 } 878 } 879 return nil 880 } 881 882 return node 883 } 884 885 // Stat looks up a specific entry in the receiver. 886 // 887 // Stat should return a Node corresponding to the entry. If the 888 // name does not exist in the directory, Stat should return ENOENT. 889 // 890 // Stat need not to handle the names "." and "..". 891 func (d *Dir) Stat(name string) (node Node, err error) { 892 // fs.Debugf(path, "Dir.Stat") 893 node, err = d.stat(name) 894 if err != nil { 895 if err != ENOENT { 896 fs.Errorf(d, "Dir.Stat error: %v", err) 897 } 898 return nil, err 899 } 900 // fs.Debugf(path, "Dir.Stat OK") 901 return node, nil 902 } 903 904 // ReadDirAll reads the contents of the directory sorted 905 func (d *Dir) ReadDirAll() (items Nodes, err error) { 906 // fs.Debugf(d.path, "Dir.ReadDirAll") 907 d.mu.Lock() 908 err = d._readDir() 909 if err != nil { 910 fs.Debugf(d.path, "Dir.ReadDirAll error: %v", err) 911 d.mu.Unlock() 912 return nil, err 913 } 914 for _, item := range d.items { 915 items = append(items, item) 916 } 917 d.mu.Unlock() 918 sort.Sort(items) 919 // fs.Debugf(d.path, "Dir.ReadDirAll OK with %d entries", len(items)) 920 return items, nil 921 } 922 923 // accessModeMask masks off the read modes from the flags 924 const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) 925 926 // Open the directory according to the flags provided 927 func (d *Dir) Open(flags int) (fd Handle, err error) { 928 rdwrMode := flags & accessModeMask 929 if rdwrMode != os.O_RDONLY { 930 fs.Errorf(d, "Can only open directories read only") 931 return nil, EPERM 932 } 933 return newDirHandle(d), nil 934 } 935 936 // Create makes a new file node 937 func (d *Dir) Create(name string, flags int) (*File, error) { 938 // fs.Debugf(path, "Dir.Create") 939 // Return existing node if one exists 940 node, err := d.stat(name) 941 switch err { 942 case ENOENT: 943 // not found, carry on 944 case nil: 945 // found so check what it is 946 if node.IsFile() { 947 return node.(*File), err 948 } 949 return nil, EEXIST // EISDIR would be better but we don't have that 950 default: 951 // a different error - report 952 fs.Errorf(d, "Dir.Create stat failed: %v", err) 953 return nil, err 954 } 955 // node doesn't exist so create it 956 if d.vfs.Opt.ReadOnly { 957 return nil, EROFS 958 } 959 if err = d.SetModTime(time.Now()); err != nil { 960 fs.Errorf(d, "Dir.Create failed to set modtime on parent dir: %v", err) 961 return nil, err 962 } 963 // This gets added to the directory when the file is opened for write 964 return newFile(d, d.Path(), nil, name), nil 965 } 966 967 // Mkdir creates a new directory 968 func (d *Dir) Mkdir(name string) (*Dir, error) { 969 if d.vfs.Opt.ReadOnly { 970 return nil, EROFS 971 } 972 path := path.Join(d.path, name) 973 node, err := d.stat(name) 974 switch err { 975 case ENOENT: 976 // not found, carry on 977 case nil: 978 // found so check what it is 979 if node.IsDir() { 980 return node.(*Dir), err 981 } 982 return nil, EEXIST 983 default: 984 // a different error - report 985 fs.Errorf(d, "Dir.Mkdir failed to read directory: %v", err) 986 return nil, err 987 } 988 // fs.Debugf(path, "Dir.Mkdir") 989 err = d.f.Mkdir(context.TODO(), path) 990 if err != nil { 991 fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err) 992 return nil, err 993 } 994 fsDir := fs.NewDir(path, time.Now()) 995 dir := newDir(d.vfs, d.f, d, fsDir) 996 d.addObject(dir) 997 if err = d.SetModTime(time.Now()); err != nil { 998 fs.Errorf(d, "Dir.Mkdir failed to set modtime on parent dir: %v", err) 999 return nil, err 1000 } 1001 // fs.Debugf(path, "Dir.Mkdir OK") 1002 return dir, nil 1003 } 1004 1005 // Remove the directory 1006 func (d *Dir) Remove() error { 1007 if d.vfs.Opt.ReadOnly { 1008 return EROFS 1009 } 1010 // Check directory is empty first 1011 empty, err := d.isEmpty() 1012 if err != nil { 1013 fs.Errorf(d, "Dir.Remove dir error: %v", err) 1014 return err 1015 } 1016 if !empty { 1017 fs.Errorf(d, "Dir.Remove not empty") 1018 return ENOTEMPTY 1019 } 1020 // remove directory 1021 err = d.f.Rmdir(context.TODO(), d.path) 1022 if err != nil { 1023 fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err) 1024 return err 1025 } 1026 // Remove the item from the parent directory listing 1027 if d.parent != nil { 1028 d.parent.delObject(d.Name()) 1029 } 1030 return nil 1031 } 1032 1033 // RemoveAll removes the directory and any contents recursively 1034 func (d *Dir) RemoveAll() error { 1035 if d.vfs.Opt.ReadOnly { 1036 return EROFS 1037 } 1038 // Remove contents of the directory 1039 nodes, err := d.ReadDirAll() 1040 if err != nil { 1041 fs.Errorf(d, "Dir.RemoveAll failed to read directory: %v", err) 1042 return err 1043 } 1044 for _, node := range nodes { 1045 err = node.RemoveAll() 1046 if err != nil { 1047 fs.Errorf(node.Path(), "Dir.RemoveAll failed to remove: %v", err) 1048 return err 1049 } 1050 } 1051 return d.Remove() 1052 } 1053 1054 // DirEntry returns the underlying fs.DirEntry 1055 func (d *Dir) DirEntry() (entry fs.DirEntry) { 1056 return d.entry 1057 } 1058 1059 // RemoveName removes the entry with the given name from the receiver, 1060 // which must be a directory. The entry to be removed may correspond 1061 // to a file (unlink) or to a directory (rmdir). 1062 func (d *Dir) RemoveName(name string) error { 1063 if d.vfs.Opt.ReadOnly { 1064 return EROFS 1065 } 1066 // fs.Debugf(path, "Dir.Remove") 1067 node, err := d.stat(name) 1068 if err != nil { 1069 fs.Errorf(d, "Dir.Remove error: %v", err) 1070 return err 1071 } 1072 if err = d.SetModTime(time.Now()); err != nil { 1073 fs.Errorf(d, "Dir.Remove failed to set modtime on parent dir: %v", err) 1074 return err 1075 } 1076 return node.Remove() 1077 } 1078 1079 // Rename the file 1080 func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { 1081 // fs.Debugf(d, "BEFORE\n%s", d.dump()) 1082 if d.vfs.Opt.ReadOnly { 1083 return EROFS 1084 } 1085 oldPath := path.Join(d.path, oldName) 1086 newPath := path.Join(destDir.path, newName) 1087 // fs.Debugf(oldPath, "Dir.Rename to %q", newPath) 1088 oldNode, err := d.stat(oldName) 1089 if err != nil { 1090 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1091 return err 1092 } 1093 switch x := oldNode.DirEntry().(type) { 1094 case nil: 1095 if oldFile, ok := oldNode.(*File); ok { 1096 if err = oldFile.rename(context.TODO(), destDir, newName); err != nil { 1097 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1098 return err 1099 } 1100 } else { 1101 fs.Errorf(oldPath, "Dir.Rename can't rename open file that is not a vfs.File") 1102 return EPERM 1103 } 1104 case fs.Object: 1105 if oldFile, ok := oldNode.(*File); ok { 1106 if err = oldFile.rename(context.TODO(), destDir, newName); err != nil { 1107 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1108 return err 1109 } 1110 } else { 1111 err := fmt.Errorf("Fs %q can't rename file that is not a vfs.File", d.f) 1112 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1113 return err 1114 } 1115 case fs.Directory: 1116 features := d.f.Features() 1117 if features.DirMove == nil && features.Move == nil && features.Copy == nil { 1118 err := fmt.Errorf("Fs %q can't rename directories (no DirMove, Move or Copy)", d.f) 1119 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1120 return err 1121 } 1122 srcRemote := x.Remote() 1123 dstRemote := newPath 1124 err = operations.DirMove(context.TODO(), d.f, srcRemote, dstRemote) 1125 if err != nil { 1126 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 1127 return err 1128 } 1129 newDir := fs.NewDirCopy(context.TODO(), x).SetRemote(newPath) 1130 // Update the node with the new details 1131 if oldNode != nil { 1132 if oldDir, ok := oldNode.(*Dir); ok { 1133 fs.Debugf(x, "Updating dir with %v %p", newDir, oldDir) 1134 oldDir.rename(destDir, newDir) 1135 } 1136 } 1137 default: 1138 err = fmt.Errorf("unknown type %T", oldNode) 1139 fs.Errorf(d.path, "Dir.Rename error: %v", err) 1140 return err 1141 } 1142 1143 // Show moved - delete from old dir and add to new 1144 d.delObject(oldName) 1145 destDir.addObject(oldNode) 1146 if err = d.SetModTime(time.Now()); err != nil { 1147 fs.Errorf(d, "Dir.Rename failed to set modtime on parent dir: %v", err) 1148 return err 1149 } 1150 1151 // fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath) 1152 // fs.Debugf(d, "AFTER\n%s", d.dump()) 1153 return nil 1154 } 1155 1156 // Sync the directory 1157 // 1158 // Note that we don't do anything except return OK 1159 func (d *Dir) Sync() error { 1160 return nil 1161 } 1162 1163 // VFS returns the instance of the VFS 1164 func (d *Dir) VFS() *VFS { 1165 // No locking required 1166 return d.vfs 1167 } 1168 1169 // Fs returns the Fs that the Dir is on 1170 func (d *Dir) Fs() fs.Fs { 1171 // No locking required 1172 return d.f 1173 } 1174 1175 // Truncate changes the size of the named file. 1176 func (d *Dir) Truncate(size int64) error { 1177 return ENOSYS 1178 }