diff --git a/fs/object/object.go b/fs/object/object.go index 01b38f57a..a8346edee 100644 --- a/fs/object/object.go +++ b/fs/object/object.go @@ -195,6 +195,7 @@ type MemoryObject struct { modTime time.Time content []byte meta fs.Metadata + fs fs.Fs } // NewMemoryObject returns an in memory Object with the modTime and content passed in @@ -203,6 +204,7 @@ func NewMemoryObject(remote string, modTime time.Time, content []byte) *MemoryOb remote: remote, modTime: modTime, content: content, + fs: MemoryFs, } } @@ -219,7 +221,16 @@ func (o *MemoryObject) Content() []byte { // Fs returns read only access to the Fs that this object is part of func (o *MemoryObject) Fs() fs.Info { - return MemoryFs + return o.fs +} + +// SetFs sets the Fs that this memory object thinks it is part of +// It will ignore nil f +func (o *MemoryObject) SetFs(f fs.Fs) *MemoryObject { + if f != nil { + o.fs = f + } + return o } // Remote returns the remote path diff --git a/fs/operations/copy.go b/fs/operations/copy.go index 41605e901..43afc5f01 100644 --- a/fs/operations/copy.go +++ b/fs/operations/copy.go @@ -180,7 +180,11 @@ func (c *copy) rcat(ctx context.Context, in io.ReadCloser) (actionTaken string, } // NB Rcat closes in0 - newDst, err = Rcat(ctx, c.f, c.remoteForCopy, in, c.src.ModTime(ctx), meta) + fsrc, ok := c.src.Fs().(fs.Fs) + if !ok { + fsrc = nil + } + newDst, err = rcatSrc(ctx, c.f, c.remoteForCopy, in, c.src.ModTime(ctx), meta, fsrc) if c.doUpdate { actionTaken = "Copied (Rcat, replaced existing)" } else { diff --git a/fs/operations/operations.go b/fs/operations/operations.go index 8a7eb339b..59877bcc8 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -1270,6 +1270,13 @@ func Cat(ctx context.Context, f fs.Fs, w io.Writer, offset, count int64, sep []b // Rcat reads data from the Reader until EOF and uploads it to a file on remote func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, modTime time.Time, meta fs.Metadata) (dst fs.Object, err error) { + return rcatSrc(ctx, fdst, dstFileName, in, modTime, meta, nil) +} + +// rcatSrc reads data from the Reader until EOF and uploads it to a file on remote +// +// Pass in fsrc if known or nil if not +func rcatSrc(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, modTime time.Time, meta fs.Metadata, fsrc fs.Fs) (dst fs.Object, err error) { ci := fs.GetConfig(ctx) tr := accounting.Stats(ctx).NewTransferRemoteSize(dstFileName, -1, nil, fdst) defer func() { @@ -1322,7 +1329,7 @@ func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, buf := make([]byte, ci.StreamingUploadCutoff) if n, err := io.ReadFull(trackingIn, buf); err == io.EOF || err == io.ErrUnexpectedEOF { fs.Debugf(fdst, "File to upload is small (%d bytes), uploading instead of streaming", n) - src := object.NewMemoryObject(dstFileName, modTime, buf[:n]).WithMetadata(meta) + src := object.NewMemoryObject(dstFileName, modTime, buf[:n]).WithMetadata(meta).SetFs(fsrc) return Copy(ctx, fdst, nil, dstFileName, src) } @@ -1355,7 +1362,7 @@ func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, return nil, err } - objInfo := object.NewStaticObjectInfo(dstFileName, modTime, -1, false, nil, nil).WithMetadata(meta) + objInfo := object.NewStaticObjectInfo(dstFileName, modTime, -1, false, nil, fsrc).WithMetadata(meta) if dst, err = fStreamTo.Features().PutStream(ctx, in, objInfo, options...); err != nil { return dst, err }