github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/union/policy/epff.go (about) 1 package policy 2 3 import ( 4 "context" 5 "path" 6 7 "github.com/rclone/rclone/backend/union/upstream" 8 "github.com/rclone/rclone/fs" 9 ) 10 11 func init() { 12 registerPolicy("epff", &EpFF{}) 13 } 14 15 // EpFF stands for existing path, first found 16 // Given the order of the candidates, act on the first one found where the relative path exists. 17 type EpFF struct{} 18 19 func (p *EpFF) epff(ctx context.Context, upstreams []*upstream.Fs, filePath string) (*upstream.Fs, error) { 20 ch := make(chan *upstream.Fs, len(upstreams)) 21 ctx, cancel := context.WithCancel(ctx) 22 defer cancel() 23 for _, u := range upstreams { 24 u := u // Closure 25 go func() { 26 rfs := u.RootFs 27 remote := path.Join(u.RootPath, filePath) 28 if findEntry(ctx, rfs, remote) == nil { 29 u = nil 30 } 31 ch <- u 32 }() 33 } 34 var u *upstream.Fs 35 for range upstreams { 36 u = <-ch 37 if u != nil { 38 break 39 } 40 } 41 if u == nil { 42 return nil, fs.ErrorObjectNotFound 43 } 44 return u, nil 45 } 46 47 // Action category policy, governing the modification of files and directories 48 func (p *EpFF) Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 49 if len(upstreams) == 0 { 50 return nil, fs.ErrorObjectNotFound 51 } 52 upstreams = filterRO(upstreams) 53 if len(upstreams) == 0 { 54 return nil, fs.ErrorPermissionDenied 55 } 56 u, err := p.epff(ctx, upstreams, path) 57 return []*upstream.Fs{u}, err 58 } 59 60 // ActionEntries is ACTION category policy but receiving a set of candidate entries 61 func (p *EpFF) ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 62 if len(entries) == 0 { 63 return nil, fs.ErrorObjectNotFound 64 } 65 entries = filterROEntries(entries) 66 if len(entries) == 0 { 67 return nil, fs.ErrorPermissionDenied 68 } 69 return entries[:1], nil 70 } 71 72 // Create category policy, governing the creation of files and directories 73 func (p *EpFF) Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 74 if len(upstreams) == 0 { 75 return nil, fs.ErrorObjectNotFound 76 } 77 upstreams = filterNC(upstreams) 78 if len(upstreams) == 0 { 79 return nil, fs.ErrorPermissionDenied 80 } 81 u, err := p.epff(ctx, upstreams, path+"/..") 82 return []*upstream.Fs{u}, err 83 } 84 85 // CreateEntries is CREATE category policy but receiving a set of candidate entries 86 func (p *EpFF) CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 87 if len(entries) == 0 { 88 return nil, fs.ErrorObjectNotFound 89 } 90 entries = filterNCEntries(entries) 91 if len(entries) == 0 { 92 return nil, fs.ErrorPermissionDenied 93 } 94 return entries[:1], nil 95 } 96 97 // Search category policy, governing the access to files and directories 98 func (p *EpFF) Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error) { 99 if len(upstreams) == 0 { 100 return nil, fs.ErrorObjectNotFound 101 } 102 return p.epff(ctx, upstreams, path) 103 } 104 105 // SearchEntries is SEARCH category policy but receiving a set of candidate entries 106 func (p *EpFF) SearchEntries(entries ...upstream.Entry) (upstream.Entry, error) { 107 if len(entries) == 0 { 108 return nil, fs.ErrorObjectNotFound 109 } 110 return entries[0], nil 111 }