Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
Nick Craig-Wood
4488bc0cd7 union: make server side copies possible from outside the union
Before this change, only server side copies within the union would be
permitted.

This change allows server side copies from outside the union to
happen, delegating the checking to the individual upstream backend.

The same change should be made to Move and DirMove

Fixes #6287
2022-09-12 13:27:22 +01:00
Nick Craig-Wood
404059fd95 operations: allow --server-side-across-configs to work between any backends
Before this change --server-side-across-configs would only work
between two backends of the same type.

This meant that server side copies from a backend to a union of that
backend didn't work where they really should have done.

Fixes #6287
2022-09-12 13:27:22 +01:00
2 changed files with 27 additions and 13 deletions

View file

@ -222,19 +222,19 @@ func (f *Fs) Purge(ctx context.Context, dir string) error {
//
// If it isn't possible then return fs.ErrorCantCopy
func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
srcObj, ok := src.(*Object)
if !ok {
fs.Debugf(src, "Can't copy - not same remote type")
return nil, fs.ErrorCantCopy
}
o := srcObj.UnWrapUpstream()
su := o.UpstreamFs()
if su.Features().Copy == nil {
return nil, fs.ErrorCantCopy
var srcFs fs.Info
if srcObj, ok := src.(*Object); ok {
// Have a union object - unwrap
o := srcObj.UnWrapUpstream()
srcFs = o.UpstreamFs()
src = o
} else {
// Have a non union object - it might be compatible with a union member
srcFs = src.Fs()
}
var du *upstream.Fs
for _, u := range f.upstreams {
if operations.Same(u.RootFs, su.RootFs) {
if u.Features().Copy != nil && operations.Same(u.RootFs, srcFs) {
du = u
}
}
@ -244,7 +244,7 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
if !du.IsCreatable() {
return nil, fs.ErrorPermissionDenied
}
co, err := du.Features().Copy(ctx, o, remote)
co, err := du.Features().Copy(ctx, src, remote)
if err != nil || co == nil {
return nil, err
}

View file

@ -383,6 +383,20 @@ func CommonHash(ctx context.Context, fa, fb fs.Info) (hash.Type, *fs.HashesOptio
return hashType, &fs.HashesOption{Hashes: common}
}
// Is it OK to server side move/copy from src to dst
func serverSideOK(ci *fs.ConfigInfo, fDst, fSrc fs.Info) bool {
if ci.ServerSideAcrossConfigs {
return true
}
if SameConfig(fSrc, fDst) {
return true
}
if SameRemoteType(fSrc, fDst) {
return fDst.Features().ServerSideAcrossConfigs
}
return false
}
// Copy src object to dst or f if nil. If dst is nil then it uses
// remote as the name of the new object.
//
@ -424,7 +438,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
return nil, accounting.ErrorMaxTransferLimitReachedGraceful
}
}
if doCopy := f.Features().Copy; doCopy != nil && (SameConfig(src.Fs(), f) || (SameRemoteType(src.Fs(), f) && (f.Features().ServerSideAcrossConfigs || ci.ServerSideAcrossConfigs))) {
if doCopy := f.Features().Copy; doCopy != nil && serverSideOK(ci, f, src.Fs()) {
in := tr.Account(ctx, nil) // account the transfer
in.ServerSideCopyStart()
newDst, err = doCopy(ctx, src, remote)
@ -619,7 +633,7 @@ func Move(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.
return newDst, nil
}
// See if we have Move available
if doMove := fdst.Features().Move; doMove != nil && (SameConfig(src.Fs(), fdst) || (SameRemoteType(src.Fs(), fdst) && (fdst.Features().ServerSideAcrossConfigs || ci.ServerSideAcrossConfigs))) {
if doMove := fdst.Features().Move; doMove != nil && serverSideOK(ci, fdst, src.Fs()) {
// Delete destination if it exists and is not the same file as src (could be same file while seemingly different if the remote is case insensitive)
if dst != nil && !SameObject(src, dst) {
err = DeleteFile(ctx, dst)