fixes #72 adds WithNoFollow option with caveat
diff --git a/README.md b/README.md
index 91f3084..be715ff 100644
--- a/README.md
+++ b/README.md
@@ -139,6 +139,24 @@
 `FilepathGlob`. In this context, "files" are anything that is not a directory
 or a symlink to a directory.
 
+Note: if combined with the WithNoFollow option, symlinks to directories _will_
+be included in the result since no attempt is made to follow the symlink.
+
+```go
+WithNoFollow()
+```
+
+If passed, doublestar will not follow symlinks while traversing the filesystem.
+However, due to io/fs's _very_ poor support for querying the filesystem about
+symlinks, there's a caveat here: if part of the pattern before any meta
+characters contains a reference to a symlink, it will be followed. For example,
+a pattern such as `path/to/symlink/*` will be followed assuming it is a valid
+symlink to a directory. However, from this same example, a pattern such as
+`path/to/**` will not traverse the `symlink`, nor would `path/*/symlink/*`
+
+Note: if combined with the WithFilesOnly option, symlinks to directories _will_
+be included in the result since no attempt is made to follow the symlink.
+
 ### Glob
 
 ```go
diff --git a/doublestar_test.go b/doublestar_test.go
index cddd619..82507d8 100644
--- a/doublestar_test.go
+++ b/doublestar_test.go
@@ -146,6 +146,7 @@
 	{"working-symlink/c/*", "working-symlink/c/d", true, true, nil, false, false, true, !onWindows, 1, 1},
 	{"working-sym*/*", "working-symlink/c", true, true, nil, false, false, true, !onWindows, 1, 1},
 	{"b/**/f", "b/symlink-dir/f", true, true, nil, false, false, false, !onWindows, 2, 2},
+	{"*/symlink-dir/*", "b/symlink-dir/f", true, true, nil, !onWindows, false, true, !onWindows, 2, 2},
 	{"e/**", "e/**", true, true, nil, false, false, false, !onWindows, 11, 6},
 	{"e/**", "e/*", true, true, nil, false, false, false, !onWindows, 11, 6},
 	{"e/**", "e/?", true, true, nil, false, false, false, !onWindows, 11, 6},
@@ -188,10 +189,18 @@
 	{"nopermission/file", "nopermission/file", true, false, nil, true, false, true, !onWindows, 0, 0},
 }
 
-// Calculate the number of results that we expect WithFilesOnly at runtime and
-// memoize them here
+// Calculate the number of results that we expect
+// WithFilesOnly at runtime and memoize them here
 var numResultsFilesOnly []int
 
+// Calculate the number of results that we expect
+// WithNoFollow at runtime and memoize them here
+var numResultsNoFollow []int
+
+// Calculate the number of results that we expect with all
+// of the options enabled at runtime and memoize them here
+var numResultsAllOpts []int
+
 func TestValidatePattern(t *testing.T) {
 	for idx, tt := range matchTests {
 		testValidatePatternWith(t, idx, tt)
@@ -374,8 +383,12 @@
 	doGlobTest(t, WithFilesOnly())
 }
 
+func TestGlobWithNoFollow(t *testing.T) {
+	doGlobTest(t, WithNoFollow())
+}
+
 func TestGlobWithAllOptions(t *testing.T) {
-	doGlobTest(t, WithFailOnIOErrors(), WithFailOnPatternNotExist(), WithFilesOnly())
+	doGlobTest(t, WithFailOnIOErrors(), WithFailOnPatternNotExist(), WithFilesOnly(), WithNoFollow())
 }
 
 func doGlobTest(t *testing.T, opts ...GlobOption) {
@@ -418,8 +431,12 @@
 	doGlobWalkTest(t, WithFilesOnly())
 }
 
+func TestGlobWalkWithNoFollow(t *testing.T) {
+	doGlobWalkTest(t, WithNoFollow())
+}
+
 func TestGlobWalkWithAllOptions(t *testing.T) {
-	doGlobWalkTest(t, WithFailOnIOErrors(), WithFailOnPatternNotExist(), WithFilesOnly())
+	doGlobWalkTest(t, WithFailOnIOErrors(), WithFailOnPatternNotExist(), WithFilesOnly(), WithNoFollow())
 }
 
 func doGlobWalkTest(t *testing.T, opts ...GlobOption) {
@@ -475,6 +492,10 @@
 	doFilepathGlobTest(t, WithFilesOnly())
 }
 
+func TestFilepathGlobWithNoFollow(t *testing.T) {
+	doFilepathGlobTest(t, WithNoFollow())
+}
+
 func doFilepathGlobTest(t *testing.T, opts ...GlobOption) {
 	glob := newGlob(opts...)
 	fsys := os.DirFS("test")
@@ -537,13 +558,19 @@
 			numResults = tt.winNumResults
 		}
 		if g.filesOnly {
-			numResults = numResultsFilesOnly[idx]
+			if g.noFollow {
+				numResults = numResultsAllOpts[idx]
+			} else {
+				numResults = numResultsFilesOnly[idx]
+			}
+		} else if g.noFollow {
+			numResults = numResultsNoFollow[idx]
 		}
 
 		if len(matches) != numResults {
 			t.Errorf("#%v. %v(%#q, %#v) = %#v - should have %#v results, got %#v", idx, fn, tt.pattern, g, matches, numResults, len(matches))
 		}
-		if !g.filesOnly && inSlice(tt.testPath, matches) != tt.shouldMatchGlob {
+		if !g.filesOnly && !g.noFollow && inSlice(tt.testPath, matches) != tt.shouldMatchGlob {
 			if tt.shouldMatchGlob {
 				t.Errorf("#%v. %v(%#q, %#v) = %#v - doesn't contain %v, but should", idx, fn, tt.pattern, g, matches, tt.testPath)
 			} else {
@@ -656,23 +683,40 @@
 	return len(diff) == 0
 }
 
-func buildNumResultsFilesOnly() {
+func buildNumResults() {
 	testLen := len(matchTests)
 	numResultsFilesOnly = make([]int, testLen, testLen)
+	numResultsNoFollow = make([]int, testLen, testLen)
+	numResultsAllOpts = make([]int, testLen, testLen)
 
 	fsys := os.DirFS("test")
 	g := newGlob()
 	for idx, tt := range matchTests {
 		if tt.testOnDisk {
-			count := 0
+			filesOnly := 0
+			noFollow := 0
+			allOpts := 0
 			GlobWalk(fsys, tt.pattern, func(p string, d fs.DirEntry) error {
 				isDir, _ := g.isDir(fsys, "", p, d)
 				if !isDir {
-					count++
+					filesOnly++
 				}
+
+				hasNoFollow := (strings.HasPrefix(tt.pattern, "working-symlink") || !strings.Contains(p, "working-symlink/")) && !strings.Contains(p, "/symlink-dir/")
+				if hasNoFollow {
+					noFollow++
+				}
+
+				if hasNoFollow && (!isDir || p == "working-symlink") {
+					allOpts++
+				}
+
 				return nil
 			})
-			numResultsFilesOnly[idx] = count
+
+			numResultsFilesOnly[idx] = filesOnly
+			numResultsNoFollow[idx] = noFollow
+			numResultsAllOpts[idx] = allOpts
 		}
 	}
 }
@@ -770,7 +814,7 @@
 	}
 
 	// initialize numResultsFilesOnly
-	buildNumResultsFilesOnly()
+	buildNumResults()
 
 	os.Exit(m.Run())
 }
diff --git a/glob.go b/glob.go
index 0393a27..519601b 100644
--- a/glob.go
+++ b/glob.go
@@ -389,7 +389,7 @@
 // represents a symbolic link, the link is followed by running fs.Stat() on
 // `path.Join(dir, name)` (if dir is "", name will be used without joining)
 func (g *glob) isDir(fsys fs.FS, dir, name string, info fs.DirEntry) (bool, error) {
-	if (info.Type() & fs.ModeSymlink) > 0 {
+	if !g.noFollow && (info.Type()&fs.ModeSymlink) > 0 {
 		p := name
 		if dir != "" {
 			p = path.Join(dir, name)
diff --git a/globoptions.go b/globoptions.go
index 6b3d057..9483c4b 100644
--- a/globoptions.go
+++ b/globoptions.go
@@ -7,6 +7,7 @@
 	failOnIOErrors        bool
 	failOnPatternNotExist bool
 	filesOnly             bool
+	noFollow              bool
 }
 
 // GlobOption represents a setting that can be passed to Glob, GlobWalk, and
@@ -52,12 +53,36 @@
 // FilepathGlob. If passed, doublestar will only return files that match the
 // pattern, not directories.
 //
+// Note: if combined with the WithNoFollow option, symlinks to directories
+// _will_ be included in the result since no attempt is made to follow the
+// symlink.
+//
 func WithFilesOnly() GlobOption {
 	return func(g *glob) {
 		g.filesOnly = true
 	}
 }
 
+// WithNoFollow is an option that can be passed to Glob, GlobWalk, or
+// FilepathGlob. If passed, doublestar will not follow symlinks while
+// traversing the filesystem. However, due to io/fs's _very_ poor support for
+// querying the filesystem about symlinks, there's a caveat here: if part of
+// the pattern before any meta characters contains a reference to a symlink, it
+// will be followed. For example, a pattern such as `path/to/symlink/*` will be
+// followed assuming it is a valid symlink to a directory. However, from this
+// same example, a pattern such as `path/to/**` will not traverse the
+// `symlink`, nor would `path/*/symlink/*`
+//
+// Note: if combined with the WithFilesOnly option, symlinks to directories
+// _will_ be included in the result since no attempt is made to follow the
+// symlink.
+//
+func WithNoFollow() GlobOption {
+	return func(g *glob) {
+		g.noFollow = true
+	}
+}
+
 // forwardErrIfFailOnIOErrors is used to wrap the return values of I/O
 // functions. When failOnIOErrors is enabled, it will return err; otherwise, it
 // always returns nil.
@@ -86,24 +111,31 @@
 	b.WriteString("opts: ")
 
 	hasOpts := false
-	if (g.failOnIOErrors) {
+	if g.failOnIOErrors {
 		b.WriteString("WithFailOnIOErrors")
 		hasOpts = true
 	}
-	if (g.failOnPatternNotExist) {
+	if g.failOnPatternNotExist {
 		if hasOpts {
 			b.WriteString(", ")
 		}
 		b.WriteString("WithFailOnPatternNotExist")
 		hasOpts = true
 	}
-	if (g.filesOnly) {
+	if g.filesOnly {
 		if hasOpts {
 			b.WriteString(", ")
 		}
 		b.WriteString("WithFilesOnly")
 		hasOpts = true
 	}
+	if g.noFollow {
+		if hasOpts {
+			b.WriteString(", ")
+		}
+		b.WriteString("WithNoFollow")
+		hasOpts = true
+	}
 
 	if !hasOpts {
 		b.WriteString("nil")
diff --git a/utils_test.go b/utils_test.go
index b4ca696..5488a86 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -1,8 +1,8 @@
 package doublestar
 
 import (
-	"testing"
 	"path/filepath"
+	"testing"
 )
 
 var filepathGlobTests = []string{