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