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 }