mirror of
https://github.com/kopia/kopia.git
synced 2026-10-24 15:18:48 -04:00
Fuse: Passthrough options to allow other-users access and mounting in empty directory. (#691)
This commit is contained in:
1 parent
dddee8a5ec
commit
bf729095dc
7 files changed
+62
-9
No files matched your search
+21
-2
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user