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  }