Handle dangling symlinks when following symlinks

When globbing with following symlinks enabled, treat dangling symlinks
as files instead of erroring.

Bug: 202547639
Test: TestGlobFollowDanglingSymlinks
Change-Id: Ic1b241d3fcf1bc6989cb724d00c2b97fefa8dcdb
diff --git a/pathtools/glob.go b/pathtools/glob.go
index 14cdacf..4da4496 100644
--- a/pathtools/glob.go
+++ b/pathtools/glob.go
@@ -130,6 +130,10 @@
 			info, err = fs.Lstat(match)
 		} else {
 			info, err = fs.Stat(match)
+			if err != nil && os.IsNotExist(err) {
+				// ErrNotExist from Stat may be due to a dangling symlink, retry with lstat.
+				info, err = fs.Lstat(match)
+			}
 		}
 		if err != nil {
 			return GlobResult{}, err
diff --git a/pathtools/glob_test.go b/pathtools/glob_test.go
index d847bad..37af483 100644
--- a/pathtools/glob_test.go
+++ b/pathtools/glob_test.go
@@ -721,6 +721,57 @@
 	}
 }
 
+var globFollowDanglingSymlinkTestCases = []globTestCase{
+	{
+		pattern: `**/*`,
+		matches: []string{"a/", "b/", "c/", "d/", "dangling", "e", "f", "a/a/", "a/a/a", "a/a/f", "b/a/", "b/a/a", "b/a/f", "c/a", "c/f", "d/a", "d/f"},
+		deps:    []string{".", "a", "a/a", "b", "b/a", "c", "d"},
+	},
+	{
+		pattern: `dangling`,
+		matches: []string{"dangling"},
+		deps:    []string{"dangling"},
+	},
+}
+
+func TestMockGlobFollowDanglingSymlinks(t *testing.T) {
+	files := []string{
+		"a/a/a",
+		"a/a/f -> ../../f",
+		"b -> a",
+		"c -> a/a",
+		"d -> c",
+		"e -> a/a/a",
+		"f",
+		"dangling -> missing",
+	}
+
+	mockFiles := make(map[string][]byte)
+
+	for _, f := range files {
+		mockFiles[f] = nil
+	}
+
+	mock := MockFs(mockFiles)
+
+	for _, testCase := range globFollowDanglingSymlinkTestCases {
+		t.Run(testCase.pattern, func(t *testing.T) {
+			testGlob(t, mock, testCase, FollowSymlinks)
+		})
+	}
+}
+
+func TestGlobFollowDanglingSymlinks(t *testing.T) {
+	os.Chdir("testdata/dangling")
+	defer os.Chdir("../..")
+
+	for _, testCase := range globFollowDanglingSymlinkTestCases {
+		t.Run(testCase.pattern, func(t *testing.T) {
+			testGlob(t, OsFs, testCase, FollowSymlinks)
+		})
+	}
+}
+
 func testGlob(t *testing.T, fs FileSystem, testCase globTestCase, follow ShouldFollowSymlinks) {
 	t.Helper()
 	result, err := fs.Glob(testCase.pattern, testCase.excludes, follow)