@ 261102.1 · fetching

261025.1 · 26ff936df038b6a62ec42cf18db27b2ea2bb8ec3

Check walker ancestor symlinks against the current root only

- A symlink in one root was skipped when its target was an ancestor of
another root, hiding files reachable only through it
- Fix and tests by @mabunemeh

Close #4944

reading declarations

Changes to src/reader_test.go. All files

src/reader_test.go

@@ -1,6 +1,10 @@ package fzf  import (+	"os"+	"path/filepath"+	"slices"+	"sync" 	"testing" 	"time" @@ -66,3 +70,70 @@ func TestReadFromCommand(t *testing.T) { 		t.Error("EvtReadFin should be set") 	} }++func walkFiles(t *testing.T, roots ...string) []string {+	t.Helper()+	var mu sync.Mutex+	files := []string{}+	reader := NewReader(func(data []byte) bool {+		mu.Lock()+		defer mu.Unlock()+		files = append(files, filepath.FromSlash(string(data)))+		return true+	}, util.NewEventBox(), nil, false, false)+	if !reader.readFiles(roots, walkerOpts{file: true, follow: true}, nil) {+		t.Fatal("file walk failed")+	}+	slices.Sort(files)+	return files+}++func TestReadFilesSymlinkAcrossRoots(t *testing.T) {+	base := t.TempDir()+	app := filepath.Join(base, "app")+	shared := filepath.Join(base, "shared")+	frontend := filepath.Join(shared, "frontend")+	os.MkdirAll(app, 0755)+	os.MkdirAll(frontend, 0755)+	os.WriteFile(filepath.Join(shared, "docs.txt"), nil, 0644)+	os.WriteFile(filepath.Join(frontend, "index.js"), nil, 0644)+	if err := os.Symlink(filepath.Join("..", "shared"), filepath.Join(app, "shared")); err != nil {+		t.Skipf("cannot create symlink: %v", err)+	}++	viaApp := []string{+		filepath.Join(app, "shared", "docs.txt"),+		filepath.Join(app, "shared", "frontend", "index.js"),+	}+	both := append(slices.Clone(viaApp), filepath.Join(frontend, "index.js"))+	slices.Sort(both)+	for _, tc := range []struct {+		roots []string+		want  []string+	}{+		{[]string{app}, viaApp},+		{[]string{app, frontend}, both},+		{[]string{frontend, app}, both},+	} {+		if files := walkFiles(t, tc.roots...); !slices.Equal(files, tc.want) {+			t.Errorf("roots = %v, files = %v, want %v", tc.roots, files, tc.want)+		}+	}+}++func TestReadFilesSkipsAncestorSymlinks(t *testing.T) {+	base := t.TempDir()+	project := filepath.Join(base, "project")+	os.Mkdir(project, 0755)+	file := filepath.Join(project, "file.txt")+	os.WriteFile(file, nil, 0644)+	os.WriteFile(filepath.Join(base, "outside.txt"), nil, 0644)+	for name, target := range map[string]string{"parent": "..", "self": "."} {+		if err := os.Symlink(target, filepath.Join(project, name)); err != nil {+			t.Skipf("cannot create symlink: %v", err)+		}+	}+	if files := walkFiles(t, project); !slices.Equal(files, []string{file}) {+		t.Errorf("files = %v, want [%s]", files, file)+	}+}