github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/backend/union/union.go (about)

     1  package union
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"path"
     9  	"path/filepath"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/pkg/errors"
    15  	"github.com/rclone/rclone/backend/union/policy"
    16  	"github.com/rclone/rclone/backend/union/upstream"
    17  	"github.com/rclone/rclone/fs"
    18  	"github.com/rclone/rclone/fs/config/configmap"
    19  	"github.com/rclone/rclone/fs/config/configstruct"
    20  	"github.com/rclone/rclone/fs/hash"
    21  	"github.com/rclone/rclone/fs/operations"
    22  	"github.com/rclone/rclone/fs/walk"
    23  )
    24  
    25  // Register with Fs
    26  func init() {
    27  	fsi := &fs.RegInfo{
    28  		Name:        "union",
    29  		Description: "Union merges the contents of several upstream fs",
    30  		NewFs:       NewFs,
    31  		Options: []fs.Option{{
    32  			Name:     "upstreams",
    33  			Help:     "List of space separated upstreams.\nCan be 'upstreama:test/dir upstreamb:', '\"upstreama:test/space:ro dir\" upstreamb:', etc.\n",
    34  			Required: true,
    35  		}, {
    36  			Name:     "action_policy",
    37  			Help:     "Policy to choose upstream on ACTION category.",
    38  			Required: true,
    39  			Default:  "epall",
    40  		}, {
    41  			Name:     "create_policy",
    42  			Help:     "Policy to choose upstream on CREATE category.",
    43  			Required: true,
    44  			Default:  "epmfs",
    45  		}, {
    46  			Name:     "search_policy",
    47  			Help:     "Policy to choose upstream on SEARCH category.",
    48  			Required: true,
    49  			Default:  "ff",
    50  		}, {
    51  			Name:     "cache_time",
    52  			Help:     "Cache time of usage and free space (in seconds). This option is only useful when a path preserving policy is used.",
    53  			Required: true,
    54  			Default:  120,
    55  		}},
    56  	}
    57  	fs.Register(fsi)
    58  }
    59  
    60  // Options defines the configuration for this backend
    61  type Options struct {
    62  	Upstreams    fs.SpaceSepList `config:"upstreams"`
    63  	Remotes      fs.SpaceSepList `config:"remotes"` // Depreated
    64  	ActionPolicy string          `config:"action_policy"`
    65  	CreatePolicy string          `config:"create_policy"`
    66  	SearchPolicy string          `config:"search_policy"`
    67  	CacheTime    int             `config:"cache_time"`
    68  }
    69  
    70  // Fs represents a union of upstreams
    71  type Fs struct {
    72  	name         string         // name of this remote
    73  	features     *fs.Features   // optional features
    74  	opt          Options        // options for this Fs
    75  	root         string         // the path we are working on
    76  	upstreams    []*upstream.Fs // slice of upstreams
    77  	hashSet      hash.Set       // intersection of hash types
    78  	actionPolicy policy.Policy  // policy for ACTION
    79  	createPolicy policy.Policy  // policy for CREATE
    80  	searchPolicy policy.Policy  // policy for SEARCH
    81  }
    82  
    83  // Wrap candidate objects in to a union Object
    84  func (f *Fs) wrapEntries(entries ...upstream.Entry) (entry, error) {
    85  	e, err := f.searchEntries(entries...)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	switch e.(type) {
    90  	case *upstream.Object:
    91  		return &Object{
    92  			Object: e.(*upstream.Object),
    93  			fs:     f,
    94  			co:     entries,
    95  		}, nil
    96  	case *upstream.Directory:
    97  		return &Directory{
    98  			Directory: e.(*upstream.Directory),
    99  			cd:        entries,
   100  		}, nil
   101  	default:
   102  		return nil, errors.Errorf("unknown object type %T", e)
   103  	}
   104  }
   105  
   106  // Name of the remote (as passed into NewFs)
   107  func (f *Fs) Name() string {
   108  	return f.name
   109  }
   110  
   111  // Root of the remote (as passed into NewFs)
   112  func (f *Fs) Root() string {
   113  	return f.root
   114  }
   115  
   116  // String converts this Fs to a string
   117  func (f *Fs) String() string {
   118  	return fmt.Sprintf("union root '%s'", f.root)
   119  }
   120  
   121  // Features returns the optional features of this Fs
   122  func (f *Fs) Features() *fs.Features {
   123  	return f.features
   124  }
   125  
   126  // Rmdir removes the root directory of the Fs object
   127  func (f *Fs) Rmdir(ctx context.Context, dir string) error {
   128  	upstreams, err := f.action(ctx, dir)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	errs := Errors(make([]error, len(upstreams)))
   133  	multithread(len(upstreams), func(i int) {
   134  		err := upstreams[i].Rmdir(ctx, dir)
   135  		errs[i] = errors.Wrap(err, upstreams[i].Name())
   136  	})
   137  	return errs.Err()
   138  }
   139  
   140  // Hashes returns hash.HashNone to indicate remote hashing is unavailable
   141  func (f *Fs) Hashes() hash.Set {
   142  	return f.hashSet
   143  }
   144  
   145  // Mkdir makes the root directory of the Fs object
   146  func (f *Fs) Mkdir(ctx context.Context, dir string) error {
   147  	upstreams, err := f.create(ctx, dir)
   148  	if err == fs.ErrorObjectNotFound && dir != parentDir(dir) {
   149  		if err := f.Mkdir(ctx, parentDir(dir)); err != nil {
   150  			return err
   151  		}
   152  		upstreams, err = f.create(ctx, dir)
   153  	}
   154  	if err != nil {
   155  		return err
   156  	}
   157  	errs := Errors(make([]error, len(upstreams)))
   158  	multithread(len(upstreams), func(i int) {
   159  		err := upstreams[i].Mkdir(ctx, dir)
   160  		errs[i] = errors.Wrap(err, upstreams[i].Name())
   161  	})
   162  	return errs.Err()
   163  }
   164  
   165  // Purge all files in the root and the root directory
   166  //
   167  // Implement this if you have a way of deleting all the files
   168  // quicker than just running Remove() on the result of List()
   169  //
   170  // Return an error if it doesn't exist
   171  func (f *Fs) Purge(ctx context.Context) error {
   172  	for _, r := range f.upstreams {
   173  		if r.Features().Purge == nil {
   174  			return fs.ErrorCantPurge
   175  		}
   176  	}
   177  	upstreams, err := f.action(ctx, "")
   178  	if err != nil {
   179  		return err
   180  	}
   181  	errs := Errors(make([]error, len(upstreams)))
   182  	multithread(len(upstreams), func(i int) {
   183  		err := upstreams[i].Features().Purge(ctx)
   184  		errs[i] = errors.Wrap(err, upstreams[i].Name())
   185  	})
   186  	return errs.Err()
   187  }
   188  
   189  // Copy src to this remote using server side copy operations.
   190  //
   191  // This is stored with the remote path given
   192  //
   193  // It returns the destination Object and a possible error
   194  //
   195  // Will only be called if src.Fs().Name() == f.Name()
   196  //
   197  // If it isn't possible then return fs.ErrorCantCopy
   198  func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
   199  	srcObj, ok := src.(*Object)
   200  	if !ok {
   201  		fs.Debugf(src, "Can't copy - not same remote type")
   202  		return nil, fs.ErrorCantCopy
   203  	}
   204  	o := srcObj.UnWrap()
   205  	su := o.UpstreamFs()
   206  	if su.Features().Copy == nil {
   207  		return nil, fs.ErrorCantCopy
   208  	}
   209  	var du *upstream.Fs
   210  	for _, u := range f.upstreams {
   211  		if operations.Same(u.RootFs, su.RootFs) {
   212  			du = u
   213  		}
   214  	}
   215  	if du == nil {
   216  		return nil, fs.ErrorCantCopy
   217  	}
   218  	if !du.IsCreatable() {
   219  		return nil, fs.ErrorPermissionDenied
   220  	}
   221  	co, err := du.Features().Copy(ctx, o, remote)
   222  	if err != nil || co == nil {
   223  		return nil, err
   224  	}
   225  	wo, err := f.wrapEntries(du.WrapObject(co))
   226  	return wo.(*Object), err
   227  }
   228  
   229  // Move src to this remote using server side move operations.
   230  //
   231  // This is stored with the remote path given
   232  //
   233  // It returns the destination Object and a possible error
   234  //
   235  // Will only be called if src.Fs().Name() == f.Name()
   236  //
   237  // If it isn't possible then return fs.ErrorCantMove
   238  func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
   239  	o, ok := src.(*Object)
   240  	if !ok {
   241  		fs.Debugf(src, "Can't move - not same remote type")
   242  		return nil, fs.ErrorCantMove
   243  	}
   244  	entries, err := f.actionEntries(o.candidates()...)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  	for _, e := range entries {
   249  		if e.UpstreamFs().Features().Move == nil {
   250  			return nil, fs.ErrorCantMove
   251  		}
   252  	}
   253  	objs := make([]*upstream.Object, len(entries))
   254  	errs := Errors(make([]error, len(entries)))
   255  	multithread(len(entries), func(i int) {
   256  		su := entries[i].UpstreamFs()
   257  		o, ok := entries[i].(*upstream.Object)
   258  		if !ok {
   259  			errs[i] = errors.Wrap(fs.ErrorNotAFile, su.Name())
   260  			return
   261  		}
   262  		var du *upstream.Fs
   263  		for _, u := range f.upstreams {
   264  			if operations.Same(u.RootFs, su.RootFs) {
   265  				du = u
   266  			}
   267  		}
   268  		if du == nil {
   269  			errs[i] = errors.Wrap(fs.ErrorCantMove, su.Name()+":"+remote)
   270  			return
   271  		}
   272  		mo, err := du.Features().Move(ctx, o.UnWrap(), remote)
   273  		if err != nil || mo == nil {
   274  			errs[i] = errors.Wrap(err, su.Name())
   275  			return
   276  		}
   277  		objs[i] = du.WrapObject(mo)
   278  	})
   279  	var en []upstream.Entry
   280  	for _, o := range objs {
   281  		if o != nil {
   282  			en = append(en, o)
   283  		}
   284  	}
   285  	e, err := f.wrapEntries(en...)
   286  	if err != nil {
   287  		return nil, err
   288  	}
   289  	return e.(*Object), errs.Err()
   290  }
   291  
   292  // DirMove moves src, srcRemote to this remote at dstRemote
   293  // using server side move operations.
   294  //
   295  // Will only be called if src.Fs().Name() == f.Name()
   296  //
   297  // If it isn't possible then return fs.ErrorCantDirMove
   298  //
   299  // If destination exists then return fs.ErrorDirExists
   300  func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error {
   301  	sfs, ok := src.(*Fs)
   302  	if !ok {
   303  		fs.Debugf(src, "Can't move directory - not same remote type")
   304  		return fs.ErrorCantDirMove
   305  	}
   306  	upstreams, err := sfs.action(ctx, srcRemote)
   307  	if err != nil {
   308  		return err
   309  	}
   310  	for _, u := range upstreams {
   311  		if u.Features().DirMove == nil {
   312  			return fs.ErrorCantDirMove
   313  		}
   314  	}
   315  	errs := Errors(make([]error, len(upstreams)))
   316  	multithread(len(upstreams), func(i int) {
   317  		su := upstreams[i]
   318  		var du *upstream.Fs
   319  		for _, u := range f.upstreams {
   320  			if operations.Same(u.RootFs, su.RootFs) {
   321  				du = u
   322  			}
   323  		}
   324  		if du == nil {
   325  			errs[i] = errors.Wrap(fs.ErrorCantDirMove, su.Name()+":"+su.Root())
   326  			return
   327  		}
   328  		err := du.Features().DirMove(ctx, su.Fs, srcRemote, dstRemote)
   329  		errs[i] = errors.Wrap(err, du.Name()+":"+du.Root())
   330  	})
   331  	errs = errs.FilterNil()
   332  	if len(errs) == 0 {
   333  		return nil
   334  	}
   335  	for _, e := range errs {
   336  		if errors.Cause(e) != fs.ErrorDirExists {
   337  			return errs
   338  		}
   339  	}
   340  	return fs.ErrorDirExists
   341  }
   342  
   343  // ChangeNotify calls the passed function with a path
   344  // that has had changes. If the implementation
   345  // uses polling, it should adhere to the given interval.
   346  // At least one value will be written to the channel,
   347  // specifying the initial value and updated values might
   348  // follow. A 0 Duration should pause the polling.
   349  // The ChangeNotify implementation must empty the channel
   350  // regularly. When the channel gets closed, the implementation
   351  // should stop polling and release resources.
   352  func (f *Fs) ChangeNotify(ctx context.Context, fn func(string, fs.EntryType), ch <-chan time.Duration) {
   353  	var uChans []chan time.Duration
   354  
   355  	for _, u := range f.upstreams {
   356  		if ChangeNotify := u.Features().ChangeNotify; ChangeNotify != nil {
   357  			ch := make(chan time.Duration)
   358  			uChans = append(uChans, ch)
   359  			ChangeNotify(ctx, fn, ch)
   360  		}
   361  	}
   362  
   363  	go func() {
   364  		for i := range ch {
   365  			for _, c := range uChans {
   366  				c <- i
   367  			}
   368  		}
   369  		for _, c := range uChans {
   370  			close(c)
   371  		}
   372  	}()
   373  }
   374  
   375  // DirCacheFlush resets the directory cache - used in testing
   376  // as an optional interface
   377  func (f *Fs) DirCacheFlush() {
   378  	multithread(len(f.upstreams), func(i int) {
   379  		if do := f.upstreams[i].Features().DirCacheFlush; do != nil {
   380  			do()
   381  		}
   382  	})
   383  }
   384  
   385  func (f *Fs) put(ctx context.Context, in io.Reader, src fs.ObjectInfo, stream bool, options ...fs.OpenOption) (fs.Object, error) {
   386  	srcPath := src.Remote()
   387  	upstreams, err := f.create(ctx, srcPath)
   388  	if err == fs.ErrorObjectNotFound {
   389  		if err := f.Mkdir(ctx, parentDir(srcPath)); err != nil {
   390  			return nil, err
   391  		}
   392  		upstreams, err = f.create(ctx, srcPath)
   393  	}
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	if len(upstreams) == 1 {
   398  		u := upstreams[0]
   399  		var o fs.Object
   400  		var err error
   401  		if stream {
   402  			o, err = u.Features().PutStream(ctx, in, src, options...)
   403  		} else {
   404  			o, err = u.Put(ctx, in, src, options...)
   405  		}
   406  		if err != nil {
   407  			return nil, err
   408  		}
   409  		e, err := f.wrapEntries(u.WrapObject(o))
   410  		return e.(*Object), err
   411  	}
   412  	errs := Errors(make([]error, len(upstreams)+1))
   413  	// Get multiple reader
   414  	readers := make([]io.Reader, len(upstreams))
   415  	writers := make([]io.Writer, len(upstreams))
   416  	for i := range writers {
   417  		r, w := io.Pipe()
   418  		bw := bufio.NewWriter(w)
   419  		readers[i], writers[i] = r, bw
   420  		defer func() {
   421  			err := w.Close()
   422  			if err != nil {
   423  				panic(err)
   424  			}
   425  		}()
   426  	}
   427  	go func() {
   428  		mw := io.MultiWriter(writers...)
   429  		es := make([]error, len(writers)+1)
   430  		_, es[len(es)-1] = io.Copy(mw, in)
   431  		for i, bw := range writers {
   432  			es[i] = bw.(*bufio.Writer).Flush()
   433  		}
   434  		errs[len(upstreams)] = Errors(es).Err()
   435  	}()
   436  	// Multi-threading
   437  	objs := make([]upstream.Entry, len(upstreams))
   438  	multithread(len(upstreams), func(i int) {
   439  		u := upstreams[i]
   440  		var o fs.Object
   441  		var err error
   442  		if stream {
   443  			o, err = u.Features().PutStream(ctx, readers[i], src, options...)
   444  		} else {
   445  			o, err = u.Put(ctx, readers[i], src, options...)
   446  		}
   447  		if err != nil {
   448  			errs[i] = errors.Wrap(err, u.Name())
   449  			return
   450  		}
   451  		objs[i] = u.WrapObject(o)
   452  	})
   453  	err = errs.Err()
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  	e, err := f.wrapEntries(objs...)
   458  	return e.(*Object), err
   459  }
   460  
   461  // Put in to the remote path with the modTime given of the given size
   462  //
   463  // May create the object even if it returns an error - if so
   464  // will return the object and the error, otherwise will return
   465  // nil and the error
   466  func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
   467  	o, err := f.NewObject(ctx, src.Remote())
   468  	switch err {
   469  	case nil:
   470  		return o, o.Update(ctx, in, src, options...)
   471  	case fs.ErrorObjectNotFound:
   472  		return f.put(ctx, in, src, false, options...)
   473  	default:
   474  		return nil, err
   475  	}
   476  }
   477  
   478  // PutStream uploads to the remote path with the modTime given of indeterminate size
   479  //
   480  // May create the object even if it returns an error - if so
   481  // will return the object and the error, otherwise will return
   482  // nil and the error
   483  func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
   484  	o, err := f.NewObject(ctx, src.Remote())
   485  	switch err {
   486  	case nil:
   487  		return o, o.Update(ctx, in, src, options...)
   488  	case fs.ErrorObjectNotFound:
   489  		return f.put(ctx, in, src, true, options...)
   490  	default:
   491  		return nil, err
   492  	}
   493  }
   494  
   495  // About gets quota information from the Fs
   496  func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
   497  	usage := &fs.Usage{
   498  		Total:   new(int64),
   499  		Used:    new(int64),
   500  		Trashed: new(int64),
   501  		Other:   new(int64),
   502  		Free:    new(int64),
   503  		Objects: new(int64),
   504  	}
   505  	for _, u := range f.upstreams {
   506  		usg, err := u.About(ctx)
   507  		if err != nil {
   508  			return nil, err
   509  		}
   510  		if usg.Total != nil && usage.Total != nil {
   511  			*usage.Total += *usg.Total
   512  		} else {
   513  			usage.Total = nil
   514  		}
   515  		if usg.Used != nil && usage.Used != nil {
   516  			*usage.Used += *usg.Used
   517  		} else {
   518  			usage.Used = nil
   519  		}
   520  		if usg.Trashed != nil && usage.Trashed != nil {
   521  			*usage.Trashed += *usg.Trashed
   522  		} else {
   523  			usage.Trashed = nil
   524  		}
   525  		if usg.Other != nil && usage.Other != nil {
   526  			*usage.Other += *usg.Other
   527  		} else {
   528  			usage.Other = nil
   529  		}
   530  		if usg.Free != nil && usage.Free != nil {
   531  			*usage.Free += *usg.Free
   532  		} else {
   533  			usage.Free = nil
   534  		}
   535  		if usg.Objects != nil && usage.Objects != nil {
   536  			*usage.Objects += *usg.Objects
   537  		} else {
   538  			usage.Objects = nil
   539  		}
   540  	}
   541  	return usage, nil
   542  }
   543  
   544  // List the objects and directories in dir into entries.  The
   545  // entries can be returned in any order but should be for a
   546  // complete directory.
   547  //
   548  // dir should be "" to list the root, and should not have
   549  // trailing slashes.
   550  //
   551  // This should return ErrDirNotFound if the directory isn't
   552  // found.
   553  func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
   554  	entriess := make([][]upstream.Entry, len(f.upstreams))
   555  	errs := Errors(make([]error, len(f.upstreams)))
   556  	multithread(len(f.upstreams), func(i int) {
   557  		u := f.upstreams[i]
   558  		entries, err := u.List(ctx, dir)
   559  		if err != nil {
   560  			errs[i] = errors.Wrap(err, u.Name())
   561  			return
   562  		}
   563  		uEntries := make([]upstream.Entry, len(entries))
   564  		for j, e := range entries {
   565  			uEntries[j], _ = u.WrapEntry(e)
   566  		}
   567  		entriess[i] = uEntries
   568  	})
   569  	if len(errs) == len(errs.FilterNil()) {
   570  		errs = errs.Map(func(e error) error {
   571  			if errors.Cause(e) == fs.ErrorDirNotFound {
   572  				return nil
   573  			}
   574  			return e
   575  		})
   576  		if len(errs) == 0 {
   577  			return nil, fs.ErrorDirNotFound
   578  		}
   579  		return nil, errs.Err()
   580  	}
   581  	return f.mergeDirEntries(entriess)
   582  }
   583  
   584  // ListR lists the objects and directories of the Fs starting
   585  // from dir recursively into out.
   586  //
   587  // dir should be "" to start from the root, and should not
   588  // have trailing slashes.
   589  //
   590  // This should return ErrDirNotFound if the directory isn't
   591  // found.
   592  //
   593  // It should call callback for each tranche of entries read.
   594  // These need not be returned in any particular order.  If
   595  // callback returns an error then the listing will stop
   596  // immediately.
   597  //
   598  // Don't implement this unless you have a more efficient way
   599  // of listing recursively that doing a directory traversal.
   600  func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) (err error) {
   601  	var entriess [][]upstream.Entry
   602  	errs := Errors(make([]error, len(f.upstreams)))
   603  	var mutex sync.Mutex
   604  	multithread(len(f.upstreams), func(i int) {
   605  		u := f.upstreams[i]
   606  		var err error
   607  		callback := func(entries fs.DirEntries) error {
   608  			uEntries := make([]upstream.Entry, len(entries))
   609  			for j, e := range entries {
   610  				uEntries[j], _ = u.WrapEntry(e)
   611  			}
   612  			mutex.Lock()
   613  			entriess = append(entriess, uEntries)
   614  			mutex.Unlock()
   615  			return nil
   616  		}
   617  		do := u.Features().ListR
   618  		if do != nil {
   619  			err = do(ctx, dir, callback)
   620  		} else {
   621  			err = walk.ListR(ctx, u, dir, true, -1, walk.ListAll, callback)
   622  		}
   623  		if err != nil {
   624  			errs[i] = errors.Wrap(err, u.Name())
   625  			return
   626  		}
   627  	})
   628  	if len(errs) == len(errs.FilterNil()) {
   629  		errs = errs.Map(func(e error) error {
   630  			if errors.Cause(e) == fs.ErrorDirNotFound {
   631  				return nil
   632  			}
   633  			return e
   634  		})
   635  		if len(errs) == 0 {
   636  			return fs.ErrorDirNotFound
   637  		}
   638  		return errs.Err()
   639  	}
   640  	entries, err := f.mergeDirEntries(entriess)
   641  	if err != nil {
   642  		return err
   643  	}
   644  	return callback(entries)
   645  }
   646  
   647  // NewObject creates a new remote union file object
   648  func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
   649  	objs := make([]*upstream.Object, len(f.upstreams))
   650  	errs := Errors(make([]error, len(f.upstreams)))
   651  	multithread(len(f.upstreams), func(i int) {
   652  		u := f.upstreams[i]
   653  		o, err := u.NewObject(ctx, remote)
   654  		if err != nil && err != fs.ErrorObjectNotFound {
   655  			errs[i] = errors.Wrap(err, u.Name())
   656  			return
   657  		}
   658  		objs[i] = u.WrapObject(o)
   659  	})
   660  	var entries []upstream.Entry
   661  	for _, o := range objs {
   662  		if o != nil {
   663  			entries = append(entries, o)
   664  		}
   665  	}
   666  	if len(entries) == 0 {
   667  		return nil, fs.ErrorObjectNotFound
   668  	}
   669  	e, err := f.wrapEntries(entries...)
   670  	if err != nil {
   671  		return nil, err
   672  	}
   673  	return e.(*Object), errs.Err()
   674  }
   675  
   676  // Precision is the greatest Precision of all upstreams
   677  func (f *Fs) Precision() time.Duration {
   678  	var greatestPrecision time.Duration
   679  	for _, u := range f.upstreams {
   680  		if u.Precision() > greatestPrecision {
   681  			greatestPrecision = u.Precision()
   682  		}
   683  	}
   684  	return greatestPrecision
   685  }
   686  
   687  func (f *Fs) action(ctx context.Context, path string) ([]*upstream.Fs, error) {
   688  	return f.actionPolicy.Action(ctx, f.upstreams, path)
   689  }
   690  
   691  func (f *Fs) actionEntries(entries ...upstream.Entry) ([]upstream.Entry, error) {
   692  	return f.actionPolicy.ActionEntries(entries...)
   693  }
   694  
   695  func (f *Fs) create(ctx context.Context, path string) ([]*upstream.Fs, error) {
   696  	return f.createPolicy.Create(ctx, f.upstreams, path)
   697  }
   698  
   699  func (f *Fs) createEntries(entries ...upstream.Entry) ([]upstream.Entry, error) {
   700  	return f.createPolicy.CreateEntries(entries...)
   701  }
   702  
   703  func (f *Fs) search(ctx context.Context, path string) (*upstream.Fs, error) {
   704  	return f.searchPolicy.Search(ctx, f.upstreams, path)
   705  }
   706  
   707  func (f *Fs) searchEntries(entries ...upstream.Entry) (upstream.Entry, error) {
   708  	return f.searchPolicy.SearchEntries(entries...)
   709  }
   710  
   711  func (f *Fs) mergeDirEntries(entriess [][]upstream.Entry) (fs.DirEntries, error) {
   712  	entryMap := make(map[string]([]upstream.Entry))
   713  	for _, en := range entriess {
   714  		if en == nil {
   715  			continue
   716  		}
   717  		for _, entry := range en {
   718  			remote := entry.Remote()
   719  			if f.Features().CaseInsensitive {
   720  				remote = strings.ToLower(remote)
   721  			}
   722  			entryMap[remote] = append(entryMap[remote], entry)
   723  		}
   724  	}
   725  	var entries fs.DirEntries
   726  	for path := range entryMap {
   727  		e, err := f.wrapEntries(entryMap[path]...)
   728  		if err != nil {
   729  			return nil, err
   730  		}
   731  		entries = append(entries, e)
   732  	}
   733  	return entries, nil
   734  }
   735  
   736  // NewFs constructs an Fs from the path.
   737  //
   738  // The returned Fs is the actual Fs, referenced by remote in the config
   739  func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
   740  	// Parse config into Options struct
   741  	opt := new(Options)
   742  	err := configstruct.Set(m, opt)
   743  	if err != nil {
   744  		return nil, err
   745  	}
   746  	// Backward compatible to old config
   747  	if len(opt.Upstreams) == 0 && len(opt.Remotes) > 0 {
   748  		for i := 0; i < len(opt.Remotes)-1; i++ {
   749  			opt.Remotes[i] = opt.Remotes[i] + ":ro"
   750  		}
   751  		opt.Upstreams = opt.Remotes
   752  	}
   753  	if len(opt.Upstreams) == 0 {
   754  		return nil, errors.New("union can't point to an empty upstream - check the value of the upstreams setting")
   755  	}
   756  	if len(opt.Upstreams) == 1 {
   757  		return nil, errors.New("union can't point to a single upstream - check the value of the upstreams setting")
   758  	}
   759  	for _, u := range opt.Upstreams {
   760  		if strings.HasPrefix(u, name+":") {
   761  			return nil, errors.New("can't point union remote at itself - check the value of the upstreams setting")
   762  		}
   763  	}
   764  
   765  	upstreams := make([]*upstream.Fs, len(opt.Upstreams))
   766  	errs := Errors(make([]error, len(opt.Upstreams)))
   767  	multithread(len(opt.Upstreams), func(i int) {
   768  		u := opt.Upstreams[i]
   769  		upstreams[i], errs[i] = upstream.New(u, root, time.Duration(opt.CacheTime)*time.Second)
   770  	})
   771  	var usedUpstreams []*upstream.Fs
   772  	var fserr error
   773  	for i, err := range errs {
   774  		if err != nil && err != fs.ErrorIsFile {
   775  			return nil, err
   776  		}
   777  		// Only the upstreams returns ErrorIsFile would be used if any
   778  		if err == fs.ErrorIsFile {
   779  			usedUpstreams = append(usedUpstreams, upstreams[i])
   780  			fserr = fs.ErrorIsFile
   781  		}
   782  	}
   783  	if fserr == nil {
   784  		usedUpstreams = upstreams
   785  	}
   786  
   787  	f := &Fs{
   788  		name:      name,
   789  		root:      root,
   790  		opt:       *opt,
   791  		upstreams: usedUpstreams,
   792  	}
   793  	f.actionPolicy, err = policy.Get(opt.ActionPolicy)
   794  	if err != nil {
   795  		return nil, err
   796  	}
   797  	f.createPolicy, err = policy.Get(opt.CreatePolicy)
   798  	if err != nil {
   799  		return nil, err
   800  	}
   801  	f.searchPolicy, err = policy.Get(opt.SearchPolicy)
   802  	if err != nil {
   803  		return nil, err
   804  	}
   805  	var features = (&fs.Features{
   806  		CaseInsensitive:         true,
   807  		DuplicateFiles:          false,
   808  		ReadMimeType:            true,
   809  		WriteMimeType:           true,
   810  		CanHaveEmptyDirectories: true,
   811  		BucketBased:             true,
   812  		SetTier:                 true,
   813  		GetTier:                 true,
   814  	}).Fill(f)
   815  	for _, f := range upstreams {
   816  		features = features.Mask(f) // Mask all upstream fs
   817  	}
   818  
   819  	// Enable ListR when upstreams either support ListR or is local
   820  	// But not when all upstreams are local
   821  	if features.ListR == nil {
   822  		for _, u := range upstreams {
   823  			if u.Features().ListR != nil {
   824  				features.ListR = f.ListR
   825  			} else if !u.Features().IsLocal {
   826  				features.ListR = nil
   827  				break
   828  			}
   829  		}
   830  	}
   831  
   832  	f.features = features
   833  
   834  	// Get common intersection of hashes
   835  	hashSet := f.upstreams[0].Hashes()
   836  	for _, u := range f.upstreams[1:] {
   837  		hashSet = hashSet.Overlap(u.Hashes())
   838  	}
   839  	f.hashSet = hashSet
   840  
   841  	return f, fserr
   842  }
   843  
   844  func parentDir(absPath string) string {
   845  	parent := path.Dir(strings.TrimRight(filepath.ToSlash(absPath), "/"))
   846  	if parent == "." {
   847  		parent = ""
   848  	}
   849  	return parent
   850  }
   851  
   852  func multithread(num int, fn func(int)) {
   853  	var wg sync.WaitGroup
   854  	for i := 0; i < num; i++ {
   855  		wg.Add(1)
   856  		i := i
   857  		go func() {
   858  			defer wg.Done()
   859  			fn(i)
   860  		}()
   861  	}
   862  	wg.Wait()
   863  }
   864  
   865  // Check the interfaces are satisfied
   866  var (
   867  	_ fs.Fs              = (*Fs)(nil)
   868  	_ fs.Purger          = (*Fs)(nil)
   869  	_ fs.PutStreamer     = (*Fs)(nil)
   870  	_ fs.Copier          = (*Fs)(nil)
   871  	_ fs.Mover           = (*Fs)(nil)
   872  	_ fs.DirMover        = (*Fs)(nil)
   873  	_ fs.DirCacheFlusher = (*Fs)(nil)
   874  	_ fs.ChangeNotifier  = (*Fs)(nil)
   875  	_ fs.Abouter         = (*Fs)(nil)
   876  	_ fs.ListRer         = (*Fs)(nil)
   877  )