From e8883e9fdb5b5ca7c2a97f51064c94ae74430d93 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sun, 29 Oct 2017 11:00:56 +0000 Subject: [PATCH] vfs: factor flags into vfsflags and remove global variables --- cmd/cmount/fs.go | 11 +-- cmd/cmount/mount.go | 3 +- cmd/mount/dir.go | 8 +- cmd/mount/file.go | 10 +-- cmd/mount/fs.go | 3 +- cmd/mount/mount.go | 3 +- cmd/mountlib/mount.go | 4 +- cmd/mountlib/mounttest/fs.go | 6 +- vfs/dir.go | 21 +++-- vfs/file.go | 18 +++- vfs/read.go | 4 +- vfs/vfs.go | 90 +++++++------------ vfs/vfs_unix.go | 19 ---- vfs/vfsflags/vfsflags.go | 38 ++++++++ .../vfsflags_non_unix.go} | 2 +- vfs/vfsflags/vfsflags_unix.go | 19 ++++ 16 files changed, 144 insertions(+), 115 deletions(-) delete mode 100644 vfs/vfs_unix.go create mode 100644 vfs/vfsflags/vfsflags.go rename vfs/{vfs_non_unix.go => vfsflags/vfsflags_non_unix.go} (90%) create mode 100644 vfs/vfsflags/vfsflags_unix.go diff --git a/cmd/cmount/fs.go b/cmd/cmount/fs.go index 1f1afc486..642d4613d 100644 --- a/cmd/cmount/fs.go +++ b/cmd/cmount/fs.go @@ -14,6 +14,7 @@ import ( "github.com/billziss-gh/cgofuse/fuse" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/vfs" + "github.com/ncw/rclone/vfs/vfsflags" "github.com/pkg/errors" ) @@ -32,7 +33,7 @@ type FS struct { // NewFS makes a new FS func NewFS(f fs.Fs) *FS { fsys := &FS{ - VFS: vfs.New(f), + VFS: vfs.New(f, &vfsflags.Opt), f: f, openDirs: newOpenFiles(0x01), openFilesWr: newOpenFiles(0x02), @@ -201,19 +202,19 @@ func (fsys *FS) stat(node vfs.Node, stat *fuse.Stat_t) (errc int) { switch x := node.(type) { case *vfs.Dir: modTime = x.ModTime() - Mode = vfs.DirPerms | fuse.S_IFDIR + Mode = fsys.VFS.Opt.DirPerms | fuse.S_IFDIR case *vfs.File: modTime = x.ModTime() Size = uint64(x.Size()) Blocks = (Size + 511) / 512 - Mode = vfs.FilePerms | fuse.S_IFREG + Mode = fsys.VFS.Opt.FilePerms | fuse.S_IFREG } //stat.Dev = 1 stat.Ino = node.Inode() // FIXME do we need to set the inode number? stat.Mode = uint32(Mode) stat.Nlink = 1 - stat.Uid = vfs.UID - stat.Gid = vfs.GID + stat.Uid = fsys.VFS.Opt.UID + stat.Gid = fsys.VFS.Opt.GID //stat.Rdev stat.Size = int64(Size) t := fuse.NewTimespec(modTime) diff --git a/cmd/cmount/mount.go b/cmd/cmount/mount.go index 3bcedc7d6..2c946d54f 100644 --- a/cmd/cmount/mount.go +++ b/cmd/cmount/mount.go @@ -20,6 +20,7 @@ import ( "github.com/ncw/rclone/cmd/mountlib" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/vfs" + "github.com/ncw/rclone/vfs/vfsflags" "github.com/pkg/errors" ) @@ -70,7 +71,7 @@ func mountOptions(device string, mountpoint string) (options []string) { if mountlib.DefaultPermissions { options = append(options, "-o", "default_permissions") } - if vfs.ReadOnly { + if vfsflags.Opt.ReadOnly { options = append(options, "-o", "ro") } if mountlib.WritebackCache { diff --git a/cmd/mount/dir.go b/cmd/mount/dir.go index 036259840..16738c6d5 100644 --- a/cmd/mount/dir.go +++ b/cmd/mount/dir.go @@ -36,9 +36,9 @@ var _ fusefs.Node = (*Dir)(nil) // Attr updates the attributes of a directory func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) { defer fs.Trace(d, "")("attr=%+v, err=%v", a, &err) - a.Gid = vfs.GID - a.Uid = vfs.UID - a.Mode = os.ModeDir | vfs.DirPerms + a.Gid = d.VFS().Opt.GID + a.Uid = d.VFS().Opt.UID + a.Mode = os.ModeDir | d.VFS().Opt.DirPerms modTime := d.ModTime() a.Atime = modTime a.Mtime = modTime @@ -55,7 +55,7 @@ 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) (err error) { defer fs.Trace(d, "stat=%+v", req)("err=%v", &err) - if vfs.NoModTime { + if d.VFS().Opt.NoModTime { return nil } diff --git a/cmd/mount/file.go b/cmd/mount/file.go index 73b90b0c4..024acc2ee 100644 --- a/cmd/mount/file.go +++ b/cmd/mount/file.go @@ -27,9 +27,9 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) { modTime := f.File.ModTime() Size := uint64(f.File.Size()) Blocks := (Size + 511) / 512 - a.Gid = vfs.GID - a.Uid = vfs.UID - a.Mode = vfs.FilePerms + a.Gid = f.VFS().Opt.GID + a.Uid = f.VFS().Opt.UID + a.Mode = f.VFS().Opt.FilePerms a.Size = Size a.Atime = modTime a.Mtime = modTime @@ -45,7 +45,7 @@ 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) (err error) { defer fs.Trace(f, "a=%+v", req)("err=%v", &err) - if vfs.NoModTime { + if f.VFS().Opt.NoModTime { return nil } if req.Valid.MtimeNow() { @@ -64,7 +64,7 @@ func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR defer fs.Trace(f, "flags=%v", req.Flags)("fh=%v, err=%v", &fh, &err) switch { case req.Flags.IsReadOnly(): - if vfs.NoSeek { + if f.VFS().Opt.NoSeek { resp.Flags |= fuse.OpenNonSeekable } var rfh *vfs.ReadFileHandle diff --git a/cmd/mount/fs.go b/cmd/mount/fs.go index e2520d1be..8327d0e90 100644 --- a/cmd/mount/fs.go +++ b/cmd/mount/fs.go @@ -11,6 +11,7 @@ import ( fusefs "bazil.org/fuse/fs" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/vfs" + "github.com/ncw/rclone/vfs/vfsflags" "github.com/pkg/errors" "golang.org/x/net/context" ) @@ -27,7 +28,7 @@ var _ fusefs.FS = (*FS)(nil) // NewFS makes a new FS func NewFS(f fs.Fs) *FS { fsys := &FS{ - VFS: vfs.New(f), + VFS: vfs.New(f, &vfsflags.Opt), f: f, } return fsys diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go index 6d751282a..05f1d459d 100644 --- a/cmd/mount/mount.go +++ b/cmd/mount/mount.go @@ -14,6 +14,7 @@ import ( "github.com/ncw/rclone/cmd/mountlib" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/vfs" + "github.com/ncw/rclone/vfs/vfsflags" "github.com/pkg/errors" ) @@ -49,7 +50,7 @@ func mountOptions(device string) (options []fuse.MountOption) { if mountlib.DefaultPermissions { options = append(options, fuse.DefaultPermissions()) } - if vfs.ReadOnly { + if vfsflags.Opt.ReadOnly { options = append(options, fuse.ReadOnly()) } if mountlib.WritebackCache { diff --git a/cmd/mountlib/mount.go b/cmd/mountlib/mount.go index 6d7514d83..d8234978d 100644 --- a/cmd/mountlib/mount.go +++ b/cmd/mountlib/mount.go @@ -5,7 +5,7 @@ import ( "github.com/ncw/rclone/cmd" "github.com/ncw/rclone/fs" - "github.com/ncw/rclone/vfs" + "github.com/ncw/rclone/vfs/vfsflags" "github.com/spf13/cobra" ) @@ -163,7 +163,7 @@ like this: //flags.BoolVarP(&foreground, "foreground", "", foreground, "Do not detach.") // Add in the generic flags - vfs.AddFlags(flags) + vfsflags.AddFlags(flags) return commandDefintion } diff --git a/cmd/mountlib/mounttest/fs.go b/cmd/mountlib/mounttest/fs.go index 062b20c9d..6f700f33c 100644 --- a/cmd/mountlib/mounttest/fs.go +++ b/cmd/mountlib/mounttest/fs.go @@ -207,10 +207,10 @@ func (r *Run) readLocal(t *testing.T, dir dirMap, filepath string) { if fi.IsDir() { dir[name+"/"] = struct{}{} r.readLocal(t, dir, name) - assert.Equal(t, vfs.DirPerms, fi.Mode().Perm()) + assert.Equal(t, run.vfs.Opt.DirPerms, fi.Mode().Perm()) } else { dir[fmt.Sprintf("%s %d", name, fi.Size())] = struct{}{} - assert.Equal(t, vfs.FilePerms, fi.Mode().Perm()) + assert.Equal(t, run.vfs.Opt.FilePerms, fi.Mode().Perm()) } } } @@ -292,5 +292,5 @@ func TestRoot(t *testing.T) { fi, err := os.Lstat(run.mountPath) require.NoError(t, err) assert.True(t, fi.IsDir()) - assert.Equal(t, fi.Mode().Perm(), vfs.DirPerms) + assert.Equal(t, fi.Mode().Perm(), run.vfs.Opt.DirPerms) } diff --git a/vfs/dir.go b/vfs/dir.go index a3c209495..a21ea6dfc 100644 --- a/vfs/dir.go +++ b/vfs/dir.go @@ -169,7 +169,7 @@ func (d *Dir) _readDir() error { // fs.Debugf(d.path, "Reading directory") } else { age := when.Sub(d.read) - if age < d.vfs.dirCacheTime { + if age < d.vfs.Opt.DirCacheTime { return nil } fs.Debugf(d.path, "Re-reading directory (%v old)", age) @@ -260,7 +260,7 @@ func (d *Dir) Size() int64 { // SetModTime sets the modTime for this dir func (d *Dir) SetModTime(modTime time.Time) error { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return EROFS } d.mu.Lock() @@ -309,7 +309,7 @@ func (d *Dir) ReadDirAll() (items Nodes, err error) { // Create makes a new file func (d *Dir) Create(name string) (*File, *WriteFileHandle, error) { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return nil, nil, EROFS } path := path.Join(d.path, name) @@ -328,7 +328,7 @@ func (d *Dir) Create(name string) (*File, *WriteFileHandle, error) { // Mkdir creates a new directory func (d *Dir) Mkdir(name string) (*Dir, error) { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return nil, EROFS } path := path.Join(d.path, name) @@ -347,7 +347,7 @@ func (d *Dir) Mkdir(name string) (*Dir, error) { // Remove the directory func (d *Dir) Remove() error { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return EROFS } // Check directory is empty first @@ -375,7 +375,7 @@ func (d *Dir) Remove() error { // RemoveAll removes the directory and any contents recursively func (d *Dir) RemoveAll() error { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return EROFS } // Remove contents of the directory @@ -403,7 +403,7 @@ func (d *Dir) DirEntry() (entry fs.DirEntry) { // which must be a directory. The entry to be removed may correspond // to a file (unlink) or to a directory (rmdir). func (d *Dir) RemoveName(name string) error { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return EROFS } path := path.Join(d.path, name) @@ -418,7 +418,7 @@ func (d *Dir) RemoveName(name string) error { // Rename the file func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { - if d.vfs.readOnly { + if d.vfs.Opt.ReadOnly { return EROFS } oldPath := path.Join(d.path, oldName) @@ -494,3 +494,8 @@ func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { func (d *Dir) Fsync() error { return nil } + +// VFS returns the instance of the VFS +func (d *Dir) VFS() *VFS { + return d.vfs +} diff --git a/vfs/file.go b/vfs/file.go index e4f5a8c18..d0d2133eb 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -98,7 +98,7 @@ func (f *File) ModTime() (modTime time.Time) { f.mu.Lock() defer f.mu.Unlock() - if !f.d.vfs.noModTime { + if !f.d.vfs.Opt.NoModTime { // if o is nil it isn't valid yet or there are writers, so return the size so far if f.o == nil || f.writers != 0 { if !f.pendingModTime.IsZero() { @@ -126,7 +126,7 @@ func (f *File) Size() int64 { // SetModTime sets the modtime for the file func (f *File) SetModTime(modTime time.Time) error { - if f.d.vfs.readOnly { + if f.d.vfs.Opt.ReadOnly { return EROFS } f.mu.Lock() @@ -224,7 +224,7 @@ func (f *File) OpenRead() (fh *ReadFileHandle, err error) { // OpenWrite open the file for write func (f *File) OpenWrite() (fh *WriteFileHandle, err error) { - if f.d.vfs.readOnly { + if f.d.vfs.Opt.ReadOnly { return nil, EROFS } // if o is nil it isn't valid yet @@ -254,7 +254,7 @@ func (f *File) Fsync() error { // Remove the file func (f *File) Remove() error { - if f.d.vfs.readOnly { + if f.d.vfs.Opt.ReadOnly { return EROFS } err := f.o.Remove() @@ -276,3 +276,13 @@ func (f *File) RemoveAll() error { func (f *File) DirEntry() (entry fs.DirEntry) { return f.o } + +// Dir returns the directory this file is in +func (f *File) Dir() *Dir { + return f.d +} + +// VFS returns the instance of the VFS +func (f *File) VFS() *VFS { + return f.d.vfs +} diff --git a/vfs/read.go b/vfs/read.go index 4666cb630..d0aab4a5b 100644 --- a/vfs/read.go +++ b/vfs/read.go @@ -34,7 +34,7 @@ var ( func newReadFileHandle(f *File, o fs.Object) (*ReadFileHandle, error) { var hash *fs.MultiHasher var err error - if !f.d.vfs.noChecksum { + if !f.d.vfs.Opt.NoChecksum { hash, err = fs.NewMultiHasherTypes(o.Fs().Hashes()) if err != nil { fs.Errorf(o.Fs(), "newReadFileHandle hash error: %v", err) @@ -43,7 +43,7 @@ func newReadFileHandle(f *File, o fs.Object) (*ReadFileHandle, error) { fh := &ReadFileHandle{ o: o, - noSeek: f.d.vfs.noSeek, + noSeek: f.d.vfs.Opt.NoSeek, file: f, hash: hash, } diff --git a/vfs/vfs.go b/vfs/vfs.go index c69dd6264..0669d9d97 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -17,25 +17,6 @@ import ( "time" "github.com/ncw/rclone/fs" - "github.com/spf13/pflag" -) - -// Options set by command line flags -var ( - NoModTime = false - NoChecksum = false - NoSeek = false - DirCacheTime = 5 * 60 * time.Second - PollInterval = time.Minute - // mount options - ReadOnly = false - Umask = 0 - UID = ^uint32(0) // these values instruct WinFSP-FUSE to use the current user - GID = ^uint32(0) // overriden for non windows in mount_unix.go - // foreground = false - // default permissions for directories - modified by umask in New - DirPerms = os.FileMode(0777) - FilePerms = os.FileMode(0666) ) // Node represents either a directory (*Dir) or a file (*File) @@ -48,6 +29,7 @@ type Node interface { Remove() error RemoveAll() error DirEntry() fs.DirEntry + VFS() *VFS } // Check interfaces @@ -80,44 +62,45 @@ var ( // VFS represents the top level filing system type VFS struct { - f fs.Fs - root *Dir - noSeek bool // don't allow seeking if set - noChecksum bool // don't check checksums if set - readOnly bool // if set VFS is read only - noModTime bool // don't read mod times for files - dirCacheTime time.Duration // how long to consider directory listing cache valid + f fs.Fs + root *Dir + Opt Options } -// New creates a new VFS and root directory -func New(f fs.Fs) *VFS { +// Options is options for creating the vfs +type Options struct { + NoSeek bool // don't allow seeking if set + NoChecksum bool // don't check checksums if set + ReadOnly bool // if set VFS is read only + NoModTime bool // don't read mod times for files + DirCacheTime time.Duration // how long to consider directory listing cache valid + PollInterval time.Duration + Umask int + UID uint32 + GID uint32 + DirPerms os.FileMode + FilePerms os.FileMode +} + +// New creates a new VFS and root directory. If opt is nil, then +// defaults will be used. +func New(f fs.Fs, opt *Options) *VFS { fsDir := fs.NewDir("", time.Now()) vfs := &VFS{ - f: f, + f: f, + Opt: *opt, } - // Mask permissions - DirPerms = 0777 &^ os.FileMode(Umask) - FilePerms = 0666 &^ os.FileMode(Umask) - - if NoSeek { - vfs.noSeek = true - } - if NoChecksum { - vfs.noChecksum = true - } - if ReadOnly { - vfs.readOnly = true - } - if NoModTime { - vfs.noModTime = true - } - vfs.dirCacheTime = DirCacheTime + // Mask the permissions with the umask + vfs.Opt.DirPerms &= ^os.FileMode(vfs.Opt.Umask) + vfs.Opt.FilePerms &= ^os.FileMode(vfs.Opt.Umask) + // Create root directory vfs.root = newDir(vfs, f, nil, fsDir) - if PollInterval > 0 { - vfs.PollChanges(PollInterval) + // Start polling if required + if vfs.Opt.PollInterval > 0 { + vfs.PollChanges(vfs.Opt.PollInterval) } return vfs } @@ -190,14 +173,3 @@ func (vfs *VFS) Statfs() error { */ return nil } - -// AddFlags adds the non filing system specific flags to the command -func AddFlags(flags *pflag.FlagSet) { - flags.BoolVarP(&NoModTime, "no-modtime", "", NoModTime, "Don't read/write the modification time (can speed things up).") - flags.BoolVarP(&NoChecksum, "no-checksum", "", NoChecksum, "Don't compare checksums on up/download.") - flags.BoolVarP(&NoSeek, "no-seek", "", NoSeek, "Don't allow seeking in files.") - flags.DurationVarP(&DirCacheTime, "dir-cache-time", "", DirCacheTime, "Time to cache directory entries for.") - flags.DurationVarP(&PollInterval, "poll-interval", "", PollInterval, "Time to wait between polling for changes. Must be smaller than dir-cache-time. Only on supported remotes. Set to 0 to disable.") - flags.BoolVarP(&ReadOnly, "read-only", "", ReadOnly, "Mount read-only.") - platformFlags(flags) -} diff --git a/vfs/vfs_unix.go b/vfs/vfs_unix.go deleted file mode 100644 index a981f84a7..000000000 --- a/vfs/vfs_unix.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build linux darwin freebsd - -package vfs - -import ( - "github.com/spf13/pflag" - "golang.org/x/sys/unix" -) - -// add any extra platform specific flags -func platformFlags(flags *pflag.FlagSet) { - flags.IntVarP(&Umask, "umask", "", Umask, "Override the permission bits set by the filesystem.") - Umask = unix.Umask(0) // read the umask - unix.Umask(Umask) // set it back to what it was - UID = uint32(unix.Geteuid()) - GID = uint32(unix.Getegid()) - flags.Uint32VarP(&UID, "uid", "", UID, "Override the uid field set by the filesystem.") - flags.Uint32VarP(&GID, "gid", "", GID, "Override the gid field set by the filesystem.") -} diff --git a/vfs/vfsflags/vfsflags.go b/vfs/vfsflags/vfsflags.go new file mode 100644 index 000000000..053213079 --- /dev/null +++ b/vfs/vfsflags/vfsflags.go @@ -0,0 +1,38 @@ +// Package vfsflags implements command line flags to set up a vfs +package vfsflags + +import ( + "os" + "time" + + "github.com/ncw/rclone/vfs" + "github.com/spf13/pflag" +) + +// Options set by command line flags +var ( + Opt = vfs.Options{ + NoModTime: false, + NoChecksum: false, + NoSeek: false, + DirCacheTime: 5 * 60 * time.Second, + PollInterval: time.Minute, + ReadOnly: false, + Umask: 0, + UID: ^uint32(0), // these values instruct WinFSP-FUSE to use the current user + GID: ^uint32(0), // overriden for non windows in mount_unix.go + DirPerms: os.FileMode(0777), + FilePerms: os.FileMode(0666), + } +) + +// AddFlags adds the non filing system specific flags to the command +func AddFlags(flags *pflag.FlagSet) { + flags.BoolVarP(&Opt.NoModTime, "no-modtime", "", Opt.NoModTime, "Don't read/write the modification time (can speed things up).") + flags.BoolVarP(&Opt.NoChecksum, "no-checksum", "", Opt.NoChecksum, "Don't compare checksums on up/download.") + flags.BoolVarP(&Opt.NoSeek, "no-seek", "", Opt.NoSeek, "Don't allow seeking in files.") + flags.DurationVarP(&Opt.DirCacheTime, "dir-cache-time", "", Opt.DirCacheTime, "Time to cache directory entries for.") + flags.DurationVarP(&Opt.PollInterval, "poll-interval", "", Opt.PollInterval, "Time to wait between polling for changes. Must be smaller than dir-cache-time. Only on supported remotes. Set to 0 to disable.") + flags.BoolVarP(&Opt.ReadOnly, "read-only", "", Opt.ReadOnly, "Mount read-only.") + platformFlags(flags) +} diff --git a/vfs/vfs_non_unix.go b/vfs/vfsflags/vfsflags_non_unix.go similarity index 90% rename from vfs/vfs_non_unix.go rename to vfs/vfsflags/vfsflags_non_unix.go index 960f8a7fc..6e90fac77 100644 --- a/vfs/vfs_non_unix.go +++ b/vfs/vfsflags/vfsflags_non_unix.go @@ -1,6 +1,6 @@ // +build !linux,!darwin,!freebsd -package vfs +package vfsflags import ( "github.com/spf13/pflag" diff --git a/vfs/vfsflags/vfsflags_unix.go b/vfs/vfsflags/vfsflags_unix.go new file mode 100644 index 000000000..5b9b5f1ed --- /dev/null +++ b/vfs/vfsflags/vfsflags_unix.go @@ -0,0 +1,19 @@ +// +build linux darwin freebsd + +package vfsflags + +import ( + "github.com/spf13/pflag" + "golang.org/x/sys/unix" +) + +// add any extra platform specific flags +func platformFlags(flags *pflag.FlagSet) { + flags.IntVarP(&Opt.Umask, "umask", "", Opt.Umask, "Override the permission bits set by the filesystem.") + Opt.Umask = unix.Umask(0) // read the umask + unix.Umask(Opt.Umask) // set it back to what it was + Opt.UID = uint32(unix.Geteuid()) + Opt.GID = uint32(unix.Getegid()) + flags.Uint32VarP(&Opt.UID, "uid", "", Opt.UID, "Override the uid field set by the filesystem.") + flags.Uint32VarP(&Opt.GID, "gid", "", Opt.GID, "Override the gid field set by the filesystem.") +}