diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 6e85901dc..cb88a70e2 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -134,36 +134,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, 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 +220,36 @@ func runMount(ctx context.Context, opts MountOptions, gopts global.Options, args return err } +func validateMountpoint(mountpoint string, 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) { + return errors.Fatal(fmt.Sprintf("mountpoint %s does not exist", mountpoint)) + } else if !stat.IsDir() { + return errors.Fatal(fmt.Sprintf("mountpoint %s is not a directory", mountpoint)) + } + + err = unix.Access(mountpoint, unix.W_OK|unix.X_OK) + if err != nil { + return errors.Fatal(fmt.Sprintf("mountpoint %s is not writeable or not executable", 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