github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/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) 21 for _, u := range upstreams { 22 u := u // Closure 23 go func() { 24 rfs := u.RootFs 25 remote := path.Join(u.RootPath, filePath) 26 if findEntry(ctx, rfs, remote) == nil { 27 u = nil 28 } 29 ch <- u 30 }() 31 } 32 var u *upstream.Fs 33 for i := 0; i < len(upstreams); i++ { 34 u = <-ch 35 if u != nil { 36 // close remaining goroutines 37 go func(num int) { 38 defer close(ch) 39 for i := 0; i < num; i++ { 40 <-ch 41 } 42 }(len(upstreams) - 1 - i) 43 } 44 } 45 if u == nil { 46 return nil, fs.ErrorObjectNotFound 47 } 48 return u, nil 49 } 50 51 // Action category policy, governing the modification of files and directories 52 func (p *EpFF) Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 53 if len(upstreams) == 0 { 54 return nil, fs.ErrorObjectNotFound 55 } 56 upstreams = filterRO(upstreams) 57 if len(upstreams) == 0 { 58 return nil, fs.ErrorPermissionDenied 59 } 60 u, err := p.epff(ctx, upstreams, path) 61 return []*upstream.Fs{u}, err 62 } 63 64 // ActionEntries is ACTION category policy but receiving a set of candidate entries 65 func (p *EpFF) ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 66 if len(entries) == 0 { 67 return nil, fs.ErrorObjectNotFound 68 } 69 entries = filterROEntries(entries) 70 if len(entries) == 0 { 71 return nil, fs.ErrorPermissionDenied 72 } 73 return entries[:1], nil 74 } 75 76 // Create category policy, governing the creation of files and directories 77 func (p *EpFF) Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 78 if len(upstreams) == 0 { 79 return nil, fs.ErrorObjectNotFound 80 } 81 upstreams = filterNC(upstreams) 82 if len(upstreams) == 0 { 83 return nil, fs.ErrorPermissionDenied 84 } 85 u, err := p.epff(ctx, upstreams, path+"/..") 86 return []*upstream.Fs{u}, err 87 } 88 89 // CreateEntries is CREATE category policy but receiving a set of candidate entries 90 func (p *EpFF) CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 91 if len(entries) == 0 { 92 return nil, fs.ErrorObjectNotFound 93 } 94 entries = filterNCEntries(entries) 95 if len(entries) == 0 { 96 return nil, fs.ErrorPermissionDenied 97 } 98 return entries[:1], nil 99 } 100 101 // Search category policy, governing the access to files and directories 102 func (p *EpFF) Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error) { 103 if len(upstreams) == 0 { 104 return nil, fs.ErrorObjectNotFound 105 } 106 return p.epff(ctx, upstreams, path) 107 } 108 109 // SearchEntries is SEARCH category policy but receiving a set of candidate entries 110 func (p *EpFF) SearchEntries(entries ...upstream.Entry) (upstream.Entry, error) { 111 if len(entries) == 0 { 112 return nil, fs.ErrorObjectNotFound 113 } 114 return entries[0], nil 115 }