vfs: factor flags into vfsflags and remove global variables

s3-about
Nick Craig-Wood 2017-10-29 11:00:56 +00:00
parent 1a8f824bad
commit e8883e9fdb
16 changed files with 144 additions and 115 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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)
}

View File

@ -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.")
}

38
vfs/vfsflags/vfsflags.go Normal file
View File

@ -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)
}

View File

@ -1,6 +1,6 @@
// +build !linux,!darwin,!freebsd
package vfs
package vfsflags
import (
"github.com/spf13/pflag"

View File

@ -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.")
}