mirror of
https://github.com/rclone/rclone.git
synced 2024-12-05 23:44:24 +08:00
130 lines
3.1 KiB
Go
130 lines
3.1 KiB
Go
|
package policy
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"math/rand"
|
||
|
"path"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/rclone/rclone/backend/union/upstream"
|
||
|
"github.com/rclone/rclone/fs"
|
||
|
)
|
||
|
|
||
|
var policies = make(map[string]Policy)
|
||
|
|
||
|
// Policy is the interface of a set of defined behavior choosing
|
||
|
// the upstream Fs to operate on
|
||
|
type Policy interface {
|
||
|
// Action category policy, governing the modification of files and directories
|
||
|
Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error)
|
||
|
|
||
|
// Create category policy, governing the creation of files and directories
|
||
|
Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error)
|
||
|
|
||
|
// Search category policy, governing the access to files and directories
|
||
|
Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error)
|
||
|
|
||
|
// ActionEntries is ACTION category policy but receving a set of candidate entries
|
||
|
ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error)
|
||
|
|
||
|
// CreateEntries is CREATE category policy but receving a set of candidate entries
|
||
|
CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error)
|
||
|
|
||
|
// SearchEntries is SEARCH category policy but receving a set of candidate entries
|
||
|
SearchEntries(entries ...upstream.Entry) (upstream.Entry, error)
|
||
|
}
|
||
|
|
||
|
func registerPolicy(name string, p Policy) {
|
||
|
policies[strings.ToLower(name)] = p
|
||
|
}
|
||
|
|
||
|
// Get a Policy from the list
|
||
|
func Get(name string) (Policy, error) {
|
||
|
p, ok := policies[strings.ToLower(name)]
|
||
|
if !ok {
|
||
|
return nil, errors.Errorf("didn't find policy called %q", name)
|
||
|
}
|
||
|
return p, nil
|
||
|
}
|
||
|
|
||
|
func filterRO(ufs []*upstream.Fs) (wufs []*upstream.Fs) {
|
||
|
for _, u := range ufs {
|
||
|
if u.IsWritable() {
|
||
|
wufs = append(wufs, u)
|
||
|
}
|
||
|
}
|
||
|
return wufs
|
||
|
}
|
||
|
|
||
|
func filterROEntries(ue []upstream.Entry) (wue []upstream.Entry) {
|
||
|
for _, e := range ue {
|
||
|
if e.UpstreamFs().IsWritable() {
|
||
|
wue = append(wue, e)
|
||
|
}
|
||
|
}
|
||
|
return wue
|
||
|
}
|
||
|
|
||
|
func filterNC(ufs []*upstream.Fs) (wufs []*upstream.Fs) {
|
||
|
for _, u := range ufs {
|
||
|
if u.IsCreatable() {
|
||
|
wufs = append(wufs, u)
|
||
|
}
|
||
|
}
|
||
|
return wufs
|
||
|
}
|
||
|
|
||
|
func filterNCEntries(ue []upstream.Entry) (wue []upstream.Entry) {
|
||
|
for _, e := range ue {
|
||
|
if e.UpstreamFs().IsCreatable() {
|
||
|
wue = append(wue, e)
|
||
|
}
|
||
|
}
|
||
|
return wue
|
||
|
}
|
||
|
|
||
|
func parentDir(absPath string) string {
|
||
|
parent := path.Dir(strings.TrimRight(absPath, "/"))
|
||
|
if parent == "." {
|
||
|
parent = ""
|
||
|
}
|
||
|
return parent
|
||
|
}
|
||
|
|
||
|
func clean(absPath string) string {
|
||
|
cleanPath := path.Clean(absPath)
|
||
|
if cleanPath == "." {
|
||
|
cleanPath = ""
|
||
|
}
|
||
|
return cleanPath
|
||
|
}
|
||
|
|
||
|
func findEntry(ctx context.Context, f fs.Fs, remote string) fs.DirEntry {
|
||
|
remote = clean(remote)
|
||
|
dir := parentDir(remote)
|
||
|
entries, err := f.List(ctx, dir)
|
||
|
if remote == dir {
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
// random modtime for root
|
||
|
randomNow := time.Unix(time.Now().Unix()-rand.Int63n(10000), 0)
|
||
|
return fs.NewDir("", randomNow)
|
||
|
}
|
||
|
found := false
|
||
|
for _, e := range entries {
|
||
|
eRemote := e.Remote()
|
||
|
if f.Features().CaseInsensitive {
|
||
|
found = strings.EqualFold(remote, eRemote)
|
||
|
} else {
|
||
|
found = (remote == eRemote)
|
||
|
}
|
||
|
if found {
|
||
|
return e
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|