From b1c8071163398c744cb02f5736f4d87f69f442b3 Mon Sep 17 00:00:00 2001
From: Pauline Middelink <middelin@google.com>
Date: Wed, 8 Mar 2017 19:59:19 +0100
Subject: [PATCH] Add filtering to `mount` command

---
 src/cmds/restic/cmd_mount.go | 16 ++++++++++++----
 src/restic/fuse/snapshot.go  | 17 +++++++++++++++--
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/src/cmds/restic/cmd_mount.go b/src/cmds/restic/cmd_mount.go
index a4b8340cd..20ce5dec3 100644
--- a/src/cmds/restic/cmd_mount.go
+++ b/src/cmds/restic/cmd_mount.go
@@ -35,6 +35,9 @@ type MountOptions struct {
 	OwnerRoot  bool
 	AllowRoot  bool
 	AllowOther bool
+	Host       string
+	Tags       []string
+	Paths      []string
 }
 
 var mountOptions MountOptions
@@ -42,9 +45,14 @@ var mountOptions MountOptions
 func init() {
 	cmdRoot.AddCommand(cmdMount)
 
-	cmdMount.Flags().BoolVar(&mountOptions.OwnerRoot, "owner-root", false, "use 'root' as the owner of files and dirs")
-	cmdMount.Flags().BoolVar(&mountOptions.AllowRoot, "allow-root", false, "allow root user to access the data in the mounted directory")
-	cmdMount.Flags().BoolVar(&mountOptions.AllowOther, "allow-other", false, "allow other users to access the data in the mounted directory")
+	mountFlags := cmdMount.Flags()
+	mountFlags.BoolVar(&mountOptions.OwnerRoot, "owner-root", false, "use 'root' as the owner of files and dirs")
+	mountFlags.BoolVar(&mountOptions.AllowRoot, "allow-root", false, "allow root user to access the data in the mounted directory")
+	mountFlags.BoolVar(&mountOptions.AllowOther, "allow-other", false, "allow other users to access the data in the mounted directory")
+
+	mountFlags.StringVarP(&mountOptions.Host, "host", "H", "", `only consider snapshots for this host`)
+	mountFlags.StringSliceVar(&mountOptions.Tags, "tag", nil, "only consider snapshots which include this `tag`")
+	mountFlags.StringSliceVar(&mountOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`")
 }
 
 func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error {
@@ -91,7 +99,7 @@ func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error {
 	Printf("Don't forget to umount after quitting!\n")
 
 	root := fs.Tree{}
-	root.Add("snapshots", fuse.NewSnapshotsDir(repo, opts.OwnerRoot))
+	root.Add("snapshots", fuse.NewSnapshotsDir(repo, opts.OwnerRoot, opts.Paths, opts.Tags, opts.Host))
 
 	debug.Log("serving mount at %v", mountpoint)
 	err = fs.Serve(c, &root)
diff --git a/src/restic/fuse/snapshot.go b/src/restic/fuse/snapshot.go
index 1e1092dea..2a654397b 100644
--- a/src/restic/fuse/snapshot.go
+++ b/src/restic/fuse/snapshot.go
@@ -32,6 +32,9 @@ var _ = fs.NodeStringLookuper(&SnapshotsDir{})
 type SnapshotsDir struct {
 	repo        restic.Repository
 	ownerIsRoot bool
+	paths       []string
+	tags        []string
+	host        string
 
 	// knownSnapshots maps snapshot timestamp to the snapshot
 	sync.RWMutex
@@ -40,12 +43,15 @@ type SnapshotsDir struct {
 }
 
 // NewSnapshotsDir returns a new dir object for the snapshots.
-func NewSnapshotsDir(repo restic.Repository, ownerIsRoot bool) *SnapshotsDir {
+func NewSnapshotsDir(repo restic.Repository, ownerIsRoot bool, paths []string, tags []string, host string) *SnapshotsDir {
 	debug.Log("fuse mount initiated")
 	return &SnapshotsDir{
 		repo:           repo,
-		knownSnapshots: make(map[string]SnapshotWithId),
 		ownerIsRoot:    ownerIsRoot,
+		paths:          paths,
+		tags:           tags,
+		host:           host,
+		knownSnapshots: make(map[string]SnapshotWithId),
 		processed:      restic.NewIDSet(),
 	}
 }
@@ -79,6 +85,13 @@ func (sn *SnapshotsDir) updateCache(ctx context.Context) error {
 			return err
 		}
 
+		// Filter snapshots we don't care for.
+		if (sn.host != "" && sn.host != snapshot.Hostname) ||
+			!snapshot.HasTags(sn.tags) ||
+			!snapshot.HasPaths(sn.paths) {
+			continue
+		}
+
 		timestamp := snapshot.Time.Format(time.RFC3339)
 		for i := 1; ; i++ {
 			if _, ok := sn.knownSnapshots[timestamp]; !ok {