1
mirror of https://github.com/rclone/rclone synced 2024-12-29 22:26:24 +01:00

implement ModTime via FUSE for remotes that support it (fixes #1197)

This commit is contained in:
Stefan Breunig 2017-03-23 20:41:21 +01:00 committed by Stefan Breunig
parent 216499d78b
commit 4dc030d081
5 changed files with 112 additions and 4 deletions

View File

@ -169,7 +169,7 @@ func (d *Dir) isEmpty() (bool, error) {
// Check interface satsified
var _ fusefs.Node = (*Dir)(nil)
// Attr updates the attribes of a directory
// Attr updates the attributes of a directory
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
a.Gid = gid
a.Uid = uid
@ -183,6 +183,27 @@ func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
return nil
}
// Check interface satisfied
var _ fusefs.NodeSetattrer = (*Dir)(nil)
// Setattr handles attribute changes from FUSE. Currently supports ModTime only.
func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
if noModTime {
return nil
}
d.mu.Lock()
defer d.mu.Unlock()
if req.Valid.MtimeNow() {
d.modTime = time.Now()
} else if req.Valid.Mtime() {
d.modTime = req.Mtime
}
return nil
}
// lookupNode calls lookup then makes sure the node is not nil in the DirEntry
func (d *Dir) lookupNode(leaf string) (item *DirEntry, err error) {
item, err = d.lookup(leaf)

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -133,3 +134,20 @@ func TestDirRenameFullDir(t *testing.T) {
run.rmdir(t, "dir")
run.checkDir(t, "")
}
func TestDirModTime(t *testing.T) {
run.skipIfNoFUSE(t)
run.mkdir(t, "dir")
mtime := time.Date(2012, 11, 18, 17, 32, 31, 0, time.UTC)
err := os.Chtimes(run.path("dir"), mtime, mtime)
require.NoError(t, err)
info, err := os.Stat(run.path("dir"))
require.NoError(t, err)
// avoid errors because of timezone differences
assert.Equal(t, info.ModTime().Unix(), mtime.Unix())
run.rmdir(t, "dir")
}

View File

@ -74,6 +74,47 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) error {
return nil
}
// Check interface satisfied
var _ fusefs.NodeSetattrer = (*File)(nil)
// Setattr handles attribute changes from FUSE. Currently supports ModTime only.
func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
if noModTime {
return nil
}
// if o is nil it isn't valid yet
o, err := f.waitForValidObject()
if err != nil {
return err
}
f.mu.Lock()
defer f.mu.Unlock()
var newTime time.Time
if req.Valid.MtimeNow() {
newTime = time.Now()
} else if req.Valid.Mtime() {
newTime = req.Mtime
}
if !newTime.IsZero() {
err := o.SetModTime(newTime)
switch err {
case nil:
fs.Debugf(o, "File.Setattr ModTime OK")
case fs.ErrorCantSetModTime:
// do nothing, in order to not break "touch somefile" if it exists already
default:
fs.Errorf(o, "File.Setattr ModTime error: %v", err)
return err
}
}
return nil
}
// Update the size while writing
func (f *File) written(n int64) {
atomic.AddInt64(&f.size, n)

30
cmd/mount/file_test.go Normal file
View File

@ -0,0 +1,30 @@
// +build linux darwin freebsd
package mount
import (
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFileModTime(t *testing.T) {
run.skipIfNoFUSE(t)
run.createFile(t, "file", "123")
mtime := time.Date(2012, 11, 18, 17, 32, 31, 0, time.UTC)
err := os.Chtimes(run.path("file"), mtime, mtime)
require.NoError(t, err)
info, err := os.Stat(run.path("file"))
require.NoError(t, err)
// avoid errors because of timezone differences
assert.Equal(t, info.ModTime().Unix(), mtime.Unix())
run.rm(t, "file")
}

View File

@ -46,7 +46,7 @@ func init() {
umask = unix.Umask(0) // read the umask
unix.Umask(umask) // set it back to what it was
cmd.Root.AddCommand(commandDefintion)
commandDefintion.Flags().BoolVarP(&noModTime, "no-modtime", "", noModTime, "Don't read the modification time (can speed things up).")
commandDefintion.Flags().BoolVarP(&noModTime, "no-modtime", "", noModTime, "Don't read/write the modification time (can speed things up).")
commandDefintion.Flags().BoolVarP(&debugFUSE, "debug-fuse", "", debugFUSE, "Debug the FUSE internals - needs -v.")
commandDefintion.Flags().BoolVarP(&noSeek, "no-seek", "", noSeek, "Don't allow seeking in files.")
commandDefintion.Flags().DurationVarP(&dirCacheTime, "dir-cache-time", "", dirCacheTime, "Time to cache directory entries for.")
@ -130,8 +130,6 @@ files to be visible in the mount.
### TODO ###
* Check hashes on upload/download
* Preserve timestamps
* Move directories
`,
Run: func(command *cobra.Command, args []string) {
cmd.CheckArgs(2, 2, command, args)