From 5c91623148e271c02014c36907735003277b948b Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 9 Sep 2016 08:39:19 +0100 Subject: [PATCH] mount: Implement FUSE mount options - fixes #653 --- cmd/mount/dir.go | 2 ++ cmd/mount/file.go | 2 ++ cmd/mount/fs.go | 38 +++++++++++++++++++++++++++++------- cmd/mount/mount.go | 48 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/cmd/mount/dir.go b/cmd/mount/dir.go index e99c71ca2..0ec53e888 100644 --- a/cmd/mount/dir.go +++ b/cmd/mount/dir.go @@ -130,6 +130,8 @@ var _ fusefs.Node = (*Dir)(nil) // Attr updates the attribes of a directory func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error { fs.Debug(d.path, "Dir.Attr") + a.Gid = gid + a.Uid = uid a.Mode = os.ModeDir | dirPerms // FIXME include Valid so get some caching? Also mtime return nil diff --git a/cmd/mount/file.go b/cmd/mount/file.go index c287be687..73535dccf 100644 --- a/cmd/mount/file.go +++ b/cmd/mount/file.go @@ -46,6 +46,8 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) error { f.mu.Lock() defer f.mu.Unlock() fs.Debug(f.o, "File.Attr") + a.Gid = gid + a.Uid = uid a.Mode = filePerms // if o is nil it isn't valid yet, so return the size so far if f.o == nil { diff --git a/cmd/mount/fs.go b/cmd/mount/fs.go index f3b1fb493..c9e6bf834 100644 --- a/cmd/mount/fs.go +++ b/cmd/mount/fs.go @@ -10,12 +10,6 @@ import ( "github.com/ncw/rclone/fs" ) -// Default permissions -const ( - dirPerms = 0755 - filePerms = 0644 -) - // FS represents the top level filing system type FS struct { f fs.Fs @@ -30,6 +24,36 @@ func (f *FS) Root() (fusefs.Node, error) { return newDir(f.f, ""), nil } +// mountOptions configures the options from the command line flags +func mountOptions(device string) (options []fuse.MountOption) { + options = []fuse.MountOption{ + fuse.MaxReadahead(uint32(maxReadAhead)), + fuse.Subtype("rclone"), + fuse.FSName(device), fuse.VolumeName(device), + fuse.NoAppleDouble(), + fuse.NoAppleXattr(), + } + if allowNonEmpty { + options = append(options, fuse.AllowNonEmptyMount()) + } + if allowOther { + options = append(options, fuse.AllowOther()) + } + if allowRoot { + options = append(options, fuse.AllowRoot()) + } + if defaultPermissions { + options = append(options, fuse.DefaultPermissions()) + } + if readOnly { + options = append(options, fuse.ReadOnly()) + } + if writebackCache { + options = append(options, fuse.WritebackCache()) + } + return options +} + // mount the file system // // The mount point will be ready when this returns. @@ -37,7 +61,7 @@ func (f *FS) Root() (fusefs.Node, error) { // returns an error, and an error channel for the serve process to // report an error when fusermount is called. func mount(f fs.Fs, mountpoint string) (<-chan error, error) { - c, err := fuse.Mount(mountpoint) + c, err := fuse.Mount(mountpoint, mountOptions(f.Name()+":"+f.Root())...) if err != nil { return nil, err } diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go index e8a08e081..5f8e68f00 100644 --- a/cmd/mount/mount.go +++ b/cmd/mount/mount.go @@ -5,23 +5,56 @@ package mount import ( + "log" + "os" + "bazil.org/fuse" "github.com/ncw/rclone/cmd" "github.com/ncw/rclone/fs" "github.com/pkg/errors" "github.com/spf13/cobra" + "golang.org/x/sys/unix" ) // Globals var ( noModTime = false debugFUSE = false + // mount options + readOnly = false + allowNonEmpty = false + allowRoot = false + allowOther = false + defaultPermissions = false + writebackCache = false + maxReadAhead fs.SizeSuffix = 128 * 1024 + umask = 0 + uid = uint32(unix.Geteuid()) + gid = uint32(unix.Getegid()) + // foreground = false + // default permissions for directories - modified by umask in Mount + dirPerms = os.FileMode(0777) + filePerms = os.FileMode(0666) ) func init() { + umask = unix.Umask(0) // read the umask + unix.Umask(umask) // set it back to what it was cmd.Root.AddCommand(mountCmd) - mountCmd.Flags().BoolVarP(&noModTime, "no-modtime", "", false, "Don't read the modification time (can speed things up).") - mountCmd.Flags().BoolVarP(&debugFUSE, "debug-fuse", "", false, "Debug the FUSE internals - needs -v.") + mountCmd.Flags().BoolVarP(&noModTime, "no-modtime", "", noModTime, "Don't read the modification time (can speed things up).") + mountCmd.Flags().BoolVarP(&debugFUSE, "debug-fuse", "", debugFUSE, "Debug the FUSE internals - needs -v.") + // mount options + mountCmd.Flags().BoolVarP(&readOnly, "read-only", "", readOnly, "Mount read-only.") + mountCmd.Flags().BoolVarP(&allowNonEmpty, "allow-non-empty", "", allowNonEmpty, "Allow mounting over a non-empty directory.") + mountCmd.Flags().BoolVarP(&allowRoot, "allow-root", "", allowRoot, "Allow access to root user.") + mountCmd.Flags().BoolVarP(&allowOther, "allow-other", "", allowOther, "Allow access to other users.") + mountCmd.Flags().BoolVarP(&defaultPermissions, "default-permissions", "", defaultPermissions, "Makes kernel enforce access control based on the file mode.") + mountCmd.Flags().BoolVarP(&writebackCache, "write-back-cache", "", writebackCache, "Makes kernel buffer writes before sending them to rclone. Without this, writethrough caching is used.") + mountCmd.Flags().VarP(&maxReadAhead, "max-read-ahead", "", "The number of bytes that can be prefetched for sequential reads.") + mountCmd.Flags().IntVarP(&umask, "umask", "", umask, "Override the permission bits set by the filesystem.") + mountCmd.Flags().Uint32VarP(&uid, "uid", "", uid, "Override the uid field set by the filesystem.") + mountCmd.Flags().Uint32VarP(&gid, "gid", "", gid, "Override the gid field set by the filesystem.") + //mountCmd.Flags().BoolVarP(&foreground, "foreground", "", foreground, "Do not detach.") } var mountCmd = &cobra.Command{ @@ -85,10 +118,13 @@ mount won't do that, so will be less reliable than the rclone command. * Preserve timestamps * Move directories `, - RunE: func(command *cobra.Command, args []string) error { + Run: func(command *cobra.Command, args []string) { cmd.CheckArgs(2, 2, command, args) fdst := cmd.NewFsDst(args) - return Mount(fdst, args[1]) + err := Mount(fdst, args[1]) + if err != nil { + log.Fatalf("Fatal error: %v", err) + } }, } @@ -102,6 +138,10 @@ func Mount(f fs.Fs, mountpoint string) error { } } + // Set permissions + dirPerms = 0777 &^ os.FileMode(umask) + filePerms = 0666 &^ os.FileMode(umask) + // Mount it errChan, err := mount(f, mountpoint) if err != nil {