mirror of
https://github.com/rclone/rclone.git
synced 2026-05-12 18:38:00 -04:00
vfscache: fix grace timer reusing stale fd after _checkObject removes cache file
Before this change when a cache item was in its grace period (with HandleCaching) and the file is reopened, _checkObject runs before the grace timer recovery check. If the remote object's fingerprint changed _checkObject removes the cache file from disk. However the grace recovery path still reused the now-stale fd pointing to a deleted inode, skipping _createFile entirely. This left no cache file on disk, causing cache.Exists() to return false and breaking rename-while-writing logic. Fix this by checking the cache file still exists before reusing the fd in grace recovery. If the file was removed, close the stale fd and downloaders and fall through to _createFile. Also update the fingerprint in item.rename after setting the new object, preventing unnecessary cache invalidation when a file is reopened after a rename. This was discovered in the integration tests on backends that update modtime on rename (like mailru).
This commit is contained in:
@@ -541,9 +541,26 @@ func (item *Item) open(o fs.Object) (err error) {
|
||||
if item.graceTimer != nil {
|
||||
item.graceTimer.Stop()
|
||||
item.graceTimer = nil
|
||||
// fd and downloaders still alive - reuse them
|
||||
// _checkObject already called above
|
||||
return nil
|
||||
// If the cache file still exists, reuse fd and downloaders.
|
||||
// _checkObject (called above) may have removed the cache
|
||||
// file if the remote fingerprint changed (e.g. modtime
|
||||
// changed during a rename/move). In that case we must
|
||||
// close the stale fd and fall through to _createFile.
|
||||
if item._exists() {
|
||||
return nil
|
||||
}
|
||||
fs.Debugf(item.name, "vfs cache: cache file vanished during grace period, recreating")
|
||||
if item.fd != nil {
|
||||
_ = item.fd.Close()
|
||||
item.fd = nil
|
||||
}
|
||||
if item.downloaders != nil {
|
||||
dls := item.downloaders
|
||||
item.downloaders = nil
|
||||
item.mu.Unlock()
|
||||
_ = dls.Close(nil)
|
||||
item.mu.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
err = item._createFile(osPath)
|
||||
@@ -1486,6 +1503,7 @@ func (item *Item) rename(name string, newName string, newObj fs.Object) (err err
|
||||
// Set internal state
|
||||
item.name = newName
|
||||
item.o = newObj
|
||||
item._updateFingerprint()
|
||||
|
||||
// Rename cache file if it exists
|
||||
err = rename(item.c.toOSPath(name), item.c.toOSPath(newName)) // No locking in Cache
|
||||
|
||||
Reference in New Issue
Block a user