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