vfs: fix modtimes not updating when writing via cache - fixes #4763
This reads modtime from a dirty cache item if it exists. This mirrors the way reading the size works. This fixes the mod time not updating when the file is written, only when the writeback completes. See: https://forum.rclone.org/t/rclone-mount-and-changing-timestamps-after-writes/22629
This commit is contained in:
parent
c387eb8c09
commit
aea8776a43
3 changed files with 37 additions and 8 deletions
11
vfs/file.go
11
vfs/file.go
|
@ -300,6 +300,17 @@ func (f *File) ModTime() (modTime time.Time) {
|
|||
if d.vfs.Opt.NoModTime {
|
||||
return d.ModTime()
|
||||
}
|
||||
// Read the modtime from a dirty item if it exists
|
||||
if f.d.vfs.Opt.CacheMode >= vfscommon.CacheModeMinimal {
|
||||
if item := f.d.vfs.cache.DirtyItem(f._path()); item != nil {
|
||||
modTime, err := item.GetModTime()
|
||||
if err != nil {
|
||||
fs.Errorf(f._path(), "ModTime: Item GetModTime failed: %v", err)
|
||||
} else {
|
||||
return modTime
|
||||
}
|
||||
}
|
||||
}
|
||||
if !pendingModTime.IsZero() {
|
||||
return pendingModTime
|
||||
}
|
||||
|
|
|
@ -237,7 +237,8 @@ func (c *Cache) InUse(name string) bool {
|
|||
return item.inUse()
|
||||
}
|
||||
|
||||
// DirtyItem the Item if it exists in the cache and is Dirty
|
||||
// DirtyItem returns the Item if it exists in the cache **and** is
|
||||
// dirty otherwise it returns nil.
|
||||
//
|
||||
// name should be a remote path not an osPath
|
||||
func (c *Cache) DirtyItem(name string) (item *Item) {
|
||||
|
|
|
@ -359,17 +359,22 @@ func (item *Item) Truncate(size int64) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// _stat gets the current stat of the backing file
|
||||
//
|
||||
// Call with mutex held
|
||||
func (item *Item) _stat() (fi os.FileInfo, err error) {
|
||||
if item.fd != nil {
|
||||
return item.fd.Stat()
|
||||
}
|
||||
osPath := item.c.toOSPath(item.name) // No locking in Cache
|
||||
return os.Stat(osPath)
|
||||
}
|
||||
|
||||
// _getSize gets the current size of the item and updates item.info.Size
|
||||
//
|
||||
// Call with mutex held
|
||||
func (item *Item) _getSize() (size int64, err error) {
|
||||
var fi os.FileInfo
|
||||
if item.fd != nil {
|
||||
fi, err = item.fd.Stat()
|
||||
} else {
|
||||
osPath := item.c.toOSPath(item.name) // No locking in Cache
|
||||
fi, err = os.Stat(osPath)
|
||||
}
|
||||
fi, err := item._stat()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) && item.o != nil {
|
||||
size = item.o.Size()
|
||||
|
@ -1187,6 +1192,18 @@ func (item *Item) setModTime(modTime time.Time) {
|
|||
item.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetModTime of the cache file
|
||||
func (item *Item) GetModTime() (modTime time.Time, err error) {
|
||||
// defer log.Trace(item.name, "modTime=%v", modTime)("")
|
||||
item.mu.Lock()
|
||||
defer item.mu.Unlock()
|
||||
fi, err := item._stat()
|
||||
if err == nil {
|
||||
modTime = fi.ModTime()
|
||||
}
|
||||
return modTime, nil
|
||||
}
|
||||
|
||||
// ReadAt bytes from the file at off
|
||||
func (item *Item) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
n = 0
|
||||
|
|
Loading…
Reference in a new issue