github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/vfs/dir.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "os" 6 "path" 7 "sort" 8 "strings" 9 "sync" 10 "time" 11 12 "github.com/ncw/rclone/fs" 13 "github.com/ncw/rclone/fs/dirtree" 14 "github.com/ncw/rclone/fs/list" 15 "github.com/ncw/rclone/fs/operations" 16 "github.com/ncw/rclone/fs/walk" 17 "github.com/pkg/errors" 18 ) 19 20 // Dir represents a directory entry 21 type Dir struct { 22 vfs *VFS 23 inode uint64 // inode number 24 f fs.Fs 25 parent *Dir // parent, nil for root 26 path string 27 modTime time.Time 28 entry fs.Directory 29 mu sync.Mutex // protects the following 30 read time.Time // time directory entry last read 31 items map[string]Node // directory entries - can be empty but not nil 32 } 33 34 func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir { 35 return &Dir{ 36 vfs: vfs, 37 f: f, 38 parent: parent, 39 entry: fsDir, 40 path: fsDir.Remote(), 41 modTime: fsDir.ModTime(context.TODO()), 42 inode: newInode(), 43 items: make(map[string]Node), 44 } 45 } 46 47 // String converts it to printablee 48 func (d *Dir) String() string { 49 if d == nil { 50 return "<nil *Dir>" 51 } 52 return d.path + "/" 53 } 54 55 // IsFile returns false for Dir - satisfies Node interface 56 func (d *Dir) IsFile() bool { 57 return false 58 } 59 60 // IsDir returns true for Dir - satisfies Node interface 61 func (d *Dir) IsDir() bool { 62 return true 63 } 64 65 // Mode bits of the directory - satisfies Node interface 66 func (d *Dir) Mode() (mode os.FileMode) { 67 return d.vfs.Opt.DirPerms 68 } 69 70 // Name (base) of the directory - satisfies Node interface 71 func (d *Dir) Name() (name string) { 72 name = path.Base(d.path) 73 if name == "." { 74 name = "/" 75 } 76 return name 77 } 78 79 // Path of the directory - satisfies Node interface 80 func (d *Dir) Path() (name string) { 81 return d.path 82 } 83 84 // Sys returns underlying data source (can be nil) - satisfies Node interface 85 func (d *Dir) Sys() interface{} { 86 return nil 87 } 88 89 // Inode returns the inode number - satisfies Node interface 90 func (d *Dir) Inode() uint64 { 91 return d.inode 92 } 93 94 // Node returns the Node assocuated with this - satisfies Noder interface 95 func (d *Dir) Node() Node { 96 return d 97 } 98 99 // ForgetAll ensures the directory and all its children are purged 100 // from the cache. 101 func (d *Dir) ForgetAll() { 102 d.ForgetPath("", fs.EntryDirectory) 103 } 104 105 // ForgetPath clears the cache for itself and all subdirectories if 106 // they match the given path. The path is specified relative from the 107 // directory it is called from. The cache of the parent directory is 108 // marked as stale, but not cleared otherwise. 109 // It is not possible to traverse the directory tree upwards, i.e. 110 // you cannot clear the cache for the Dir's ancestors or siblings. 111 func (d *Dir) ForgetPath(relativePath string, entryType fs.EntryType) { 112 if absPath := path.Join(d.path, relativePath); absPath != "" { 113 parent := path.Dir(absPath) 114 if parent == "." || parent == "/" { 115 parent = "" 116 } 117 parentNode := d.vfs.root.cachedNode(parent) 118 if dir, ok := parentNode.(*Dir); ok { 119 dir.mu.Lock() 120 if !dir.read.IsZero() { 121 fs.Debugf(dir.path, "invalidating directory cache") 122 dir.read = time.Time{} 123 } 124 dir.mu.Unlock() 125 } 126 } 127 128 if entryType == fs.EntryDirectory { 129 if dir := d.cachedDir(relativePath); dir != nil { 130 dir.walk(func(dir *Dir) { 131 fs.Debugf(dir.path, "forgetting directory cache") 132 dir.read = time.Time{} 133 dir.items = make(map[string]Node) 134 }) 135 } 136 } 137 } 138 139 // walk runs a function on all cached directories. It will be called 140 // on a directory's children first. 141 func (d *Dir) walk(fun func(*Dir)) { 142 d.mu.Lock() 143 defer d.mu.Unlock() 144 for _, node := range d.items { 145 if dir, ok := node.(*Dir); ok { 146 dir.walk(fun) 147 } 148 } 149 150 fun(d) 151 } 152 153 // stale returns true if the directory contents will be read the next 154 // time it is accessed. stale must be called with d.mu held. 155 func (d *Dir) stale(when time.Time) bool { 156 _, stale := d.age(when) 157 return stale 158 } 159 160 // age returns the duration since the last time the directory contents 161 // was read and the content is cosidered stale. age will be 0 and 162 // stale true if the last read time is empty. 163 // age must be called with d.mu held. 164 func (d *Dir) age(when time.Time) (age time.Duration, stale bool) { 165 if d.read.IsZero() { 166 return age, true 167 } 168 age = when.Sub(d.read) 169 stale = age > d.vfs.Opt.DirCacheTime 170 return 171 } 172 173 // rename should be called after the directory is renamed 174 // 175 // Reset the directory to new state, discarding all the objects and 176 // reading everything again 177 func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) { 178 d.ForgetAll() 179 d.parent = newParent 180 d.entry = fsDir 181 d.path = fsDir.Remote() 182 d.modTime = fsDir.ModTime(context.TODO()) 183 d.read = time.Time{} 184 } 185 186 // addObject adds a new object or directory to the directory 187 // 188 // note that we add new objects rather than updating old ones 189 func (d *Dir) addObject(node Node) { 190 d.mu.Lock() 191 d.items[node.Name()] = node 192 d.mu.Unlock() 193 } 194 195 // delObject removes an object from the directory 196 func (d *Dir) delObject(leaf string) { 197 d.mu.Lock() 198 delete(d.items, leaf) 199 d.mu.Unlock() 200 } 201 202 // read the directory and sets d.items - must be called with the lock held 203 func (d *Dir) _readDir() error { 204 when := time.Now() 205 if age, stale := d.age(when); stale { 206 if age != 0 { 207 fs.Debugf(d.path, "Re-reading directory (%v old)", age) 208 } 209 } else { 210 return nil 211 } 212 entries, err := list.DirSorted(context.TODO(), d.f, false, d.path) 213 if err == fs.ErrorDirNotFound { 214 // We treat directory not found as empty because we 215 // create directories on the fly 216 } else if err != nil { 217 return err 218 } 219 220 err = d._readDirFromEntries(entries, nil, time.Time{}) 221 if err != nil { 222 return err 223 } 224 225 d.read = when 226 return nil 227 } 228 229 // update d.items for each dir in the DirTree below this one and 230 // set the last read time - must be called with the lock held 231 func (d *Dir) _readDirFromDirTree(dirTree dirtree.DirTree, when time.Time) error { 232 return d._readDirFromEntries(dirTree[d.path], dirTree, when) 233 } 234 235 // update d.items and if dirTree is not nil update each dir in the DirTree below this one and 236 // set the last read time - must be called with the lock held 237 func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree, when time.Time) error { 238 var err error 239 // Cache the items by name 240 found := make(map[string]struct{}) 241 for _, entry := range entries { 242 name := path.Base(entry.Remote()) 243 if name == "." || name == ".." { 244 continue 245 } 246 node := d.items[name] 247 found[name] = struct{}{} 248 switch item := entry.(type) { 249 case fs.Object: 250 obj := item 251 // Reuse old file value if it exists 252 if file, ok := node.(*File); node != nil && ok { 253 file.setObjectNoUpdate(obj) 254 } else { 255 node = newFile(d, obj, name) 256 } 257 case fs.Directory: 258 // Reuse old dir value if it exists 259 if node == nil || !node.IsDir() { 260 node = newDir(d.vfs, d.f, d, item) 261 } 262 if dirTree != nil { 263 dir := node.(*Dir) 264 dir.mu.Lock() 265 err = dir._readDirFromDirTree(dirTree, when) 266 if err != nil { 267 dir.read = time.Time{} 268 } else { 269 dir.read = when 270 } 271 dir.mu.Unlock() 272 if err != nil { 273 return err 274 } 275 } 276 default: 277 err = errors.Errorf("unknown type %T", item) 278 fs.Errorf(d, "readDir error: %v", err) 279 return err 280 } 281 d.items[name] = node 282 } 283 // delete unused entries 284 for name := range d.items { 285 if _, ok := found[name]; !ok { 286 delete(d.items, name) 287 } 288 } 289 return nil 290 } 291 292 // readDirTree forces a refresh of the complete directory tree 293 func (d *Dir) readDirTree() error { 294 d.mu.Lock() 295 f, path := d.f, d.path 296 d.mu.Unlock() 297 when := time.Now() 298 fs.Debugf(path, "Reading directory tree") 299 dt, err := walk.NewDirTree(context.TODO(), f, path, false, -1) 300 if err != nil { 301 return err 302 } 303 d.mu.Lock() 304 defer d.mu.Unlock() 305 d.read = time.Time{} 306 err = d._readDirFromDirTree(dt, when) 307 if err != nil { 308 return err 309 } 310 fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when)) 311 d.read = when 312 return nil 313 } 314 315 // readDir forces a refresh of the directory 316 func (d *Dir) readDir() error { 317 d.mu.Lock() 318 defer d.mu.Unlock() 319 d.read = time.Time{} 320 return d._readDir() 321 } 322 323 // stat a single item in the directory 324 // 325 // returns ENOENT if not found. 326 func (d *Dir) stat(leaf string) (Node, error) { 327 d.mu.Lock() 328 defer d.mu.Unlock() 329 err := d._readDir() 330 if err != nil { 331 return nil, err 332 } 333 item, ok := d.items[leaf] 334 if !ok { 335 return nil, ENOENT 336 } 337 return item, nil 338 } 339 340 // Check to see if a directory is empty 341 func (d *Dir) isEmpty() (bool, error) { 342 d.mu.Lock() 343 defer d.mu.Unlock() 344 err := d._readDir() 345 if err != nil { 346 return false, err 347 } 348 return len(d.items) == 0, nil 349 } 350 351 // ModTime returns the modification time of the directory 352 func (d *Dir) ModTime() time.Time { 353 // fs.Debugf(d.path, "Dir.ModTime %v", d.modTime) 354 return d.modTime 355 } 356 357 // Size of the directory 358 func (d *Dir) Size() int64 { 359 return 0 360 } 361 362 // SetModTime sets the modTime for this dir 363 func (d *Dir) SetModTime(modTime time.Time) error { 364 if d.vfs.Opt.ReadOnly { 365 return EROFS 366 } 367 d.mu.Lock() 368 defer d.mu.Unlock() 369 d.modTime = modTime 370 return nil 371 } 372 373 func (d *Dir) cachedDir(relativePath string) (dir *Dir) { 374 dir, _ = d.cachedNode(relativePath).(*Dir) 375 return 376 } 377 378 func (d *Dir) cachedNode(relativePath string) Node { 379 segments := strings.Split(strings.Trim(relativePath, "/"), "/") 380 var node Node = d 381 for _, s := range segments { 382 if s == "" { 383 continue 384 } 385 if dir, ok := node.(*Dir); ok { 386 dir.mu.Lock() 387 node = dir.items[s] 388 dir.mu.Unlock() 389 390 if node != nil { 391 continue 392 } 393 } 394 return nil 395 } 396 397 return node 398 } 399 400 // Stat looks up a specific entry in the receiver. 401 // 402 // Stat should return a Node corresponding to the entry. If the 403 // name does not exist in the directory, Stat should return ENOENT. 404 // 405 // Stat need not to handle the names "." and "..". 406 func (d *Dir) Stat(name string) (node Node, err error) { 407 // fs.Debugf(path, "Dir.Stat") 408 node, err = d.stat(name) 409 if err != nil { 410 if err != ENOENT { 411 fs.Errorf(d, "Dir.Stat error: %v", err) 412 } 413 return nil, err 414 } 415 // fs.Debugf(path, "Dir.Stat OK") 416 return node, nil 417 } 418 419 // ReadDirAll reads the contents of the directory sorted 420 func (d *Dir) ReadDirAll() (items Nodes, err error) { 421 // fs.Debugf(d.path, "Dir.ReadDirAll") 422 d.mu.Lock() 423 defer d.mu.Unlock() 424 err = d._readDir() 425 if err != nil { 426 fs.Debugf(d.path, "Dir.ReadDirAll error: %v", err) 427 return nil, err 428 } 429 for _, item := range d.items { 430 items = append(items, item) 431 } 432 sort.Sort(items) 433 // fs.Debugf(d.path, "Dir.ReadDirAll OK with %d entries", len(items)) 434 return items, nil 435 } 436 437 // accessModeMask masks off the read modes from the flags 438 const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) 439 440 // Open the directory according to the flags provided 441 func (d *Dir) Open(flags int) (fd Handle, err error) { 442 rdwrMode := flags & accessModeMask 443 if rdwrMode != os.O_RDONLY { 444 fs.Errorf(d, "Can only open directories read only") 445 return nil, EPERM 446 } 447 return newDirHandle(d), nil 448 } 449 450 // Create makes a new file node 451 func (d *Dir) Create(name string, flags int) (*File, error) { 452 // fs.Debugf(path, "Dir.Create") 453 if d.vfs.Opt.ReadOnly { 454 return nil, EROFS 455 } 456 // This gets added to the directory when the file is opened for write 457 return newFile(d, nil, name), nil 458 } 459 460 // Mkdir creates a new directory 461 func (d *Dir) Mkdir(name string) (*Dir, error) { 462 if d.vfs.Opt.ReadOnly { 463 return nil, EROFS 464 } 465 path := path.Join(d.path, name) 466 node, err := d.stat(name) 467 switch err { 468 case ENOENT: 469 // not found, carry on 470 case nil: 471 // found so check what it is 472 if node.IsDir() { 473 return node.(*Dir), err 474 } 475 return nil, EEXIST 476 default: 477 // a different error - report 478 fs.Errorf(d, "Dir.Mkdir failed to read directory: %v", err) 479 return nil, err 480 } 481 // fs.Debugf(path, "Dir.Mkdir") 482 err = d.f.Mkdir(context.TODO(), path) 483 if err != nil { 484 fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err) 485 return nil, err 486 } 487 fsDir := fs.NewDir(path, time.Now()) 488 dir := newDir(d.vfs, d.f, d, fsDir) 489 d.addObject(dir) 490 // fs.Debugf(path, "Dir.Mkdir OK") 491 return dir, nil 492 } 493 494 // Remove the directory 495 func (d *Dir) Remove() error { 496 if d.vfs.Opt.ReadOnly { 497 return EROFS 498 } 499 // Check directory is empty first 500 empty, err := d.isEmpty() 501 if err != nil { 502 fs.Errorf(d, "Dir.Remove dir error: %v", err) 503 return err 504 } 505 if !empty { 506 fs.Errorf(d, "Dir.Remove not empty") 507 return ENOTEMPTY 508 } 509 // remove directory 510 err = d.f.Rmdir(context.TODO(), d.path) 511 if err != nil { 512 fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err) 513 return err 514 } 515 // Remove the item from the parent directory listing 516 if d.parent != nil { 517 d.parent.delObject(d.Name()) 518 } 519 return nil 520 } 521 522 // RemoveAll removes the directory and any contents recursively 523 func (d *Dir) RemoveAll() error { 524 if d.vfs.Opt.ReadOnly { 525 return EROFS 526 } 527 // Remove contents of the directory 528 nodes, err := d.ReadDirAll() 529 if err != nil { 530 fs.Errorf(d, "Dir.RemoveAll failed to read directory: %v", err) 531 return err 532 } 533 for _, node := range nodes { 534 err = node.RemoveAll() 535 if err != nil { 536 fs.Errorf(node.Path(), "Dir.RemoveAll failed to remove: %v", err) 537 return err 538 } 539 } 540 return d.Remove() 541 } 542 543 // DirEntry returns the underlying fs.DirEntry 544 func (d *Dir) DirEntry() (entry fs.DirEntry) { 545 return d.entry 546 } 547 548 // RemoveName removes the entry with the given name from the receiver, 549 // which must be a directory. The entry to be removed may correspond 550 // to a file (unlink) or to a directory (rmdir). 551 func (d *Dir) RemoveName(name string) error { 552 if d.vfs.Opt.ReadOnly { 553 return EROFS 554 } 555 // fs.Debugf(path, "Dir.Remove") 556 node, err := d.stat(name) 557 if err != nil { 558 fs.Errorf(d, "Dir.Remove error: %v", err) 559 return err 560 } 561 return node.Remove() 562 } 563 564 // Rename the file 565 func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { 566 if d.vfs.Opt.ReadOnly { 567 return EROFS 568 } 569 oldPath := path.Join(d.path, oldName) 570 newPath := path.Join(destDir.path, newName) 571 // fs.Debugf(oldPath, "Dir.Rename to %q", newPath) 572 oldNode, err := d.stat(oldName) 573 if err != nil { 574 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 575 return err 576 } 577 switch x := oldNode.DirEntry().(type) { 578 case nil: 579 if oldFile, ok := oldNode.(*File); ok { 580 if err = oldFile.rename(context.TODO(), destDir, newName); err != nil { 581 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 582 return err 583 } 584 } else { 585 fs.Errorf(oldPath, "Dir.Rename can't rename open file that is not a vfs.File") 586 return EPERM 587 } 588 case fs.Object: 589 if oldFile, ok := oldNode.(*File); ok { 590 if err = oldFile.rename(context.TODO(), destDir, newName); err != nil { 591 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 592 return err 593 } 594 } else { 595 err := errors.Errorf("Fs %q can't rename file that is not a vfs.File", d.f) 596 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 597 return err 598 } 599 case fs.Directory: 600 features := d.f.Features() 601 if features.DirMove == nil && features.Move == nil && features.Copy == nil { 602 err := errors.Errorf("Fs %q can't rename directories (no DirMove, Move or Copy)", d.f) 603 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 604 return err 605 } 606 srcRemote := x.Remote() 607 dstRemote := newPath 608 err = operations.DirMove(context.TODO(), d.f, srcRemote, dstRemote) 609 if err != nil { 610 fs.Errorf(oldPath, "Dir.Rename error: %v", err) 611 return err 612 } 613 newDir := fs.NewDirCopy(context.TODO(), x).SetRemote(newPath) 614 // Update the node with the new details 615 if oldNode != nil { 616 if oldDir, ok := oldNode.(*Dir); ok { 617 fs.Debugf(x, "Updating dir with %v %p", newDir, oldDir) 618 oldDir.rename(destDir, newDir) 619 } 620 } 621 default: 622 err = errors.Errorf("unknown type %T", oldNode) 623 fs.Errorf(d.path, "Dir.Rename error: %v", err) 624 return err 625 } 626 627 // Show moved - delete from old dir and add to new 628 d.delObject(oldName) 629 destDir.addObject(oldNode) 630 631 // fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath) 632 return nil 633 } 634 635 // Sync the directory 636 // 637 // Note that we don't do anything except return OK 638 func (d *Dir) Sync() error { 639 return nil 640 } 641 642 // VFS returns the instance of the VFS 643 func (d *Dir) VFS() *VFS { 644 return d.vfs 645 } 646 647 // Truncate changes the size of the named file. 648 func (d *Dir) Truncate(size int64) error { 649 return ENOSYS 650 }