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 // If it isn't possible then return fs.ErrorCantCopy
func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
srcObj, ok := src.(*Object) var srcFs fs.Info
if !ok { if srcObj, ok := src.(*Object); ok {
fs.Debugf(src, "Can't copy - not same remote type") // Have a union object - unwrap
return nil, fs.ErrorCantCopy o := srcObj.UnWrapUpstream()
} srcFs = o.UpstreamFs()
o := srcObj.UnWrapUpstream() src = o
su := o.UpstreamFs() } else {
if su.Features().Copy == nil { // Have a non union object - it might be compatible with a union member
return nil, fs.ErrorCantCopy srcFs = src.Fs()
} }
var du *upstream.Fs var du *upstream.Fs
for _, u := range f.upstreams { for _, u := range f.upstreams {
if operations.Same(u.RootFs, su.RootFs) { if u.Features().Copy != nil && operations.Same(u.RootFs, srcFs) {
du = u du = u
} }
} }
@ -244,7 +244,7 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
if !du.IsCreatable() { if !du.IsCreatable() {
return nil, fs.ErrorPermissionDenied 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 { if err != nil || co == nil {
return nil, err 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} 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 // Copy src object to dst or f if nil. If dst is nil then it uses
// remote as the name of the new object. // 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 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 := tr.Account(ctx, nil) // account the transfer
in.ServerSideCopyStart() in.ServerSideCopyStart()
newDst, err = doCopy(ctx, src, remote) 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 return newDst, nil
} }
// See if we have Move available // 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) // 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) { if dst != nil && !SameObject(src, dst) {
err = DeleteFile(ctx, dst) err = DeleteFile(ctx, dst)