vfs/vfscache: fix IO error by recreating the cache file if it has been removed

_createFile opened the cache file with O_RDWR but not O_CREATE, relying
on the file already existing. When the file had been removed underneath
rclone - either by _checkObject dropping a stale entry during open, or by
external deletion - the open failed and surfaced a hard "IO error" to the
application instead of recreating the file. Add O_CREATE so the cache
self-heals in that case.
This commit is contained in:
Nick Craig-Wood
2026-07-03 12:14:21 +01:00
parent d66235d556
commit 6e0cde076a

View File

@@ -471,7 +471,10 @@ func (item *Item) _createFile(osPath string) (err error) {
}
item.modified = false
// t0 := time.Now()
fd, err := file.OpenFile(osPath, os.O_RDWR, 0600)
// Use O_CREATE so the cache file is recreated if it has been removed
// underneath us (e.g. _checkObject dropped a stale entry, or an external
// deletion), rather than failing the open with a hard IO error.
fd, err := file.OpenFile(osPath, os.O_RDWR|os.O_CREATE, 0600)
// fs.Debugf(item.name, "OpenFile took %v", time.Since(t0))
if err != nil {
return fmt.Errorf("vfs cache item: open failed: %w", err)
@@ -560,6 +563,10 @@ func (item *Item) open(o fs.Object) (err error) {
return nil
}
fs.Debugf(item.name, "vfs cache: cache file vanished during grace period, recreating")
// The backing file is gone, so any ranges are invalid.
item.info.Rs = nil
// It also can't be dirty if the data no longer exists.
item.info.Dirty = false
if item.fd != nil {
_ = item.fd.Close()
item.fd = nil