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  }