mirror of
https://github.com/rclone/rclone.git
synced 2025-08-12 06:59:29 +02:00
union: fix wrong behavior of NewFs, List and Purge
This commit is contained in:
@ -105,13 +105,16 @@ func clean(absPath string) string {
|
|||||||
func findEntry(ctx context.Context, f fs.Fs, remote string) fs.DirEntry {
|
func findEntry(ctx context.Context, f fs.Fs, remote string) fs.DirEntry {
|
||||||
remote = clean(remote)
|
remote = clean(remote)
|
||||||
dir := parentDir(remote)
|
dir := parentDir(remote)
|
||||||
|
entries, err := f.List(ctx, dir);
|
||||||
if remote == dir {
|
if remote == dir {
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// random modtime for root
|
// random modtime for root
|
||||||
randomNow := time.Unix(time.Now().Unix() - rand.Int63n(10000), 0)
|
randomNow := time.Unix(time.Now().Unix() - rand.Int63n(10000), 0)
|
||||||
return fs.NewDir("", randomNow)
|
return fs.NewDir("", randomNow)
|
||||||
}
|
}
|
||||||
found := false
|
found := false
|
||||||
entries, _ := f.List(ctx, dir);
|
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
eRemote := e.Remote()
|
eRemote := e.Remote()
|
||||||
if f.Features().CaseInsensitive {
|
if f.Features().CaseInsensitive {
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -337,15 +336,13 @@ func (f *Fs) Purge(ctx context.Context) error {
|
|||||||
return fs.ErrorCantPurge
|
return fs.ErrorCantPurge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, r := range f.upstreams {
|
upstreams, err := f.action(ctx, "")
|
||||||
// Can't Purge if any read-only upstreams
|
if err != nil {
|
||||||
if !r.IsWritable() {
|
return err
|
||||||
return fs.ErrorPermissionDenied
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
errs := make([]error, len(f.upstreams))
|
errs := make([]error, len(upstreams))
|
||||||
multithread(len(f.upstreams), func(i int){
|
multithread(len(upstreams), func(i int){
|
||||||
errs[i] = f.upstreams[i].Features().Purge(ctx)
|
errs[i] = upstreams[i].Features().Purge(ctx)
|
||||||
})
|
})
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -678,36 +675,35 @@ func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
|
|||||||
// This should return ErrDirNotFound if the directory isn't
|
// This should return ErrDirNotFound if the directory isn't
|
||||||
// found.
|
// found.
|
||||||
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
|
||||||
var found int32
|
|
||||||
entriess := make([][]upstream.Entry, len(f.upstreams))
|
entriess := make([][]upstream.Entry, len(f.upstreams))
|
||||||
errs := make([]error, len(f.upstreams))
|
errs := make([]error, len(f.upstreams))
|
||||||
multithread(len(f.upstreams), func(i int){
|
multithread(len(f.upstreams), func(i int){
|
||||||
u := f.upstreams[i]
|
u := f.upstreams[i]
|
||||||
entries, err := u.List(ctx, dir)
|
entries, err := u.List(ctx, dir)
|
||||||
if err != nil && err != fs.ErrorDirNotFound {
|
if err != nil {
|
||||||
errs[i] = err
|
errs[i] = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&found, 1)
|
|
||||||
uEntries := make([]upstream.Entry, len(entries))
|
uEntries := make([]upstream.Entry, len(entries))
|
||||||
for j, e := range entries {
|
for j, e := range entries {
|
||||||
uEntries[j], _ = u.WrapEntry(e)
|
uEntries[j], _ = u.WrapEntry(e)
|
||||||
}
|
}
|
||||||
entriess[i] = uEntries
|
entriess[i] = uEntries
|
||||||
})
|
})
|
||||||
if found == 0 {
|
found := false
|
||||||
|
for _, err := range errs {
|
||||||
|
if err == fs.ErrorDirNotFound {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
return nil, fs.ErrorDirNotFound
|
return nil, fs.ErrorDirNotFound
|
||||||
}
|
}
|
||||||
entries, err = f.mergeDirEntries(entriess)
|
return f.mergeDirEntries(entriess)
|
||||||
if err != nil {
|
|
||||||
return entries, err
|
|
||||||
}
|
|
||||||
for _, err := range errs {
|
|
||||||
if err != nil {
|
|
||||||
return entries, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewObject creates a new remote union file object
|
// NewObject creates a new remote union file object
|
||||||
@ -826,22 +822,33 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var upstreams []*upstream.Fs
|
upstreams := make([]*upstream.Fs, len(opt.Upstreams))
|
||||||
for i := range opt.Upstreams {
|
errs := make([]error, len(opt.Upstreams))
|
||||||
// Last remote first so we return the correct (last) matching fs in case of fs.ErrorIsFile
|
multithread(len(opt.Upstreams), func(i int) {
|
||||||
var u = opt.Upstreams[len(opt.Upstreams)-i-1]
|
u := opt.Upstreams[i]
|
||||||
uFs, err := upstream.New(u, root, time.Duration(opt.CacheTime) * time.Second)
|
upstreams[i], errs[i] = upstream.New(u, root, time.Duration(opt.CacheTime) * time.Second)
|
||||||
if err != nil {
|
})
|
||||||
|
var usedUpstreams []*upstream.Fs
|
||||||
|
var fserr error
|
||||||
|
for i, err := range errs {
|
||||||
|
if err != nil && err != fs.ErrorIsFile {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
upstreams = append(upstreams, uFs)
|
// Only the upstreams returns ErrorIsFile would be used if any
|
||||||
|
if err == fs.ErrorIsFile {
|
||||||
|
usedUpstreams = append(usedUpstreams, upstreams[i])
|
||||||
|
fserr = fs.ErrorIsFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fserr == nil {
|
||||||
|
usedUpstreams = upstreams
|
||||||
}
|
}
|
||||||
|
|
||||||
f := &Fs{
|
f := &Fs{
|
||||||
name: name,
|
name: name,
|
||||||
root: root,
|
root: root,
|
||||||
opt: *opt,
|
opt: *opt,
|
||||||
upstreams: upstreams,
|
upstreams: usedUpstreams,
|
||||||
}
|
}
|
||||||
f.actionPolicy, err = policy.Get(opt.ActionPolicy)
|
f.actionPolicy, err = policy.Get(opt.ActionPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -907,7 +914,7 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
}
|
}
|
||||||
f.hashSet = hashSet
|
f.hashSet = hashSet
|
||||||
|
|
||||||
return f, nil
|
return f, fserr
|
||||||
}
|
}
|
||||||
|
|
||||||
func parentDir(absPath string) string {
|
func parentDir(absPath string) string {
|
||||||
|
@ -90,11 +90,11 @@ func New(remote, root string, cacheTime time.Duration) (*Fs, error) {
|
|||||||
rootString = configName + ":" + rootString
|
rootString = configName + ":" + rootString
|
||||||
}
|
}
|
||||||
myFs, err := cache.Get(rootString)
|
myFs, err := cache.Get(rootString)
|
||||||
if err != nil {
|
if err != nil && err != fs.ErrorIsFile {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rFs.Fs = myFs
|
rFs.Fs = myFs
|
||||||
return rFs, nil
|
return rFs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapDirectory wraps a fs.Directory to include the info
|
// WrapDirectory wraps a fs.Directory to include the info
|
||||||
@ -144,6 +144,12 @@ func (o *Object) UpstreamFs() *Fs {
|
|||||||
return o.f
|
return o.f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnWrap returns the Object that this Object is wrapping or
|
||||||
|
// nil if it isn't wrapping anything
|
||||||
|
func (o *Object) UnWrap() fs.Object {
|
||||||
|
return o.Object
|
||||||
|
}
|
||||||
|
|
||||||
// IsCreatable return if the fs is allowed to create new objects
|
// IsCreatable return if the fs is allowed to create new objects
|
||||||
func (f *Fs) IsCreatable() bool {
|
func (f *Fs) IsCreatable() bool {
|
||||||
return f.creatable
|
return f.creatable
|
||||||
|
Reference in New Issue
Block a user