From 2a40f000770851fb0b227855e763d4108f1dd612 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 19 Apr 2021 23:10:16 +0100 Subject: [PATCH] vfs: fix a code path which allows dirty data to be removed causing data loss Before this change the VFS layer could remove a locally cached file even if it had data which needed to be written back, thus causing data loss. See: https://forum.rclone.org/t/rclone-1-55-doesnt-save-file-changes-if-the-file-has-been-reopened-during-upload-google-drive-mount/23646 --- vfs/vfscache/item.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/vfs/vfscache/item.go b/vfs/vfscache/item.go index b7f6f0700..7c42563c8 100644 --- a/vfs/vfscache/item.go +++ b/vfs/vfscache/item.go @@ -774,6 +774,9 @@ func (item *Item) reload(ctx context.Context) error { // check the fingerprint of an object and update the item or delete // the cached file accordingly // +// If we have local modifications then they take precedence +// over a change in the remote +// // It ensures the file is the correct size for the object // // call with lock held @@ -781,8 +784,12 @@ func (item *Item) _checkObject(o fs.Object) error { if o == nil { if item.info.Fingerprint != "" { // no remote object && local object - // remove local object - item._remove("stale (remote deleted)") + // remove local object unless dirty + if !item.info.Dirty { + item._remove("stale (remote deleted)") + } else { + fs.Debugf(item.name, "vfs cache: remote object has gone but local object modified - keeping it") + } } else { // no remote object && no local object // OK @@ -793,8 +800,12 @@ func (item *Item) _checkObject(o fs.Object) error { if item.info.Fingerprint != "" { // remote object && local object if remoteFingerprint != item.info.Fingerprint { - fs.Debugf(item.name, "vfs cache: removing cached entry as stale (remote fingerprint %q != cached fingerprint %q)", remoteFingerprint, item.info.Fingerprint) - item._remove("stale (remote is different)") + if !item.info.Dirty { + fs.Debugf(item.name, "vfs cache: removing cached entry as stale (remote fingerprint %q != cached fingerprint %q)", remoteFingerprint, item.info.Fingerprint) + item._remove("stale (remote is different)") + } else { + fs.Debugf(item.name, "vfs cache: remote object has changed but local object modified - keeping it (remote fingerprint %q != cached fingerprint %q)", remoteFingerprint, item.info.Fingerprint) + } } } else { // remote object && no local object