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:
parent
216499d78b
commit
4dc030d081
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
30
cmd/mount/file_test.go
Normal 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")
|
||||
}
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user