github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/union/policy/epmfs.go (about) 1 package policy 2 3 import ( 4 "context" 5 6 "github.com/rclone/rclone/backend/union/upstream" 7 "github.com/rclone/rclone/fs" 8 ) 9 10 func init() { 11 registerPolicy("epmfs", &EpMfs{}) 12 } 13 14 // EpMfs stands for existing path, most free space 15 // Of all the candidates on which the path exists choose the one with the most free space. 16 type EpMfs struct { 17 EpAll 18 } 19 20 func (p *EpMfs) mfs(upstreams []*upstream.Fs) (*upstream.Fs, error) { 21 var maxFreeSpace int64 22 var mfsupstream *upstream.Fs 23 for _, u := range upstreams { 24 space, err := u.GetFreeSpace() 25 if err != nil { 26 fs.LogPrintf(fs.LogLevelNotice, nil, 27 "Free Space is not supported for upstream %s, treating as infinite", u.Name()) 28 } 29 if maxFreeSpace < space { 30 maxFreeSpace = space 31 mfsupstream = u 32 } 33 } 34 if mfsupstream == nil { 35 return nil, fs.ErrorObjectNotFound 36 } 37 return mfsupstream, nil 38 } 39 40 func (p *EpMfs) mfsEntries(entries []upstream.Entry) (upstream.Entry, error) { 41 var maxFreeSpace int64 42 var mfsEntry upstream.Entry 43 for _, e := range entries { 44 space, err := e.UpstreamFs().GetFreeSpace() 45 if err != nil { 46 fs.LogPrintf(fs.LogLevelNotice, nil, 47 "Free Space is not supported for upstream %s, treating as infinite", e.UpstreamFs().Name()) 48 } 49 if maxFreeSpace < space { 50 maxFreeSpace = space 51 mfsEntry = e 52 } 53 } 54 return mfsEntry, nil 55 } 56 57 // Action category policy, governing the modification of files and directories 58 func (p *EpMfs) Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 59 upstreams, err := p.EpAll.Action(ctx, upstreams, path) 60 if err != nil { 61 return nil, err 62 } 63 u, err := p.mfs(upstreams) 64 return []*upstream.Fs{u}, err 65 } 66 67 // ActionEntries is ACTION category policy but receiving a set of candidate entries 68 func (p *EpMfs) ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 69 entries, err := p.EpAll.ActionEntries(entries...) 70 if err != nil { 71 return nil, err 72 } 73 e, err := p.mfsEntries(entries) 74 return []upstream.Entry{e}, err 75 } 76 77 // Create category policy, governing the creation of files and directories 78 func (p *EpMfs) Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 79 upstreams, err := p.EpAll.Create(ctx, upstreams, path) 80 if err != nil { 81 return nil, err 82 } 83 u, err := p.mfs(upstreams) 84 return []*upstream.Fs{u}, err 85 } 86 87 // CreateEntries is CREATE category policy but receiving a set of candidate entries 88 func (p *EpMfs) CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 89 entries, err := p.EpAll.CreateEntries(entries...) 90 if err != nil { 91 return nil, err 92 } 93 e, err := p.mfsEntries(entries) 94 return []upstream.Entry{e}, err 95 } 96 97 // Search category policy, governing the access to files and directories 98 func (p *EpMfs) Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error) { 99 if len(upstreams) == 0 { 100 return nil, fs.ErrorObjectNotFound 101 } 102 upstreams, err := p.epall(ctx, upstreams, path) 103 if err != nil { 104 return nil, err 105 } 106 return p.mfs(upstreams) 107 } 108 109 // SearchEntries is SEARCH category policy but receiving a set of candidate entries 110 func (p *EpMfs) SearchEntries(entries ...upstream.Entry) (upstream.Entry, error) { 111 if len(entries) == 0 { 112 return nil, fs.ErrorObjectNotFound 113 } 114 return p.mfsEntries(entries) 115 }