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

     1  package policy
     2  
     3  import (
     4  	"context"
     5  	"math/rand"
     6  	"path"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  	"github.com/rclone/rclone/backend/union/upstream"
    12  	"github.com/rclone/rclone/fs"
    13  )
    14  
    15  var policies = make(map[string]Policy)
    16  
    17  // Policy is the interface of a set of defined behavior choosing
    18  // the upstream Fs to operate on
    19  type Policy interface {
    20  	// Action category policy, governing the modification of files and directories
    21  	Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error)
    22  
    23  	// Create category policy, governing the creation of files and directories
    24  	Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error)
    25  
    26  	// Search category policy, governing the access to files and directories
    27  	Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error)
    28  
    29  	// ActionEntries is ACTION category policy but receiving a set of candidate entries
    30  	ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error)
    31  
    32  	// CreateEntries is CREATE category policy but receiving a set of candidate entries
    33  	CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error)
    34  
    35  	// SearchEntries is SEARCH category policy but receiving a set of candidate entries
    36  	SearchEntries(entries ...upstream.Entry) (upstream.Entry, error)
    37  }
    38  
    39  func registerPolicy(name string, p Policy) {
    40  	policies[strings.ToLower(name)] = p
    41  }
    42  
    43  // Get a Policy from the list
    44  func Get(name string) (Policy, error) {
    45  	p, ok := policies[strings.ToLower(name)]
    46  	if !ok {
    47  		return nil, errors.Errorf("didn't find policy called %q", name)
    48  	}
    49  	return p, nil
    50  }
    51  
    52  func filterRO(ufs []*upstream.Fs) (wufs []*upstream.Fs) {
    53  	for _, u := range ufs {
    54  		if u.IsWritable() {
    55  			wufs = append(wufs, u)
    56  		}
    57  	}
    58  	return wufs
    59  }
    60  
    61  func filterROEntries(ue []upstream.Entry) (wue []upstream.Entry) {
    62  	for _, e := range ue {
    63  		if e.UpstreamFs().IsWritable() {
    64  			wue = append(wue, e)
    65  		}
    66  	}
    67  	return wue
    68  }
    69  
    70  func filterNC(ufs []*upstream.Fs) (wufs []*upstream.Fs) {
    71  	for _, u := range ufs {
    72  		if u.IsCreatable() {
    73  			wufs = append(wufs, u)
    74  		}
    75  	}
    76  	return wufs
    77  }
    78  
    79  func filterNCEntries(ue []upstream.Entry) (wue []upstream.Entry) {
    80  	for _, e := range ue {
    81  		if e.UpstreamFs().IsCreatable() {
    82  			wue = append(wue, e)
    83  		}
    84  	}
    85  	return wue
    86  }
    87  
    88  func parentDir(absPath string) string {
    89  	parent := path.Dir(strings.TrimRight(absPath, "/"))
    90  	if parent == "." {
    91  		parent = ""
    92  	}
    93  	return parent
    94  }
    95  
    96  func clean(absPath string) string {
    97  	cleanPath := path.Clean(absPath)
    98  	if cleanPath == "." {
    99  		cleanPath = ""
   100  	}
   101  	return cleanPath
   102  }
   103  
   104  func findEntry(ctx context.Context, f fs.Fs, remote string) fs.DirEntry {
   105  	remote = clean(remote)
   106  	dir := parentDir(remote)
   107  	entries, err := f.List(ctx, dir)
   108  	if remote == dir {
   109  		if err != nil {
   110  			return nil
   111  		}
   112  		// random modtime for root
   113  		randomNow := time.Unix(time.Now().Unix()-rand.Int63n(10000), 0)
   114  		return fs.NewDir("", randomNow)
   115  	}
   116  	found := false
   117  	for _, e := range entries {
   118  		eRemote := e.Remote()
   119  		if f.Features().CaseInsensitive {
   120  			found = strings.EqualFold(remote, eRemote)
   121  		} else {
   122  			found = (remote == eRemote)
   123  		}
   124  		if found {
   125  			return e
   126  		}
   127  	}
   128  	return nil
   129  }