vfs: fix incorrect modtime for mv into mount with --vfs-cache-modes write
When a file has its modtime set while it is open we delay setting the modtime until the file is closed. The file is then uploaded in Flush. In Release we check the cached file has been uploaded by comparing modtimes and or hashes and upload it again if it has changed. Before this change we forgot to change the time on the cached file when we updated the time file on the object, so this mean that Release reset the time to the wrong time and uploaded the file again on remotes which don't support hashes (eg crypt). The fix was to set the modtime of the cached file at the same time we set the modtime of the remote object. This means that the files check as identical in Release so it doesn't try to upload the file. This means that we avoid a double upload and the modtime is correct. See: https://forum.rclone.org/t/modification-time-with-vfs-cache/13906/8
This commit is contained in:
parent
7cf8ea354c
commit
84191ac6dc
3 changed files with 33 additions and 3 deletions
|
@ -381,6 +381,15 @@ func (c *cache) removeDir(dir string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// setModTime should be called to set the modification time of the cache file
|
||||
func (c *cache) setModTime(name string, modTime time.Time) {
|
||||
osPath := c.toOSPath(name)
|
||||
err := os.Chtimes(osPath, modTime, modTime)
|
||||
if err != nil {
|
||||
fs.Errorf(name, "Failed to set modification time of cached file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// cleanUp empties the cache of everything
|
||||
func (c *cache) cleanUp() error {
|
||||
return os.RemoveAll(c.root)
|
||||
|
|
14
vfs/file.go
14
vfs/file.go
|
@ -88,11 +88,17 @@ func (f *File) Name() (name string) {
|
|||
return f.leaf
|
||||
}
|
||||
|
||||
// _path returns the full path of the file
|
||||
// use when lock is held
|
||||
func (f *File) _path() string {
|
||||
return path.Join(f.d.path, f.leaf)
|
||||
}
|
||||
|
||||
// Path returns the full path of the file
|
||||
func (f *File) Path() string {
|
||||
f.mu.RLock()
|
||||
defer f.mu.RUnlock()
|
||||
return path.Join(f.d.path, f.leaf)
|
||||
return f._path()
|
||||
}
|
||||
|
||||
// osPath returns the full path of the file in the cache in OS format
|
||||
|
@ -372,6 +378,12 @@ func (f *File) _applyPendingModTime() error {
|
|||
return errors.New("Cannot apply ModTime, file object is not available")
|
||||
}
|
||||
|
||||
// set the time of the file in the cache
|
||||
if f.d.vfs.Opt.CacheMode != CacheModeOff {
|
||||
f.d.vfs.cache.setModTime(f._path(), f.pendingModTime)
|
||||
}
|
||||
|
||||
// set the time of the object
|
||||
err := f.o.SetModTime(context.TODO(), f.pendingModTime)
|
||||
switch err {
|
||||
case nil:
|
||||
|
|
|
@ -2,6 +2,7 @@ package vfs
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -687,7 +688,12 @@ func TestRWFileModTimeWithOpenWriters(t *testing.T) {
|
|||
err = fh.Node().SetModTime(mtime)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = fh.Close()
|
||||
// Using Flush/Release to mimic mount instead of Close
|
||||
|
||||
err = fh.Flush()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = fh.Release()
|
||||
require.NoError(t, err)
|
||||
|
||||
info, err := vfs.Stat("file1")
|
||||
|
@ -695,8 +701,11 @@ func TestRWFileModTimeWithOpenWriters(t *testing.T) {
|
|||
|
||||
if r.Fremote.Precision() != fs.ModTimeNotSupported {
|
||||
// avoid errors because of timezone differences
|
||||
assert.Equal(t, info.ModTime().Unix(), mtime.Unix())
|
||||
assert.Equal(t, info.ModTime().Unix(), mtime.Unix(), fmt.Sprintf("Time mismatch: %v != %v", info.ModTime(), mtime))
|
||||
}
|
||||
|
||||
file1 := fstest.NewItem("file1", "hi", mtime)
|
||||
fstest.CheckItems(t, r.Fremote, file1)
|
||||
}
|
||||
|
||||
func TestRWCacheRename(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue