Fuse: Passthrough options to allow other-users access and mounting in empty directory. (#691)

This commit is contained in:
Piotr Tabor authored and GitHub committed 2020-10-31 21:57:27 -07:00
1 parent dddee8a5ec
commit bf729095dc
7 files changed
+62 -9

No files matched your search

+21 -2
View File
@@ -21,6 +21,9 @@ var (
mountPoint = mountCommand.Arg("mountPoint", "Mount point").Default("*").String()
mountPointBrowse = mountCommand.Flag("browse", "Open file browser").Bool()
mountTraceFS = mountCommand.Flag("trace-fs", "Trace filesystem operations").Bool()
mountFuseAllowOther = mountCommand.Flag("fuse-allow-other", "Allows other users to access the file system.").Bool()
mountFuseAllowNonEmptyMount = mountCommand.Flag("fuse-allow-non-empty-mount", "Allows the mounting over a non-empty directory. The files in it will be shadowed by the freshly created mount.").Bool()
)
func runMountCommand(ctx context.Context, rep repo.Repository) error {
@@ -42,7 +45,11 @@ func runMountCommand(ctx context.Context, rep repo.Repository) error {
entry = cachefs.Wrap(entry, newFSCache()).(fs.Directory)
ctrl, mountErr := mount.Directory(ctx, entry, *mountPoint)
ctrl, mountErr := mount.Directory(ctx, entry, *mountPoint,
mount.Options{
FuseAllowOther: *mountFuseAllowOther,
FuseAllowNonEmptyMount: *mountFuseAllowNonEmptyMount,
})
if mountErr != nil {
return errors.Wrap(mountErr, "mount error")
@@ -68,15 +75,27 @@ func runMountCommand(ctx context.Context, rep repo.Repository) error {
onCtrlC(func() {
close(ctrlCPressed)
})
select {
case <-ctrlCPressed:
log(ctx).Infof("Unmounting...")
return ctrl.Unmount(ctx)
// TODO: Consider lazy unmounting (-z) and polling till the filesystem is unmounted instead of failing with:
// "unmount error: exit status 1: fusermount: failed to unmount /tmp/kopia-mount719819963: Device or resource busy, try --help"
err := ctrl.Unmount(ctx)
if err != nil {
return err
}
case <-ctrl.Done():
log(ctx).Infof("Unmounted.")
return nil
}
// Reporting clean unmount in case of interrupt signal.
<-ctrl.Done()
log(ctx).Infof("Unmounted.")
return nil
}
func init() {
+1
View File
@@ -54,4 +54,5 @@ require (
google.golang.org/protobuf v1.25.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/kothar/go-backblaze.v0 v0.0.0-20191215213626-7594ed38700f
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6 // indirect
)
+4
View File
@@ -597,6 +597,7 @@ github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@@ -944,6 +945,7 @@ golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200814172026-c4923e618c08/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@@ -1127,6 +1129,8 @@ honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6 h1:z+/YqapuV7VZPvBb3GYmuEJbA88M3PFUxaHilHYVCpQ=
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+9
View File
@@ -15,3 +15,12 @@ type Controller interface {
MountPath() string
Done() <-chan struct{}
}
// Options cary set of flags passed to the mount layer.
type Options struct {
// AllowOther allows other users to access the file system. Supported on FUSE"
FuseAllowOther bool
// Allows the mounting over a non-empty directory. The files in it will be shadowed by the freshly created mount.
// Supported only on Fuse.
FuseAllowNonEmptyMount bool
}
+25 -5
View File
@@ -23,8 +23,27 @@ func (r *root) Root() (fusefs.Node, error) {
return r.Node, nil
}
func (mo *Options) toFuseMountOptions() []fuse.MountOption {
options := []fuse.MountOption{
fuse.ReadOnly(),
fuse.FSName("kopia"),
fuse.Subtype("kopia"),
fuse.VolumeName("Kopia"),
}
if mo.FuseAllowOther {
options = append(options, fuse.AllowOther())
}
if mo.FuseAllowNonEmptyMount {
options = append(options, fuse.AllowNonEmptyMount())
}
return options
}
// Directory mounts the given directory using FUSE.
func Directory(ctx context.Context, entry fs.Directory, mountPoint string) (Controller, error) {
func Directory(ctx context.Context, entry fs.Directory, mountPoint string, mountOptions Options) (Controller, error) {
isTempDir := false
if mountPoint == "*" {
@@ -40,13 +59,14 @@ func Directory(ctx context.Context, entry fs.Directory, mountPoint string) (Cont
rootNode := fusemount.NewDirectoryNode(entry)
fuseConnection, err := fuse.Mount(
mountPoint,
options := append(
mountOptions.toFuseMountOptions(),
fuse.ReadOnly(),
fuse.FSName("kopia"),
fuse.Subtype("kopia"),
fuse.VolumeName("Kopia"),
)
fuse.VolumeName("Kopia"))
fuseConnection, err := fuse.Mount(mountPoint, options...)
if err != nil {
return nil, errors.Wrap(err, "error creating fuse connection")
}
+1 -1
View File
@@ -14,7 +14,7 @@ import (
)
// Directory mounts a given directory under a provided drive letter.
func Directory(ctx context.Context, entry fs.Directory, driveLetter string) (Controller, error) {
func Directory(ctx context.Context, entry fs.Directory, driveLetter string, _ Options) (Controller, error) {
if !isValidWindowsDriveOrAsterisk(driveLetter) {
return nil, errors.Errorf("must be a valid drive letter or asteris")
}
+1 -1
View File
@@ -31,7 +31,7 @@ func (s *Server) handleMountCreate(ctx context.Context, r *http.Request, body []
log(ctx).Debugf("mount controller for %v not found, starting", oid)
var err error
c, err = mount.Directory(ctx, snapshotfs.DirectoryEntry(s.rep, oid, nil), "*")
c, err = mount.Directory(ctx, snapshotfs.DirectoryEntry(s.rep, oid, nil), "*", mount.Options{})
if err != nil {
return nil, internalServerError(err)