mirror of
https://github.com/docker/compose.git
synced 2026-10-12 02:13:08 +00:00
fix(watch): skip unreadable directories instead of failing the watch
Signed-off-by: Endika Iglesias <[email protected]>
This commit is contained in:
committed by
Nicolas De loof
parent
7bc2630b65
commit
fb543842d8
@@ -113,6 +113,12 @@ func (d *naiveNotify) watchRecursively(dir string) error {
|
||||
|
||||
return filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
// A directory we are not allowed to read is not a reason to abandon the
|
||||
// whole watch: we simply cannot see inside it, so skip it and carry on.
|
||||
if os.IsPermission(err) {
|
||||
logrus.Debugf("Not watching %s: %v", path, err)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -130,6 +136,10 @@ func (d *naiveNotify) watchRecursively(dir string) error {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if os.IsPermission(err) {
|
||||
logrus.Debugf("Not watching %s: %v", path, err)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return fmt.Errorf("watcher.Add(%q): %w", path, err)
|
||||
}
|
||||
return nil
|
||||
@@ -180,6 +190,10 @@ func (d *naiveNotify) loop() { //nolint:gocyclo
|
||||
// TODO(dbentley): if there's a delete should we call d.watcher.Remove to prevent leaking?
|
||||
err := filepath.WalkDir(e.Name, func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
if os.IsPermission(err) {
|
||||
logrus.Debugf("Not watching %s: %v", path, err)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -157,3 +157,39 @@ func TestDontRecurseWhenWatchingParentsOfNonExistentFiles(t *testing.T) {
|
||||
t.Fatalf("watching more than 5 files: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
// A directory the current user cannot read costs us visibility into that
|
||||
// subtree, but it must not prevent the rest of the tree from being watched.
|
||||
func TestWatchRecursivelySkipsUnreadableDir(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("permission semantics differ on windows")
|
||||
}
|
||||
if os.Geteuid() == 0 {
|
||||
t.Skip("root bypasses the permission bit this test relies on")
|
||||
}
|
||||
|
||||
root := t.TempDir()
|
||||
unreadable := filepath.Join(root, "unreadable")
|
||||
if err := os.MkdirAll(filepath.Join(unreadable, "inner"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, "watched.txt"), []byte("x"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chmod(unreadable, 0o000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.Chmod(unreadable, 0o755) })
|
||||
|
||||
if _, err := os.ReadDir(unreadable); err == nil {
|
||||
t.Skip("could not make the directory unreadable in this environment")
|
||||
}
|
||||
|
||||
notify, err := NewWatcher([]string{root})
|
||||
assert.NilError(t, err)
|
||||
t.Cleanup(func() { _ = notify.Close() })
|
||||
|
||||
if err := notify.Start(); err != nil {
|
||||
t.Fatalf("Start() must not fail because of an unreadable directory: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user