github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/vfs/file.go (about)

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