github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/vfs/file.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "os" 6 "path" 7 "sync" 8 "sync/atomic" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/log" 14 "github.com/rclone/rclone/fs/operations" 15 ) 16 17 // File represents a file 18 type File struct { 19 inode uint64 // inode number - read only 20 size int64 // size of file - read and written with atomic int64 - must be 64 bit aligned 21 22 mu sync.RWMutex // protects the following 23 d *Dir // parent directory 24 o fs.Object // NB o may be nil if file is being written 25 leaf string // leaf name of the object 26 rwOpenCount int // number of open files on this handle 27 writers []Handle // writers for this file 28 nwriters int32 // len(writers) which is read/updated with atomic 29 readWriters int // how many RWFileHandle are open for writing 30 readWriterClosing bool // is a RWFileHandle currently cosing? 31 modified bool // has the cache file be modified by a RWFileHandle? 32 pendingModTime time.Time // will be applied once o becomes available, i.e. after file was written 33 pendingRenameFun func(ctx context.Context) error // will be run/renamed after all writers close 34 appendMode bool // file was opened with O_APPEND 35 36 muRW sync.Mutex // synchonize RWFileHandle.openPending(), RWFileHandle.close() and File.Remove 37 } 38 39 // newFile creates a new File 40 // 41 // o may be nil 42 func newFile(d *Dir, o fs.Object, leaf string) *File { 43 f := &File{ 44 d: d, 45 o: o, 46 leaf: leaf, 47 inode: newInode(), 48 } 49 if o != nil { 50 f.size = o.Size() 51 } 52 return f 53 } 54 55 // String converts it to printable 56 func (f *File) String() string { 57 if f == nil { 58 return "<nil *File>" 59 } 60 return f.Path() 61 } 62 63 // IsFile returns true for File - satisfies Node interface 64 func (f *File) IsFile() bool { 65 return true 66 } 67 68 // IsDir returns false for File - satisfies Node interface 69 func (f *File) IsDir() bool { 70 return false 71 } 72 73 // Mode bits of the file or directory - satisfies Node interface 74 func (f *File) Mode() (mode os.FileMode) { 75 f.mu.RLock() 76 defer f.mu.RUnlock() 77 mode = f.d.vfs.Opt.FilePerms 78 if f.appendMode { 79 mode |= os.ModeAppend 80 } 81 return mode 82 } 83 84 // Name (base) of the directory - satisfies Node interface 85 func (f *File) Name() (name string) { 86 f.mu.RLock() 87 defer f.mu.RUnlock() 88 return f.leaf 89 } 90 91 // _path returns the full path of the file 92 // use when lock is held 93 func (f *File) _path() string { 94 return path.Join(f.d.path, f.leaf) 95 } 96 97 // Path returns the full path of the file 98 func (f *File) Path() string { 99 f.mu.RLock() 100 defer f.mu.RUnlock() 101 return f._path() 102 } 103 104 // osPath returns the full path of the file in the cache in OS format 105 func (f *File) osPath() string { 106 return f.d.vfs.cache.toOSPath(f.Path()) 107 } 108 109 // Sys returns underlying data source (can be nil) - satisfies Node interface 110 func (f *File) Sys() interface{} { 111 return nil 112 } 113 114 // Inode returns the inode number - satisfies Node interface 115 func (f *File) Inode() uint64 { 116 return f.inode 117 } 118 119 // Node returns the Node assocuated with this - satisfies Noder interface 120 func (f *File) Node() Node { 121 return f 122 } 123 124 // applyPendingRename runs a previously set rename operation if there are no 125 // more remaining writers. Call without lock held. 126 func (f *File) applyPendingRename() { 127 f.mu.RLock() 128 fun := f.pendingRenameFun 129 writing := f._writingInProgress() 130 f.mu.RUnlock() 131 if fun == nil || writing { 132 return 133 } 134 fs.Debugf(f.o, "Running delayed rename now") 135 if err := fun(context.TODO()); err != nil { 136 fs.Errorf(f.Path(), "delayed File.Rename error: %v", err) 137 } 138 } 139 140 // rename attempts to immediately rename a file if there are no open writers. 141 // Otherwise it will queue the rename operation on the remote until no writers 142 // remain. 143 func (f *File) rename(ctx context.Context, destDir *Dir, newName string) error { 144 f.mu.RLock() 145 d := f.d 146 o := f.o 147 oldPendingRenameFun := f.pendingRenameFun 148 f.mu.RUnlock() 149 150 if features := d.f.Features(); features.Move == nil && features.Copy == nil { 151 err := errors.Errorf("Fs %q can't rename files (no server side Move or Copy)", d.f) 152 fs.Errorf(f.Path(), "Dir.Rename error: %v", err) 153 return err 154 } 155 156 newPath := path.Join(destDir.path, newName) 157 158 renameCall := func(ctx context.Context) error { 159 // chain rename calls if any 160 if oldPendingRenameFun != nil { 161 err := oldPendingRenameFun(ctx) 162 if err != nil { 163 return err 164 } 165 } 166 167 f.mu.RLock() 168 o := f.o 169 f.mu.RUnlock() 170 if o == nil { 171 return errors.New("Cannot rename: file object is not available") 172 } 173 if o.Remote() == newPath { 174 return nil // no need to rename 175 } 176 177 // do the move of the remote object 178 dstOverwritten, _ := d.f.NewObject(ctx, newPath) 179 newObject, err := operations.Move(ctx, d.f, dstOverwritten, newPath, o) 180 if err != nil { 181 fs.Errorf(f.Path(), "File.Rename error: %v", err) 182 return err 183 } 184 185 // newObject can be nil here for example if --dry-run 186 if newObject == nil { 187 err = errors.New("rename failed: nil object returned") 188 fs.Errorf(f.Path(), "File.Rename %v", err) 189 return err 190 } 191 // Update the node with the new details 192 fs.Debugf(o, "Updating file with %v %p", newObject, f) 193 // f.rename(destDir, newObject) 194 f.mu.Lock() 195 f.o = newObject 196 f.pendingRenameFun = nil 197 f.mu.Unlock() 198 return nil 199 } 200 201 // Rename in the cache if it exists 202 if f.d.vfs.Opt.CacheMode != CacheModeOff && f.d.vfs.cache.exists(f.Path()) { 203 if err := f.d.vfs.cache.rename(f.Path(), newPath); err != nil { 204 fs.Infof(f.Path(), "File.Rename failed in Cache: %v", err) 205 } 206 } 207 208 // rename the file object 209 f.mu.Lock() 210 f.d = destDir 211 f.leaf = newName 212 writing := f._writingInProgress() 213 f.mu.Unlock() 214 215 if writing { 216 fs.Debugf(o, "File is currently open, delaying rename %p", f) 217 f.mu.Lock() 218 f.pendingRenameFun = renameCall 219 f.mu.Unlock() 220 return nil 221 } 222 223 return renameCall(ctx) 224 } 225 226 // addWriter adds a write handle to the file 227 func (f *File) addWriter(h Handle) { 228 f.mu.Lock() 229 f.writers = append(f.writers, h) 230 atomic.AddInt32(&f.nwriters, 1) 231 if _, ok := h.(*RWFileHandle); ok { 232 f.readWriters++ 233 } 234 f.mu.Unlock() 235 } 236 237 // delWriter removes a write handle from the file 238 func (f *File) delWriter(h Handle, modifiedCacheFile bool) (lastWriterAndModified bool) { 239 f.mu.Lock() 240 defer f.applyPendingRename() 241 defer f.mu.Unlock() 242 var found = -1 243 for i := range f.writers { 244 if f.writers[i] == h { 245 found = i 246 break 247 } 248 } 249 if found >= 0 { 250 f.writers = append(f.writers[:found], f.writers[found+1:]...) 251 atomic.AddInt32(&f.nwriters, -1) 252 } else { 253 fs.Debugf(f.o, "File.delWriter couldn't find handle") 254 } 255 if _, ok := h.(*RWFileHandle); ok { 256 f.readWriters-- 257 } 258 f.readWriterClosing = true 259 if modifiedCacheFile { 260 f.modified = true 261 } 262 lastWriterAndModified = len(f.writers) == 0 && f.modified 263 if lastWriterAndModified { 264 f.modified = false 265 } 266 return 267 } 268 269 // addRWOpen should be called by ReadWriteHandle when they have 270 // actually opened the file for read or write. 271 func (f *File) addRWOpen() { 272 f.mu.Lock() 273 f.rwOpenCount++ 274 f.mu.Unlock() 275 } 276 277 // delRWOpen should be called by ReadWriteHandle when they have closed 278 // an actually opene file for read or write. 279 func (f *File) delRWOpen() { 280 f.mu.Lock() 281 f.rwOpenCount-- 282 f.mu.Unlock() 283 } 284 285 // rwOpens returns how many active open ReadWriteHandles there are. 286 // Note that file handles which are in pending open state aren't 287 // counted. 288 func (f *File) rwOpens() int { 289 f.mu.RLock() 290 defer f.mu.RUnlock() 291 return f.rwOpenCount 292 } 293 294 // finishWriterClose resets the readWriterClosing flag 295 func (f *File) finishWriterClose() { 296 f.mu.Lock() 297 f.readWriterClosing = false 298 f.mu.Unlock() 299 f.applyPendingRename() 300 } 301 302 // activeWriters returns the number of writers on the file 303 // 304 // Note that we don't take the mutex here. If we do then we can get a 305 // deadlock. 306 func (f *File) activeWriters() int { 307 return int(atomic.LoadInt32(&f.nwriters)) 308 } 309 310 // ModTime returns the modified time of the file 311 // 312 // if NoModTime is set then it returns the mod time of the directory 313 func (f *File) ModTime() (modTime time.Time) { 314 f.mu.RLock() 315 defer f.mu.RUnlock() 316 317 if f.d.vfs.Opt.NoModTime { 318 return f.d.modTime 319 } 320 if !f.pendingModTime.IsZero() { 321 return f.pendingModTime 322 } 323 if f.o == nil { 324 return f.d.modTime 325 } 326 return f.o.ModTime(context.TODO()) 327 } 328 329 // nonNegative returns 0 if i is -ve, i otherwise 330 func nonNegative(i int64) int64 { 331 if i >= 0 { 332 return i 333 } 334 return 0 335 } 336 337 // Size of the file 338 func (f *File) Size() int64 { 339 f.mu.RLock() 340 defer f.mu.RUnlock() 341 342 // if o is nil it isn't valid yet or there are writers, so return the size so far 343 if f._writingInProgress() { 344 return atomic.LoadInt64(&f.size) 345 } 346 return nonNegative(f.o.Size()) 347 } 348 349 // SetModTime sets the modtime for the file 350 func (f *File) SetModTime(modTime time.Time) error { 351 if f.d.vfs.Opt.ReadOnly { 352 return EROFS 353 } 354 f.mu.Lock() 355 defer f.mu.Unlock() 356 357 f.pendingModTime = modTime 358 359 // Only update the ModTime when there are no writers, setObject will do it 360 if !f._writingInProgress() { 361 return f._applyPendingModTime() 362 } 363 364 // queue up for later, hoping f.o becomes available 365 return nil 366 } 367 368 // Apply a pending mod time 369 // Call with the write mutex held 370 func (f *File) _applyPendingModTime() error { 371 if f.pendingModTime.IsZero() { 372 return nil 373 } 374 375 defer func() { f.pendingModTime = time.Time{} }() 376 377 if f.o == nil { 378 return errors.New("Cannot apply ModTime, file object is not available") 379 } 380 381 // set the time of the file in the cache 382 if f.d.vfs.Opt.CacheMode != CacheModeOff { 383 f.d.vfs.cache.setModTime(f._path(), f.pendingModTime) 384 } 385 386 // set the time of the object 387 err := f.o.SetModTime(context.TODO(), f.pendingModTime) 388 switch err { 389 case nil: 390 fs.Debugf(f.o, "File._applyPendingModTime OK") 391 case fs.ErrorCantSetModTime, fs.ErrorCantSetModTimeWithoutDelete: 392 // do nothing, in order to not break "touch somefile" if it exists already 393 default: 394 fs.Errorf(f, "File._applyPendingModTime error: %v", err) 395 return err 396 } 397 398 return nil 399 } 400 401 // _writingInProgress returns true of there are any open writers 402 // Call with read lock held 403 func (f *File) _writingInProgress() bool { 404 return f.o == nil || len(f.writers) != 0 || f.readWriterClosing 405 } 406 407 // Update the size while writing 408 func (f *File) setSize(n int64) { 409 atomic.StoreInt64(&f.size, n) 410 } 411 412 // Update the object when written and add it to the directory 413 func (f *File) setObject(o fs.Object) { 414 f.mu.Lock() 415 f.o = o 416 _ = f._applyPendingModTime() 417 f.mu.Unlock() 418 419 f.d.addObject(f) 420 } 421 422 // Update the object but don't update the directory cache - for use by 423 // the directory cache 424 func (f *File) setObjectNoUpdate(o fs.Object) { 425 f.mu.Lock() 426 f.o = o 427 f.mu.Unlock() 428 } 429 430 // Get the current fs.Object - may be nil 431 func (f *File) getObject() fs.Object { 432 f.mu.RLock() 433 defer f.mu.RUnlock() 434 return f.o 435 } 436 437 // exists returns whether the file exists already 438 func (f *File) exists() bool { 439 f.mu.RLock() 440 defer f.mu.RUnlock() 441 return f.o != nil 442 } 443 444 // Wait for f.o to become non nil for a short time returning it or an 445 // error. Use when opening a read handle. 446 // 447 // Call without the mutex held 448 func (f *File) waitForValidObject() (o fs.Object, err error) { 449 for i := 0; i < 50; i++ { 450 f.mu.RLock() 451 o = f.o 452 nwriters := len(f.writers) 453 wclosing := f.readWriterClosing 454 f.mu.RUnlock() 455 if o != nil { 456 return o, nil 457 } 458 if nwriters == 0 && !wclosing { 459 return nil, errors.New("can't open file - writer failed") 460 } 461 time.Sleep(100 * time.Millisecond) 462 } 463 return nil, ENOENT 464 } 465 466 // openRead open the file for read 467 func (f *File) openRead() (fh *ReadFileHandle, err error) { 468 // if o is nil it isn't valid yet 469 _, err = f.waitForValidObject() 470 if err != nil { 471 return nil, err 472 } 473 // fs.Debugf(o, "File.openRead") 474 475 fh, err = newReadFileHandle(f) 476 if err != nil { 477 fs.Errorf(f, "File.openRead failed: %v", err) 478 return nil, err 479 } 480 return fh, nil 481 } 482 483 // openWrite open the file for write 484 func (f *File) openWrite(flags int) (fh *WriteFileHandle, err error) { 485 f.mu.RLock() 486 d := f.d 487 f.mu.RUnlock() 488 489 if d.vfs.Opt.ReadOnly { 490 return nil, EROFS 491 } 492 // fs.Debugf(o, "File.openWrite") 493 494 fh, err = newWriteFileHandle(d, f, f.Path(), flags) 495 if err != nil { 496 fs.Errorf(f, "File.openWrite failed: %v", err) 497 return nil, err 498 } 499 return fh, nil 500 } 501 502 // openRW open the file for read and write using a temporay file 503 // 504 // It uses the open flags passed in. 505 func (f *File) openRW(flags int) (fh *RWFileHandle, err error) { 506 f.mu.RLock() 507 d := f.d 508 f.mu.RUnlock() 509 510 // FIXME chunked 511 if flags&accessModeMask != os.O_RDONLY && d.vfs.Opt.ReadOnly { 512 return nil, EROFS 513 } 514 // fs.Debugf(o, "File.openRW") 515 516 fh, err = newRWFileHandle(d, f, flags) 517 if err != nil { 518 fs.Errorf(f, "File.openRW failed: %v", err) 519 return nil, err 520 } 521 return fh, nil 522 } 523 524 // Sync the file 525 // 526 // Note that we don't do anything except return OK 527 func (f *File) Sync() error { 528 return nil 529 } 530 531 // Remove the file 532 func (f *File) Remove() error { 533 f.mu.RLock() 534 d := f.d 535 f.mu.RUnlock() 536 537 if d.vfs.Opt.ReadOnly { 538 return EROFS 539 } 540 f.muRW.Lock() // muRW must be locked before mu to avoid 541 f.mu.Lock() // deadlock in RWFileHandle.openPending and .close 542 if f.o != nil { 543 err := f.o.Remove(context.TODO()) 544 if err != nil { 545 fs.Errorf(f, "File.Remove file error: %v", err) 546 f.mu.Unlock() 547 f.muRW.Unlock() 548 return err 549 } 550 } 551 f.mu.Unlock() 552 f.muRW.Unlock() 553 554 // Remove the item from the directory listing 555 d.delObject(f.Name()) 556 // Remove the object from the cache 557 if d.vfs.Opt.CacheMode >= CacheModeMinimal { 558 d.vfs.cache.remove(f.Path()) 559 } 560 return nil 561 } 562 563 // RemoveAll the file - same as remove for files 564 func (f *File) RemoveAll() error { 565 return f.Remove() 566 } 567 568 // DirEntry returns the underlying fs.DirEntry - may be nil 569 func (f *File) DirEntry() (entry fs.DirEntry) { 570 f.mu.RLock() 571 defer f.mu.RUnlock() 572 return f.o 573 } 574 575 // Dir returns the directory this file is in 576 func (f *File) Dir() *Dir { 577 f.mu.RLock() 578 defer f.mu.RUnlock() 579 return f.d 580 } 581 582 // VFS returns the instance of the VFS 583 func (f *File) VFS() *VFS { 584 f.mu.RLock() 585 defer f.mu.RUnlock() 586 return f.d.vfs 587 } 588 589 // Open a file according to the flags provided 590 // 591 // O_RDONLY open the file read-only. 592 // O_WRONLY open the file write-only. 593 // O_RDWR open the file read-write. 594 // 595 // O_APPEND append data to the file when writing. 596 // O_CREATE create a new file if none exists. 597 // O_EXCL used with O_CREATE, file must not exist 598 // O_SYNC open for synchronous I/O. 599 // O_TRUNC if possible, truncate file when opene 600 // 601 // We ignore O_SYNC and O_EXCL 602 func (f *File) Open(flags int) (fd Handle, err error) { 603 defer log.Trace(f, "flags=%s", decodeOpenFlags(flags))("fd=%v, err=%v", &fd, &err) 604 var ( 605 write bool // if set need write support 606 read bool // if set need read support 607 rdwrMode = flags & accessModeMask 608 ) 609 610 // http://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html 611 // The result of using O_TRUNC with O_RDONLY is undefined. 612 // Linux seems to truncate the file, but we prefer to return EINVAL 613 if rdwrMode == os.O_RDONLY && flags&os.O_TRUNC != 0 { 614 return nil, EINVAL 615 } 616 617 // Figure out the read/write intents 618 switch { 619 case rdwrMode == os.O_RDONLY: 620 read = true 621 case rdwrMode == os.O_WRONLY: 622 write = true 623 case rdwrMode == os.O_RDWR: 624 read = true 625 write = true 626 default: 627 fs.Errorf(f, "Can't figure out how to open with flags: 0x%X", flags) 628 return nil, EPERM 629 } 630 631 // If append is set then set read to force openRW 632 if flags&os.O_APPEND != 0 { 633 read = true 634 f.mu.Lock() 635 f.appendMode = true 636 f.mu.Unlock() 637 } 638 639 // If truncate is set then set write to force openRW 640 if flags&os.O_TRUNC != 0 { 641 write = true 642 } 643 644 // Open the correct sort of handle 645 f.mu.RLock() 646 d := f.d 647 f.mu.RUnlock() 648 CacheMode := d.vfs.Opt.CacheMode 649 if CacheMode >= CacheModeMinimal && (d.vfs.cache.opens(f.Path()) > 0 || d.vfs.cache.exists(f.Path())) { 650 fd, err = f.openRW(flags) 651 } else if read && write { 652 if CacheMode >= CacheModeMinimal { 653 fd, err = f.openRW(flags) 654 } else { 655 // Open write only and hope the user doesn't 656 // want to read. If they do they will get an 657 // EPERM plus an Error log. 658 fd, err = f.openWrite(flags) 659 } 660 } else if write { 661 if CacheMode >= CacheModeWrites { 662 fd, err = f.openRW(flags) 663 } else { 664 fd, err = f.openWrite(flags) 665 } 666 } else if read { 667 if CacheMode >= CacheModeFull { 668 fd, err = f.openRW(flags) 669 } else { 670 fd, err = f.openRead() 671 } 672 } else { 673 fs.Errorf(f, "Can't figure out how to open with flags: 0x%X", flags) 674 return nil, EPERM 675 } 676 // if creating a file, add the file to the directory 677 if err == nil && flags&os.O_CREATE != 0 { 678 d.addObject(f) 679 } 680 return fd, err 681 } 682 683 // Truncate changes the size of the named file. 684 func (f *File) Truncate(size int64) (err error) { 685 // make a copy of fh.writers with the lock held then unlock so 686 // we can call other file methods. 687 f.mu.Lock() 688 writers := make([]Handle, len(f.writers)) 689 copy(writers, f.writers) 690 o := f.o 691 f.mu.Unlock() 692 693 // FIXME: handle closing writer 694 695 // If have writers then call truncate for each writer 696 if len(writers) != 0 { 697 fs.Debugf(f, "Truncating %d file handles", len(writers)) 698 for _, h := range writers { 699 truncateErr := h.Truncate(size) 700 if truncateErr != nil { 701 err = truncateErr 702 } 703 } 704 return err 705 } 706 707 // If no writers, and size is already correct then all done 708 if o.Size() == size { 709 return nil 710 } 711 712 fs.Debugf(f, "Truncating file") 713 714 // Otherwise if no writers then truncate the file by opening 715 // the file and truncating it. 716 flags := os.O_WRONLY 717 if size == 0 { 718 flags |= os.O_TRUNC 719 } 720 fh, err := f.Open(flags) 721 if err != nil { 722 return err 723 } 724 defer fs.CheckClose(fh, &err) 725 if size != 0 { 726 return fh.Truncate(size) 727 } 728 return nil 729 }