From 49f9e67520bd66ccf39f7b595a016d9f214228e1 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 12 Jun 2026 22:21:32 +0200 Subject: [PATCH] mount: factor out mountpoint validation into helper --- cmd/restic/cmd_mount.go | 63 +++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 6e85901dc..34170047d 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -21,6 +21,7 @@ import ( "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/global" "github.com/restic/restic/internal/ui" + "github.com/restic/restic/internal/ui/progress" "github.com/restic/restic/internal/fuse" @@ -134,36 +135,9 @@ func runMount(ctx context.Context, opts MountOptions, gopts global.Options, args } mountpoint := args[0] - - // Check the existence of the mount point at the earliest stage to - // prevent unnecessary computations while opening the repository. - stat, err := os.Stat(mountpoint) - if errors.Is(err, os.ErrNotExist) { - printer.P("Mountpoint %s doesn't exist", mountpoint) - return errors.Fatal("invalid mountpoint") - } else if !stat.IsDir() { - printer.P("Mountpoint %s is not a directory", mountpoint) - return errors.Fatal("invalid mountpoint") - } - - err = unix.Access(mountpoint, unix.W_OK|unix.X_OK) - if err != nil { - printer.P("Mountpoint %s is not writeable or not executable", mountpoint) - return errors.Fatal("inaccessible mountpoint") - } - - // Refuse to mount onto (or under, or over) the local repository directory. - // Doing so makes the FUSE server read its own backend files through the - // mount it just created, deadlocking the kernel (GH #5234). - loc, err := location.Parse(gopts.Backends, gopts.Repo) - if err != nil { + if err := validateMountpoint(mountpoint, printer, gopts); err != nil { return err } - if loc.Scheme == "local" { - if err := checkMountpointOverlap(loc.Config.(*local.Config).Path, mountpoint); err != nil { - return err - } - } debug.Log("start mount") defer debug.Log("finish mount") @@ -247,6 +221,39 @@ func runMount(ctx context.Context, opts MountOptions, gopts global.Options, args return err } +func validateMountpoint(mountpoint string, printer progress.Printer, gopts global.Options) error { + // Check the existence of the mount point at the earliest stage to + // prevent unnecessary computations while opening the repository. + stat, err := os.Stat(mountpoint) + if errors.Is(err, os.ErrNotExist) { + printer.P("Mountpoint %s doesn't exist", mountpoint) + return errors.Fatal("invalid mountpoint") + } else if !stat.IsDir() { + printer.P("Mountpoint %s is not a directory", mountpoint) + return errors.Fatal("invalid mountpoint") + } + + err = unix.Access(mountpoint, unix.W_OK|unix.X_OK) + if err != nil { + printer.P("Mountpoint %s is not writeable or not executable", mountpoint) + return errors.Fatal("inaccessible mountpoint") + } + + // Refuse to mount onto (or under, or over) the local repository directory. + // Doing so makes the FUSE server read its own backend files through the + // mount it just created, deadlocking the kernel (GH #5234). + loc, err := location.Parse(gopts.Backends, gopts.Repo) + if err != nil { + return err + } + if loc.Scheme == "local" { + if err := checkMountpointOverlap(loc.Config.(*local.Config).Path, mountpoint); err != nil { + return err + } + } + return nil +} + // checkMountpointOverlap returns an error.Fatal if the local repository at // repoPath and the mountpoint overlap: equal paths, mountpoint nested inside // the repo, or the repo nested inside the mountpoint. Any overlap deadlocks