mirror of
https://github.com/rclone/rclone
synced 2025-01-02 02: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
|
// Check interface satsified
|
||||||
var _ fusefs.Node = (*Dir)(nil)
|
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 {
|
func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Gid = gid
|
a.Gid = gid
|
||||||
a.Uid = uid
|
a.Uid = uid
|
||||||
@ -183,6 +183,27 @@ func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
|
|||||||
return nil
|
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
|
// lookupNode calls lookup then makes sure the node is not nil in the DirEntry
|
||||||
func (d *Dir) lookupNode(leaf string) (item *DirEntry, err error) {
|
func (d *Dir) lookupNode(leaf string) (item *DirEntry, err error) {
|
||||||
item, err = d.lookup(leaf)
|
item, err = d.lookup(leaf)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -133,3 +134,20 @@ func TestDirRenameFullDir(t *testing.T) {
|
|||||||
run.rmdir(t, "dir")
|
run.rmdir(t, "dir")
|
||||||
run.checkDir(t, "")
|
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
|
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
|
// Update the size while writing
|
||||||
func (f *File) written(n int64) {
|
func (f *File) written(n int64) {
|
||||||
atomic.AddInt64(&f.size, n)
|
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
|
umask = unix.Umask(0) // read the umask
|
||||||
unix.Umask(umask) // set it back to what it was
|
unix.Umask(umask) // set it back to what it was
|
||||||
cmd.Root.AddCommand(commandDefintion)
|
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(&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().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.")
|
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 ###
|
### TODO ###
|
||||||
|
|
||||||
* Check hashes on upload/download
|
* Check hashes on upload/download
|
||||||
* Preserve timestamps
|
|
||||||
* Move directories
|
|
||||||
`,
|
`,
|
||||||
Run: func(command *cobra.Command, args []string) {
|
Run: func(command *cobra.Command, args []string) {
|
||||||
cmd.CheckArgs(2, 2, command, args)
|
cmd.CheckArgs(2, 2, command, args)
|
||||||
|
Loading…
Reference in New Issue
Block a user