vfs: fix open file renaming on drive when using --vfs-cache-mode writes

Before this change, when uploading files from the VFS cache which were
pending a rename, rclone would use the new path of the object when
specifiying the destination remote.  This didn't cause a problem with
most backends as the subsequent rename did nothing, however with the
drive backend, since it updates objects, the incorrect Remote was
embedded in the object.  This caused the rename to apparently succeed
but the object be at the wrong location.

The fix for this was to make sure we upload to the path stored in the
object if available.

This problem was spotted by the new rename tests for the VFS layer.
s3-about
Nick Craig-Wood 2020-01-13 17:37:54 +00:00
parent 5f822f2660
commit 63128834da
2 changed files with 16 additions and 8 deletions

View File

@ -150,13 +150,6 @@ func (f *File) rename(ctx context.Context, destDir *Dir, newName string) error {
newPath := path.Join(destDir.path, newName)
renameCall := func(ctx context.Context) error {
f.mu.RLock()
o := f.o
f.mu.RUnlock()
if o == nil {
return errors.New("Cannot rename: file object is not available")
}
// chain rename calls if any
if oldPendingRenameFun != nil {
err := oldPendingRenameFun(ctx)
@ -165,6 +158,16 @@ func (f *File) rename(ctx context.Context, destDir *Dir, newName string) error {
}
}
f.mu.RLock()
o := f.o
f.mu.RUnlock()
if o == nil {
return errors.New("Cannot rename: file object is not available")
}
if o.Remote() == newPath {
return nil // no need to rename
}
// do the move of the remote object
dstOverwritten, _ := d.f.NewObject(ctx, newPath)
newObject, err := operations.Move(ctx, d.f, dstOverwritten, newPath, o)

View File

@ -284,7 +284,12 @@ func (fh *RWFileHandle) flushWrites(closeFile bool) error {
return err
}
o, err := copyObj(fh.d.vfs.f, fh.file.getObject(), fh.file.Path(), cacheObj)
objPath := fh.file.Path()
objOld := fh.file.getObject()
if objOld != nil {
objPath = objOld.Remote() // use the path of the actual object if available
}
o, err := copyObj(fh.d.vfs.f, objOld, objPath, cacheObj)
if err != nil {
err = errors.Wrap(err, "failed to transfer file from cache to remote")
fs.Errorf(fh.logPrefix(), "%v", err)