diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go
index 1fb08c7a2..e45ffb9d0 100644
--- a/cmd/restic/cmd_ls.go
+++ b/cmd/restic/cmd_ls.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	"context"
-	"path"
 	"strings"
 
 	"github.com/spf13/cobra"
@@ -76,6 +75,40 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
 		}
 	}
 
+	withinDir := func(nodepath string) bool {
+		if len(dirs) == 0 {
+			return true
+		}
+
+		for _, dir := range dirs {
+			// we're within one of the selected dirs, example:
+			//   nodepath: "/test/foo"
+			//   dir:      "/test"
+			if fs.HasPathPrefix(dir, nodepath) {
+				return true
+			}
+		}
+		return false
+	}
+
+	approachingMatchingTree := func(nodepath string) bool {
+		if len(dirs) == 0 {
+			return true
+		}
+
+		for _, dir := range dirs {
+			// the current node path is a prefix for one of the
+			// directories, so we're interested in something deeper in the
+			// tree. Example:
+			//   nodepath: "/test"
+			//   dir:      "/test/foo"
+			if fs.HasPathPrefix(nodepath, dir) {
+				return true
+			}
+		}
+		return false
+	}
+
 	repo, err := OpenRepository(gopts)
 	if err != nil {
 		return err
@@ -98,85 +131,31 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
 				return false, nil
 			}
 
-			// apply any directory filters
-			if len(dirs) > 0 {
-				nodeDir := path.Dir(nodepath)
+			if withinDir(nodepath) {
+				// if we're within a dir, print the node
+				Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong))
 
-				// this first iteration ensures we do not traverse branches that
-				// are not in matching trees or will not lead us to matching trees
-				var walk bool
-				for _, dir := range dirs {
-
-					// the current node path is a prefix for one of the
-					// directories, so we're interested in something deeper in the
-					// tree. Example:
-					//   nodepath: "/test"
-					//   dir:      "/test/foo"
-					approachingMatchingTree := fs.HasPathPrefix(nodepath, dir)
-
-					// we're within one of the selected dirs, example:
-					//   nodepath: "/test/foo"
-					//   dir:      "/test"
-					inMatchingTree := fs.HasPathPrefix(dir, nodepath)
-
-					// this condition is complex, but it basically requires that we
-					// are either approaching a matching tree (not yet deep enough)
-					// or: if recursive, we have entered a matching tree; if non-
-					// recursive, then that we are at exactly the right depth
-					// (we can do the walk correctly by just using the condition of
-					// "approachingMatchingTree || inMatchingTree", but it will be
-					// much slower for non-recursive queries since it will continue
-					// to traverse subtrees that are too deep and won't match -- this
-					// extra check allows us to return SkipNode if we've gone TOO deep,
-					// which skips all its subfolders)
-					if approachingMatchingTree || opts.Recursive || (inMatchingTree && dir == nodeDir) {
-						walk = true
-						break
-					}
-				}
-				if !walk {
-					if node.Type == "dir" {
-						// signal Walk() that it should not descend into the tree.
-						return false, walker.SkipNode
-					}
-
-					// we must not return SkipNode for non-dir nodes because
-					// then the remaining nodes in the same tree would be
-					// skipped, so return nil instead
-					return false, nil
-				}
-
-				// this second iteration ensures that we get an exact match
-				// according to the filter and whether we should match subfolders
-				var match bool
-				for _, dir := range dirs {
-					if nodepath == dir {
-						// special case: match the directory filter exactly,
-						// which may or may not be desirable depending on your
-						// use case (for example, this is unnecessary when
-						// wanting to simply list the contents of a folder,
-						// rather than all files matching a directory prefix)
-						match = true
-						break
-					}
-					if opts.Recursive && fs.HasPathPrefix(dir, nodepath) {
-						match = true
-						break
-					}
-					if !opts.Recursive && nodeDir == dir {
-						match = true
-						break
-					}
-				}
-				if !match {
+				// if recursive listing is requested, signal the walker that it
+				// should continue walking recursively
+				if opts.Recursive {
 					return false, nil
 				}
 			}
 
-			Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong))
+			// if there's an upcoming match deeper in the tree (but we're not
+			// there yet), signal the walker to descend into any subdirs
+			if approachingMatchingTree(nodepath) {
+				return false, nil
+			}
 
+			// otherwise, signal the walker to not walk recursively into any
+			// subdirs
+			if node.Type == "dir" {
+				return false, walker.SkipNode
+			}
 			return false, nil
 		})
+
 		if err != nil {
 			return err
 		}