github.com/artpar/rclone@v1.67.3/fs/features.go (about)

     1  // Filesystem features and optional interfaces
     2  
     3  package fs
     4  
     5  import (
     6  	"context"
     7  	"io"
     8  	"reflect"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  // Features describe the optional features of the Fs
    14  type Features struct {
    15  	// Feature flags, whether Fs
    16  	CaseInsensitive          bool // has case insensitive files
    17  	DuplicateFiles           bool // allows duplicate files
    18  	ReadMimeType             bool // can read the mime type of objects
    19  	WriteMimeType            bool // can set the mime type of objects
    20  	CanHaveEmptyDirectories  bool // can have empty directories
    21  	BucketBased              bool // is bucket based (like s3, swift, etc.)
    22  	BucketBasedRootOK        bool // is bucket based and can use from root
    23  	SetTier                  bool // allows set tier functionality on objects
    24  	GetTier                  bool // allows to retrieve storage tier of objects
    25  	ServerSideAcrossConfigs  bool // can server-side copy between different remotes of the same type
    26  	IsLocal                  bool // is the local backend
    27  	SlowModTime              bool // if calling ModTime() generally takes an extra transaction
    28  	SlowHash                 bool // if calling Hash() generally takes an extra transaction
    29  	ReadMetadata             bool // can read metadata from objects
    30  	WriteMetadata            bool // can write metadata to objects
    31  	UserMetadata             bool // can read/write general purpose metadata
    32  	ReadDirMetadata          bool // can read metadata from directories (implements Directory.Metadata)
    33  	WriteDirMetadata         bool // can write metadata to directories (implements Directory.SetMetadata)
    34  	WriteDirSetModTime       bool // can write metadata to directories (implements Directory.SetModTime)
    35  	UserDirMetadata          bool // can read/write general purpose metadata to/from directories
    36  	DirModTimeUpdatesOnWrite bool // indicate writing files to a directory updates its modtime
    37  	FilterAware              bool // can make use of filters if provided for listing
    38  	PartialUploads           bool // uploaded file can appear incomplete on the fs while it's being uploaded
    39  	NoMultiThreading         bool // set if can't have multiplethreads on one download open
    40  	Overlay                  bool // this wraps one or more backends to add functionality
    41  	ChunkWriterDoesntSeek    bool // set if the chunk writer doesn't need to read the data more than once
    42  
    43  	// Purge all files in the directory specified
    44  	//
    45  	// Implement this if you have a way of deleting all the files
    46  	// quicker than just running Remove() on the result of List()
    47  	//
    48  	// Return an error if it doesn't exist
    49  	Purge func(ctx context.Context, dir string) error
    50  
    51  	// Copy src to this remote using server-side copy operations.
    52  	//
    53  	// This is stored with the remote path given
    54  	//
    55  	// It returns the destination Object and a possible error
    56  	//
    57  	// Will only be called if src.Fs().Name() == f.Name()
    58  	//
    59  	// If it isn't possible then return fs.ErrorCantCopy
    60  	Copy func(ctx context.Context, src Object, remote string) (Object, error)
    61  
    62  	// Move src to this remote using server-side move operations.
    63  	//
    64  	// This is stored with the remote path given
    65  	//
    66  	// It returns the destination Object and a possible error
    67  	//
    68  	// Will only be called if src.Fs().Name() == f.Name()
    69  	//
    70  	// If it isn't possible then return fs.ErrorCantMove
    71  	Move func(ctx context.Context, src Object, remote string) (Object, error)
    72  
    73  	// DirMove moves src, srcRemote to this remote at dstRemote
    74  	// using server-side move operations.
    75  	//
    76  	// Will only be called if src.Fs().Name() == f.Name()
    77  	//
    78  	// If it isn't possible then return fs.ErrorCantDirMove
    79  	//
    80  	// If destination exists then return fs.ErrorDirExists
    81  	DirMove func(ctx context.Context, src Fs, srcRemote, dstRemote string) error
    82  
    83  	// MkdirMetadata makes the directory passed in as dir.
    84  	//
    85  	// It shouldn't return an error if it already exists.
    86  	//
    87  	// If the metadata is not nil it is set.
    88  	//
    89  	// It returns the directory that was created.
    90  	MkdirMetadata func(ctx context.Context, dir string, metadata Metadata) (Directory, error)
    91  
    92  	// ChangeNotify calls the passed function with a path
    93  	// that has had changes. If the implementation
    94  	// uses polling, it should adhere to the given interval.
    95  	ChangeNotify func(context.Context, func(string, EntryType), <-chan time.Duration)
    96  
    97  	// UnWrap returns the Fs that this Fs is wrapping
    98  	UnWrap func() Fs
    99  
   100  	// WrapFs returns the Fs that is wrapping this Fs
   101  	WrapFs func() Fs
   102  
   103  	// SetWrapper sets the Fs that is wrapping this Fs
   104  	SetWrapper func(f Fs)
   105  
   106  	// DirCacheFlush resets the directory cache - used in testing
   107  	// as an optional interface
   108  	DirCacheFlush func()
   109  
   110  	// PublicLink generates a public link to the remote path (usually readable by anyone)
   111  	PublicLink func(ctx context.Context, remote string, expire Duration, unlink bool) (string, error)
   112  
   113  	// Put in to the remote path with the modTime given of the given size
   114  	//
   115  	// May create the object even if it returns an error - if so
   116  	// will return the object and the error, otherwise will return
   117  	// nil and the error
   118  	//
   119  	// May create duplicates or return errors if src already
   120  	// exists.
   121  	PutUnchecked func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   122  
   123  	// PutStream uploads to the remote path with the modTime given of indeterminate size
   124  	//
   125  	// May create the object even if it returns an error - if so
   126  	// will return the object and the error, otherwise will return
   127  	// nil and the error
   128  	PutStream func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   129  
   130  	// MergeDirs merges the contents of all the directories passed
   131  	// in into the first one and rmdirs the other directories.
   132  	MergeDirs func(ctx context.Context, dirs []Directory) error
   133  
   134  	// DirSetModTime sets the metadata on the directory to set the modification date
   135  	DirSetModTime func(ctx context.Context, dir string, modTime time.Time) error
   136  
   137  	// CleanUp the trash in the Fs
   138  	//
   139  	// Implement this if you have a way of emptying the trash or
   140  	// otherwise cleaning up old versions of files.
   141  	CleanUp func(ctx context.Context) error
   142  
   143  	// ListR lists the objects and directories of the Fs starting
   144  	// from dir recursively into out.
   145  	//
   146  	// dir should be "" to start from the root, and should not
   147  	// have trailing slashes.
   148  	//
   149  	// This should return ErrDirNotFound if the directory isn't
   150  	// found.
   151  	//
   152  	// It should call callback for each tranche of entries read.
   153  	// These need not be returned in any particular order.  If
   154  	// callback returns an error then the listing will stop
   155  	// immediately.
   156  	//
   157  	// Don't implement this unless you have a more efficient way
   158  	// of listing recursively that doing a directory traversal.
   159  	ListR ListRFn
   160  
   161  	// About gets quota information from the Fs
   162  	About func(ctx context.Context) (*Usage, error)
   163  
   164  	// OpenWriterAt opens with a handle for random access writes
   165  	//
   166  	// Pass in the remote desired and the size if known.
   167  	//
   168  	// It truncates any existing object
   169  	OpenWriterAt func(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
   170  
   171  	// OpenChunkWriter returns the chunk size and a ChunkWriter
   172  	//
   173  	// Pass in the remote and the src object
   174  	// You can also use options to hint at the desired chunk size
   175  	//
   176  	OpenChunkWriter func(ctx context.Context, remote string, src ObjectInfo, options ...OpenOption) (info ChunkWriterInfo, writer ChunkWriter, err error)
   177  
   178  	// UserInfo returns info about the connected user
   179  	UserInfo func(ctx context.Context) (map[string]string, error)
   180  
   181  	// Disconnect the current user
   182  	Disconnect func(ctx context.Context) error
   183  
   184  	// Command the backend to run a named command
   185  	//
   186  	// The command run is name
   187  	// args may be used to read arguments from
   188  	// opts may be used to read optional arguments from
   189  	//
   190  	// The result should be capable of being JSON encoded
   191  	// If it is a string or a []string it will be shown to the user
   192  	// otherwise it will be JSON encoded and shown to the user like that
   193  	Command func(ctx context.Context, name string, arg []string, opt map[string]string) (interface{}, error)
   194  
   195  	// Shutdown the backend, closing any background tasks and any
   196  	// cached connections.
   197  	Shutdown func(ctx context.Context) error
   198  }
   199  
   200  // Disable nil's out the named feature.  If it isn't found then it
   201  // will log a message.
   202  func (ft *Features) Disable(name string) *Features {
   203  	// Prefix boolean values with ! to set the feature
   204  	invert := false
   205  	if strings.HasPrefix(name, "!") {
   206  		name = name[1:]
   207  		invert = true
   208  	}
   209  	v := reflect.ValueOf(ft).Elem()
   210  	vType := v.Type()
   211  	for i := 0; i < v.NumField(); i++ {
   212  		vName := vType.Field(i).Name
   213  		field := v.Field(i)
   214  		if strings.EqualFold(name, vName) {
   215  			if !field.CanSet() {
   216  				Errorf(nil, "Can't set Feature %q", name)
   217  			} else {
   218  				if invert {
   219  					if field.Type().Kind() == reflect.Bool {
   220  						field.Set(reflect.ValueOf(true))
   221  						Debugf(nil, "Set feature %q", name)
   222  					} else {
   223  						Errorf(nil, "Can't set Feature %q to true", name)
   224  					}
   225  				} else {
   226  					zero := reflect.Zero(field.Type())
   227  					field.Set(zero)
   228  					Debugf(nil, "Reset feature %q", name)
   229  				}
   230  			}
   231  		}
   232  	}
   233  	return ft
   234  }
   235  
   236  // List returns a slice of all the possible feature names
   237  func (ft *Features) List() (out []string) {
   238  	v := reflect.ValueOf(ft).Elem()
   239  	vType := v.Type()
   240  	for i := 0; i < v.NumField(); i++ {
   241  		out = append(out, vType.Field(i).Name)
   242  	}
   243  	return out
   244  }
   245  
   246  // Enabled returns a map of features with keys showing whether they
   247  // are enabled or not
   248  func (ft *Features) Enabled() (features map[string]bool) {
   249  	v := reflect.ValueOf(ft).Elem()
   250  	vType := v.Type()
   251  	features = make(map[string]bool, v.NumField())
   252  	for i := 0; i < v.NumField(); i++ {
   253  		vName := vType.Field(i).Name
   254  		field := v.Field(i)
   255  		if field.Kind() == reflect.Func {
   256  			// Can't compare functions
   257  			features[vName] = !field.IsNil()
   258  		} else {
   259  			zero := reflect.Zero(field.Type())
   260  			features[vName] = field.Interface() != zero.Interface()
   261  		}
   262  	}
   263  	return features
   264  }
   265  
   266  // DisableList nil's out the comma separated list of named features.
   267  // If it isn't found then it will log a message.
   268  func (ft *Features) DisableList(list []string) *Features {
   269  	for _, feature := range list {
   270  		ft.Disable(strings.TrimSpace(feature))
   271  	}
   272  	return ft
   273  }
   274  
   275  // Fill fills in the function pointers in the Features struct from the
   276  // optional interfaces.  It returns the original updated Features
   277  // struct passed in.
   278  func (ft *Features) Fill(ctx context.Context, f Fs) *Features {
   279  	if do, ok := f.(Purger); ok {
   280  		ft.Purge = do.Purge
   281  	}
   282  	if do, ok := f.(Copier); ok {
   283  		ft.Copy = do.Copy
   284  	}
   285  	if do, ok := f.(Mover); ok {
   286  		ft.Move = do.Move
   287  	}
   288  	if do, ok := f.(DirMover); ok {
   289  		ft.DirMove = do.DirMove
   290  	}
   291  	if do, ok := f.(MkdirMetadataer); ok {
   292  		ft.MkdirMetadata = do.MkdirMetadata
   293  	}
   294  	if do, ok := f.(ChangeNotifier); ok {
   295  		ft.ChangeNotify = do.ChangeNotify
   296  	}
   297  	if do, ok := f.(UnWrapper); ok {
   298  		ft.UnWrap = do.UnWrap
   299  	}
   300  	if do, ok := f.(Wrapper); ok {
   301  		ft.WrapFs = do.WrapFs
   302  		ft.SetWrapper = do.SetWrapper
   303  		ft.Overlay = true // if implement UnWrap then must be an Overlay
   304  	}
   305  	if do, ok := f.(DirCacheFlusher); ok {
   306  		ft.DirCacheFlush = do.DirCacheFlush
   307  	}
   308  	if do, ok := f.(PublicLinker); ok {
   309  		ft.PublicLink = do.PublicLink
   310  	}
   311  	if do, ok := f.(PutUncheckeder); ok {
   312  		ft.PutUnchecked = do.PutUnchecked
   313  	}
   314  	if do, ok := f.(PutStreamer); ok {
   315  		ft.PutStream = do.PutStream
   316  	}
   317  	if do, ok := f.(MergeDirser); ok {
   318  		ft.MergeDirs = do.MergeDirs
   319  	}
   320  	if do, ok := f.(DirSetModTimer); ok {
   321  		ft.DirSetModTime = do.DirSetModTime
   322  	}
   323  	if do, ok := f.(CleanUpper); ok {
   324  		ft.CleanUp = do.CleanUp
   325  	}
   326  	if do, ok := f.(ListRer); ok {
   327  		ft.ListR = do.ListR
   328  	}
   329  	if do, ok := f.(Abouter); ok {
   330  		ft.About = do.About
   331  	}
   332  	if do, ok := f.(OpenWriterAter); ok {
   333  		ft.OpenWriterAt = do.OpenWriterAt
   334  	}
   335  	if do, ok := f.(OpenChunkWriter); ok {
   336  		ft.OpenChunkWriter = do.OpenChunkWriter
   337  	}
   338  	if do, ok := f.(UserInfoer); ok {
   339  		ft.UserInfo = do.UserInfo
   340  	}
   341  	if do, ok := f.(Disconnecter); ok {
   342  		ft.Disconnect = do.Disconnect
   343  	}
   344  	if do, ok := f.(Commander); ok {
   345  		ft.Command = do.Command
   346  	}
   347  	if do, ok := f.(Shutdowner); ok {
   348  		ft.Shutdown = do.Shutdown
   349  	}
   350  	return ft.DisableList(GetConfig(ctx).DisableFeatures)
   351  }
   352  
   353  // Mask the Features with the Fs passed in
   354  //
   355  // Only optional features which are implemented in both the original
   356  // Fs AND the one passed in will be advertised.  Any features which
   357  // aren't in both will be set to false/nil, except for UnWrap/Wrap which
   358  // will be left untouched.
   359  func (ft *Features) Mask(ctx context.Context, f Fs) *Features {
   360  	mask := f.Features()
   361  	ft.CaseInsensitive = ft.CaseInsensitive && mask.CaseInsensitive
   362  	ft.DuplicateFiles = ft.DuplicateFiles && mask.DuplicateFiles
   363  	ft.ReadMimeType = ft.ReadMimeType && mask.ReadMimeType
   364  	ft.WriteMimeType = ft.WriteMimeType && mask.WriteMimeType
   365  	ft.ReadMetadata = ft.ReadMetadata && mask.ReadMetadata
   366  	ft.WriteMetadata = ft.WriteMetadata && mask.WriteMetadata
   367  	ft.UserMetadata = ft.UserMetadata && mask.UserMetadata
   368  	ft.ReadDirMetadata = ft.ReadDirMetadata && mask.ReadDirMetadata
   369  	ft.WriteDirMetadata = ft.WriteDirMetadata && mask.WriteDirMetadata
   370  	ft.WriteDirSetModTime = ft.WriteDirSetModTime && mask.WriteDirSetModTime
   371  	ft.UserDirMetadata = ft.UserDirMetadata && mask.UserDirMetadata
   372  	ft.DirModTimeUpdatesOnWrite = ft.DirModTimeUpdatesOnWrite && mask.DirModTimeUpdatesOnWrite
   373  	ft.CanHaveEmptyDirectories = ft.CanHaveEmptyDirectories && mask.CanHaveEmptyDirectories
   374  	ft.BucketBased = ft.BucketBased && mask.BucketBased
   375  	ft.BucketBasedRootOK = ft.BucketBasedRootOK && mask.BucketBasedRootOK
   376  	ft.SetTier = ft.SetTier && mask.SetTier
   377  	ft.GetTier = ft.GetTier && mask.GetTier
   378  	ft.ServerSideAcrossConfigs = ft.ServerSideAcrossConfigs && mask.ServerSideAcrossConfigs
   379  	// ft.IsLocal = ft.IsLocal && mask.IsLocal Don't propagate IsLocal
   380  	ft.SlowModTime = ft.SlowModTime && mask.SlowModTime
   381  	ft.SlowHash = ft.SlowHash && mask.SlowHash
   382  	ft.FilterAware = ft.FilterAware && mask.FilterAware
   383  	ft.PartialUploads = ft.PartialUploads && mask.PartialUploads
   384  	ft.NoMultiThreading = ft.NoMultiThreading && mask.NoMultiThreading
   385  	// ft.Overlay = ft.Overlay && mask.Overlay don't propagate Overlay
   386  
   387  	if mask.Purge == nil {
   388  		ft.Purge = nil
   389  	}
   390  	if mask.Copy == nil {
   391  		ft.Copy = nil
   392  	}
   393  	if mask.Move == nil {
   394  		ft.Move = nil
   395  	}
   396  	if mask.DirMove == nil {
   397  		ft.DirMove = nil
   398  	}
   399  	if mask.MkdirMetadata == nil {
   400  		ft.MkdirMetadata = nil
   401  	}
   402  	if mask.ChangeNotify == nil {
   403  		ft.ChangeNotify = nil
   404  	}
   405  	// if mask.UnWrap == nil {
   406  	// 	ft.UnWrap = nil
   407  	// }
   408  	// if mask.Wrapper == nil {
   409  	// 	ft.Wrapper = nil
   410  	// }
   411  	if mask.DirCacheFlush == nil {
   412  		ft.DirCacheFlush = nil
   413  	}
   414  	if mask.PublicLink == nil {
   415  		ft.PublicLink = nil
   416  	}
   417  	if mask.PutUnchecked == nil {
   418  		ft.PutUnchecked = nil
   419  	}
   420  	if mask.PutStream == nil {
   421  		ft.PutStream = nil
   422  	}
   423  	if mask.MergeDirs == nil {
   424  		ft.MergeDirs = nil
   425  	}
   426  	if mask.DirSetModTime == nil {
   427  		ft.DirSetModTime = nil
   428  	}
   429  	if mask.CleanUp == nil {
   430  		ft.CleanUp = nil
   431  	}
   432  	if mask.ListR == nil {
   433  		ft.ListR = nil
   434  	}
   435  	if mask.About == nil {
   436  		ft.About = nil
   437  	}
   438  	if mask.OpenWriterAt == nil {
   439  		ft.OpenWriterAt = nil
   440  	}
   441  	if mask.OpenChunkWriter == nil {
   442  		ft.OpenChunkWriter = nil
   443  	}
   444  	if mask.UserInfo == nil {
   445  		ft.UserInfo = nil
   446  	}
   447  	if mask.Disconnect == nil {
   448  		ft.Disconnect = nil
   449  	}
   450  	// Command is always local so we don't mask it
   451  	if mask.Shutdown == nil {
   452  		ft.Shutdown = nil
   453  	}
   454  	return ft.DisableList(GetConfig(ctx).DisableFeatures)
   455  }
   456  
   457  // Wrap makes a Copy of the features passed in, overriding the UnWrap/Wrap
   458  // method only if available in f.
   459  func (ft *Features) Wrap(f Fs) *Features {
   460  	ftCopy := new(Features)
   461  	*ftCopy = *ft
   462  	if do, ok := f.(UnWrapper); ok {
   463  		ftCopy.UnWrap = do.UnWrap
   464  	}
   465  	if do, ok := f.(Wrapper); ok {
   466  		ftCopy.WrapFs = do.WrapFs
   467  		ftCopy.SetWrapper = do.SetWrapper
   468  	}
   469  	return ftCopy
   470  }
   471  
   472  // WrapsFs adds extra information between `f` which wraps `w`
   473  func (ft *Features) WrapsFs(f Fs, w Fs) *Features {
   474  	wFeatures := w.Features()
   475  	if wFeatures.WrapFs != nil && wFeatures.SetWrapper != nil {
   476  		wFeatures.SetWrapper(f)
   477  	}
   478  	return ft
   479  }
   480  
   481  // Purger is an optional interfaces for Fs
   482  type Purger interface {
   483  	// Purge all files in the directory specified
   484  	//
   485  	// Implement this if you have a way of deleting all the files
   486  	// quicker than just running Remove() on the result of List()
   487  	//
   488  	// Return an error if it doesn't exist
   489  	Purge(ctx context.Context, dir string) error
   490  }
   491  
   492  // Copier is an optional interface for Fs
   493  type Copier interface {
   494  	// Copy src to this remote using server-side copy operations.
   495  	//
   496  	// This is stored with the remote path given
   497  	//
   498  	// It returns the destination Object and a possible error
   499  	//
   500  	// Will only be called if src.Fs().Name() == f.Name()
   501  	//
   502  	// If it isn't possible then return fs.ErrorCantCopy
   503  	Copy(ctx context.Context, src Object, remote string) (Object, error)
   504  }
   505  
   506  // Mover is an optional interface for Fs
   507  type Mover interface {
   508  	// Move src to this remote using server-side move operations.
   509  	//
   510  	// This is stored with the remote path given
   511  	//
   512  	// It returns the destination Object and a possible error
   513  	//
   514  	// Will only be called if src.Fs().Name() == f.Name()
   515  	//
   516  	// If it isn't possible then return fs.ErrorCantMove
   517  	Move(ctx context.Context, src Object, remote string) (Object, error)
   518  }
   519  
   520  // DirMover is an optional interface for Fs
   521  type DirMover interface {
   522  	// DirMove moves src, srcRemote to this remote at dstRemote
   523  	// using server-side move operations.
   524  	//
   525  	// Will only be called if src.Fs().Name() == f.Name()
   526  	//
   527  	// If it isn't possible then return fs.ErrorCantDirMove
   528  	//
   529  	// If destination exists then return fs.ErrorDirExists
   530  	DirMove(ctx context.Context, src Fs, srcRemote, dstRemote string) error
   531  }
   532  
   533  // MkdirMetadataer is an optional interface for Fs
   534  type MkdirMetadataer interface {
   535  	// MkdirMetadata makes the directory passed in as dir.
   536  	//
   537  	// It shouldn't return an error if it already exists.
   538  	//
   539  	// If the metadata is not nil it is set.
   540  	//
   541  	// It returns the directory that was created.
   542  	MkdirMetadata(ctx context.Context, dir string, metadata Metadata) (Directory, error)
   543  }
   544  
   545  // ChangeNotifier is an optional interface for Fs
   546  type ChangeNotifier interface {
   547  	// ChangeNotify calls the passed function with a path
   548  	// that has had changes. If the implementation
   549  	// uses polling, it should adhere to the given interval.
   550  	// At least one value will be written to the channel,
   551  	// specifying the initial value and updated values might
   552  	// follow. A 0 Duration should pause the polling.
   553  	// The ChangeNotify implementation must empty the channel
   554  	// regularly. When the channel gets closed, the implementation
   555  	// should stop polling and release resources.
   556  	ChangeNotify(context.Context, func(string, EntryType), <-chan time.Duration)
   557  }
   558  
   559  // EntryType can be associated with remote paths to identify their type
   560  type EntryType int
   561  
   562  // Constants
   563  const (
   564  	// EntryDirectory should be used to classify remote paths in directories
   565  	EntryDirectory EntryType = iota // 0
   566  	// EntryObject should be used to classify remote paths in objects
   567  	EntryObject // 1
   568  )
   569  
   570  // UnWrapper is an optional interfaces for Fs
   571  type UnWrapper interface {
   572  	// UnWrap returns the Fs that this Fs is wrapping
   573  	UnWrap() Fs
   574  }
   575  
   576  // Wrapper is an optional interfaces for Fs
   577  type Wrapper interface {
   578  	// Wrap returns the Fs that is wrapping this Fs
   579  	WrapFs() Fs
   580  	// SetWrapper sets the Fs that is wrapping this Fs
   581  	SetWrapper(f Fs)
   582  }
   583  
   584  // DirCacheFlusher is an optional interface for Fs
   585  type DirCacheFlusher interface {
   586  	// DirCacheFlush resets the directory cache - used in testing
   587  	// as an optional interface
   588  	DirCacheFlush()
   589  }
   590  
   591  // PutUncheckeder is an optional interface for Fs
   592  type PutUncheckeder interface {
   593  	// Put in to the remote path with the modTime given of the given size
   594  	//
   595  	// May create the object even if it returns an error - if so
   596  	// will return the object and the error, otherwise will return
   597  	// nil and the error
   598  	//
   599  	// May create duplicates or return errors if src already
   600  	// exists.
   601  	PutUnchecked(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   602  }
   603  
   604  // PutStreamer is an optional interface for Fs
   605  type PutStreamer interface {
   606  	// PutStream uploads to the remote path with the modTime given of indeterminate size
   607  	//
   608  	// May create the object even if it returns an error - if so
   609  	// will return the object and the error, otherwise will return
   610  	// nil and the error
   611  	PutStream(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   612  }
   613  
   614  // PublicLinker is an optional interface for Fs
   615  type PublicLinker interface {
   616  	// PublicLink generates a public link to the remote path (usually readable by anyone)
   617  	PublicLink(ctx context.Context, remote string, expire Duration, unlink bool) (string, error)
   618  }
   619  
   620  // MergeDirser is an option interface for Fs
   621  type MergeDirser interface {
   622  	// MergeDirs merges the contents of all the directories passed
   623  	// in into the first one and rmdirs the other directories.
   624  	MergeDirs(ctx context.Context, dirs []Directory) error
   625  }
   626  
   627  // DirSetModTimer is an optional interface for Fs
   628  type DirSetModTimer interface {
   629  	// DirSetModTime sets the metadata on the directory to set the modification date
   630  	DirSetModTime(ctx context.Context, dir string, modTime time.Time) error
   631  }
   632  
   633  // CleanUpper is an optional interfaces for Fs
   634  type CleanUpper interface {
   635  	// CleanUp the trash in the Fs
   636  	//
   637  	// Implement this if you have a way of emptying the trash or
   638  	// otherwise cleaning up old versions of files.
   639  	CleanUp(ctx context.Context) error
   640  }
   641  
   642  // ListRer is an optional interfaces for Fs
   643  type ListRer interface {
   644  	// ListR lists the objects and directories of the Fs starting
   645  	// from dir recursively into out.
   646  	//
   647  	// dir should be "" to start from the root, and should not
   648  	// have trailing slashes.
   649  	//
   650  	// This should return ErrDirNotFound if the directory isn't
   651  	// found.
   652  	//
   653  	// It should call callback for each tranche of entries read.
   654  	// These need not be returned in any particular order.  If
   655  	// callback returns an error then the listing will stop
   656  	// immediately.
   657  	//
   658  	// Don't implement this unless you have a more efficient way
   659  	// of listing recursively that doing a directory traversal.
   660  	ListR(ctx context.Context, dir string, callback ListRCallback) error
   661  }
   662  
   663  // RangeSeeker is the interface that wraps the RangeSeek method.
   664  //
   665  // Some of the returns from Object.Open() may optionally implement
   666  // this method for efficiency purposes.
   667  type RangeSeeker interface {
   668  	// RangeSeek behaves like a call to Seek(offset int64, whence
   669  	// int) with the output wrapped in an io.LimitedReader
   670  	// limiting the total length to limit.
   671  	//
   672  	// RangeSeek with a limit of < 0 is equivalent to a regular Seek.
   673  	RangeSeek(ctx context.Context, offset int64, whence int, length int64) (int64, error)
   674  }
   675  
   676  // Abouter is an optional interface for Fs
   677  type Abouter interface {
   678  	// About gets quota information from the Fs
   679  	About(ctx context.Context) (*Usage, error)
   680  }
   681  
   682  // OpenWriterAter is an optional interface for Fs
   683  type OpenWriterAter interface {
   684  	// OpenWriterAt opens with a handle for random access writes
   685  	//
   686  	// Pass in the remote desired and the size if known.
   687  	//
   688  	// It truncates any existing object
   689  	OpenWriterAt(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
   690  }
   691  
   692  // OpenWriterAtFn describes the OpenWriterAt function pointer
   693  type OpenWriterAtFn func(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
   694  
   695  // ChunkWriterInfo describes how a backend would like ChunkWriter called
   696  type ChunkWriterInfo struct {
   697  	ChunkSize         int64 // preferred chunk size
   698  	Concurrency       int   // how many chunks to write at once
   699  	LeavePartsOnError bool  // if set don't delete parts uploaded so far on error
   700  }
   701  
   702  // OpenChunkWriter is an option interface for Fs to implement chunked writing
   703  type OpenChunkWriter interface {
   704  	// OpenChunkWriter returns the chunk size and a ChunkWriter
   705  	//
   706  	// Pass in the remote and the src object
   707  	// You can also use options to hint at the desired chunk size
   708  	OpenChunkWriter(ctx context.Context, remote string, src ObjectInfo, options ...OpenOption) (info ChunkWriterInfo, writer ChunkWriter, err error)
   709  }
   710  
   711  // OpenChunkWriterFn describes the OpenChunkWriter function pointer
   712  type OpenChunkWriterFn func(ctx context.Context, remote string, src ObjectInfo, options ...OpenOption) (info ChunkWriterInfo, writer ChunkWriter, err error)
   713  
   714  // ChunkWriter is returned by OpenChunkWriter to implement chunked writing
   715  type ChunkWriter interface {
   716  	// WriteChunk will write chunk number with reader bytes, where chunk number >= 0
   717  	WriteChunk(ctx context.Context, chunkNumber int, reader io.ReadSeeker) (bytesWritten int64, err error)
   718  
   719  	// Close complete chunked writer finalising the file.
   720  	Close(ctx context.Context) error
   721  
   722  	// Abort chunk write
   723  	//
   724  	// You can and should call Abort without calling Close.
   725  	Abort(ctx context.Context) error
   726  }
   727  
   728  // UserInfoer is an optional interface for Fs
   729  type UserInfoer interface {
   730  	// UserInfo returns info about the connected user
   731  	UserInfo(ctx context.Context) (map[string]string, error)
   732  }
   733  
   734  // Disconnecter is an optional interface for Fs
   735  type Disconnecter interface {
   736  	// Disconnect the current user
   737  	Disconnect(ctx context.Context) error
   738  }
   739  
   740  // CommandHelp describes a single backend Command
   741  //
   742  // These are automatically inserted in the docs
   743  type CommandHelp struct {
   744  	Name  string            // Name of the command, e.g. "link"
   745  	Short string            // Single line description
   746  	Long  string            // Long multi-line description
   747  	Opts  map[string]string // maps option name to a single line help
   748  }
   749  
   750  // Commander is an interface to wrap the Command function
   751  type Commander interface {
   752  	// Command the backend to run a named command
   753  	//
   754  	// The command run is name
   755  	// args may be used to read arguments from
   756  	// opts may be used to read optional arguments from
   757  	//
   758  	// The result should be capable of being JSON encoded
   759  	// If it is a string or a []string it will be shown to the user
   760  	// otherwise it will be JSON encoded and shown to the user like that
   761  	Command(ctx context.Context, name string, arg []string, opt map[string]string) (interface{}, error)
   762  }
   763  
   764  // Shutdowner is an interface to wrap the Shutdown function
   765  type Shutdowner interface {
   766  	// Shutdown the backend, closing any background tasks and any
   767  	// cached connections.
   768  	Shutdown(ctx context.Context) error
   769  }
   770  
   771  // ObjectsChan is a channel of Objects
   772  type ObjectsChan chan Object
   773  
   774  // Objects is a slice of Object~s
   775  type Objects []Object
   776  
   777  // ObjectPair is a pair of Objects used to describe a potential copy
   778  // operation.
   779  type ObjectPair struct {
   780  	Src, Dst Object
   781  }
   782  
   783  // UnWrapFs unwraps f as much as possible and returns the base Fs
   784  func UnWrapFs(f Fs) Fs {
   785  	for {
   786  		unwrap := f.Features().UnWrap
   787  		if unwrap == nil {
   788  			break // not a wrapped Fs, use current
   789  		}
   790  		next := unwrap()
   791  		if next == nil {
   792  			break // no base Fs found, use current
   793  		}
   794  		f = next
   795  	}
   796  	return f
   797  }
   798  
   799  // UnWrapObject unwraps o as much as possible and returns the base object
   800  func UnWrapObject(o Object) Object {
   801  	for {
   802  		u, ok := o.(ObjectUnWrapper)
   803  		if !ok {
   804  			break // not a wrapped object, use current
   805  		}
   806  		next := u.UnWrap()
   807  		if next == nil {
   808  			break // no base object found, use current
   809  		}
   810  		o = next
   811  	}
   812  	return o
   813  }
   814  
   815  // UnWrapObjectInfo returns the underlying Object unwrapped as much as
   816  // possible or nil.
   817  func UnWrapObjectInfo(oi ObjectInfo) Object {
   818  	o, ok := oi.(Object)
   819  	if !ok {
   820  		return nil
   821  	}
   822  	return UnWrapObject(o)
   823  }