@@ -157,3 +157,39 @@ func TestDontRecurseWhenWatchingParentsOfNonExistentFiles(t *testing.T) {
157157 t .Fatalf ("watching more than 5 files: %d" , n )
158158 }
159159}
160+
161+ // A directory the current user cannot read costs us visibility into that
162+ // subtree, but it must not prevent the rest of the tree from being watched.
163+ func TestWatchRecursivelySkipsUnreadableDir (t * testing.T ) {
164+ if runtime .GOOS == "windows" {
165+ t .Skip ("permission semantics differ on windows" )
166+ }
167+ if os .Geteuid () == 0 {
168+ t .Skip ("root bypasses the permission bit this test relies on" )
169+ }
170+
171+ root := t .TempDir ()
172+ unreadable := filepath .Join (root , "unreadable" )
173+ if err := os .MkdirAll (filepath .Join (unreadable , "inner" ), 0o755 ); err != nil {
174+ t .Fatal (err )
175+ }
176+ if err := os .WriteFile (filepath .Join (root , "watched.txt" ), []byte ("x" ), 0o600 ); err != nil {
177+ t .Fatal (err )
178+ }
179+ if err := os .Chmod (unreadable , 0o000 ); err != nil {
180+ t .Fatal (err )
181+ }
182+ t .Cleanup (func () { _ = os .Chmod (unreadable , 0o755 ) })
183+
184+ if _ , err := os .ReadDir (unreadable ); err == nil {
185+ t .Skip ("could not make the directory unreadable in this environment" )
186+ }
187+
188+ notify , err := NewWatcher ([]string {root })
189+ assert .NilError (t , err )
190+ t .Cleanup (func () { _ = notify .Close () })
191+
192+ if err := notify .Start (); err != nil {
193+ t .Fatalf ("Start() must not fail because of an unreadable directory: %v" , err )
194+ }
195+ }
0 commit comments